diff --git a/all-batches.bat b/all-batches.bat index 086a4be..732ef63 100644 --- a/all-batches.bat +++ b/all-batches.bat @@ -4,3 +4,4 @@ python sheditor.py %1 --replace-original --add-item-set pack_medical.txt python sheditor.py %1 --replace-original --add-item-set pack_trade.txt python sheditor.py %1 --replace-original --add-item-set pack_weapons_basic.txt python sheditor.py %1 --replace-original --add-item-set pack_weapons_advanced.txt +python sheditor.py %1 --replace-original --add-item-set pack_fuel.txt diff --git a/pack_food.txt b/pack_food.txt index e8d2df2..62eb866 100644 --- a/pack_food.txt +++ b/pack_food.txt @@ -4,4 +4,5 @@ 707 20 # Artificial meats 712 30 # Space food 2657 20 # Nuts and seeds -71 20 # Biomatter \ No newline at end of file +71 20 # Biomatter +16 50 # Water \ No newline at end of file diff --git a/pack_fuel.txt b/pack_fuel.txt new file mode 100644 index 0000000..5449acf --- /dev/null +++ b/pack_fuel.txt @@ -0,0 +1,5 @@ +# Fuel Pack +172 200 # Hyperium +158 100 # Energium +178 100 # Hyperfuel +174 50 # Energy rods \ No newline at end of file diff --git a/research2.tsv b/research2.tsv new file mode 100644 index 0000000..ab3fc84 --- /dev/null +++ b/research2.tsv @@ -0,0 +1,76 @@ +# Tree id 2535 + +2532 Unknown +2533 Unknown +2539 Unknown +2559 Unknown +2563 Unknown +2564 Unknown +2565 Unknown +2566 Unknown +2567 Unknown +2568 Unknown +2569 Unknown +2570 Unknown +2571 Unknown +2572 Unknown +2573 Unknown +2575 Unknown +2576 Unknown +2577 Unknown +2589 Unknown +2590 Unknown +2591 Unknown +2592 Unknown +2594 Unknown +2595 Unknown +2596 Unknown +2597 Unknown +2598 Unknown +2599 Unknown +2600 Unknown +2601 Unknown +2602 Unknown +2604 Unknown +2605 Unknown +2606 Unknown +2607 Unknown +2612 Unknown +2613 Unknown +2614 Unknown +2617 Unknown +2619 Unknown +2622 Unknown +2623 Unknown +2626 Unknown +2628 Unknown +2629 Unknown +2630 Unknown +2694 Unknown +2847 Unknown +3024 Unknown +3025 Unknown +3114 Unknown +3115 Unknown +3116 Unknown +3119 Unknown +3122 Unknown +3124 Unknown +3125 Unknown +3127 Unknown +3128 Unknown +3129 Unknown +3130 Unknown +3417 Unknown +3420 Unknown +3421 Unknown +3422 Unknown +3423 Unknown +3464 Unknown +3704 Unknown +3705 Unknown +3706 Unknown +3707 Unknown +3708 Unknown +3709 Unknown +3710 Unknown \ No newline at end of file diff --git a/sheditor.py b/sheditor.py index 6d6568f..a001cef 100644 --- a/sheditor.py +++ b/sheditor.py @@ -12,6 +12,8 @@ DEFAULT_SAVEGAMEPATH = "c:\\Program Files (x86)\\GOG Galaxy\\Games\\SpaceHaven\\ # Only "normal storage" is used to insert requested items normal_storage_ids = [82, 632] +weapon_ids = [726, 725, 3383, 760, 3069, 3070, 3071, 3072, 3384] + storage_ids = { 82: {"name": "Small storage", "capacity": 50}, 632: {"name": "Large storage", "capacity": 250}, @@ -51,6 +53,38 @@ class Item: self.name = name self.quantity = quantity +class ResearchItem: + + research_ids = None + + @classmethod + def load_ids(cls, item_filename): + if cls.research_ids is not None: + return + else: + cls.research_ids = {} + + with open(item_filename, 'r') as item_file: + item_reader = csv.reader(item_file, delimiter='\t') + for row in item_reader: + # console.print(row) + if len(row) == 0 or row[0][0] == '#': + continue + cls.research_ids[int(row[0])] = row[1].strip() + + @classmethod + def get_name_from_code(cls, code): + return cls.research_ids.get(code, None) if cls.research_ids is not None else None + + def __init__(self, id, active_stage): + self.id = id + self.name = ResearchItem.get_name_from_code(id) + self.active_stage = active_stage + self.stage_states = [] + + def __str__(self): + return "{} : {} : {}".format(self.id, self.name, self.active_stage) + # A single storage area, with a list of contents (Items) class StorageArea: @@ -132,6 +166,7 @@ class Character: self.skills = [] self.attributes = [] + self.conditions = [] def set_skills(self, skill_list): # Expected format is a list of dictionaries @@ -155,6 +190,9 @@ class Character: # Max POINTS is 6 for attribute in self.attributes: attribute['points'] = 6 + + def clear_conditions(self): + self.conditions = [1550, 2246, 3311] def clone(self, new_name): # How to deep copy the skills/attributes appropriately? @@ -224,6 +262,13 @@ class Ship: total += area.get_total_occupancy() print(total) + def consolidate_weapons(self): + normal_storage_areas = [sa for sa in self.storage_areas if sa.is_normal_storage] + for area in normal_storage_areas: + for item in area.items: + if item.code in weapon_ids: + console.print("{} : {}".format(item.code, item.quantity)) + class Player: @@ -237,6 +282,7 @@ class GameData: def __init__(self, soup, item_database): self.player = None self.ships = [] + self.research = [] self.soup = soup self.item_database = item_database @@ -320,6 +366,20 @@ class GameData: attributes.append(attribute_dict) character.set_attributes(attributes) + # Step 5 - Research Data + # console.print('Finding research...') + res_tag = self.soup.find("research", treeId=True) + # console.print(res_tag) + item_ids = [] + for item in res_tag.find_all('l', techId=True): + # console.print(item['techId']) + active_stage = int(item['activeStageIndex']) + techId = int(item['techId']) + item_ids.append(int(item['techId'])) + self.research.append(ResearchItem(techId, active_stage)) + # console.print(sorted(item_ids)) + # [console.print(id) for id in sorted(item_ids)] + def writeback(self): def replace_id(dict, old_key, new_key): dict_copy = dict.copy() @@ -344,9 +404,9 @@ class GameData: self.player.tag['ca'] = self.player.currency for ship in self.ships: + # console.print('Doing chars...') for character in ship.characters: # Cloned character tags have to be added to the list - print('Doing chars...') if character.is_clone: print("ADDING CLONED CHARACTER") charlist_tag = ship.tag.find('characters') @@ -365,6 +425,19 @@ class GameData: new_tag = self.soup.new_tag('a', attrs=attribute) attribute_tag.append(new_tag) + condition_tag = character.tag.find('conditions') + condition_tag.clear() + for condition in character.conditions: + attrs = { "id": str(condition), "level" : "1", "rs" : "1"} + new_tag = self.soup.new_tag('c', attrs=attrs) + # What do the tags mean with ht and wt attrs? + # What does the ac attr mean on the m mood sub tag mean? + new_mood_tag = self.soup.new_tag('mood') + new_submood_tag = self.soup.new_tag('m', ac="5") + new_tag.append(new_mood_tag) + new_mood_tag.append(new_submood_tag) + condition_tag.append(new_tag) + for storage_area in ship.storage_areas: area_tag = storage_area.tag area_tag.clear() @@ -387,13 +460,14 @@ class GameData: for character in ship.characters: character.maximize_skills() character.maximize_attributes() + character.clear_conditions() def add_currency(self, amount): self.player.currency += amount def clone_character(self, character_name, new_name): - print("Clone char method called") - print("Warning names are case sensitive!") + console.print("Clone char method called") + console.print("Warning names are case sensitive!") for ship in self.ships: for character in ship.characters: if character.name == character_name: @@ -470,6 +544,15 @@ class GameData: for ship in self.ships: ship.redistribute_storage() + def list_research(self): + for research in self.research: + console.print(research) + + def consolidate_weapons(self): + for ship in self.ships: + if ship.owner == "Player": + ship.consolidate_weapons() + def parse_item_file(filename): @@ -501,6 +584,8 @@ def main(): parser.add_argument('--detailed-items', required=False, action='store_true', help='Print a detailed item listing from player inventory') parser.add_argument('--detailed-chars', required=False, action='store_true', help='Print a comprehensive listing of player character details') parser.add_argument('--redistribute', required=False, action='store_true', help='Redistribute internal storage') + parser.add_argument('--list-research', required=False, action='store_true', help='List all research/research states') + parser.add_argument('--consolidate-weapons', required=False, action='store_true', help='Put all weapons in one storage area') parser.add_argument('--replace-original', required=False, action='store_true', help='Replace original file instead of creating edited alternative. Renames original for backup, but USE WITH CAUTION') args = parser.parse_args() @@ -527,6 +612,9 @@ def main(): Character.load_ids('char_skills.tsv', 'char_attributes.tsv', 'char_traits.tsv', 'char_conditions.tsv') console.print("Character code database successfully loaded.") console.print() + ResearchItem.load_ids('research2.tsv') + console.print("Research name database successfully loaded.") + console.print() game_data = GameData(soup, Item) game_data.populate() @@ -534,27 +622,32 @@ def main(): edits_made = False if args.buff_chars: + console.print("Buffing chars...") game_data.buff_characters() edits_made = True print("Buffed chars") if args.add_item: + console.print("Adding item...") game_data.add_item(args.add_item[0], args.add_item[1]) edits_made = True if args.money: + console.print("Adding currency...") game_data.add_currency(args.money[0]) edits_made = True if args.list_ships: + console.print("Listing ships...") game_data.print_summary() if args.clone_character: - print("Clone char requested.") + console.print("Char clone requested...") game_data.clone_character(args.clone_character[0], args.clone_character[1]) edits_made = True if args.add_item_set: + console.print("Adding item set...") item_list = parse_item_file(args.add_item_set[0]) # console.print(item_list) console.print("Items to be added:") @@ -564,14 +657,25 @@ def main(): edits_made = True if args.detailed_items: + console.print("Printing detailed item list...") game_data.print_detailed_item_summary() if args.detailed_chars: + console.print("Printing detailed character list...") game_data.print_detailed_character_summary() if args.redistribute: + console.print("Item redistribution requested...") game_data.redistribute() + if args.list_research: + console.print("Listing research status...") + game_data.list_research() + + if args.consolidate_weapons: + console.print("Consolidating weapons...") + game_data.consolidate_weapons() + game_data.writeback() if args.test_gamedata: