From 87252c14aae238ead03ec76ed9b7ca71f4920428 Mon Sep 17 00:00:00 2001 From: Alchav <59858495+Alchav@users.noreply.github.com> Date: Wed, 6 Dec 2023 12:24:59 -0500 Subject: [PATCH] FFMQ: Update to FFMQR 1.5 (#2568) FFMQR was just updated to 1.5, adding a number of new options. This brings these updates to AP. --- worlds/ffmq/Items.py | 1 + worlds/ffmq/Options.py | 102 +++++++++++++++++++++++++++++++- worlds/ffmq/Output.py | 80 ++++++++++++++----------- worlds/ffmq/__init__.py | 4 +- worlds/ffmq/data/entrances.yaml | 35 +++++++++-- worlds/ffmq/data/rooms.yaml | 32 +++++----- worlds/ffmq/data/settings.yaml | 43 ++++++++++++++ 7 files changed, 239 insertions(+), 58 deletions(-) diff --git a/worlds/ffmq/Items.py b/worlds/ffmq/Items.py index 7660bd5d..3eab5dd5 100644 --- a/worlds/ffmq/Items.py +++ b/worlds/ffmq/Items.py @@ -187,6 +187,7 @@ item_table = { "Pazuzu 5F": ItemData(None, ItemClassification.progression), "Pazuzu 6F": ItemData(None, ItemClassification.progression), "Dark King": ItemData(None, ItemClassification.progression), + "Tristam Bone Item Given": ItemData(None, ItemClassification.progression), #"Barred": ItemData(None, ItemClassification.progression), } diff --git a/worlds/ffmq/Options.py b/worlds/ffmq/Options.py index 2746bb19..eaf30974 100644 --- a/worlds/ffmq/Options.py +++ b/worlds/ffmq/Options.py @@ -1,4 +1,4 @@ -from Options import Choice, FreeText, Toggle +from Options import Choice, FreeText, Toggle, Range class Logic(Choice): @@ -131,6 +131,21 @@ class EnemizerAttacks(Choice): default = 0 +class EnemizerGroups(Choice): + """Set which enemy groups will be affected by Enemizer.""" + display_name = "Enemizer Groups" + option_mobs_only = 0 + option_mobs_and_bosses = 1 + option_mobs_bosses_and_dark_king = 2 + default = 1 + + +class ShuffleResWeakType(Toggle): + """Resistance and Weakness types are shuffled for all enemies.""" + display_name = "Shuffle Resistance/Weakness Types" + default = 0 + + class ShuffleEnemiesPositions(Toggle): """Instead of their original position in a given map, enemies are randomly placed.""" display_name = "Shuffle Enemies' Positions" @@ -231,6 +246,81 @@ class BattlefieldsBattlesQuantities(Choice): option_random_one_through_ten = 6 +class CompanionLevelingType(Choice): + """Set how companions gain levels. + Quests: Complete each companion's individual quest for them to promote to their second version. + Quests Extended: Each companion has four exclusive quests, leveling each time a quest is completed. + Save the Crystals (All): Each time a Crystal is saved, all companions gain levels. + Save the Crystals (Individual): Each companion will level to their second version when a specific Crystal is saved. + Benjamin Level: Companions' level tracks Benjamin's.""" + option_quests = 0 + option_quests_extended = 1 + option_save_crystals_individual = 2 + option_save_crystals_all = 3 + option_benjamin_level = 4 + option_benjamin_level_plus_5 = 5 + option_benjamin_level_plus_10 = 6 + default = 0 + display_name = "Companion Leveling Type" + + +class CompanionSpellbookType(Choice): + """Update companions' spellbook. + Standard: Original game spellbooks. + Standard Extended: Add some extra spells. Tristam gains Exit and Quake and Reuben gets Blizzard. + Random Balanced: Randomize the spellbooks with an appropriate mix of spells. + Random Chaos: Randomize the spellbooks in total free-for-all.""" + option_standard = 0 + option_standard_extended = 1 + option_random_balanced = 2 + option_random_chaos = 3 + default = 0 + display_name = "Companion Spellbook Type" + + +class StartingCompanion(Choice): + """Set a companion to start with. + Random Companion: Randomly select one companion. + Random Plus None: Randomly select a companion, with the possibility of none selected.""" + display_name = "Starting Companion" + default = 0 + option_none = 0 + option_kaeli = 1 + option_tristam = 2 + option_phoebe = 3 + option_reuben = 4 + option_random_companion = 5 + option_random_plus_none = 6 + + +class AvailableCompanions(Range): + """Select randomly which companions will join your party. Unavailable companions can still be reached to get their items and complete their quests if needed. + Note: If a Starting Companion is selected, it will always be available, regardless of this setting.""" + display_name = "Available Companions" + default = 4 + range_start = 0 + range_end = 4 + + +class CompanionsLocations(Choice): + """Set the primary location of companions. Their secondary location is always the same. + Standard: Companions will be at the same locations as in the original game. + Shuffled: Companions' locations are shuffled amongst themselves. + Shuffled Extended: Add all the Temples, as well as Phoebe's House and the Rope Bridge as possible locations.""" + display_name = "Companions' Locations" + default = 0 + option_standard = 0 + option_shuffled = 1 + option_shuffled_extended = 2 + + +class KaelisMomFightsMinotaur(Toggle): + """Transfer Kaeli's requirements (Tree Wither, Elixir) and the two items she's giving to her mom. + Kaeli will be available to join the party right away without the Tree Wither.""" + display_name = "Kaeli's Mom Fights Minotaur" + default = 0 + + option_definitions = { "logic": Logic, "brown_boxes": BrownBoxes, @@ -238,12 +328,21 @@ option_definitions = { "shattered_sky_coin_quantity": ShatteredSkyCoinQuantity, "starting_weapon": StartingWeapon, "progressive_gear": ProgressiveGear, + "leveling_curve": LevelingCurve, + "starting_companion": StartingCompanion, + "available_companions": AvailableCompanions, + "companions_locations": CompanionsLocations, + "kaelis_mom_fight_minotaur": KaelisMomFightsMinotaur, + "companion_leveling_type": CompanionLevelingType, + "companion_spellbook_type": CompanionSpellbookType, "enemies_density": EnemiesDensity, "enemies_scaling_lower": EnemiesScalingLower, "enemies_scaling_upper": EnemiesScalingUpper, "bosses_scaling_lower": BossesScalingLower, "bosses_scaling_upper": BossesScalingUpper, "enemizer_attacks": EnemizerAttacks, + "enemizer_groups": EnemizerGroups, + "shuffle_res_weak_types": ShuffleResWeakType, "shuffle_enemies_position": ShuffleEnemiesPositions, "progressive_formations": ProgressiveFormations, "doom_castle_mode": DoomCastle, @@ -253,6 +352,5 @@ option_definitions = { "crest_shuffle": CrestShuffle, "shuffle_battlefield_rewards": ShuffleBattlefieldRewards, "map_shuffle_seed": MapShuffleSeed, - "leveling_curve": LevelingCurve, "battlefields_battles_quantities": BattlefieldsBattlesQuantities, } diff --git a/worlds/ffmq/Output.py b/worlds/ffmq/Output.py index c4c4605c..98ecd289 100644 --- a/worlds/ffmq/Output.py +++ b/worlds/ffmq/Output.py @@ -35,46 +35,58 @@ def generate_output(self, output_directory): "item_name": location.item.name}) def cc(option): - return option.current_key.title().replace("_", "").replace("OverworldAndDungeons", "OverworldDungeons") + return option.current_key.title().replace("_", "").replace("OverworldAndDungeons", + "OverworldDungeons").replace("MobsAndBosses", "MobsBosses").replace("MobsBossesAndDarkKing", + "MobsBossesDK").replace("BenjaminLevelPlus", "BenPlus").replace("BenjaminLevel", "BenPlus0").replace( + "RandomCompanion", "Random") def tf(option): return True if option else False options = deepcopy(settings_template) options["name"] = self.multiworld.player_name[self.player] - option_writes = { - "enemies_density": cc(self.multiworld.enemies_density[self.player]), - "chests_shuffle": "Include", - "shuffle_boxes_content": self.multiworld.brown_boxes[self.player] == "shuffle", - "npcs_shuffle": "Include", - "battlefields_shuffle": "Include", - "logic_options": cc(self.multiworld.logic[self.player]), - "shuffle_enemies_position": tf(self.multiworld.shuffle_enemies_position[self.player]), - "enemies_scaling_lower": cc(self.multiworld.enemies_scaling_lower[self.player]), - "enemies_scaling_upper": cc(self.multiworld.enemies_scaling_upper[self.player]), - "bosses_scaling_lower": cc(self.multiworld.bosses_scaling_lower[self.player]), - "bosses_scaling_upper": cc(self.multiworld.bosses_scaling_upper[self.player]), - "enemizer_attacks": cc(self.multiworld.enemizer_attacks[self.player]), - "leveling_curve": cc(self.multiworld.leveling_curve[self.player]), - "battles_quantity": cc(self.multiworld.battlefields_battles_quantities[self.player]) if - self.multiworld.battlefields_battles_quantities[self.player].value < 5 else - "RandomLow" if - self.multiworld.battlefields_battles_quantities[self.player].value == 5 else - "RandomHigh", - "shuffle_battlefield_rewards": tf(self.multiworld.shuffle_battlefield_rewards[self.player]), - "random_starting_weapon": True, - "progressive_gear": tf(self.multiworld.progressive_gear[self.player]), - "tweaked_dungeons": tf(self.multiworld.tweak_frustrating_dungeons[self.player]), - "doom_castle_mode": cc(self.multiworld.doom_castle_mode[self.player]), - "doom_castle_shortcut": tf(self.multiworld.doom_castle_shortcut[self.player]), - "sky_coin_mode": cc(self.multiworld.sky_coin_mode[self.player]), - "sky_coin_fragments_qty": cc(self.multiworld.shattered_sky_coin_quantity[self.player]), - "enable_spoilers": False, - "progressive_formations": cc(self.multiworld.progressive_formations[self.player]), - "map_shuffling": cc(self.multiworld.map_shuffle[self.player]), - "crest_shuffle": tf(self.multiworld.crest_shuffle[self.player]), - } + "enemies_density": cc(self.multiworld.enemies_density[self.player]), + "chests_shuffle": "Include", + "shuffle_boxes_content": self.multiworld.brown_boxes[self.player] == "shuffle", + "npcs_shuffle": "Include", + "battlefields_shuffle": "Include", + "logic_options": cc(self.multiworld.logic[self.player]), + "shuffle_enemies_position": tf(self.multiworld.shuffle_enemies_position[self.player]), + "enemies_scaling_lower": cc(self.multiworld.enemies_scaling_lower[self.player]), + "enemies_scaling_upper": cc(self.multiworld.enemies_scaling_upper[self.player]), + "bosses_scaling_lower": cc(self.multiworld.bosses_scaling_lower[self.player]), + "bosses_scaling_upper": cc(self.multiworld.bosses_scaling_upper[self.player]), + "enemizer_attacks": cc(self.multiworld.enemizer_attacks[self.player]), + "leveling_curve": cc(self.multiworld.leveling_curve[self.player]), + "battles_quantity": cc(self.multiworld.battlefields_battles_quantities[self.player]) if + self.multiworld.battlefields_battles_quantities[self.player].value < 5 else + "RandomLow" if + self.multiworld.battlefields_battles_quantities[self.player].value == 5 else + "RandomHigh", + "shuffle_battlefield_rewards": tf(self.multiworld.shuffle_battlefield_rewards[self.player]), + "random_starting_weapon": True, + "progressive_gear": tf(self.multiworld.progressive_gear[self.player]), + "tweaked_dungeons": tf(self.multiworld.tweak_frustrating_dungeons[self.player]), + "doom_castle_mode": cc(self.multiworld.doom_castle_mode[self.player]), + "doom_castle_shortcut": tf(self.multiworld.doom_castle_shortcut[self.player]), + "sky_coin_mode": cc(self.multiworld.sky_coin_mode[self.player]), + "sky_coin_fragments_qty": cc(self.multiworld.shattered_sky_coin_quantity[self.player]), + "enable_spoilers": False, + "progressive_formations": cc(self.multiworld.progressive_formations[self.player]), + "map_shuffling": cc(self.multiworld.map_shuffle[self.player]), + "crest_shuffle": tf(self.multiworld.crest_shuffle[self.player]), + "enemizer_groups": cc(self.multiworld.enemizer_groups[self.player]), + "shuffle_res_weak_type": tf(self.multiworld.shuffle_res_weak_types[self.player]), + "companion_leveling_type": cc(self.multiworld.companion_leveling_type[self.player]), + "companion_spellbook_type": cc(self.multiworld.companion_spellbook_type[self.player]), + "starting_companion": cc(self.multiworld.starting_companion[self.player]), + "available_companions": ["Zero", "One", "Two", + "Three", "Four"][self.multiworld.available_companions[self.player].value], + "companions_locations": cc(self.multiworld.companions_locations[self.player]), + "kaelis_mom_fight_minotaur": tf(self.multiworld.kaelis_mom_fight_minotaur[self.player]), + } + for option, data in option_writes.items(): options["Final Fantasy Mystic Quest"][option][data] = 1 @@ -83,7 +95,7 @@ def generate_output(self, output_directory): 'utf8') self.rom_name_available_event.set() - setup = {"version": "1.4", "name": self.multiworld.player_name[self.player], "romname": rom_name, "seed": + setup = {"version": "1.5", "name": self.multiworld.player_name[self.player], "romname": rom_name, "seed": hex(self.multiworld.per_slot_randoms[self.player].randint(0, 0xFFFFFFFF)).split("0x")[1].upper()} starting_items = [output_item_name(item) for item in self.multiworld.precollected_items[self.player]] diff --git a/worlds/ffmq/__init__.py b/worlds/ffmq/__init__.py index b6f19a77..b995cc42 100644 --- a/worlds/ffmq/__init__.py +++ b/worlds/ffmq/__init__.py @@ -108,8 +108,10 @@ class FFMQWorld(World): map_shuffle = multiworld.map_shuffle[world.player].value crest_shuffle = multiworld.crest_shuffle[world.player].current_key battlefield_shuffle = multiworld.shuffle_battlefield_rewards[world.player].current_key + companion_shuffle = multiworld.companions_locations[world.player].value + kaeli_mom = multiworld.kaelis_mom_fight_minotaur[world.player].current_key - query = f"s={seed}&m={map_shuffle}&c={crest_shuffle}&b={battlefield_shuffle}" + query = f"s={seed}&m={map_shuffle}&c={crest_shuffle}&b={battlefield_shuffle}&cs={companion_shuffle}&km={kaeli_mom}" if query in rooms_data: world.rooms = rooms_data[query] diff --git a/worlds/ffmq/data/entrances.yaml b/worlds/ffmq/data/entrances.yaml index 15bcd02b..1dfef265 100644 --- a/worlds/ffmq/data/entrances.yaml +++ b/worlds/ffmq/data/entrances.yaml @@ -827,12 +827,12 @@ id: 164 area: 47 coordinates: [14, 6] - teleporter: [16, 2] + teleporter: [98, 8] # Script for reuben, original value [16, 2] - name: Fireburg - Hotel id: 165 area: 47 coordinates: [20, 8] - teleporter: [17, 2] + teleporter: [96, 8] # It's a script now for tristam, original value [17, 2] - name: Fireburg - GrenadeMan House Script id: 166 area: 47 @@ -1178,6 +1178,16 @@ area: 60 coordinates: [2, 7] teleporter: [123, 0] +- name: Lava Dome Pointless Room - Visit Quest Script 1 + id: 490 + area: 60 + coordinates: [4, 4] + teleporter: [99, 8] +- name: Lava Dome Pointless Room - Visit Quest Script 2 + id: 491 + area: 60 + coordinates: [4, 5] + teleporter: [99, 8] - name: Lava Dome Lower Moon Helm Room - Left Entrance id: 235 area: 60 @@ -1568,6 +1578,11 @@ area: 79 coordinates: [2, 45] teleporter: [174, 0] +- name: Mount Gale - Visit Quest + id: 494 + area: 79 + coordinates: [44, 7] + teleporter: [101, 8] - name: Windia - Main Entrance 1 id: 312 area: 80 @@ -1613,11 +1628,11 @@ area: 80 coordinates: [21, 39] teleporter: [30, 5] -- name: Windia - INN's Script # Change to teleporter +- name: Windia - INN's Script # Change to teleporter / Change back to script! id: 321 area: 80 coordinates: [18, 34] - teleporter: [31, 2] # Original value [79, 8] + teleporter: [97, 8] # Original value [79, 8] > [31, 2] - name: Windia - Vendor House id: 322 area: 80 @@ -1697,7 +1712,7 @@ id: 337 area: 82 coordinates: [45, 24] - teleporter: [215, 0] + teleporter: [102, 8] # Changed to script, original value [215, 0] - name: Windia Inn Lobby - Exit id: 338 area: 82 @@ -1998,6 +2013,16 @@ area: 95 coordinates: [29, 37] teleporter: [70, 8] +- name: Light Temple - Visit Quest Script 1 + id: 492 + area: 95 + coordinates: [34, 39] + teleporter: [100, 8] +- name: Light Temple - Visit Quest Script 2 + id: 493 + area: 95 + coordinates: [35, 39] + teleporter: [100, 8] - name: Ship Dock - Mobius Teleporter Script id: 397 area: 96 diff --git a/worlds/ffmq/data/rooms.yaml b/worlds/ffmq/data/rooms.yaml index 4343d785..e0c2e8d7 100644 --- a/worlds/ffmq/data/rooms.yaml +++ b/worlds/ffmq/data/rooms.yaml @@ -309,13 +309,13 @@ location: "WindiaBattlefield01" location_slot: "WindiaBattlefield01" type: "BattlefieldXp" - access: [] + access: ["SandCoin", "RiverCoin"] - name: "South of Windia Battlefield" object_id: 0x14 location: "WindiaBattlefield02" location_slot: "WindiaBattlefield02" type: "BattlefieldXp" - access: [] + access: ["SandCoin", "RiverCoin"] links: - target_room: 9 # Focus Tower Windia location: "FocusTowerWindia" @@ -739,7 +739,7 @@ object_id: 0x2E type: "Box" access: [] - - name: "Kaeli 1" + - name: "Kaeli Companion" object_id: 0 type: "Trigger" on_trigger: ["Kaeli1"] @@ -838,7 +838,7 @@ - name: Sand Temple id: 24 game_objects: - - name: "Tristam Sand Temple" + - name: "Tristam Companion" object_id: 0 type: "Trigger" on_trigger: ["Tristam"] @@ -883,6 +883,11 @@ object_id: 2 type: "NPC" access: ["Tristam"] + - name: "Tristam Bone Dungeon Item Given" + object_id: 0 + type: "Trigger" + on_trigger: ["TristamBoneItemGiven"] + access: ["Tristam"] links: - target_room: 25 entrance: 59 @@ -1080,7 +1085,7 @@ object_id: 0x40 type: "Box" access: [] - - name: "Phoebe" + - name: "Phoebe Companion" object_id: 0 type: "Trigger" on_trigger: ["Phoebe1"] @@ -1846,11 +1851,11 @@ access: [] - target_room: 77 entrance: 164 - teleporter: [16, 2] + teleporter: [98, 8] # original value [16, 2] access: [] - target_room: 82 entrance: 165 - teleporter: [17, 2] + teleporter: [96, 8] # original value [17, 2] access: [] - target_room: 208 access: ["Claw"] @@ -1875,7 +1880,7 @@ object_id: 14 type: "NPC" access: ["ReubenDadSaved"] - - name: "Reuben" + - name: "Reuben Companion" object_id: 0 type: "Trigger" on_trigger: ["Reuben1"] @@ -1951,12 +1956,7 @@ - name: "Fireburg - Tristam" object_id: 10 type: "NPC" - access: [] - - name: "Tristam Fireburg" - object_id: 0 - type: "Trigger" - on_trigger: ["Tristam"] - access: [] + access: ["Tristam", "TristamBoneItemGiven"] links: - target_room: 76 entrance: 177 @@ -3183,7 +3183,7 @@ access: [] - target_room: 163 entrance: 321 - teleporter: [31, 2] + teleporter: [97, 8] access: [] - target_room: 165 entrance: 322 @@ -3292,7 +3292,7 @@ access: [] - target_room: 164 entrance: 337 - teleporter: [215, 0] + teleporter: [102, 8] access: [] - name: Windia Inn Beds id: 164 diff --git a/worlds/ffmq/data/settings.yaml b/worlds/ffmq/data/settings.yaml index aa973ee2..ff03ed26 100644 --- a/worlds/ffmq/data/settings.yaml +++ b/worlds/ffmq/data/settings.yaml @@ -73,6 +73,13 @@ Final Fantasy Mystic Quest: Chaos: 0 SelfDestruct: 0 SimpleShuffle: 0 + enemizer_groups: + MobsOnly: 0 + MobsBosses: 0 + MobsBossesDK: 0 + shuffle_res_weak_type: + true: 0 + false: 0 leveling_curve: Half: 0 Normal: 0 @@ -81,6 +88,42 @@ Final Fantasy Mystic Quest: DoubleHalf: 0 Triple: 0 Quadruple: 0 + companion_leveling_type: + Quests: 0 + QuestsExtended: 0 + SaveCrystalsIndividual: 0 + SaveCrystalsAll: 0 + BenPlus0: 0 + BenPlus5: 0 + BenPlus10: 0 + companion_spellbook_type: + Standard: 0 + StandardExtended: 0 + RandomBalanced: 0 + RandomChaos: 0 + starting_companion: + None: 0 + Kaeli: 0 + Tristam: 0 + Phoebe: 0 + Reuben: 0 + Random: 0 + RandomPlusNone: 0 + available_companions: + Zero: 0 + One: 0 + Two: 0 + Three: 0 + Four: 0 + Random14: 0 + Random04: 0 + companions_locations: + Standard: 0 + Shuffled: 0 + ShuffledExtended: 0 + kaelis_mom_fight_minotaur: + true: 0 + false: 0 battles_quantity: Ten: 0 Seven: 0