diff --git a/src/Data.py b/src/Data.py index b51bb09b..a0f5e26c 100644 --- a/src/Data.py +++ b/src/Data.py @@ -1,7 +1,8 @@ import logging +from typing import Literal from .DataValidation import DataValidation, ValidationError -from .Helpers import load_data_file as helpers_load_data_file +from .Helpers import load_data_file as helpers_load_data_file, load_data_csv from .hooks.Data import \ after_load_game_file, \ @@ -23,13 +24,20 @@ def convert_to_list(data, property_name: str) -> list: class ManualFile: filename: str data_type: dict|list + filetype: Literal['json', 'csv'] - def __init__(self, filename, data_type): + def __init__(self, filename, data_type, filetype='json'): self.filename = filename self.data_type = data_type + self.filetype = filetype def load(self): - contents = helpers_load_data_file(self.filename) + if self.filetype == 'json': + contents = helpers_load_data_file(self.filename) + elif self.filetype == 'csv': + contents = load_data_csv(self.filename) + else: + raise ValueError(f"Unsupported filetype: {self.filetype}") if not contents and type(contents) != self.data_type: return self.data_type() @@ -44,6 +52,9 @@ def load(self): category_table = ManualFile('categories.json', dict).load() #dict meta_table = ManualFile('meta.json', dict).load() #dict +item_table.extend(ManualFile('items.csv', list, 'csv').load()) #list +location_table.extend(ManualFile('locations.csv', list, 'csv').load()) #list + # Removal of schemas in root of tables region_table.pop('$schema', '') category_table.pop('$schema', '') diff --git a/src/Helpers.py b/src/Helpers.py index b810fcfa..88f2804a 100644 --- a/src/Helpers.py +++ b/src/Helpers.py @@ -1,8 +1,9 @@ +import csv import os import pkgutil import json -from BaseClasses import MultiWorld, Item, Location +from BaseClasses import MultiWorld, Item from typing import Optional, List, TYPE_CHECKING from worlds.AutoWorld import World from .hooks.Helpers import before_is_category_enabled, before_is_item_enabled, before_is_location_enabled @@ -24,6 +25,17 @@ def load_data_file(*args) -> dict: return filedata +def load_data_csv(*args) -> list[dict]: + fname = os.path.join("data", *args) + + try: + lines = pkgutil.get_data(__name__, fname).decode().splitlines() + except: + lines = [] + filedata = list(csv.DictReader(lines)) + + return filedata + def is_option_enabled(multiworld: MultiWorld, player: int, name: str) -> bool: return get_option_value(multiworld, player, name) > 0 diff --git a/src/Items.py b/src/Items.py index 6a25a4fc..26f33224 100644 --- a/src/Items.py +++ b/src/Items.py @@ -32,6 +32,9 @@ item_table[key]["id"] = count item_table[key]["progression"] = val["progression"] if "progression" in val else False + if isinstance(val.get("category", []), str): + item_table[key]["category"] = [val["category"]] + count += 1 for item in item_table: diff --git a/src/Locations.py b/src/Locations.py index 9680e5d7..d94094d8 100644 --- a/src/Locations.py +++ b/src/Locations.py @@ -24,9 +24,12 @@ location_table[key]["id"] = count - if not "region" in location_table[key]: + if "region" not in location_table[key]: location_table[key]["region"] = "Manual" # all locations are in the same region for Manual + if isinstance(location_table[key].get("category", []), str): + location_table[key]["category"] = [location_table[key]["category"]] + count += 1 if not victory_names: diff --git a/src/__init__.py b/src/__init__.py index f7b4c6b7..03b3d82e 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -221,6 +221,9 @@ def create_item(self, name: str) -> Item: if "progression_skip_balancing" in item and item["progression_skip_balancing"]: classification = ItemClassification.progression_skip_balancing + if "classification" in item: + classification = ItemClassification[item["classification"]] + item_object = ManualItem(name, classification, self.item_name_to_id[name], player=self.player) diff --git a/src/data/categories.json b/src/data/categories.json index bb0dbf14..9cf1d6dd 100644 --- a/src/data/categories.json +++ b/src/data/categories.json @@ -5,5 +5,8 @@ }, "Example Yaml-option category": { "yaml_option": ["DLC_enabled"] + }, + "Stage": { + "yaml_option": ["randomize_stages"] } } diff --git a/src/data/game.json b/src/data/game.json index ab01a191..45d761ac 100644 --- a/src/data/game.json +++ b/src/data/game.json @@ -26,6 +26,10 @@ { "items": ["Deadpool"], "yaml_option": ["start_with_deadpool"] + }, + { + "item_categories": ["Stage"], + "yaml_option": ["randomize_stages"] } ], "death_link": false diff --git a/src/data/items.csv b/src/data/items.csv new file mode 100644 index 00000000..437e947f --- /dev/null +++ b/src/data/items.csv @@ -0,0 +1,10 @@ +name,category,classification +Danger Room,Stage,progression +Shadowland,Stage,progression +S.H.I.E.L.D Air Show,Stage,progression +Asgard: Sea of Space,Stage,progression +Days of Future Past,Stage,progression +City that Never Sleeps,Stage,progression +Chaos at Tricell,Stage,progression +Demon Village Redux,Stage,progression +Bonne Wonderland,Stage,progression