Files
Grinch-AP/worlds/sa2b/GateBosses.py
PoryGone 0ad4527719 SA2B: Logic Fixes (#5095)
- Fixed King Boom Boo being able to appear in multiple boss gates
- `Final Rush - 16 Animals (Expert)` no longer requires `Sonic - Bounce Bracelet`
- `Dry Lagoon - 5 (Standard)` now requires `Rouge - Pick Nails`
- `Sand Ocean - Extra Life Box 2 (Standard/Hard/Expert)` no longer requires `Eggman - Jet Engine`
- `Security Hall - 8 Animals (Expert)` no longer requires `Rouge - Pick Nails`
- `Sky Rail - Item Box 8 (Standard)` now requires `Shadow - Air Shoes` and `Shadow - Mystic Melody`
- `Cosmic Wall - Chao Key 1 (Standard/Hard/Expert)` no longer requires `Eggman - Mystic Melody`
- `Cannon's Core - Pipe 2 (Expert)` no longer requires `Tails - Booster`
- `Cannon's Core - Gold Beetle` no longer requires `Tails - Booster` nor `Knuckles - Hammer Gloves`
2025-06-13 22:01:19 +02:00

161 lines
5.0 KiB
Python

import typing
from BaseClasses import MultiWorld
from Options import OptionError
from worlds.AutoWorld import World
from .Names import LocationName
from .Options import GateBossPlando
speed_characters_1 = "sonic vs shadow 1"
speed_characters_2 = "sonic vs shadow 2"
mech_characters_1 = "tails vs eggman 1"
mech_characters_2 = "tails vs eggman 2"
hunt_characters_1 = "knuckles vs rouge 1"
big_foot = "big foot"
hot_shot = "hot shot"
flying_dog = "flying dog"
egg_golem_sonic = "egg golem (sonic)"
egg_golem_eggman = "egg golem (eggman)"
king_boom_boo = "king boom boo"
gate_bosses_no_requirements_table = {
speed_characters_1: 0,
speed_characters_2: 1,
mech_characters_1: 2,
mech_characters_2: 3,
hunt_characters_1: 4,
big_foot: 5,
hot_shot: 6,
flying_dog: 7,
egg_golem_sonic: 8,
egg_golem_eggman: 9,
}
gate_bosses_with_requirements_table = {
king_boom_boo: 10,
}
extra_boss_rush_bosses_table = {
speed_characters_1: 11,
speed_characters_2: 12,
mech_characters_1: 13,
mech_characters_2: 14,
hunt_characters_1: 15,
}
all_gate_bosses_table = {
**gate_bosses_no_requirements_table,
**gate_bosses_with_requirements_table,
}
boss_id_to_name = {
0: "Sonic vs Shadow 1",
1: "Sonic vs Shadow 2",
2: "Tails vs Eggman 1",
3: "Tails vs Eggman 2",
4: "Knuckles vs Rouge 1",
5: "F-6t BIG FOOT",
6: "B-3x HOT SHOT",
7: "R-1/A FLYING DOG",
8: "Egg Golem (Sonic)",
9: "Egg Golem (Eggman)",
10: "King Boom Boo",
11: "Sonic vs Shadow 1",
12: "Sonic vs Shadow 2",
13: "Tails vs Eggman 1",
14: "Tails vs Eggman 2",
15: "Knuckles vs Rouge 1",
}
def get_boss_name(boss: int):
return boss_id_to_name[boss]
def boss_has_requirement(boss: int):
return boss >= len(gate_bosses_no_requirements_table)
def get_gate_bosses(world: World):
selected_bosses: typing.List[int] = []
boss_gates: typing.List[int] = []
available_bosses: typing.List[str] = list(gate_bosses_no_requirements_table.keys())
world.random.shuffle(available_bosses)
gate_boss_plando: typing.Union[int, str] = world.options.gate_boss_plando.value
plando_bosses = ["None", "None", "None", "None", "None"]
if isinstance(gate_boss_plando, str):
# boss plando
options = gate_boss_plando.split(";")
gate_boss_plando = GateBossPlando.options[options.pop()]
for option in options:
if "-" in option:
loc, boss = option.split("-")
boss_num = LocationName.boss_gate_names[loc]
if boss_num >= world.options.number_of_level_gates.value:
# Don't reject bosses plando'd into gate bosses that won't exist
pass
if boss in plando_bosses:
raise OptionError(f"Invalid input for option `plando_bosses`: "
f"No Duplicate Bosses permitted ({boss}) - for "
f"{world.player_name}")
plando_bosses[boss_num] = boss
if boss in available_bosses:
available_bosses.remove(boss)
for x in range(world.options.number_of_level_gates):
if (10 not in selected_bosses) and (king_boom_boo not in available_bosses) and ((x + 1) / world.options.number_of_level_gates) > 0.5:
available_bosses.extend(gate_bosses_with_requirements_table.keys())
world.random.shuffle(available_bosses)
chosen_boss = available_bosses[0]
if plando_bosses[x] != "None":
if plando_bosses[x] not in available_bosses:
available_bosses.append(plando_bosses[x])
chosen_boss = plando_bosses[x]
selected_bosses.append(all_gate_bosses_table[chosen_boss])
boss_gates.append(x + 1)
available_bosses.remove(chosen_boss)
bosses: typing.Dict[int, int] = dict(zip(boss_gates, selected_bosses))
return bosses
def get_boss_rush_bosses(world: World):
if world.options.boss_rush_shuffle == 0:
boss_list_o = list(range(0, 16))
boss_list_s = [5, 2, 0, 10, 8, 4, 3, 1, 6, 13, 7, 11, 9, 15, 14, 12]
return dict(zip(boss_list_o, boss_list_s))
elif world.options.boss_rush_shuffle == 1:
boss_list_o = list(range(0, 16))
boss_list_s = boss_list_o.copy()
world.random.shuffle(boss_list_s)
return dict(zip(boss_list_o, boss_list_s))
elif world.options.boss_rush_shuffle == 2:
boss_list_o = list(range(0, 16))
boss_list_s = [world.random.choice(boss_list_o) for i in range(0, 16)]
if 10 not in boss_list_s:
boss_list_s[world.random.randint(0, 15)] = 10
return dict(zip(boss_list_o, boss_list_s))
elif world.options.boss_rush_shuffle == 3:
boss_list_o = list(range(0, 16))
boss_list_s = [world.random.choice(boss_list_o)] * len(boss_list_o)
if 10 not in boss_list_s:
boss_list_s[world.random.randint(0, 15)] = 10
return dict(zip(boss_list_o, boss_list_s))
else:
return dict()