lufia2ac: rename starting_capsule/starting_party options to default_capsule/default_party
This commit is contained in:
parent
ff9c11d772
commit
4cfc73b582
|
@ -242,6 +242,81 @@ class CrowdedFloorChance(Range):
|
|||
default = 16
|
||||
|
||||
|
||||
class DefaultCapsule(Choice):
|
||||
"""Preselect the active capsule monster.
|
||||
|
||||
(Only has an effect if shuffle_capsule_monsters is set to false.)
|
||||
Supported values: jelze, flash, gusto, zeppy, darbi, sully, blaze
|
||||
Default value: jelze
|
||||
"""
|
||||
|
||||
display_name = "Default capsule monster"
|
||||
option_jelze = 0x00
|
||||
option_flash = 0x01
|
||||
option_gusto = 0x02
|
||||
option_zeppy = 0x03
|
||||
option_darbi = 0x04
|
||||
option_sully = 0x05
|
||||
option_blaze = 0x06
|
||||
default = option_jelze
|
||||
|
||||
|
||||
class DefaultParty(RandomGroupsChoice, TextChoice):
|
||||
"""Preselect the party lineup.
|
||||
|
||||
(Only has an effect if shuffle_party_members is set to false.)
|
||||
Supported values:
|
||||
Can be set to any valid combination of up to 4 party member initials, e.g.:
|
||||
M — Maxim
|
||||
DGMA — Dekar, Guy, Maxim, and Arty
|
||||
MSTL — Maxim, Selan, Tia, and Lexis
|
||||
random-2p — a random 2-person party
|
||||
random-3p — a random 3-person party
|
||||
random-4p — a random 4-person party
|
||||
Default value: M
|
||||
"""
|
||||
|
||||
display_name = "Default party lineup"
|
||||
default = "M"
|
||||
|
||||
random_groups = {
|
||||
"random-2p": ["M" + "".join(p) for p in combinations("ADGLST", 1)],
|
||||
"random-3p": ["M" + "".join(p) for p in combinations("ADGLST", 2)],
|
||||
"random-4p": ["M" + "".join(p) for p in combinations("ADGLST", 3)],
|
||||
}
|
||||
vars().update({f"option_{party}": party for party in (*random_groups, "M", *chain(*random_groups.values()))})
|
||||
_valid_sorted_parties: List[List[str]] = [sorted(party) for party in ("M", *chain(*random_groups.values()))]
|
||||
_members_to_bytes: bytes = bytes.maketrans(b"MSGATDL", bytes(range(7)))
|
||||
|
||||
def verify(self, *args, **kwargs) -> None:
|
||||
if str(self.value).lower() in self.random_groups:
|
||||
return
|
||||
if sorted(str(self.value).upper()) in self._valid_sorted_parties:
|
||||
return
|
||||
raise ValueError(f"Could not find option '{self.value}' for '{self.__class__.__name__}', known options are:\n"
|
||||
f"{', '.join(self.random_groups)}, {', '.join(('M', *chain(*self.random_groups.values())))} "
|
||||
"as well as all permutations of these.")
|
||||
|
||||
@staticmethod
|
||||
def _flip(i: int) -> int:
|
||||
return {4: 5, 5: 4}.get(i, i)
|
||||
|
||||
@property
|
||||
def event_script(self) -> bytes:
|
||||
return bytes((*(b for i in bytes(self) if i != 0 for b in (0x2B, i, 0x2E, i + 0x65, 0x1A, self._flip(i) + 1)),
|
||||
0x1E, 0x0B, len(self) - 1, 0x1C, 0x86, 0x03, *(0x00,) * (6 * (4 - len(self)))))
|
||||
|
||||
@property
|
||||
def roster(self) -> bytes:
|
||||
return bytes((len(self), *bytes(self), *(0xFF,) * (4 - len(self))))
|
||||
|
||||
def __bytes__(self) -> bytes:
|
||||
return str(self.value).upper().encode("ASCII").translate(self._members_to_bytes)
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(str(self.value))
|
||||
|
||||
|
||||
class FinalFloor(Range):
|
||||
"""The final floor, where the boss resides.
|
||||
|
||||
|
@ -439,81 +514,6 @@ class ShufflePartyMembers(Toggle):
|
|||
return 0b00000000 if self.value else 0b11111100
|
||||
|
||||
|
||||
class StartingCapsule(Choice):
|
||||
"""The capsule monster you start the game with.
|
||||
|
||||
Only has an effect if shuffle_capsule_monsters is set to false.
|
||||
Supported values: jelze, flash, gusto, zeppy, darbi, sully, blaze
|
||||
Default value: jelze
|
||||
"""
|
||||
|
||||
display_name = "Starting capsule monster"
|
||||
option_jelze = 0x00
|
||||
option_flash = 0x01
|
||||
option_gusto = 0x02
|
||||
option_zeppy = 0x03
|
||||
option_darbi = 0x04
|
||||
option_sully = 0x05
|
||||
option_blaze = 0x06
|
||||
default = option_jelze
|
||||
|
||||
|
||||
class StartingParty(RandomGroupsChoice, TextChoice):
|
||||
"""The party you start the game with.
|
||||
|
||||
Only has an effect if shuffle_party_members is set to false.
|
||||
Supported values:
|
||||
Can be set to any valid combination of up to 4 party member initials, e.g.:
|
||||
M — start with Maxim
|
||||
DGMA — start with Dekar, Guy, Maxim, and Arty
|
||||
MSTL — start with Maxim, Selan, Tia, and Lexis
|
||||
random-2p — a random 2-person party
|
||||
random-3p — a random 3-person party
|
||||
random-4p — a random 4-person party
|
||||
Default value: M
|
||||
"""
|
||||
|
||||
display_name = "Starting party"
|
||||
default = "M"
|
||||
|
||||
random_groups = {
|
||||
"random-2p": ["M" + "".join(p) for p in combinations("ADGLST", 1)],
|
||||
"random-3p": ["M" + "".join(p) for p in combinations("ADGLST", 2)],
|
||||
"random-4p": ["M" + "".join(p) for p in combinations("ADGLST", 3)],
|
||||
}
|
||||
vars().update({f"option_{party}": party for party in (*random_groups, "M", *chain(*random_groups.values()))})
|
||||
_valid_sorted_parties: List[List[str]] = [sorted(party) for party in ("M", *chain(*random_groups.values()))]
|
||||
_members_to_bytes: bytes = bytes.maketrans(b"MSGATDL", bytes(range(7)))
|
||||
|
||||
def verify(self, *args, **kwargs) -> None:
|
||||
if str(self.value).lower() in self.random_groups:
|
||||
return
|
||||
if sorted(str(self.value).upper()) in self._valid_sorted_parties:
|
||||
return
|
||||
raise ValueError(f"Could not find option '{self.value}' for '{self.__class__.__name__}', known options are:\n"
|
||||
f"{', '.join(self.random_groups)}, {', '.join(('M', *chain(*self.random_groups.values())))} "
|
||||
"as well as all permutations of these.")
|
||||
|
||||
@staticmethod
|
||||
def _flip(i: int) -> int:
|
||||
return {4: 5, 5: 4}.get(i, i)
|
||||
|
||||
@property
|
||||
def event_script(self) -> bytes:
|
||||
return bytes((*(b for i in bytes(self) if i != 0 for b in (0x2B, i, 0x2E, i + 0x65, 0x1A, self._flip(i) + 1)),
|
||||
0x1E, 0x0B, len(self) - 1, 0x1C, 0x86, 0x03, *(0x00,) * (6 * (4 - len(self)))))
|
||||
|
||||
@property
|
||||
def roster(self) -> bytes:
|
||||
return bytes((len(self), *bytes(self), *(0xFF,) * (4 - len(self))))
|
||||
|
||||
def __bytes__(self) -> bytes:
|
||||
return str(self.value).upper().encode("ASCII").translate(self._members_to_bytes)
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(str(self.value))
|
||||
|
||||
|
||||
l2ac_option_definitions: Dict[str, type(Option)] = {
|
||||
"blue_chest_chance": BlueChestChance,
|
||||
"blue_chest_count": BlueChestCount,
|
||||
|
@ -523,6 +523,8 @@ l2ac_option_definitions: Dict[str, type(Option)] = {
|
|||
"capsule_starting_level": CapsuleStartingLevel,
|
||||
"crowded_floor_chance": CrowdedFloorChance,
|
||||
"death_link": DeathLink,
|
||||
"default_capsule": DefaultCapsule,
|
||||
"default_party": DefaultParty,
|
||||
"final_floor": FinalFloor,
|
||||
"gear_variety_after_b9": GearVarietyAfterB9,
|
||||
"goal": Goal,
|
||||
|
@ -535,6 +537,4 @@ l2ac_option_definitions: Dict[str, type(Option)] = {
|
|||
"run_speed": RunSpeed,
|
||||
"shuffle_capsule_monsters": ShuffleCapsuleMonsters,
|
||||
"shuffle_party_members": ShufflePartyMembers,
|
||||
"starting_capsule": StartingCapsule,
|
||||
"starting_party": StartingParty,
|
||||
}
|
||||
|
|
|
@ -12,8 +12,8 @@ from worlds.generic.Rules import add_rule, set_rule
|
|||
from .Client import L2ACSNIClient # noqa: F401
|
||||
from .Items import ItemData, ItemType, l2ac_item_name_to_id, l2ac_item_table, L2ACItem, start_id as items_start_id
|
||||
from .Locations import l2ac_location_name_to_id, L2ACLocation
|
||||
from .Options import Boss, CapsuleStartingForm, CapsuleStartingLevel, Goal, l2ac_option_definitions, MasterHp, \
|
||||
PartyStartingLevel, ShuffleCapsuleMonsters, ShufflePartyMembers, StartingParty
|
||||
from .Options import Boss, CapsuleStartingForm, CapsuleStartingLevel, DefaultParty, Goal, l2ac_option_definitions, \
|
||||
MasterHp, PartyStartingLevel, ShuffleCapsuleMonsters, ShufflePartyMembers
|
||||
from .Rom import get_base_rom_bytes, get_base_rom_path, L2ACDeltaPatch
|
||||
from .basepatch import apply_basepatch
|
||||
|
||||
|
@ -64,6 +64,8 @@ class L2ACWorld(World):
|
|||
capsule_starting_level: Optional[CapsuleStartingLevel]
|
||||
crowded_floor_chance: Optional[int]
|
||||
death_link: Optional[int]
|
||||
default_capsule: Optional[int]
|
||||
default_party: Optional[DefaultParty]
|
||||
final_floor: Optional[int]
|
||||
gear_variety_after_b9: Optional[int]
|
||||
goal: Optional[int]
|
||||
|
@ -76,8 +78,6 @@ class L2ACWorld(World):
|
|||
run_speed: Optional[int]
|
||||
shuffle_capsule_monsters: Optional[ShuffleCapsuleMonsters]
|
||||
shuffle_party_members: Optional[ShufflePartyMembers]
|
||||
starting_capsule: Optional[int]
|
||||
starting_party: Optional[StartingParty]
|
||||
|
||||
@classmethod
|
||||
def stage_assert_generate(cls, _multiworld: MultiWorld) -> None:
|
||||
|
@ -103,6 +103,8 @@ class L2ACWorld(World):
|
|||
self.capsule_starting_level = self.multiworld.capsule_starting_level[self.player]
|
||||
self.crowded_floor_chance = self.multiworld.crowded_floor_chance[self.player].value
|
||||
self.death_link = self.multiworld.death_link[self.player].value
|
||||
self.default_capsule = self.multiworld.default_capsule[self.player].value
|
||||
self.default_party = self.multiworld.default_party[self.player]
|
||||
self.final_floor = self.multiworld.final_floor[self.player].value
|
||||
self.gear_variety_after_b9 = self.multiworld.gear_variety_after_b9[self.player].value
|
||||
self.goal = self.multiworld.goal[self.player].value
|
||||
|
@ -115,8 +117,6 @@ class L2ACWorld(World):
|
|||
self.run_speed = self.multiworld.run_speed[self.player].value
|
||||
self.shuffle_capsule_monsters = self.multiworld.shuffle_capsule_monsters[self.player]
|
||||
self.shuffle_party_members = self.multiworld.shuffle_party_members[self.player]
|
||||
self.starting_capsule = self.multiworld.starting_capsule[self.player].value
|
||||
self.starting_party = self.multiworld.starting_party[self.player]
|
||||
|
||||
if self.capsule_starting_level.value == CapsuleStartingLevel.special_range_names["party_starting_level"]:
|
||||
self.capsule_starting_level.value = self.party_starting_level.value
|
||||
|
@ -125,7 +125,7 @@ class L2ACWorld(World):
|
|||
if self.master_hp == MasterHp.special_range_names["scale"]:
|
||||
self.master_hp = MasterHp.scale(self.final_floor)
|
||||
if self.shuffle_party_members:
|
||||
self.starting_party.value = StartingParty.default
|
||||
self.default_party.value = DefaultParty.default
|
||||
|
||||
def create_regions(self) -> None:
|
||||
menu = Region("Menu", RegionType.Generic, "Menu", self.player, self.multiworld)
|
||||
|
@ -234,13 +234,13 @@ class L2ACWorld(World):
|
|||
rom_bytearray[0x019E82:0x019E82 + 1] = self.final_floor.to_bytes(1, "little")
|
||||
rom_bytearray[0x01FC75:0x01FC75 + 1] = self.run_speed.to_bytes(1, "little")
|
||||
rom_bytearray[0x01FC81:0x01FC81 + 1] = self.run_speed.to_bytes(1, "little")
|
||||
rom_bytearray[0x02B2A1:0x02B2A1 + 5] = self.starting_party.roster
|
||||
rom_bytearray[0x02B2A1:0x02B2A1 + 5] = self.default_party.roster
|
||||
for offset in range(0x02B395, 0x02B452, 0x1B):
|
||||
rom_bytearray[offset:offset + 1] = self.party_starting_level.value.to_bytes(1, "little")
|
||||
for offset in range(0x02B39A, 0x02B457, 0x1B):
|
||||
rom_bytearray[offset:offset + 3] = self.party_starting_level.xp.to_bytes(3, "little")
|
||||
rom_bytearray[0x05699E:0x05699E + 147] = self.get_goal_text_bytes()
|
||||
rom_bytearray[0x056AA3:0x056AA3 + 24] = self.starting_party.event_script
|
||||
rom_bytearray[0x056AA3:0x056AA3 + 24] = self.default_party.event_script
|
||||
rom_bytearray[0x072742:0x072742 + 1] = self.boss.value.to_bytes(1, "little")
|
||||
rom_bytearray[0x072748:0x072748 + 1] = self.boss.flag.to_bytes(1, "little")
|
||||
rom_bytearray[0x09D59B:0x09D59B + 256] = self.get_node_connection_table()
|
||||
|
@ -248,7 +248,7 @@ class L2ACWorld(World):
|
|||
rom_bytearray[0x280010:0x280010 + 2] = self.blue_chest_count.to_bytes(2, "little")
|
||||
rom_bytearray[0x280012:0x280012 + 3] = self.capsule_starting_level.xp.to_bytes(3, "little")
|
||||
rom_bytearray[0x280015:0x280015 + 1] = self.initial_floor.to_bytes(1, "little")
|
||||
rom_bytearray[0x280016:0x280016 + 1] = self.starting_capsule.to_bytes(1, "little")
|
||||
rom_bytearray[0x280016:0x280016 + 1] = self.default_capsule.to_bytes(1, "little")
|
||||
rom_bytearray[0x280017:0x280017 + 1] = self.iris_treasures_required.to_bytes(1, "little")
|
||||
rom_bytearray[0x280018:0x280018 + 1] = self.shuffle_party_members.unlock.to_bytes(1, "little")
|
||||
rom_bytearray[0x280019:0x280019 + 1] = self.shuffle_capsule_monsters.unlock.to_bytes(1, "little")
|
||||
|
|
|
@ -42,9 +42,9 @@ Your Party Leader will hold up the item they received when not in a fight or in
|
|||
Retrieve a (customizable) number of iris treasures from the cave; 4) Retrieve the iris treasures *and* defeat the boss
|
||||
- You can also randomize the goal; The blue-haired NPC in front of the cafe can tell you about the selected objective
|
||||
- Customize (or randomize) the chances of encountering blue chests, healing tiles, iris treasures, etc.
|
||||
- Customize (or randomize) your starting party members and/or party level
|
||||
- Customize (or randomize) your starting capsule monster and/or capsule monster level as well as form
|
||||
- Customize (or randomize) the initial and/or final floor numbers
|
||||
- Customize (or randomize) the default party lineup and capsule monster
|
||||
- Customize (or randomize) the party starting level as well as capsule monster level and form
|
||||
- Customize (or randomize) the initial and final floor numbers
|
||||
- Customize (or randomize) the boss that resides on the final floor
|
||||
- Customize start inventory, i.e., begin every run with certain items or spells of your choice
|
||||
- Option to shuffle your party members and/or capsule monsters into the multiworld, meaning that someone will have to
|
||||
|
|
Loading…
Reference in New Issue