Skip to content

Commit

Permalink
lufia2ac: rename starting_capsule/starting_party options to default_c…
Browse files Browse the repository at this point in the history
…apsule/default_party
  • Loading branch information
el-u authored and Berserker66 committed Dec 19, 2022
1 parent ff9c11d commit 4cfc73b
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 90 deletions.
154 changes: 77 additions & 77 deletions worlds/lufia2ac/Options.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -439,81 +514,6 @@ def unlock(self) -> int:
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,
Expand All @@ -523,6 +523,8 @@ def __len__(self) -> int:
"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,
Expand All @@ -535,6 +537,4 @@ def __len__(self) -> int:
"run_speed": RunSpeed,
"shuffle_capsule_monsters": ShuffleCapsuleMonsters,
"shuffle_party_members": ShufflePartyMembers,
"starting_capsule": StartingCapsule,
"starting_party": StartingParty,
}
20 changes: 10 additions & 10 deletions worlds/lufia2ac/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
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

Expand Down Expand Up @@ -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]
Expand All @@ -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:
Expand All @@ -103,6 +103,8 @@ def generate_early(self) -> None:
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
Expand All @@ -115,8 +117,6 @@ def generate_early(self) -> None:
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
Expand All @@ -125,7 +125,7 @@ def generate_early(self) -> None:
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)
Expand Down Expand Up @@ -234,21 +234,21 @@ def generate_output(self, output_directory: str) -> None:
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()
rom_bytearray[0x0B4F02:0x0B4F02 + 2] = self.master_hp.to_bytes(2, "little")
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")
Expand Down
6 changes: 3 additions & 3 deletions worlds/lufia2ac/docs/en_Lufia II Ancient Cave.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 4cfc73b

Please sign in to comment.