mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 12:11:33 -06:00
FFMQ: Efficiency Improvement and Use New Options Methods (#2767)
* FFMQ Efficiency improvement and use new options methods * Hard check for 0x01 game status * Fixes * Why were Mac's Ship entrance hints excluded? * Two remaining per_slot_randoms purged * reformat generate_early * Utils.parse_yaml
This commit is contained in:
@@ -71,7 +71,7 @@ class FFMQClient(SNIClient):
|
||||
received = await snes_read(ctx, RECEIVED_DATA[0], RECEIVED_DATA[1])
|
||||
data = await snes_read(ctx, READ_DATA_START, READ_DATA_END - READ_DATA_START)
|
||||
check_2 = await snes_read(ctx, 0xF53749, 1)
|
||||
if check_1 in (b'\x00', b'\x55') or check_2 in (b'\x00', b'\x55'):
|
||||
if check_1 != b'01' or check_2 != b'01':
|
||||
return
|
||||
|
||||
def get_range(data_range):
|
||||
|
@@ -222,10 +222,10 @@ for item, data in item_table.items():
|
||||
|
||||
def create_items(self) -> None:
|
||||
items = []
|
||||
starting_weapon = self.multiworld.starting_weapon[self.player].current_key.title().replace("_", " ")
|
||||
starting_weapon = self.options.starting_weapon.current_key.title().replace("_", " ")
|
||||
self.multiworld.push_precollected(self.create_item(starting_weapon))
|
||||
self.multiworld.push_precollected(self.create_item("Steel Armor"))
|
||||
if self.multiworld.sky_coin_mode[self.player] == "start_with":
|
||||
if self.options.sky_coin_mode == "start_with":
|
||||
self.multiworld.push_precollected(self.create_item("Sky Coin"))
|
||||
|
||||
precollected_item_names = {item.name for item in self.multiworld.precollected_items[self.player]}
|
||||
@@ -233,28 +233,28 @@ def create_items(self) -> None:
|
||||
def add_item(item_name):
|
||||
if item_name in ["Steel Armor", "Sky Fragment"] or "Progressive" in item_name:
|
||||
return
|
||||
if item_name.lower().replace(" ", "_") == self.multiworld.starting_weapon[self.player].current_key:
|
||||
if item_name.lower().replace(" ", "_") == self.options.starting_weapon.current_key:
|
||||
return
|
||||
if self.multiworld.progressive_gear[self.player]:
|
||||
if self.options.progressive_gear:
|
||||
for item_group in prog_map:
|
||||
if item_name in self.item_name_groups[item_group]:
|
||||
item_name = prog_map[item_group]
|
||||
break
|
||||
if item_name == "Sky Coin":
|
||||
if self.multiworld.sky_coin_mode[self.player] == "shattered_sky_coin":
|
||||
if self.options.sky_coin_mode == "shattered_sky_coin":
|
||||
for _ in range(40):
|
||||
items.append(self.create_item("Sky Fragment"))
|
||||
return
|
||||
elif self.multiworld.sky_coin_mode[self.player] == "save_the_crystals":
|
||||
elif self.options.sky_coin_mode == "save_the_crystals":
|
||||
items.append(self.create_filler())
|
||||
return
|
||||
if item_name in precollected_item_names:
|
||||
items.append(self.create_filler())
|
||||
return
|
||||
i = self.create_item(item_name)
|
||||
if self.multiworld.logic[self.player] != "friendly" and item_name in ("Magic Mirror", "Mask"):
|
||||
if self.options.logic != "friendly" and item_name in ("Magic Mirror", "Mask"):
|
||||
i.classification = ItemClassification.useful
|
||||
if (self.multiworld.logic[self.player] == "expert" and self.multiworld.map_shuffle[self.player] == "none" and
|
||||
if (self.options.logic == "expert" and self.options.map_shuffle == "none" and
|
||||
item_name == "Exit Book"):
|
||||
i.classification = ItemClassification.progression
|
||||
items.append(i)
|
||||
@@ -263,11 +263,11 @@ def create_items(self) -> None:
|
||||
for item in self.item_name_groups[item_group]:
|
||||
add_item(item)
|
||||
|
||||
if self.multiworld.brown_boxes[self.player] == "include":
|
||||
if self.options.brown_boxes == "include":
|
||||
filler_items = []
|
||||
for item, count in fillers.items():
|
||||
filler_items += [self.create_item(item) for _ in range(count)]
|
||||
if self.multiworld.sky_coin_mode[self.player] == "shattered_sky_coin":
|
||||
if self.options.sky_coin_mode == "shattered_sky_coin":
|
||||
self.multiworld.random.shuffle(filler_items)
|
||||
filler_items = filler_items[39:]
|
||||
items += filler_items
|
||||
|
@@ -1,4 +1,5 @@
|
||||
from Options import Choice, FreeText, Toggle, Range
|
||||
from Options import Choice, FreeText, Toggle, Range, PerGameCommonOptions
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
class Logic(Choice):
|
||||
@@ -321,36 +322,36 @@ class KaelisMomFightsMinotaur(Toggle):
|
||||
default = 0
|
||||
|
||||
|
||||
option_definitions = {
|
||||
"logic": Logic,
|
||||
"brown_boxes": BrownBoxes,
|
||||
"sky_coin_mode": SkyCoinMode,
|
||||
"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,
|
||||
"doom_castle_shortcut": DoomCastleShortcut,
|
||||
"tweak_frustrating_dungeons": TweakFrustratingDungeons,
|
||||
"map_shuffle": MapShuffle,
|
||||
"crest_shuffle": CrestShuffle,
|
||||
"shuffle_battlefield_rewards": ShuffleBattlefieldRewards,
|
||||
"map_shuffle_seed": MapShuffleSeed,
|
||||
"battlefields_battles_quantities": BattlefieldsBattlesQuantities,
|
||||
}
|
||||
@dataclass
|
||||
class FFMQOptions(PerGameCommonOptions):
|
||||
logic: Logic
|
||||
brown_boxes: BrownBoxes
|
||||
sky_coin_mode: SkyCoinMode
|
||||
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
|
||||
doom_castle_shortcut: DoomCastleShortcut
|
||||
tweak_frustrating_dungeons: TweakFrustratingDungeons
|
||||
map_shuffle: MapShuffle
|
||||
crest_shuffle: CrestShuffle
|
||||
shuffle_battlefield_rewards: ShuffleBattlefieldRewards
|
||||
map_shuffle_seed: MapShuffleSeed
|
||||
battlefields_battles_quantities: BattlefieldsBattlesQuantities
|
||||
|
@@ -1,13 +1,13 @@
|
||||
import yaml
|
||||
import os
|
||||
import zipfile
|
||||
import Utils
|
||||
from copy import deepcopy
|
||||
from .Regions import object_id_table
|
||||
from Utils import __version__
|
||||
from worlds.Files import APPatch
|
||||
import pkgutil
|
||||
|
||||
settings_template = yaml.load(pkgutil.get_data(__name__, "data/settings.yaml"), yaml.Loader)
|
||||
settings_template = Utils.parse_yaml(pkgutil.get_data(__name__, "data/settings.yaml"))
|
||||
|
||||
|
||||
def generate_output(self, output_directory):
|
||||
@@ -21,7 +21,7 @@ def generate_output(self, output_directory):
|
||||
item_name = "".join(item_name.split(" "))
|
||||
else:
|
||||
if item.advancement or item.useful or (item.trap and
|
||||
self.multiworld.per_slot_randoms[self.player].randint(0, 1)):
|
||||
self.random.randint(0, 1)):
|
||||
item_name = "APItem"
|
||||
else:
|
||||
item_name = "APItemFiller"
|
||||
@@ -46,60 +46,60 @@ def generate_output(self, output_directory):
|
||||
options = deepcopy(settings_template)
|
||||
options["name"] = self.multiworld.player_name[self.player]
|
||||
option_writes = {
|
||||
"enemies_density": cc(self.multiworld.enemies_density[self.player]),
|
||||
"enemies_density": cc(self.options.enemies_density),
|
||||
"chests_shuffle": "Include",
|
||||
"shuffle_boxes_content": self.multiworld.brown_boxes[self.player] == "shuffle",
|
||||
"shuffle_boxes_content": self.options.brown_boxes == "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
|
||||
"logic_options": cc(self.options.logic),
|
||||
"shuffle_enemies_position": tf(self.options.shuffle_enemies_position),
|
||||
"enemies_scaling_lower": cc(self.options.enemies_scaling_lower),
|
||||
"enemies_scaling_upper": cc(self.options.enemies_scaling_upper),
|
||||
"bosses_scaling_lower": cc(self.options.bosses_scaling_lower),
|
||||
"bosses_scaling_upper": cc(self.options.bosses_scaling_upper),
|
||||
"enemizer_attacks": cc(self.options.enemizer_attacks),
|
||||
"leveling_curve": cc(self.options.leveling_curve),
|
||||
"battles_quantity": cc(self.options.battlefields_battles_quantities) if
|
||||
self.options.battlefields_battles_quantities.value < 5 else
|
||||
"RandomLow" if
|
||||
self.multiworld.battlefields_battles_quantities[self.player].value == 5 else
|
||||
self.options.battlefields_battles_quantities.value == 5 else
|
||||
"RandomHigh",
|
||||
"shuffle_battlefield_rewards": tf(self.multiworld.shuffle_battlefield_rewards[self.player]),
|
||||
"shuffle_battlefield_rewards": tf(self.options.shuffle_battlefield_rewards),
|
||||
"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]),
|
||||
"progressive_gear": tf(self.options.progressive_gear),
|
||||
"tweaked_dungeons": tf(self.options.tweak_frustrating_dungeons),
|
||||
"doom_castle_mode": cc(self.options.doom_castle_mode),
|
||||
"doom_castle_shortcut": tf(self.options.doom_castle_shortcut),
|
||||
"sky_coin_mode": cc(self.options.sky_coin_mode),
|
||||
"sky_coin_fragments_qty": cc(self.options.shattered_sky_coin_quantity),
|
||||
"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]),
|
||||
"progressive_formations": cc(self.options.progressive_formations),
|
||||
"map_shuffling": cc(self.options.map_shuffle),
|
||||
"crest_shuffle": tf(self.options.crest_shuffle),
|
||||
"enemizer_groups": cc(self.options.enemizer_groups),
|
||||
"shuffle_res_weak_type": tf(self.options.shuffle_res_weak_types),
|
||||
"companion_leveling_type": cc(self.options.companion_leveling_type),
|
||||
"companion_spellbook_type": cc(self.options.companion_spellbook_type),
|
||||
"starting_companion": cc(self.options.starting_companion),
|
||||
"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]),
|
||||
"Three", "Four"][self.options.available_companions.value],
|
||||
"companions_locations": cc(self.options.companions_locations),
|
||||
"kaelis_mom_fight_minotaur": tf(self.options.kaelis_mom_fight_minotaur),
|
||||
}
|
||||
|
||||
for option, data in option_writes.items():
|
||||
options["Final Fantasy Mystic Quest"][option][data] = 1
|
||||
|
||||
rom_name = f'MQ{__version__.replace(".", "")[0:3]}_{self.player}_{self.multiworld.seed_name:11}'[:21]
|
||||
rom_name = f'MQ{Utils.__version__.replace(".", "")[0:3]}_{self.player}_{self.multiworld.seed_name:11}'[:21]
|
||||
self.rom_name = bytearray(rom_name,
|
||||
'utf8')
|
||||
self.rom_name_available_event.set()
|
||||
|
||||
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()}
|
||||
hex(self.random.randint(0, 0xFFFFFFFF)).split("0x")[1].upper()}
|
||||
|
||||
starting_items = [output_item_name(item) for item in self.multiworld.precollected_items[self.player]]
|
||||
if self.multiworld.sky_coin_mode[self.player] == "shattered_sky_coin":
|
||||
if self.options.sky_coin_mode == "shattered_sky_coin":
|
||||
starting_items.append("SkyCoin")
|
||||
|
||||
file_path = os.path.join(output_directory, f"{self.multiworld.get_out_file_name_base(self.player)}.apmq")
|
||||
|
@@ -1,11 +1,9 @@
|
||||
from BaseClasses import Region, MultiWorld, Entrance, Location, LocationProgressType, ItemClassification
|
||||
from worlds.generic.Rules import add_rule
|
||||
from .data.rooms import rooms, entrances
|
||||
from .Items import item_groups, yaml_item
|
||||
import pkgutil
|
||||
import yaml
|
||||
|
||||
rooms = yaml.load(pkgutil.get_data(__name__, "data/rooms.yaml"), yaml.Loader)
|
||||
entrance_names = {entrance["id"]: entrance["name"] for entrance in yaml.load(pkgutil.get_data(__name__, "data/entrances.yaml"), yaml.Loader)}
|
||||
entrance_names = {entrance["id"]: entrance["name"] for entrance in entrances}
|
||||
|
||||
object_id_table = {}
|
||||
object_type_table = {}
|
||||
@@ -69,7 +67,7 @@ def create_regions(self):
|
||||
location_table else None, object["type"], object["access"],
|
||||
self.create_item(yaml_item(object["on_trigger"][0])) if object["type"] == "Trigger" else None) for object in
|
||||
room["game_objects"] if "Hero Chest" not in object["name"] and object["type"] not in ("BattlefieldGp",
|
||||
"BattlefieldXp") and (object["type"] != "Box" or self.multiworld.brown_boxes[self.player] == "include") and
|
||||
"BattlefieldXp") and (object["type"] != "Box" or self.options.brown_boxes == "include") and
|
||||
not (object["name"] == "Kaeli Companion" and not object["on_trigger"])], room["links"]))
|
||||
|
||||
dark_king_room = self.multiworld.get_region("Doom Castle Dark King Room", self.player)
|
||||
@@ -91,15 +89,13 @@ def create_regions(self):
|
||||
if "entrance" in link and link["entrance"] != -1:
|
||||
spoiler = False
|
||||
if link["entrance"] in crest_warps:
|
||||
if self.multiworld.crest_shuffle[self.player]:
|
||||
if self.options.crest_shuffle:
|
||||
spoiler = True
|
||||
elif self.multiworld.map_shuffle[self.player] == "everything":
|
||||
elif self.options.map_shuffle == "everything":
|
||||
spoiler = True
|
||||
elif "Subregion" in region.name and self.multiworld.map_shuffle[self.player] not in ("dungeons",
|
||||
"none"):
|
||||
elif "Subregion" in region.name and self.options.map_shuffle not in ("dungeons", "none"):
|
||||
spoiler = True
|
||||
elif "Subregion" not in region.name and self.multiworld.map_shuffle[self.player] not in ("none",
|
||||
"overworld"):
|
||||
elif "Subregion" not in region.name and self.options.map_shuffle not in ("none", "overworld"):
|
||||
spoiler = True
|
||||
|
||||
if spoiler:
|
||||
@@ -111,6 +107,7 @@ def create_regions(self):
|
||||
connection.connect(connect_room)
|
||||
break
|
||||
|
||||
|
||||
non_dead_end_crest_rooms = [
|
||||
'Libra Temple', 'Aquaria Gemini Room', "GrenadeMan's Mobius Room", 'Fireburg Gemini Room',
|
||||
'Sealed Temple', 'Alive Forest', 'Kaidge Temple Upper Ledge',
|
||||
@@ -140,7 +137,7 @@ def set_rules(self) -> None:
|
||||
add_rule(self.multiworld.get_location("Gidrah", self.player), hard_boss_logic)
|
||||
add_rule(self.multiworld.get_location("Dullahan", self.player), hard_boss_logic)
|
||||
|
||||
if self.multiworld.map_shuffle[self.player]:
|
||||
if self.options.map_shuffle:
|
||||
for boss in ("Freezer Crab", "Ice Golem", "Jinn", "Medusa", "Dualhead Hydra"):
|
||||
loc = self.multiworld.get_location(boss, self.player)
|
||||
checked_regions = {loc.parent_region}
|
||||
@@ -158,12 +155,12 @@ def set_rules(self) -> None:
|
||||
return True
|
||||
check_foresta(loc.parent_region)
|
||||
|
||||
if self.multiworld.logic[self.player] == "friendly":
|
||||
if self.options.logic == "friendly":
|
||||
process_rules(self.multiworld.get_entrance("Overworld - Ice Pyramid", self.player),
|
||||
["MagicMirror"])
|
||||
process_rules(self.multiworld.get_entrance("Overworld - Volcano", self.player),
|
||||
["Mask"])
|
||||
if self.multiworld.map_shuffle[self.player] in ("none", "overworld"):
|
||||
if self.options.map_shuffle in ("none", "overworld"):
|
||||
process_rules(self.multiworld.get_entrance("Overworld - Bone Dungeon", self.player),
|
||||
["Bomb"])
|
||||
process_rules(self.multiworld.get_entrance("Overworld - Wintry Cave", self.player),
|
||||
@@ -185,8 +182,8 @@ def set_rules(self) -> None:
|
||||
process_rules(self.multiworld.get_entrance("Overworld - Mac Ship Doom", self.player),
|
||||
["DragonClaw", "CaptainCap"])
|
||||
|
||||
if self.multiworld.logic[self.player] == "expert":
|
||||
if self.multiworld.map_shuffle[self.player] == "none" and not self.multiworld.crest_shuffle[self.player]:
|
||||
if self.options.logic == "expert":
|
||||
if self.options.map_shuffle == "none" and not self.options.crest_shuffle:
|
||||
inner_room = self.multiworld.get_region("Wintry Temple Inner Room", self.player)
|
||||
connection = Entrance(self.player, "Sealed Temple Exit Trick", inner_room)
|
||||
connection.connect(self.multiworld.get_region("Wintry Temple Outer Room", self.player))
|
||||
@@ -198,14 +195,14 @@ def set_rules(self) -> None:
|
||||
if entrance.connected_region.name in non_dead_end_crest_rooms:
|
||||
entrance.access_rule = lambda state: False
|
||||
|
||||
if self.multiworld.sky_coin_mode[self.player] == "shattered_sky_coin":
|
||||
logic_coins = [16, 24, 32, 32, 38][self.multiworld.shattered_sky_coin_quantity[self.player].value]
|
||||
if self.options.sky_coin_mode == "shattered_sky_coin":
|
||||
logic_coins = [16, 24, 32, 32, 38][self.options.shattered_sky_coin_quantity.value]
|
||||
self.multiworld.get_entrance("Focus Tower 1F - Sky Door", self.player).access_rule = \
|
||||
lambda state: state.has("Sky Fragment", self.player, logic_coins)
|
||||
elif self.multiworld.sky_coin_mode[self.player] == "save_the_crystals":
|
||||
elif self.options.sky_coin_mode == "save_the_crystals":
|
||||
self.multiworld.get_entrance("Focus Tower 1F - Sky Door", self.player).access_rule = \
|
||||
lambda state: state.has_all(["Flamerus Rex", "Dualhead Hydra", "Ice Golem", "Pazuzu"], self.player)
|
||||
elif self.multiworld.sky_coin_mode[self.player] in ("standard", "start_with"):
|
||||
elif self.options.sky_coin_mode in ("standard", "start_with"):
|
||||
self.multiworld.get_entrance("Focus Tower 1F - Sky Door", self.player).access_rule = \
|
||||
lambda state: state.has("Sky Coin", self.player)
|
||||
|
||||
@@ -213,26 +210,24 @@ def set_rules(self) -> None:
|
||||
def stage_set_rules(multiworld):
|
||||
# If there's no enemies, there's no repeatable income sources
|
||||
no_enemies_players = [player for player in multiworld.get_game_players("Final Fantasy Mystic Quest")
|
||||
if multiworld.enemies_density[player] == "none"]
|
||||
if multiworld.worlds[player].options.enemies_density == "none"]
|
||||
if (len([item for item in multiworld.itempool if item.classification in (ItemClassification.filler,
|
||||
ItemClassification.trap)]) > len([player for player in no_enemies_players if
|
||||
multiworld.accessibility[player] == "minimal"]) * 3):
|
||||
multiworld.worlds[player].options.accessibility == "minimal"]) * 3):
|
||||
for player in no_enemies_players:
|
||||
for location in vendor_locations:
|
||||
if multiworld.accessibility[player] == "locations":
|
||||
if multiworld.worlds[player].options.accessibility == "locations":
|
||||
multiworld.get_location(location, player).progress_type = LocationProgressType.EXCLUDED
|
||||
else:
|
||||
multiworld.get_location(location, player).access_rule = lambda state: False
|
||||
else:
|
||||
# There are not enough junk items to fill non-minimal players' vendors. Just set an item rule not allowing
|
||||
# advancement items so that useful items can be placed
|
||||
# advancement items so that useful items can be placed.
|
||||
for player in no_enemies_players:
|
||||
for location in vendor_locations:
|
||||
multiworld.get_location(location, player).item_rule = lambda item: not item.advancement
|
||||
|
||||
|
||||
|
||||
|
||||
class FFMQLocation(Location):
|
||||
game = "Final Fantasy Mystic Quest"
|
||||
|
||||
|
@@ -10,7 +10,7 @@ from .Regions import create_regions, location_table, set_rules, stage_set_rules,
|
||||
non_dead_end_crest_warps
|
||||
from .Items import item_table, item_groups, create_items, FFMQItem, fillers
|
||||
from .Output import generate_output
|
||||
from .Options import option_definitions
|
||||
from .Options import FFMQOptions
|
||||
from .Client import FFMQClient
|
||||
|
||||
|
||||
@@ -45,7 +45,8 @@ class FFMQWorld(World):
|
||||
|
||||
item_name_to_id = {name: data.id for name, data in item_table.items() if data.id is not None}
|
||||
location_name_to_id = location_table
|
||||
option_definitions = option_definitions
|
||||
options_dataclass = FFMQOptions
|
||||
options: FFMQOptions
|
||||
|
||||
topology_present = True
|
||||
|
||||
@@ -67,20 +68,14 @@ class FFMQWorld(World):
|
||||
super().__init__(world, player)
|
||||
|
||||
def generate_early(self):
|
||||
if self.multiworld.sky_coin_mode[self.player] == "shattered_sky_coin":
|
||||
self.multiworld.brown_boxes[self.player].value = 1
|
||||
if self.multiworld.enemies_scaling_lower[self.player].value > \
|
||||
self.multiworld.enemies_scaling_upper[self.player].value:
|
||||
(self.multiworld.enemies_scaling_lower[self.player].value,
|
||||
self.multiworld.enemies_scaling_upper[self.player].value) =\
|
||||
(self.multiworld.enemies_scaling_upper[self.player].value,
|
||||
self.multiworld.enemies_scaling_lower[self.player].value)
|
||||
if self.multiworld.bosses_scaling_lower[self.player].value > \
|
||||
self.multiworld.bosses_scaling_upper[self.player].value:
|
||||
(self.multiworld.bosses_scaling_lower[self.player].value,
|
||||
self.multiworld.bosses_scaling_upper[self.player].value) =\
|
||||
(self.multiworld.bosses_scaling_upper[self.player].value,
|
||||
self.multiworld.bosses_scaling_lower[self.player].value)
|
||||
if self.options.sky_coin_mode == "shattered_sky_coin":
|
||||
self.options.brown_boxes.value = 1
|
||||
if self.options.enemies_scaling_lower.value > self.options.enemies_scaling_upper.value:
|
||||
self.options.enemies_scaling_lower.value, self.options.enemies_scaling_upper.value = \
|
||||
self.options.enemies_scaling_upper.value, self.options.enemies_scaling_lower.value
|
||||
if self.options.bosses_scaling_lower.value > self.options.bosses_scaling_upper.value:
|
||||
self.options.bosses_scaling_lower.value, self.options.bosses_scaling_upper.value = \
|
||||
self.options.bosses_scaling_upper.value, self.options.bosses_scaling_lower.value
|
||||
|
||||
@classmethod
|
||||
def stage_generate_early(cls, multiworld):
|
||||
@@ -94,20 +89,20 @@ class FFMQWorld(World):
|
||||
rooms_data = {}
|
||||
|
||||
for world in multiworld.get_game_worlds("Final Fantasy Mystic Quest"):
|
||||
if (world.multiworld.map_shuffle[world.player] or world.multiworld.crest_shuffle[world.player] or
|
||||
world.multiworld.crest_shuffle[world.player]):
|
||||
if world.multiworld.map_shuffle_seed[world.player].value.isdigit():
|
||||
multiworld.random.seed(int(world.multiworld.map_shuffle_seed[world.player].value))
|
||||
elif world.multiworld.map_shuffle_seed[world.player].value != "random":
|
||||
multiworld.random.seed(int(hash(world.multiworld.map_shuffle_seed[world.player].value))
|
||||
+ int(world.multiworld.seed))
|
||||
if (world.options.map_shuffle or world.options.crest_shuffle or world.options.shuffle_battlefield_rewards
|
||||
or world.options.companions_locations):
|
||||
if world.options.map_shuffle_seed.value.isdigit():
|
||||
multiworld.random.seed(int(world.options.map_shuffle_seed.value))
|
||||
elif world.options.map_shuffle_seed.value != "random":
|
||||
multiworld.random.seed(int(hash(world.options.map_shuffle_seed.value))
|
||||
+ int(world.multiworld.seed))
|
||||
|
||||
seed = hex(multiworld.random.randint(0, 0xFFFFFFFF)).split("0x")[1].upper()
|
||||
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
|
||||
map_shuffle = world.options.map_shuffle.value
|
||||
crest_shuffle = world.options.crest_shuffle.current_key
|
||||
battlefield_shuffle = world.options.shuffle_battlefield_rewards.current_key
|
||||
companion_shuffle = world.options.companions_locations.value
|
||||
kaeli_mom = world.options.kaelis_mom_fight_minotaur.current_key
|
||||
|
||||
query = f"s={seed}&m={map_shuffle}&c={crest_shuffle}&b={battlefield_shuffle}&cs={companion_shuffle}&km={kaeli_mom}"
|
||||
|
||||
@@ -175,14 +170,14 @@ class FFMQWorld(World):
|
||||
|
||||
def extend_hint_information(self, hint_data):
|
||||
hint_data[self.player] = {}
|
||||
if self.multiworld.map_shuffle[self.player]:
|
||||
if self.options.map_shuffle:
|
||||
single_location_regions = ["Subregion Volcano Battlefield", "Subregion Mac's Ship", "Subregion Doom Castle"]
|
||||
for subregion in ["Subregion Foresta", "Subregion Aquaria", "Subregion Frozen Fields", "Subregion Fireburg",
|
||||
"Subregion Volcano Battlefield", "Subregion Windia", "Subregion Mac's Ship",
|
||||
"Subregion Doom Castle"]:
|
||||
region = self.multiworld.get_region(subregion, self.player)
|
||||
for location in region.locations:
|
||||
if location.address and self.multiworld.map_shuffle[self.player] != "dungeons":
|
||||
if location.address and self.options.map_shuffle != "dungeons":
|
||||
hint_data[self.player][location.address] = (subregion.split("Subregion ")[-1]
|
||||
+ (" Region" if subregion not in
|
||||
single_location_regions else ""))
|
||||
@@ -202,14 +197,13 @@ class FFMQWorld(World):
|
||||
for location in exit_check.connected_region.locations:
|
||||
if location.address:
|
||||
hint = []
|
||||
if self.multiworld.map_shuffle[self.player] != "dungeons":
|
||||
if self.options.map_shuffle != "dungeons":
|
||||
hint.append((subregion.split("Subregion ")[-1] + (" Region" if subregion not
|
||||
in single_location_regions else "")))
|
||||
if self.multiworld.map_shuffle[self.player] != "overworld" and subregion not in \
|
||||
("Subregion Mac's Ship", "Subregion Doom Castle"):
|
||||
if self.options.map_shuffle != "overworld":
|
||||
hint.append(overworld_spot.name.split("Overworld - ")[-1].replace("Pazuzu",
|
||||
"Pazuzu's"))
|
||||
hint = " - ".join(hint)
|
||||
hint = " - ".join(hint).replace(" - Mac Ship", "")
|
||||
if location.address in hint_data[self.player]:
|
||||
hint_data[self.player][location.address] += f"/{hint}"
|
||||
else:
|
||||
|
File diff suppressed because it is too large
Load Diff
2
worlds/ffmq/data/rooms.py
Normal file
2
worlds/ffmq/data/rooms.py
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user