mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
SA2B: v2.4 - Minigame Madness (#4663)
Changelog: Features: - New Goal - Minigame Madness - Win a certain number of each type of Minigame Trap, then defeat the Finalhazard to win! - How many of each Minigame are required can be set by an Option - When the required amount of a Minigame has been received, that Minigame can be replayed in the Chao World Lobby - New optional Location Checks - Bigsanity - Go fishing with Big in each stage for a Location Check - Itemboxsanity - Either Extra Life Boxes or All Item Boxes - New Items - New Traps - Literature Trap - Controller Drift Trap - Poison Trap - Bee Trap - New Minigame Traps - Breakout Trap - Fishing Trap - Trivia Trap - Pokemon Trivia Trap - Pokemon Count Trap - Number Sequence Trap - Light Up Path Trap - Pinball Trap - Math Quiz Trap - Snake Trap - Input Sequence Trap - Trap Link - When you receive a trap, you send a copy of it to every other player with Trap Link enabled - Boss Gate Plando - Expert Logic Difficulty - Use at your own risk. This difficulty requires complete mastery of SA2. - Missions can now be enabled and disabled per-character, instead of just per-style - Minigame Difficulty can now be set to "Chaos", which selects a new difficulty randomly per-trap received Quality of Life: - Gate Stages and Mission Orders are now displayed in the spoiler log - Additional play stats are saved and displayed with the randomizer credits - Stage Locations progress UI now displays in multiple pages when Itemboxsanity is enabled - Current stage mission order and progress are now shown when paused in-level - Chaos Emeralds are now shown when paused in-level - Location Name Groups were created - Moved SA2B to the new Options system - Option Presets were created - Error Messages are more obvious Bug Fixes: - Added missing `Dry Lagoon - 12 Animals` location - Flying Dog boss should no longer crash when you have done at least 3 Intermediate Kart Races - Invincibility can no longer be received in the King Boom Boo fight, preventing a crash - Chaos Emeralds should no longer disproportionately end up in Cannon's Core or the final Level Gate - Going into submenus from the pause menu should no longer reset traps - `Sonic - Magic Gloves` are now plural - Junk items will no longer cause a crash when in a falling state - Chao Garden: - Prevent races from occasionally becoming uncompletable when using the "Prize Only" option - Properly allow Hero Chao to participate in Dark Races - Don't allow the Chao Garden to send locations when connected to an invalid server - Prevent the Chao Garden from resetting your life count - Fix Chao World Entrance Shuffle causing inaccessible Neutral Garden - Fix pressing the 'B' button to take you to the proper location in Chao World Entrance Shuffle - Prevent Chao Karate progress icon overflow - Prevent changing Chao Timescale while paused or while a Minigame is active - Logic Fixes: - `Mission Street - Chao Key 1` (Hard Logic) now requires no upgrades - `Mission Street - Chao Key 2` (Hard Logic) now requires no upgrades - `Crazy Gadget - Hidden 1` (Standard Logic) now requires `Sonic - Bounce Bracelet` instead of `Sonic - Light Shoes` - `Lost Colony - Hidden 1` (Standard Logic) now requires `Eggman - Jet Engine` - `Mad Space - Gold Beetle` (Standard Logic) now only requires `Rouge - Iron Boots` - `Cosmic Wall - Gold Beetle` (Standard and Hard Logic) now only requires `Eggman - Jet Engine`
This commit is contained in:
@@ -150,6 +150,26 @@ sample_chao_names = [
|
|||||||
"Hubert",
|
"Hubert",
|
||||||
"Corvus",
|
"Corvus",
|
||||||
"Nigel",
|
"Nigel",
|
||||||
|
"Benjamin",
|
||||||
|
"Gooey",
|
||||||
|
"Maddy",
|
||||||
|
"AFGNCAAP",
|
||||||
|
"Reinhardt",
|
||||||
|
"Claire",
|
||||||
|
"Yoshi",
|
||||||
|
"Peasley",
|
||||||
|
"Faux",
|
||||||
|
"Naija",
|
||||||
|
"Kaiba",
|
||||||
|
"Hat Kid",
|
||||||
|
"TzTokJad",
|
||||||
|
"Sora",
|
||||||
|
"WoodMan",
|
||||||
|
"Yachty",
|
||||||
|
"Grieve",
|
||||||
|
"Portia",
|
||||||
|
"Graves",
|
||||||
|
"Kaycee",
|
||||||
]
|
]
|
||||||
|
|
||||||
totally_real_item_names = [
|
totally_real_item_names = [
|
||||||
@@ -240,6 +260,35 @@ totally_real_item_names = [
|
|||||||
"Ladder",
|
"Ladder",
|
||||||
|
|
||||||
"Visible Dots",
|
"Visible Dots",
|
||||||
|
|
||||||
|
"CooCoo",
|
||||||
|
|
||||||
|
"Blueberry",
|
||||||
|
|
||||||
|
"Ear of Luigi",
|
||||||
|
|
||||||
|
"Mega Nut",
|
||||||
|
|
||||||
|
"DUELIST ALLIANCE",
|
||||||
|
"DUEL OVERLOAD",
|
||||||
|
"POWER OF THE ELEMENTS",
|
||||||
|
"S:P Little Knight",
|
||||||
|
"Red-Eyes Dark Dragoon",
|
||||||
|
|
||||||
|
"Fire Hat",
|
||||||
|
|
||||||
|
"Area: Taverly",
|
||||||
|
"Area: Meiyerditch",
|
||||||
|
"Fire Cape",
|
||||||
|
|
||||||
|
"Donald Zeta Flare",
|
||||||
|
|
||||||
|
"Category One of a Kind",
|
||||||
|
"Category Fuller House",
|
||||||
|
|
||||||
|
"Passive Camoflage",
|
||||||
|
|
||||||
|
"Earth Card",
|
||||||
]
|
]
|
||||||
|
|
||||||
all_exits = [
|
all_exits = [
|
||||||
|
@@ -1,6 +1,82 @@
|
|||||||
# Sonic Adventure 2 Battle - Changelog
|
# Sonic Adventure 2 Battle - Changelog
|
||||||
|
|
||||||
|
|
||||||
|
## v2.4 - Minigame Madness
|
||||||
|
|
||||||
|
### Features:
|
||||||
|
- New Goal
|
||||||
|
- Minigame Madness
|
||||||
|
- Win a certain number of each type of Minigame Trap, then defeat the Finalhazard to win!
|
||||||
|
- How many of each Minigame are required can be set by an Option
|
||||||
|
- When the required amount of a Minigame has been received, that Minigame can be replayed in the Chao World Lobby
|
||||||
|
- New optional Location Checks
|
||||||
|
- Bigsanity
|
||||||
|
- Go fishing with Big in each stage for a Location Check
|
||||||
|
- Itemboxsanity
|
||||||
|
- Either Extra Life Boxes or All Item Boxes
|
||||||
|
- New Items
|
||||||
|
- New Traps
|
||||||
|
- Literature Trap
|
||||||
|
- Controller Drift Trap
|
||||||
|
- Poison Trap
|
||||||
|
- Bee Trap
|
||||||
|
- New Minigame Traps
|
||||||
|
- Breakout Trap
|
||||||
|
- Fishing Trap
|
||||||
|
- Trivia Trap
|
||||||
|
- Pokemon Trivia Trap
|
||||||
|
- Pokemon Count Trap
|
||||||
|
- Number Sequence Trap
|
||||||
|
- Light Up Path Trap
|
||||||
|
- Pinball Trap
|
||||||
|
- Math Quiz Trap
|
||||||
|
- Snake Trap
|
||||||
|
- Input Sequence Trap
|
||||||
|
- Trap Link
|
||||||
|
- When you receive a trap, you send a copy of it to every other player with Trap Link enabled
|
||||||
|
- Boss Gate Plando
|
||||||
|
- Expert Logic Difficulty
|
||||||
|
- Use at your own risk. This difficulty requires complete mastery of SA2.
|
||||||
|
- Missions can now be enabled and disabled per-character, instead of just per-style
|
||||||
|
- Minigame Difficulty can now be set to "Chaos", which selects a new difficulty randomly per-trap received
|
||||||
|
|
||||||
|
### Quality of Life:
|
||||||
|
- Gate Stages and Mission Orders are now displayed in the spoiler log
|
||||||
|
- Additional play stats are saved and displayed with the randomizer credits
|
||||||
|
- Stage Locations progress UI now displays in multiple pages when Itemboxsanity is enabled
|
||||||
|
- Current stage mission order and progress are now shown when paused in-level
|
||||||
|
- Chaos Emeralds are now shown when paused in-level
|
||||||
|
- Location Name Groups were created
|
||||||
|
- Moved SA2B to the new Options system
|
||||||
|
- Option Presets were created
|
||||||
|
- Error Messages are more obvious
|
||||||
|
|
||||||
|
### Bug Fixes:
|
||||||
|
- Added missing `Dry Lagoon - 12 Animals` location
|
||||||
|
- Flying Dog boss should no longer crash when you have done at least 3 Intermediate Kart Races
|
||||||
|
- Invincibility can no longer be received in the King Boom Boo fight, preventing a crash
|
||||||
|
- Chaos Emeralds should no longer disproportionately end up in Cannon's Core or the final Level Gate
|
||||||
|
- Going into submenus from the pause menu should no longer reset traps
|
||||||
|
- `Sonic - Magic Gloves` are now plural
|
||||||
|
- Junk items will no longer cause a crash when in a falling state
|
||||||
|
- Chao Garden:
|
||||||
|
- Prevent races from occasionally becoming uncompletable when using the "Prize Only" option
|
||||||
|
- Properly allow Hero Chao to participate in Dark Races
|
||||||
|
- Don't allow the Chao Garden to send locations when connected to an invalid server
|
||||||
|
- Prevent the Chao Garden from resetting your life count
|
||||||
|
- Fix Chao World Entrance Shuffle causing inaccessible Neutral Garden
|
||||||
|
- Fix pressing the 'B' button to take you to the proper location in Chao World Entrance Shuffle
|
||||||
|
- Prevent Chao Karate progress icon overflow
|
||||||
|
- Prevent changing Chao Timescale while paused or while a Minigame is active
|
||||||
|
- Logic Fixes:
|
||||||
|
- `Mission Street - Chao Key 1` (Hard Logic) now requires no upgrades
|
||||||
|
- `Mission Street - Chao Key 2` (Hard Logic) now requires no upgrades
|
||||||
|
- `Crazy Gadget - Hidden 1` (Standard Logic) now requires `Sonic - Bounce Bracelet` instead of `Sonic - Light Shoes`
|
||||||
|
- `Lost Colony - Hidden 1` (Standard Logic) now requires `Eggman - Jet Engine`
|
||||||
|
- `Mad Space - Gold Beetle` (Standard Logic) now only requires `Rouge - Iron Boots`
|
||||||
|
- `Cosmic Wall - Gold Beetle` (Standard and Hard Logic) now only requires `Eggman - Jet Engine`
|
||||||
|
|
||||||
|
|
||||||
## v2.3 - The Chao Update
|
## v2.3 - The Chao Update
|
||||||
|
|
||||||
### Features:
|
### Features:
|
||||||
|
@@ -1,18 +1,23 @@
|
|||||||
import typing
|
import typing
|
||||||
|
|
||||||
from BaseClasses import MultiWorld
|
from BaseClasses import MultiWorld
|
||||||
from worlds.AutoWorld import World
|
from worlds.AutoWorld import World
|
||||||
|
|
||||||
speed_characters_1 = "Sonic vs Shadow 1"
|
from .Names import LocationName
|
||||||
speed_characters_2 = "Sonic vs Shadow 2"
|
from .Options import GateBossPlando
|
||||||
mech_characters_1 = "Tails vs Eggman 1"
|
|
||||||
mech_characters_2 = "Tails vs Eggman 2"
|
|
||||||
hunt_characters_1 = "Knuckles vs Rouge 1"
|
speed_characters_1 = "sonic vs shadow 1"
|
||||||
big_foot = "F-6t BIG FOOT"
|
speed_characters_2 = "sonic vs shadow 2"
|
||||||
hot_shot = "B-3x HOT SHOT"
|
mech_characters_1 = "tails vs eggman 1"
|
||||||
flying_dog = "R-1/A FLYING DOG"
|
mech_characters_2 = "tails vs eggman 2"
|
||||||
egg_golem_sonic = "Egg Golem (Sonic)"
|
hunt_characters_1 = "knuckles vs rouge 1"
|
||||||
egg_golem_eggman = "Egg Golem (Eggman)"
|
big_foot = "big foot"
|
||||||
king_boom_boo = "King Boom Boo"
|
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 = {
|
gate_bosses_no_requirements_table = {
|
||||||
speed_characters_1: 0,
|
speed_characters_1: 0,
|
||||||
@@ -45,44 +50,83 @@ all_gate_bosses_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):
|
def get_boss_name(boss: int):
|
||||||
for key, value in gate_bosses_no_requirements_table.items():
|
return boss_id_to_name[boss]
|
||||||
if value == boss:
|
|
||||||
return key
|
|
||||||
for key, value in gate_bosses_with_requirements_table.items():
|
|
||||||
if value == boss:
|
|
||||||
return key
|
|
||||||
for key, value in extra_boss_rush_bosses_table.items():
|
|
||||||
if value == boss:
|
|
||||||
return key
|
|
||||||
|
|
||||||
|
|
||||||
def boss_has_requirement(boss: int):
|
def boss_has_requirement(boss: int):
|
||||||
return boss >= len(gate_bosses_no_requirements_table)
|
return boss >= len(gate_bosses_no_requirements_table)
|
||||||
|
|
||||||
|
|
||||||
def get_gate_bosses(multiworld: MultiWorld, world: World):
|
def get_gate_bosses(world: World):
|
||||||
selected_bosses: typing.List[int] = []
|
selected_bosses: typing.List[int] = []
|
||||||
boss_gates: typing.List[int] = []
|
boss_gates: typing.List[int] = []
|
||||||
available_bosses: typing.List[str] = list(gate_bosses_no_requirements_table.keys())
|
available_bosses: typing.List[str] = list(gate_bosses_no_requirements_table.keys())
|
||||||
multiworld.random.shuffle(available_bosses)
|
world.random.shuffle(available_bosses)
|
||||||
halfway = False
|
|
||||||
|
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:
|
||||||
|
# TODO: Raise error here. Duplicates not allowed
|
||||||
|
pass
|
||||||
|
|
||||||
|
plando_bosses[boss_num] = boss
|
||||||
|
|
||||||
|
if boss in available_bosses:
|
||||||
|
available_bosses.remove(boss)
|
||||||
|
|
||||||
for x in range(world.options.number_of_level_gates):
|
for x in range(world.options.number_of_level_gates):
|
||||||
if (not halfway) and ((x + 1) / world.options.number_of_level_gates) > 0.5:
|
if ("king boom boo" 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)
|
available_bosses.extend(gate_bosses_with_requirements_table)
|
||||||
multiworld.random.shuffle(available_bosses)
|
world.random.shuffle(available_bosses)
|
||||||
halfway = True
|
|
||||||
selected_bosses.append(all_gate_bosses_table[available_bosses[0]])
|
chosen_boss = available_bosses[0]
|
||||||
|
if plando_bosses[x] != "None":
|
||||||
|
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)
|
boss_gates.append(x + 1)
|
||||||
available_bosses.remove(available_bosses[0])
|
available_bosses.remove(chosen_boss)
|
||||||
|
|
||||||
bosses: typing.Dict[int, int] = dict(zip(boss_gates, selected_bosses))
|
bosses: typing.Dict[int, int] = dict(zip(boss_gates, selected_bosses))
|
||||||
|
|
||||||
return bosses
|
return bosses
|
||||||
|
|
||||||
|
|
||||||
def get_boss_rush_bosses(multiworld: MultiWorld, world: World):
|
def get_boss_rush_bosses(world: World):
|
||||||
|
|
||||||
if world.options.boss_rush_shuffle == 0:
|
if world.options.boss_rush_shuffle == 0:
|
||||||
boss_list_o = list(range(0, 16))
|
boss_list_o = list(range(0, 16))
|
||||||
@@ -92,21 +136,21 @@ def get_boss_rush_bosses(multiworld: MultiWorld, world: World):
|
|||||||
elif world.options.boss_rush_shuffle == 1:
|
elif world.options.boss_rush_shuffle == 1:
|
||||||
boss_list_o = list(range(0, 16))
|
boss_list_o = list(range(0, 16))
|
||||||
boss_list_s = boss_list_o.copy()
|
boss_list_s = boss_list_o.copy()
|
||||||
multiworld.random.shuffle(boss_list_s)
|
world.random.shuffle(boss_list_s)
|
||||||
|
|
||||||
return dict(zip(boss_list_o, boss_list_s))
|
return dict(zip(boss_list_o, boss_list_s))
|
||||||
elif world.options.boss_rush_shuffle == 2:
|
elif world.options.boss_rush_shuffle == 2:
|
||||||
boss_list_o = list(range(0, 16))
|
boss_list_o = list(range(0, 16))
|
||||||
boss_list_s = [multiworld.random.choice(boss_list_o) for i in 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:
|
if 10 not in boss_list_s:
|
||||||
boss_list_s[multiworld.random.randint(0, 15)] = 10
|
boss_list_s[world.random.randint(0, 15)] = 10
|
||||||
|
|
||||||
return dict(zip(boss_list_o, boss_list_s))
|
return dict(zip(boss_list_o, boss_list_s))
|
||||||
elif world.options.boss_rush_shuffle == 3:
|
elif world.options.boss_rush_shuffle == 3:
|
||||||
boss_list_o = list(range(0, 16))
|
boss_list_o = list(range(0, 16))
|
||||||
boss_list_s = [multiworld.random.choice(boss_list_o)] * len(boss_list_o)
|
boss_list_s = [world.random.choice(boss_list_o)] * len(boss_list_o)
|
||||||
if 10 not in boss_list_s:
|
if 10 not in boss_list_s:
|
||||||
boss_list_s[multiworld.random.randint(0, 15)] = 10
|
boss_list_s[world.random.randint(0, 15)] = 10
|
||||||
|
|
||||||
return dict(zip(boss_list_o, boss_list_s))
|
return dict(zip(boss_list_o, boss_list_s))
|
||||||
else:
|
else:
|
||||||
|
@@ -2,7 +2,6 @@ import typing
|
|||||||
|
|
||||||
from BaseClasses import Item, ItemClassification
|
from BaseClasses import Item, ItemClassification
|
||||||
from .Names import ItemName
|
from .Names import ItemName
|
||||||
from worlds.alttp import ALTTPWorld
|
|
||||||
|
|
||||||
|
|
||||||
class ItemData(typing.NamedTuple):
|
class ItemData(typing.NamedTuple):
|
||||||
@@ -14,7 +13,7 @@ class ItemData(typing.NamedTuple):
|
|||||||
|
|
||||||
|
|
||||||
class SA2BItem(Item):
|
class SA2BItem(Item):
|
||||||
game: str = "Sonic Adventure 2: Battle"
|
game: str = "Sonic Adventure 2 Battle"
|
||||||
|
|
||||||
def __init__(self, name, classification: ItemClassification, code: int = None, player: int = None):
|
def __init__(self, name, classification: ItemClassification, code: int = None, player: int = None):
|
||||||
super(SA2BItem, self).__init__(name, classification, code, player)
|
super(SA2BItem, self).__init__(name, classification, code, player)
|
||||||
@@ -73,19 +72,36 @@ junk_table = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
trap_table = {
|
trap_table = {
|
||||||
ItemName.omochao_trap: ItemData(0xFF0030, False, True),
|
ItemName.omochao_trap: ItemData(0xFF0030, False, True),
|
||||||
ItemName.timestop_trap: ItemData(0xFF0031, False, True),
|
ItemName.timestop_trap: ItemData(0xFF0031, False, True),
|
||||||
ItemName.confuse_trap: ItemData(0xFF0032, False, True),
|
ItemName.confuse_trap: ItemData(0xFF0032, False, True),
|
||||||
ItemName.tiny_trap: ItemData(0xFF0033, False, True),
|
ItemName.tiny_trap: ItemData(0xFF0033, False, True),
|
||||||
ItemName.gravity_trap: ItemData(0xFF0034, False, True),
|
ItemName.gravity_trap: ItemData(0xFF0034, False, True),
|
||||||
ItemName.exposition_trap: ItemData(0xFF0035, False, True),
|
ItemName.exposition_trap: ItemData(0xFF0035, False, True),
|
||||||
#ItemName.darkness_trap: ItemData(0xFF0036, False, True),
|
#ItemName.darkness_trap: ItemData(0xFF0036, False, True),
|
||||||
ItemName.ice_trap: ItemData(0xFF0037, False, True),
|
ItemName.ice_trap: ItemData(0xFF0037, False, True),
|
||||||
ItemName.slow_trap: ItemData(0xFF0038, False, True),
|
ItemName.slow_trap: ItemData(0xFF0038, False, True),
|
||||||
ItemName.cutscene_trap: ItemData(0xFF0039, False, True),
|
ItemName.cutscene_trap: ItemData(0xFF0039, False, True),
|
||||||
ItemName.reverse_trap: ItemData(0xFF003A, False, True),
|
ItemName.reverse_trap: ItemData(0xFF003A, False, True),
|
||||||
|
ItemName.literature_trap: ItemData(0xFF003B, False, True),
|
||||||
|
ItemName.controller_drift_trap: ItemData(0xFF003C, False, True),
|
||||||
|
ItemName.poison_trap: ItemData(0xFF003D, False, True),
|
||||||
|
ItemName.bee_trap: ItemData(0xFF003E, False, True),
|
||||||
|
}
|
||||||
|
|
||||||
ItemName.pong_trap: ItemData(0xFF0050, False, True),
|
minigame_trap_table = {
|
||||||
|
ItemName.pong_trap: ItemData(0xFF0050, False, True),
|
||||||
|
ItemName.breakout_trap: ItemData(0xFF0051, False, True),
|
||||||
|
ItemName.fishing_trap: ItemData(0xFF0052, False, True),
|
||||||
|
ItemName.trivia_trap: ItemData(0xFF0053, False, True),
|
||||||
|
ItemName.pokemon_trivia_trap: ItemData(0xFF0054, False, True),
|
||||||
|
ItemName.pokemon_count_trap: ItemData(0xFF0055, False, True),
|
||||||
|
ItemName.number_sequence_trap: ItemData(0xFF0056, False, True),
|
||||||
|
ItemName.light_up_path_trap: ItemData(0xFF0057, False, True),
|
||||||
|
ItemName.pinball_trap: ItemData(0xFF0058, False, True),
|
||||||
|
ItemName.math_quiz_trap: ItemData(0xFF0059, False, True),
|
||||||
|
ItemName.snake_trap: ItemData(0xFF005A, False, True),
|
||||||
|
ItemName.input_sequence_trap: ItemData(0xFF005B, False, True),
|
||||||
}
|
}
|
||||||
|
|
||||||
emeralds_table = {
|
emeralds_table = {
|
||||||
@@ -235,7 +251,7 @@ chaos_drives_table = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
event_table = {
|
event_table = {
|
||||||
ItemName.maria: ItemData(0xFF001D, True),
|
ItemName.maria: ItemData(None, True),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Complete item table.
|
# Complete item table.
|
||||||
@@ -244,6 +260,7 @@ item_table = {
|
|||||||
**upgrades_table,
|
**upgrades_table,
|
||||||
**junk_table,
|
**junk_table,
|
||||||
**trap_table,
|
**trap_table,
|
||||||
|
**minigame_trap_table,
|
||||||
**emeralds_table,
|
**emeralds_table,
|
||||||
**eggs_table,
|
**eggs_table,
|
||||||
**fruits_table,
|
**fruits_table,
|
||||||
@@ -251,7 +268,6 @@ item_table = {
|
|||||||
**hats_table,
|
**hats_table,
|
||||||
**animals_table,
|
**animals_table,
|
||||||
**chaos_drives_table,
|
**chaos_drives_table,
|
||||||
**event_table,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lookup_id_to_name: typing.Dict[int, str] = {data.code: item_name for item_name, data in item_table.items() if data.code}
|
lookup_id_to_name: typing.Dict[int, str] = {data.code: item_name for item_name, data in item_table.items() if data.code}
|
||||||
@@ -263,7 +279,12 @@ item_groups: typing.Dict[str, str] = {
|
|||||||
"Seeds": list(seeds_table.keys()),
|
"Seeds": list(seeds_table.keys()),
|
||||||
"Hats": list(hats_table.keys()),
|
"Hats": list(hats_table.keys()),
|
||||||
"Traps": list(trap_table.keys()),
|
"Traps": list(trap_table.keys()),
|
||||||
|
"Minigames": list(minigame_trap_table.keys()),
|
||||||
}
|
}
|
||||||
|
|
||||||
ALTTPWorld.pedestal_credit_texts[item_table[ItemName.sonic_light_shoes].code] = "and the Soap Shoes"
|
try:
|
||||||
ALTTPWorld.pedestal_credit_texts[item_table[ItemName.shadow_air_shoes].code] = "and the Soap Shoes"
|
from worlds.alttp import ALTTPWorld
|
||||||
|
ALTTPWorld.pedestal_credit_texts[item_table[ItemName.sonic_light_shoes].code] = "and the Soap Shoes"
|
||||||
|
ALTTPWorld.pedestal_credit_texts[item_table[ItemName.shadow_air_shoes].code] = "and the Soap Shoes"
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
pass
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -119,11 +119,14 @@ mission_orders: typing.List[typing.List[int]] = [
|
|||||||
[4, 5, 3, 2, 1],
|
[4, 5, 3, 2, 1],
|
||||||
]
|
]
|
||||||
|
|
||||||
### 0: Speed
|
### 0: Sonic
|
||||||
### 1: Mech
|
### 1: Tails
|
||||||
### 2: Hunt
|
### 2: Knuckles
|
||||||
### 3: Kart
|
### 3: Shadow
|
||||||
### 4: Cannon's Core
|
### 4: Eggman
|
||||||
|
### 5: Rouge
|
||||||
|
### 6: Kart
|
||||||
|
### 7: Cannon's Core
|
||||||
level_styles: typing.List[int] = [
|
level_styles: typing.List[int] = [
|
||||||
0,
|
0,
|
||||||
2,
|
2,
|
||||||
@@ -133,7 +136,7 @@ level_styles: typing.List[int] = [
|
|||||||
2,
|
2,
|
||||||
1,
|
1,
|
||||||
2,
|
2,
|
||||||
3,
|
6,
|
||||||
1,
|
1,
|
||||||
0,
|
0,
|
||||||
2,
|
2,
|
||||||
@@ -142,22 +145,22 @@ level_styles: typing.List[int] = [
|
|||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
3,
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
|
|
||||||
4,
|
4,
|
||||||
|
5,
|
||||||
|
4,
|
||||||
|
3,
|
||||||
|
5,
|
||||||
|
4,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
3,
|
||||||
|
6,
|
||||||
|
3,
|
||||||
|
5,
|
||||||
|
4,
|
||||||
|
3,
|
||||||
|
|
||||||
|
7,
|
||||||
]
|
]
|
||||||
|
|
||||||
stage_name_prefixes: typing.List[str] = [
|
stage_name_prefixes: typing.List[str] = [
|
||||||
@@ -201,21 +204,33 @@ def get_mission_count_table(multiworld: MultiWorld, world: World, player: int):
|
|||||||
for level in range(31):
|
for level in range(31):
|
||||||
mission_count_table[level] = 0
|
mission_count_table[level] = 0
|
||||||
else:
|
else:
|
||||||
speed_active_missions = 1
|
sonic_active_missions = 1
|
||||||
mech_active_missions = 1
|
tails_active_missions = 1
|
||||||
hunt_active_missions = 1
|
knuckles_active_missions = 1
|
||||||
|
shadow_active_missions = 1
|
||||||
|
eggman_active_missions = 1
|
||||||
|
rouge_active_missions = 1
|
||||||
kart_active_missions = 1
|
kart_active_missions = 1
|
||||||
cannons_core_active_missions = 1
|
cannons_core_active_missions = 1
|
||||||
|
|
||||||
for i in range(2,6):
|
for i in range(2,6):
|
||||||
if getattr(world.options, "speed_mission_" + str(i), None):
|
if getattr(world.options, "sonic_mission_" + str(i), None):
|
||||||
speed_active_missions += 1
|
sonic_active_missions += 1
|
||||||
|
|
||||||
if getattr(world.options, "mech_mission_" + str(i), None):
|
if getattr(world.options, "tails_mission_" + str(i), None):
|
||||||
mech_active_missions += 1
|
tails_active_missions += 1
|
||||||
|
|
||||||
if getattr(world.options, "hunt_mission_" + str(i), None):
|
if getattr(world.options, "knuckles_mission_" + str(i), None):
|
||||||
hunt_active_missions += 1
|
knuckles_active_missions += 1
|
||||||
|
|
||||||
|
if getattr(world.options, "shadow_mission_" + str(i), None):
|
||||||
|
shadow_active_missions += 1
|
||||||
|
|
||||||
|
if getattr(world.options, "eggman_mission_" + str(i), None):
|
||||||
|
eggman_active_missions += 1
|
||||||
|
|
||||||
|
if getattr(world.options, "rouge_mission_" + str(i), None):
|
||||||
|
rouge_active_missions += 1
|
||||||
|
|
||||||
if getattr(world.options, "kart_mission_" + str(i), None):
|
if getattr(world.options, "kart_mission_" + str(i), None):
|
||||||
kart_active_missions += 1
|
kart_active_missions += 1
|
||||||
@@ -223,16 +238,22 @@ def get_mission_count_table(multiworld: MultiWorld, world: World, player: int):
|
|||||||
if getattr(world.options, "cannons_core_mission_" + str(i), None):
|
if getattr(world.options, "cannons_core_mission_" + str(i), None):
|
||||||
cannons_core_active_missions += 1
|
cannons_core_active_missions += 1
|
||||||
|
|
||||||
speed_active_missions = min(speed_active_missions, world.options.speed_mission_count.value)
|
sonic_active_missions = min(sonic_active_missions, world.options.sonic_mission_count.value)
|
||||||
mech_active_missions = min(mech_active_missions, world.options.mech_mission_count.value)
|
tails_active_missions = min(tails_active_missions, world.options.tails_mission_count.value)
|
||||||
hunt_active_missions = min(hunt_active_missions, world.options.hunt_mission_count.value)
|
knuckles_active_missions = min(knuckles_active_missions, world.options.knuckles_mission_count.value)
|
||||||
|
shadow_active_missions = min(shadow_active_missions, world.options.sonic_mission_count.value)
|
||||||
|
eggman_active_missions = min(eggman_active_missions, world.options.eggman_mission_count.value)
|
||||||
|
rouge_active_missions = min(rouge_active_missions, world.options.rouge_mission_count.value)
|
||||||
kart_active_missions = min(kart_active_missions, world.options.kart_mission_count.value)
|
kart_active_missions = min(kart_active_missions, world.options.kart_mission_count.value)
|
||||||
cannons_core_active_missions = min(cannons_core_active_missions, world.options.cannons_core_mission_count.value)
|
cannons_core_active_missions = min(cannons_core_active_missions, world.options.cannons_core_mission_count.value)
|
||||||
|
|
||||||
active_missions: typing.List[typing.List[int]] = [
|
active_missions: typing.List[typing.List[int]] = [
|
||||||
speed_active_missions,
|
sonic_active_missions,
|
||||||
mech_active_missions,
|
tails_active_missions,
|
||||||
hunt_active_missions,
|
knuckles_active_missions,
|
||||||
|
shadow_active_missions,
|
||||||
|
eggman_active_missions,
|
||||||
|
rouge_active_missions,
|
||||||
kart_active_missions,
|
kart_active_missions,
|
||||||
cannons_core_active_missions
|
cannons_core_active_missions
|
||||||
]
|
]
|
||||||
@@ -252,22 +273,34 @@ def get_mission_table(multiworld: MultiWorld, world: World, player: int):
|
|||||||
for level in range(31):
|
for level in range(31):
|
||||||
mission_table[level] = 0
|
mission_table[level] = 0
|
||||||
else:
|
else:
|
||||||
speed_active_missions: typing.List[int] = [1]
|
sonic_active_missions: typing.List[int] = [1]
|
||||||
mech_active_missions: typing.List[int] = [1]
|
tails_active_missions: typing.List[int] = [1]
|
||||||
hunt_active_missions: typing.List[int] = [1]
|
knuckles_active_missions: typing.List[int] = [1]
|
||||||
|
shadow_active_missions: typing.List[int] = [1]
|
||||||
|
eggman_active_missions: typing.List[int] = [1]
|
||||||
|
rouge_active_missions: typing.List[int] = [1]
|
||||||
kart_active_missions: typing.List[int] = [1]
|
kart_active_missions: typing.List[int] = [1]
|
||||||
cannons_core_active_missions: typing.List[int] = [1]
|
cannons_core_active_missions: typing.List[int] = [1]
|
||||||
|
|
||||||
# Add included missions
|
# Add included missions
|
||||||
for i in range(2,6):
|
for i in range(2,6):
|
||||||
if getattr(world.options, "speed_mission_" + str(i), None):
|
if getattr(world.options, "sonic_mission_" + str(i), None):
|
||||||
speed_active_missions.append(i)
|
sonic_active_missions.append(i)
|
||||||
|
|
||||||
if getattr(world.options, "mech_mission_" + str(i), None):
|
if getattr(world.options, "tails_mission_" + str(i), None):
|
||||||
mech_active_missions.append(i)
|
tails_active_missions.append(i)
|
||||||
|
|
||||||
if getattr(world.options, "hunt_mission_" + str(i), None):
|
if getattr(world.options, "knuckles_mission_" + str(i), None):
|
||||||
hunt_active_missions.append(i)
|
knuckles_active_missions.append(i)
|
||||||
|
|
||||||
|
if getattr(world.options, "shadow_mission_" + str(i), None):
|
||||||
|
shadow_active_missions.append(i)
|
||||||
|
|
||||||
|
if getattr(world.options, "eggman_mission_" + str(i), None):
|
||||||
|
eggman_active_missions.append(i)
|
||||||
|
|
||||||
|
if getattr(world.options, "rouge_mission_" + str(i), None):
|
||||||
|
rouge_active_missions.append(i)
|
||||||
|
|
||||||
if getattr(world.options, "kart_mission_" + str(i), None):
|
if getattr(world.options, "kart_mission_" + str(i), None):
|
||||||
kart_active_missions.append(i)
|
kart_active_missions.append(i)
|
||||||
@@ -276,9 +309,12 @@ def get_mission_table(multiworld: MultiWorld, world: World, player: int):
|
|||||||
cannons_core_active_missions.append(i)
|
cannons_core_active_missions.append(i)
|
||||||
|
|
||||||
active_missions: typing.List[typing.List[int]] = [
|
active_missions: typing.List[typing.List[int]] = [
|
||||||
speed_active_missions,
|
sonic_active_missions,
|
||||||
mech_active_missions,
|
tails_active_missions,
|
||||||
hunt_active_missions,
|
knuckles_active_missions,
|
||||||
|
shadow_active_missions,
|
||||||
|
eggman_active_missions,
|
||||||
|
rouge_active_missions,
|
||||||
kart_active_missions,
|
kart_active_missions,
|
||||||
cannons_core_active_missions
|
cannons_core_active_missions
|
||||||
]
|
]
|
||||||
@@ -328,13 +364,60 @@ def get_mission_table(multiworld: MultiWorld, world: World, player: int):
|
|||||||
|
|
||||||
|
|
||||||
def get_first_and_last_cannons_core_missions(mission_map: typing.Dict[int, int], mission_count_map: typing.Dict[int, int]):
|
def get_first_and_last_cannons_core_missions(mission_map: typing.Dict[int, int], mission_count_map: typing.Dict[int, int]):
|
||||||
mission_count = mission_count_map[30]
|
mission_count = mission_count_map[30]
|
||||||
mission_order: typing.List[int] = mission_orders[mission_map[30]]
|
mission_order: typing.List[int] = mission_orders[mission_map[30]]
|
||||||
stage_prefix: str = stage_name_prefixes[30]
|
stage_prefix: str = stage_name_prefixes[30]
|
||||||
|
|
||||||
first_mission_number = mission_order[0]
|
first_mission_number = mission_order[0]
|
||||||
last_mission_number = mission_order[mission_count - 1]
|
last_mission_number = mission_order[mission_count - 1]
|
||||||
first_location_name: str = stage_prefix + str(first_mission_number)
|
first_location_name: str = stage_prefix + str(first_mission_number)
|
||||||
last_location_name: str = stage_prefix + str(last_mission_number)
|
last_location_name: str = stage_prefix + str(last_mission_number)
|
||||||
|
|
||||||
return first_location_name, last_location_name
|
return first_location_name, last_location_name
|
||||||
|
|
||||||
|
|
||||||
|
def print_mission_orders_to_spoiler(mission_map: typing.Dict[int, int],
|
||||||
|
mission_count_map: typing.Dict[int, int],
|
||||||
|
shuffled_region_list: typing.Dict[int, int],
|
||||||
|
levels_per_gate: typing.Dict[int, int],
|
||||||
|
player_name: str,
|
||||||
|
spoiler_handle: typing.TextIO):
|
||||||
|
spoiler_handle.write("\n")
|
||||||
|
header_text = "SA2 Mission Orders for {}:\n"
|
||||||
|
header_text = header_text.format(player_name)
|
||||||
|
spoiler_handle.write(header_text)
|
||||||
|
|
||||||
|
level_index = 0
|
||||||
|
for gate_idx in range(len(levels_per_gate)):
|
||||||
|
gate_len = levels_per_gate[gate_idx]
|
||||||
|
gate_levels = shuffled_region_list[int(level_index):int(level_index+gate_len)]
|
||||||
|
gate_levels.sort()
|
||||||
|
|
||||||
|
gate_text = "Gate {}:\n"
|
||||||
|
gate_text = gate_text.format(gate_idx)
|
||||||
|
spoiler_handle.write(gate_text)
|
||||||
|
|
||||||
|
for i in range(len(gate_levels)):
|
||||||
|
stage = gate_levels[i]
|
||||||
|
mission_count = mission_count_map[stage]
|
||||||
|
mission_order: typing.List[int] = mission_orders[mission_map[stage]]
|
||||||
|
stage_prefix: str = stage_name_prefixes[stage]
|
||||||
|
|
||||||
|
for mission in range(mission_count):
|
||||||
|
stage_prefix += str(mission_order[mission]) + " "
|
||||||
|
|
||||||
|
spoiler_handle.write(stage_prefix)
|
||||||
|
spoiler_handle.write("\n")
|
||||||
|
|
||||||
|
level_index += gate_len
|
||||||
|
spoiler_handle.write("\n")
|
||||||
|
|
||||||
|
mission_count = mission_count_map[30]
|
||||||
|
mission_order: typing.List[int] = mission_orders[mission_map[30]]
|
||||||
|
stage_prefix: str = stage_name_prefixes[30]
|
||||||
|
|
||||||
|
for mission in range(mission_count):
|
||||||
|
stage_prefix += str(mission_order[mission]) + " "
|
||||||
|
|
||||||
|
spoiler_handle.write(stage_prefix)
|
||||||
|
spoiler_handle.write("\n\n")
|
||||||
|
@@ -5,7 +5,7 @@ emblem = "Emblem"
|
|||||||
market_token = "Chao Coin"
|
market_token = "Chao Coin"
|
||||||
|
|
||||||
# Upgrade Definitions
|
# Upgrade Definitions
|
||||||
sonic_gloves = "Sonic - Magic Glove"
|
sonic_gloves = "Sonic - Magic Gloves"
|
||||||
sonic_light_shoes = "Sonic - Light Shoes"
|
sonic_light_shoes = "Sonic - Light Shoes"
|
||||||
sonic_ancient_light = "Sonic - Ancient Light"
|
sonic_ancient_light = "Sonic - Ancient Light"
|
||||||
sonic_bounce_bracelet = "Sonic - Bounce Bracelet"
|
sonic_bounce_bracelet = "Sonic - Bounce Bracelet"
|
||||||
@@ -51,19 +51,34 @@ invincibility = "Invincibility"
|
|||||||
|
|
||||||
|
|
||||||
# Traps
|
# Traps
|
||||||
omochao_trap = "OmoTrap"
|
omochao_trap = "OmoTrap"
|
||||||
timestop_trap = "Chaos Control Trap"
|
timestop_trap = "Chaos Control Trap"
|
||||||
confuse_trap = "Confusion Trap"
|
confuse_trap = "Confusion Trap"
|
||||||
tiny_trap = "Tiny Trap"
|
tiny_trap = "Tiny Trap"
|
||||||
gravity_trap = "Gravity Trap"
|
gravity_trap = "Gravity Trap"
|
||||||
exposition_trap = "Exposition Trap"
|
exposition_trap = "Exposition Trap"
|
||||||
darkness_trap = "Darkness Trap"
|
darkness_trap = "Darkness Trap"
|
||||||
ice_trap = "Ice Trap"
|
ice_trap = "Ice Trap"
|
||||||
slow_trap = "Slow Trap"
|
slow_trap = "Slow Trap"
|
||||||
cutscene_trap = "Cutscene Trap"
|
cutscene_trap = "Cutscene Trap"
|
||||||
reverse_trap = "Reverse Trap"
|
reverse_trap = "Reverse Trap"
|
||||||
|
literature_trap = "Literature Trap"
|
||||||
|
controller_drift_trap = "Controller Drift Trap"
|
||||||
|
poison_trap = "Poison Trap"
|
||||||
|
bee_trap = "Bee Trap"
|
||||||
|
|
||||||
pong_trap = "Pong Trap"
|
pong_trap = "Pong Trap"
|
||||||
|
breakout_trap = "Breakout Trap"
|
||||||
|
fishing_trap = "Fishing Trap"
|
||||||
|
trivia_trap = "Trivia Trap"
|
||||||
|
pokemon_trivia_trap = "Pokemon Trivia Trap"
|
||||||
|
pokemon_count_trap = "Pokemon Count Trap"
|
||||||
|
number_sequence_trap = "Number Sequence Trap"
|
||||||
|
light_up_path_trap = "Light Up Path Trap"
|
||||||
|
pinball_trap = "Pinball Trap"
|
||||||
|
math_quiz_trap = "Math Quiz Trap"
|
||||||
|
snake_trap = "Snake Trap"
|
||||||
|
input_sequence_trap = "Input Sequence Trap"
|
||||||
|
|
||||||
|
|
||||||
# Chaos Emeralds
|
# Chaos Emeralds
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,8 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from Options import Choice, Range, Toggle, DeathLink, DefaultOnToggle, OptionGroup, PerGameCommonOptions
|
from Options import Choice, Range, Option, OptionGroup, Toggle, DeathLink, DefaultOnToggle, PerGameCommonOptions, PlandoBosses
|
||||||
|
|
||||||
|
from .Names import LocationName
|
||||||
|
|
||||||
|
|
||||||
class Goal(Choice):
|
class Goal(Choice):
|
||||||
@@ -22,6 +24,8 @@ class Goal(Choice):
|
|||||||
Boss Rush Chaos Emerald Hunt: Find the Seven Chaos Emeralds, then beat all of the bosses in the Boss Rush, ending with Finalhazard
|
Boss Rush Chaos Emerald Hunt: Find the Seven Chaos Emeralds, then beat all of the bosses in the Boss Rush, ending with Finalhazard
|
||||||
|
|
||||||
Chaos Chao: Raise a Chaos Chao to win
|
Chaos Chao: Raise a Chaos Chao to win
|
||||||
|
|
||||||
|
Minigame Madness: Win a certain amount of each Minigame Trap, then defeat Finalhazard
|
||||||
"""
|
"""
|
||||||
display_name = "Goal"
|
display_name = "Goal"
|
||||||
option_biolizard = 0
|
option_biolizard = 0
|
||||||
@@ -32,6 +36,7 @@ class Goal(Choice):
|
|||||||
option_cannons_core_boss_rush = 5
|
option_cannons_core_boss_rush = 5
|
||||||
option_boss_rush_chaos_emerald_hunt = 6
|
option_boss_rush_chaos_emerald_hunt = 6
|
||||||
option_chaos_chao = 7
|
option_chaos_chao = 7
|
||||||
|
option_minigame_madness = 8
|
||||||
default = 0
|
default = 0
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -71,6 +76,66 @@ class BossRushShuffle(Choice):
|
|||||||
default = 0
|
default = 0
|
||||||
|
|
||||||
|
|
||||||
|
class GateBossPlando(PlandoBosses):
|
||||||
|
"""
|
||||||
|
Possible Locations:
|
||||||
|
"Gate 1 Boss"
|
||||||
|
"Gate 2 Boss"
|
||||||
|
"Gate 3 Boss"
|
||||||
|
"Gate 4 Boss"
|
||||||
|
"Gate 5 Boss"
|
||||||
|
|
||||||
|
Possible Bosses:
|
||||||
|
"Sonic vs Shadow 1"
|
||||||
|
"Sonic vs Shadow 2"
|
||||||
|
"Tails vs Eggman 1"
|
||||||
|
"Tails vs Eggman 2"
|
||||||
|
"Knuckles vs Rouge 1"
|
||||||
|
"BIG FOOT"
|
||||||
|
"HOT SHOT"
|
||||||
|
"FLYING DOG"
|
||||||
|
"Egg Golem (Sonic)"
|
||||||
|
"Egg Golem (Eggman)"
|
||||||
|
"King Boom Boo"
|
||||||
|
"""
|
||||||
|
bosses = frozenset(LocationName.boss_names.keys())
|
||||||
|
|
||||||
|
locations = frozenset(LocationName.boss_gate_names.keys())
|
||||||
|
|
||||||
|
duplicate_bosses = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def can_place_boss(cls, boss: str, location: str) -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
display_name = "Boss Shuffle"
|
||||||
|
option_plando = 0
|
||||||
|
|
||||||
|
|
||||||
|
class MinigameMadnessRequirement(Range):
|
||||||
|
"""
|
||||||
|
Determines how many of each Minigame Trap must be won (for Minigame Madness goal)
|
||||||
|
|
||||||
|
Receiving this many of a Minigame Trap will allow you to replay that minigame at-will in the Chao World lobby
|
||||||
|
"""
|
||||||
|
display_name = "Minigame Madness Trap Requirement"
|
||||||
|
range_start = 1
|
||||||
|
range_end = 10
|
||||||
|
default = 3
|
||||||
|
|
||||||
|
|
||||||
|
class MinigameMadnessMinimum(Range):
|
||||||
|
"""
|
||||||
|
Determines the minimum number of each Minigame Trap that are created (for Minigame Madness goal)
|
||||||
|
|
||||||
|
At least this many of each trap will be created as "Progression Traps", regardless of other trap option selections
|
||||||
|
"""
|
||||||
|
display_name = "Minigame Madness Trap Minimum"
|
||||||
|
range_start = 1
|
||||||
|
range_end = 10
|
||||||
|
default = 5
|
||||||
|
|
||||||
|
|
||||||
class BaseTrapWeight(Choice):
|
class BaseTrapWeight(Choice):
|
||||||
"""
|
"""
|
||||||
Base Class for Trap Weights
|
Base Class for Trap Weights
|
||||||
@@ -159,6 +224,34 @@ class ReverseTrapWeight(BaseTrapWeight):
|
|||||||
display_name = "Reverse Trap Weight"
|
display_name = "Reverse Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
|
class LiteratureTrapWeight(BaseTrapWeight):
|
||||||
|
"""
|
||||||
|
Likelihood of receiving a trap which forces you to read
|
||||||
|
"""
|
||||||
|
display_name = "Literature Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
|
class ControllerDriftTrapWeight(BaseTrapWeight):
|
||||||
|
"""
|
||||||
|
Likelihood of receiving a trap which causes your control sticks to drift
|
||||||
|
"""
|
||||||
|
display_name = "Controller Drift Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
|
class PoisonTrapWeight(BaseTrapWeight):
|
||||||
|
"""
|
||||||
|
Likelihood of receiving a trap which causes you to lose rings over time
|
||||||
|
"""
|
||||||
|
display_name = "Poison Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
|
class BeeTrapWeight(BaseTrapWeight):
|
||||||
|
"""
|
||||||
|
Likelihood of receiving a trap which spawns a swarm of bees
|
||||||
|
"""
|
||||||
|
display_name = "Bee Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
class PongTrapWeight(BaseTrapWeight):
|
class PongTrapWeight(BaseTrapWeight):
|
||||||
"""
|
"""
|
||||||
Likelihood of receiving a trap which forces you to play a Pong minigame
|
Likelihood of receiving a trap which forces you to play a Pong minigame
|
||||||
@@ -166,14 +259,106 @@ class PongTrapWeight(BaseTrapWeight):
|
|||||||
display_name = "Pong Trap Weight"
|
display_name = "Pong Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
|
class BreakoutTrapWeight(BaseTrapWeight):
|
||||||
|
"""
|
||||||
|
Likelihood of receiving a trap which forces you to play a Breakout minigame
|
||||||
|
"""
|
||||||
|
display_name = "Breakout Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
|
class FishingTrapWeight(BaseTrapWeight):
|
||||||
|
"""
|
||||||
|
Likelihood of receiving a trap which forces you to play a Fishing minigame
|
||||||
|
"""
|
||||||
|
display_name = "Fishing Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
|
class TriviaTrapWeight(BaseTrapWeight):
|
||||||
|
"""
|
||||||
|
Likelihood of receiving a trap which forces you to play a Trivia minigame
|
||||||
|
"""
|
||||||
|
display_name = "Trivia Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
|
class PokemonTriviaTrapWeight(BaseTrapWeight):
|
||||||
|
"""
|
||||||
|
Likelihood of receiving a trap which forces you to play a Pokemon Trivia minigame
|
||||||
|
"""
|
||||||
|
display_name = "Pokemon Trivia Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
|
class PokemonCountTrapWeight(BaseTrapWeight):
|
||||||
|
"""
|
||||||
|
Likelihood of receiving a trap which forces you to play a Pokemon Count minigame
|
||||||
|
"""
|
||||||
|
display_name = "Pokemon Count Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
|
class NumberSequenceTrapWeight(BaseTrapWeight):
|
||||||
|
"""
|
||||||
|
Likelihood of receiving a trap which forces you to play a Number Sequence minigame
|
||||||
|
"""
|
||||||
|
display_name = "Number Sequence Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
|
class LightUpPathTrapWeight(BaseTrapWeight):
|
||||||
|
"""
|
||||||
|
Likelihood of receiving a trap which forces you to play a Light Up Path minigame
|
||||||
|
"""
|
||||||
|
display_name = "Light Up Path Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
|
class PinballTrapWeight(BaseTrapWeight):
|
||||||
|
"""
|
||||||
|
Likelihood of receiving a trap which forces you to play a Pinball minigame
|
||||||
|
"""
|
||||||
|
display_name = "Pinball Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
|
class MathQuizTrapWeight(BaseTrapWeight):
|
||||||
|
"""
|
||||||
|
Likelihood of receiving a trap which forces you to solve a math problem
|
||||||
|
"""
|
||||||
|
display_name = "Math Quiz Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
|
class SnakeTrapWeight(BaseTrapWeight):
|
||||||
|
"""
|
||||||
|
Likelihood of receiving a trap which forces you to play a Snake minigame
|
||||||
|
"""
|
||||||
|
display_name = "Snake Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
|
class InputSequenceTrapWeight(BaseTrapWeight):
|
||||||
|
"""
|
||||||
|
Likelihood of receiving a trap which forces you to press a sequence of inputs
|
||||||
|
"""
|
||||||
|
display_name = "Input Sequence Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
class MinigameTrapDifficulty(Choice):
|
class MinigameTrapDifficulty(Choice):
|
||||||
"""
|
"""
|
||||||
How difficult any Minigame-style traps are
|
How difficult any Minigame-style traps are
|
||||||
|
Chaos causes the difficulty to be random per-minigame
|
||||||
"""
|
"""
|
||||||
display_name = "Minigame Trap Difficulty"
|
display_name = "Minigame Trap Difficulty"
|
||||||
option_easy = 0
|
option_easy = 0
|
||||||
option_medium = 1
|
option_medium = 1
|
||||||
option_hard = 2
|
option_hard = 2
|
||||||
|
option_chaos = 3
|
||||||
|
default = 1
|
||||||
|
|
||||||
|
|
||||||
|
class BigFishingDifficulty(Choice):
|
||||||
|
"""
|
||||||
|
How difficult Big's Fishing Minigames are
|
||||||
|
Chaos causes the difficulty to be random per-minigame
|
||||||
|
"""
|
||||||
|
display_name = "Big Fishing Difficulty"
|
||||||
|
option_easy = 0
|
||||||
|
option_medium = 1
|
||||||
|
option_hard = 2
|
||||||
|
option_chaos = 3
|
||||||
default = 1
|
default = 1
|
||||||
|
|
||||||
|
|
||||||
@@ -197,7 +382,7 @@ class TrapFillPercentage(Range):
|
|||||||
default = 0
|
default = 0
|
||||||
|
|
||||||
|
|
||||||
class Keysanity(Toggle):
|
class Keysanity(DefaultOnToggle):
|
||||||
"""
|
"""
|
||||||
Determines whether picking up Chao Keys grants checks
|
Determines whether picking up Chao Keys grants checks
|
||||||
(86 Locations)
|
(86 Locations)
|
||||||
@@ -225,7 +410,7 @@ class Whistlesanity(Choice):
|
|||||||
default = 0
|
default = 0
|
||||||
|
|
||||||
|
|
||||||
class Beetlesanity(Toggle):
|
class Beetlesanity(DefaultOnToggle):
|
||||||
"""
|
"""
|
||||||
Determines whether destroying Gold Beetles grants checks
|
Determines whether destroying Gold Beetles grants checks
|
||||||
(27 Locations)
|
(27 Locations)
|
||||||
@@ -244,13 +429,35 @@ class Omosanity(Toggle):
|
|||||||
class Animalsanity(Toggle):
|
class Animalsanity(Toggle):
|
||||||
"""
|
"""
|
||||||
Determines whether unique counts of animals grant checks.
|
Determines whether unique counts of animals grant checks.
|
||||||
(421 Locations)
|
(422 Locations)
|
||||||
|
|
||||||
ALL animals must be collected in a single run of a mission to get all checks.
|
ALL animals must be collected in a single run of a mission to get all checks.
|
||||||
"""
|
"""
|
||||||
display_name = "Animalsanity"
|
display_name = "Animalsanity"
|
||||||
|
|
||||||
|
|
||||||
|
class ItemBoxsanity(Choice):
|
||||||
|
"""
|
||||||
|
Determines whether collecting Item Boxes grants checks
|
||||||
|
None: No Item Boxes grant checks
|
||||||
|
Extra Lives: Extra Life Boxes grant checks (94 Locations)
|
||||||
|
All: All Item Boxes grant checks (502 Locations Total)
|
||||||
|
"""
|
||||||
|
display_name = "Itemboxsanity"
|
||||||
|
option_none = 0
|
||||||
|
option_extra_lives = 1
|
||||||
|
option_all = 2
|
||||||
|
default = 0
|
||||||
|
|
||||||
|
|
||||||
|
class Bigsanity(Toggle):
|
||||||
|
"""
|
||||||
|
Determines whether helping Big fish grants checks.
|
||||||
|
(32 Locations)
|
||||||
|
"""
|
||||||
|
display_name = "Bigsanity"
|
||||||
|
|
||||||
|
|
||||||
class KartRaceChecks(Choice):
|
class KartRaceChecks(Choice):
|
||||||
"""
|
"""
|
||||||
Determines whether Kart Race Mode grants checks
|
Determines whether Kart Race Mode grants checks
|
||||||
@@ -313,7 +520,7 @@ class LevelGateCosts(Choice):
|
|||||||
option_low = 0
|
option_low = 0
|
||||||
option_medium = 1
|
option_medium = 1
|
||||||
option_high = 2
|
option_high = 2
|
||||||
default = 2
|
default = 0
|
||||||
|
|
||||||
|
|
||||||
class MaximumEmblemCap(Range):
|
class MaximumEmblemCap(Range):
|
||||||
@@ -523,109 +730,214 @@ class BaseMissionCount(Range):
|
|||||||
default = 2
|
default = 2
|
||||||
|
|
||||||
|
|
||||||
class SpeedMissionCount(BaseMissionCount):
|
class SonicMissionCount(BaseMissionCount):
|
||||||
"""
|
"""
|
||||||
The number of active missions to include for Sonic and Shadow stages
|
The number of active missions to include for Sonic stages
|
||||||
"""
|
"""
|
||||||
display_name = "Speed Mission Count"
|
display_name = "Sonic Mission Count"
|
||||||
|
|
||||||
|
|
||||||
class SpeedMission2(DefaultOnToggle):
|
class SonicMission2(DefaultOnToggle):
|
||||||
"""
|
"""
|
||||||
Determines if the Sonic and Shadow 100 rings missions should be included
|
Determines if the Sonic 100 rings missions should be included
|
||||||
"""
|
"""
|
||||||
display_name = "Speed Mission 2"
|
display_name = "Sonic Mission 2"
|
||||||
|
|
||||||
|
|
||||||
class SpeedMission3(DefaultOnToggle):
|
class SonicMission3(DefaultOnToggle):
|
||||||
"""
|
"""
|
||||||
Determines if the Sonic and Shadow lost chao missions should be included
|
Determines if the Sonic lost chao missions should be included
|
||||||
"""
|
"""
|
||||||
display_name = "Speed Mission 3"
|
display_name = "Sonic Mission 3"
|
||||||
|
|
||||||
|
|
||||||
class SpeedMission4(DefaultOnToggle):
|
class SonicMission4(DefaultOnToggle):
|
||||||
"""
|
"""
|
||||||
Determines if the Sonic and Shadow time trial missions should be included
|
Determines if the Sonic time trial missions should be included
|
||||||
"""
|
"""
|
||||||
display_name = "Speed Mission 4"
|
display_name = "Sonic Mission 4"
|
||||||
|
|
||||||
|
|
||||||
class SpeedMission5(DefaultOnToggle):
|
class SonicMission5(DefaultOnToggle):
|
||||||
"""
|
"""
|
||||||
Determines if the Sonic and Shadow hard missions should be included
|
Determines if the Sonic hard missions should be included
|
||||||
"""
|
"""
|
||||||
display_name = "Speed Mission 5"
|
display_name = "Sonic Mission 5"
|
||||||
|
|
||||||
|
|
||||||
class MechMissionCount(BaseMissionCount):
|
class ShadowMissionCount(BaseMissionCount):
|
||||||
"""
|
"""
|
||||||
The number of active missions to include for Tails and Eggman stages
|
The number of active missions to include for Shadow stages
|
||||||
"""
|
"""
|
||||||
display_name = "Mech Mission Count"
|
display_name = "Shadow Mission Count"
|
||||||
|
|
||||||
|
|
||||||
class MechMission2(DefaultOnToggle):
|
class ShadowMission2(DefaultOnToggle):
|
||||||
"""
|
"""
|
||||||
Determines if the Tails and Eggman 100 rings missions should be included
|
Determines if the Shadow 100 rings missions should be included
|
||||||
"""
|
"""
|
||||||
display_name = "Mech Mission 2"
|
display_name = "Shadow Mission 2"
|
||||||
|
|
||||||
|
|
||||||
class MechMission3(DefaultOnToggle):
|
class ShadowMission3(DefaultOnToggle):
|
||||||
"""
|
"""
|
||||||
Determines if the Tails and Eggman lost chao missions should be included
|
Determines if the Shadow lost chao missions should be included
|
||||||
"""
|
"""
|
||||||
display_name = "Mech Mission 3"
|
display_name = "Shadow Mission 3"
|
||||||
|
|
||||||
|
|
||||||
class MechMission4(DefaultOnToggle):
|
class ShadowMission4(DefaultOnToggle):
|
||||||
"""
|
"""
|
||||||
Determines if the Tails and Eggman time trial missions should be included
|
Determines if the Shadow time trial missions should be included
|
||||||
"""
|
"""
|
||||||
display_name = "Mech Mission 4"
|
display_name = "Shadow Mission 4"
|
||||||
|
|
||||||
|
|
||||||
class MechMission5(DefaultOnToggle):
|
class ShadowMission5(DefaultOnToggle):
|
||||||
"""
|
"""
|
||||||
Determines if the Tails and Eggman hard missions should be included
|
Determines if the Shadow hard missions should be included
|
||||||
"""
|
"""
|
||||||
display_name = "Mech Mission 5"
|
display_name = "Shadow Mission 5"
|
||||||
|
|
||||||
|
|
||||||
class HuntMissionCount(BaseMissionCount):
|
class TailsMissionCount(BaseMissionCount):
|
||||||
"""
|
"""
|
||||||
The number of active missions to include for Knuckles and Rouge stages
|
The number of active missions to include for Tails stages
|
||||||
"""
|
"""
|
||||||
display_name = "Hunt Mission Count"
|
display_name = "Tails Mission Count"
|
||||||
|
|
||||||
|
|
||||||
class HuntMission2(DefaultOnToggle):
|
class TailsMission2(DefaultOnToggle):
|
||||||
"""
|
"""
|
||||||
Determines if the Knuckles and Rouge 100 rings missions should be included
|
Determines if the Tails 100 rings missions should be included
|
||||||
"""
|
"""
|
||||||
display_name = "Hunt Mission 2"
|
display_name = "Tails Mission 2"
|
||||||
|
|
||||||
|
|
||||||
class HuntMission3(DefaultOnToggle):
|
class TailsMission3(DefaultOnToggle):
|
||||||
"""
|
"""
|
||||||
Determines if the Knuckles and Rouge lost chao missions should be included
|
Determines if the Tails lost chao missions should be included
|
||||||
"""
|
"""
|
||||||
display_name = "Hunt Mission 3"
|
display_name = "Tails Mission 3"
|
||||||
|
|
||||||
|
|
||||||
class HuntMission4(DefaultOnToggle):
|
class TailsMission4(DefaultOnToggle):
|
||||||
"""
|
"""
|
||||||
Determines if the Knuckles and Rouge time trial missions should be included
|
Determines if the Tails time trial missions should be included
|
||||||
"""
|
"""
|
||||||
display_name = "Hunt Mission 4"
|
display_name = "Tails Mission 4"
|
||||||
|
|
||||||
|
|
||||||
class HuntMission5(DefaultOnToggle):
|
class TailsMission5(DefaultOnToggle):
|
||||||
"""
|
"""
|
||||||
Determines if the Knuckles and Rouge hard missions should be included
|
Determines if the Tails hard missions should be included
|
||||||
"""
|
"""
|
||||||
display_name = "Hunt Mission 5"
|
display_name = "Tails Mission 5"
|
||||||
|
|
||||||
|
|
||||||
|
class EggmanMissionCount(BaseMissionCount):
|
||||||
|
"""
|
||||||
|
The number of active missions to include for Eggman stages
|
||||||
|
"""
|
||||||
|
display_name = "Eggman Mission Count"
|
||||||
|
|
||||||
|
|
||||||
|
class EggmanMission2(DefaultOnToggle):
|
||||||
|
"""
|
||||||
|
Determines if the Eggman 100 rings missions should be included
|
||||||
|
"""
|
||||||
|
display_name = "Eggman Mission 2"
|
||||||
|
|
||||||
|
|
||||||
|
class EggmanMission3(DefaultOnToggle):
|
||||||
|
"""
|
||||||
|
Determines if the Eggman lost chao missions should be included
|
||||||
|
"""
|
||||||
|
display_name = "Eggman Mission 3"
|
||||||
|
|
||||||
|
|
||||||
|
class EggmanMission4(DefaultOnToggle):
|
||||||
|
"""
|
||||||
|
Determines if the Eggman time trial missions should be included
|
||||||
|
"""
|
||||||
|
display_name = "Eggman Mission 4"
|
||||||
|
|
||||||
|
|
||||||
|
class EggmanMission5(DefaultOnToggle):
|
||||||
|
"""
|
||||||
|
Determines if the Eggman hard missions should be included
|
||||||
|
"""
|
||||||
|
display_name = "Eggman Mission 5"
|
||||||
|
|
||||||
|
|
||||||
|
class KnucklesMissionCount(BaseMissionCount):
|
||||||
|
"""
|
||||||
|
The number of active missions to include for Knuckles stages
|
||||||
|
"""
|
||||||
|
display_name = "Knuckles Mission Count"
|
||||||
|
|
||||||
|
|
||||||
|
class KnucklesMission2(DefaultOnToggle):
|
||||||
|
"""
|
||||||
|
Determines if the Knuckles 100 rings missions should be included
|
||||||
|
"""
|
||||||
|
display_name = "Knuckles Mission 2"
|
||||||
|
|
||||||
|
|
||||||
|
class KnucklesMission3(DefaultOnToggle):
|
||||||
|
"""
|
||||||
|
Determines if the Knuckles lost chao missions should be included
|
||||||
|
"""
|
||||||
|
display_name = "Knuckles Mission 3"
|
||||||
|
|
||||||
|
|
||||||
|
class KnucklesMission4(DefaultOnToggle):
|
||||||
|
"""
|
||||||
|
Determines if the Knuckles time trial missions should be included
|
||||||
|
"""
|
||||||
|
display_name = "Knuckles Mission 4"
|
||||||
|
|
||||||
|
|
||||||
|
class KnucklesMission5(DefaultOnToggle):
|
||||||
|
"""
|
||||||
|
Determines if the Knuckles hard missions should be included
|
||||||
|
"""
|
||||||
|
display_name = "Knuckles Mission 5"
|
||||||
|
|
||||||
|
|
||||||
|
class RougeMissionCount(BaseMissionCount):
|
||||||
|
"""
|
||||||
|
The number of active missions to include for Rouge stages
|
||||||
|
"""
|
||||||
|
display_name = "Rouge Mission Count"
|
||||||
|
|
||||||
|
|
||||||
|
class RougeMission2(DefaultOnToggle):
|
||||||
|
"""
|
||||||
|
Determines if the Rouge 100 rings missions should be included
|
||||||
|
"""
|
||||||
|
display_name = "Rouge Mission 2"
|
||||||
|
|
||||||
|
|
||||||
|
class RougeMission3(DefaultOnToggle):
|
||||||
|
"""
|
||||||
|
Determines if the Rouge lost chao missions should be included
|
||||||
|
"""
|
||||||
|
display_name = "Rouge Mission 3"
|
||||||
|
|
||||||
|
|
||||||
|
class RougeMission4(DefaultOnToggle):
|
||||||
|
"""
|
||||||
|
Determines if the Rouge time trial missions should be included
|
||||||
|
"""
|
||||||
|
display_name = "Rouge Mission 4"
|
||||||
|
|
||||||
|
|
||||||
|
class RougeMission5(DefaultOnToggle):
|
||||||
|
"""
|
||||||
|
Determines if the Rouge hard missions should be included
|
||||||
|
"""
|
||||||
|
display_name = "Rouge Mission 5"
|
||||||
|
|
||||||
|
|
||||||
class KartMissionCount(BaseMissionCount):
|
class KartMissionCount(BaseMissionCount):
|
||||||
@@ -706,7 +1018,7 @@ class RingLoss(Choice):
|
|||||||
|
|
||||||
Modern: You lose 20 rings when hit
|
Modern: You lose 20 rings when hit
|
||||||
|
|
||||||
OHKO: You die immediately when hit (NOTE: Some Hard Logic tricks may require damage boosts!)
|
OHKO: You die immediately when hit (NOTE: Some Hard or Expert Logic tricks may require damage boosts!)
|
||||||
"""
|
"""
|
||||||
display_name = "Ring Loss"
|
display_name = "Ring Loss"
|
||||||
option_classic = 0
|
option_classic = 0
|
||||||
@@ -729,6 +1041,16 @@ class RingLink(Toggle):
|
|||||||
display_name = "Ring Link"
|
display_name = "Ring Link"
|
||||||
|
|
||||||
|
|
||||||
|
class TrapLink(Toggle):
|
||||||
|
"""
|
||||||
|
Whether your received traps are linked to other players
|
||||||
|
|
||||||
|
You will also receive any linked traps from other players with Trap Link enabled,
|
||||||
|
if you have a weight above "none" set for that trap
|
||||||
|
"""
|
||||||
|
display_name = "Trap Link"
|
||||||
|
|
||||||
|
|
||||||
class SADXMusic(Choice):
|
class SADXMusic(Choice):
|
||||||
"""
|
"""
|
||||||
Whether the randomizer will include Sonic Adventure DX Music in the music pool
|
Whether the randomizer will include Sonic Adventure DX Music in the music pool
|
||||||
@@ -823,11 +1145,14 @@ class LogicDifficulty(Choice):
|
|||||||
|
|
||||||
Standard: The logic assumes the "intended" usage of Upgrades to progress through levels
|
Standard: The logic assumes the "intended" usage of Upgrades to progress through levels
|
||||||
|
|
||||||
Hard: Some simple skips or sequence breaks may be required
|
Hard: Some simple skips or sequence breaks may be required, but no out-of-bounds
|
||||||
|
|
||||||
|
Expert: If it is humanly possible, it may be required
|
||||||
"""
|
"""
|
||||||
display_name = "Logic Difficulty"
|
display_name = "Logic Difficulty"
|
||||||
option_standard = 0
|
option_standard = 0
|
||||||
option_hard = 1
|
option_hard = 1
|
||||||
|
option_expert = 2
|
||||||
default = 0
|
default = 0
|
||||||
|
|
||||||
|
|
||||||
@@ -835,6 +1160,8 @@ sa2b_option_groups = [
|
|||||||
OptionGroup("General Options", [
|
OptionGroup("General Options", [
|
||||||
Goal,
|
Goal,
|
||||||
BossRushShuffle,
|
BossRushShuffle,
|
||||||
|
MinigameMadnessRequirement,
|
||||||
|
MinigameMadnessMinimum,
|
||||||
LogicDifficulty,
|
LogicDifficulty,
|
||||||
RequiredRank,
|
RequiredRank,
|
||||||
MaximumEmblemCap,
|
MaximumEmblemCap,
|
||||||
@@ -854,6 +1181,8 @@ sa2b_option_groups = [
|
|||||||
Beetlesanity,
|
Beetlesanity,
|
||||||
Omosanity,
|
Omosanity,
|
||||||
Animalsanity,
|
Animalsanity,
|
||||||
|
ItemBoxsanity,
|
||||||
|
Bigsanity,
|
||||||
KartRaceChecks,
|
KartRaceChecks,
|
||||||
]),
|
]),
|
||||||
OptionGroup("Chao", [
|
OptionGroup("Chao", [
|
||||||
@@ -885,29 +1214,68 @@ sa2b_option_groups = [
|
|||||||
SlowTrapWeight,
|
SlowTrapWeight,
|
||||||
CutsceneTrapWeight,
|
CutsceneTrapWeight,
|
||||||
ReverseTrapWeight,
|
ReverseTrapWeight,
|
||||||
|
LiteratureTrapWeight,
|
||||||
|
ControllerDriftTrapWeight,
|
||||||
|
PoisonTrapWeight,
|
||||||
|
BeeTrapWeight,
|
||||||
|
]),
|
||||||
|
OptionGroup("Minigames", [
|
||||||
PongTrapWeight,
|
PongTrapWeight,
|
||||||
|
BreakoutTrapWeight,
|
||||||
|
FishingTrapWeight,
|
||||||
|
TriviaTrapWeight,
|
||||||
|
PokemonTriviaTrapWeight,
|
||||||
|
PokemonCountTrapWeight,
|
||||||
|
NumberSequenceTrapWeight,
|
||||||
|
LightUpPathTrapWeight,
|
||||||
|
PinballTrapWeight,
|
||||||
|
MathQuizTrapWeight,
|
||||||
|
SnakeTrapWeight,
|
||||||
|
InputSequenceTrapWeight,
|
||||||
MinigameTrapDifficulty,
|
MinigameTrapDifficulty,
|
||||||
|
BigFishingDifficulty,
|
||||||
]),
|
]),
|
||||||
OptionGroup("Speed Missions", [
|
OptionGroup("Sonic Missions", [
|
||||||
SpeedMissionCount,
|
SonicMissionCount,
|
||||||
SpeedMission2,
|
SonicMission2,
|
||||||
SpeedMission3,
|
SonicMission3,
|
||||||
SpeedMission4,
|
SonicMission4,
|
||||||
SpeedMission5,
|
SonicMission5,
|
||||||
]),
|
]),
|
||||||
OptionGroup("Mech Missions", [
|
OptionGroup("Shadow Missions", [
|
||||||
MechMissionCount,
|
ShadowMissionCount,
|
||||||
MechMission2,
|
ShadowMission2,
|
||||||
MechMission3,
|
ShadowMission3,
|
||||||
MechMission4,
|
ShadowMission4,
|
||||||
MechMission5,
|
ShadowMission5,
|
||||||
]),
|
]),
|
||||||
OptionGroup("Hunt Missions", [
|
OptionGroup("Tails Missions", [
|
||||||
HuntMissionCount,
|
TailsMissionCount,
|
||||||
HuntMission2,
|
TailsMission2,
|
||||||
HuntMission3,
|
TailsMission3,
|
||||||
HuntMission4,
|
TailsMission4,
|
||||||
HuntMission5,
|
TailsMission5,
|
||||||
|
]),
|
||||||
|
OptionGroup("Eggman Missions", [
|
||||||
|
EggmanMissionCount,
|
||||||
|
EggmanMission2,
|
||||||
|
EggmanMission3,
|
||||||
|
EggmanMission4,
|
||||||
|
EggmanMission5,
|
||||||
|
]),
|
||||||
|
OptionGroup("Knuckles Missions", [
|
||||||
|
KnucklesMissionCount,
|
||||||
|
KnucklesMission2,
|
||||||
|
KnucklesMission3,
|
||||||
|
KnucklesMission4,
|
||||||
|
KnucklesMission5,
|
||||||
|
]),
|
||||||
|
OptionGroup("Rouge Missions", [
|
||||||
|
RougeMissionCount,
|
||||||
|
RougeMission2,
|
||||||
|
RougeMission3,
|
||||||
|
RougeMission4,
|
||||||
|
RougeMission5,
|
||||||
]),
|
]),
|
||||||
OptionGroup("Kart Missions", [
|
OptionGroup("Kart Missions", [
|
||||||
KartMissionCount,
|
KartMissionCount,
|
||||||
@@ -931,11 +1299,13 @@ sa2b_option_groups = [
|
|||||||
]),
|
]),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class SA2BOptions(PerGameCommonOptions):
|
class SA2BOptions(PerGameCommonOptions):
|
||||||
goal: Goal
|
goal: Goal
|
||||||
boss_rush_shuffle: BossRushShuffle
|
boss_rush_shuffle: BossRushShuffle
|
||||||
|
minigame_madness_requirement: MinigameMadnessRequirement
|
||||||
|
minigame_madness_minimum: MinigameMadnessMinimum
|
||||||
|
gate_boss_plando: GateBossPlando
|
||||||
logic_difficulty: LogicDifficulty
|
logic_difficulty: LogicDifficulty
|
||||||
required_rank: RequiredRank
|
required_rank: RequiredRank
|
||||||
max_emblem_cap: MaximumEmblemCap
|
max_emblem_cap: MaximumEmblemCap
|
||||||
@@ -953,6 +1323,8 @@ class SA2BOptions(PerGameCommonOptions):
|
|||||||
beetlesanity: Beetlesanity
|
beetlesanity: Beetlesanity
|
||||||
omosanity: Omosanity
|
omosanity: Omosanity
|
||||||
animalsanity: Animalsanity
|
animalsanity: Animalsanity
|
||||||
|
itemboxsanity: ItemBoxsanity
|
||||||
|
bigsanity: Bigsanity
|
||||||
kart_race_checks: KartRaceChecks
|
kart_race_checks: KartRaceChecks
|
||||||
|
|
||||||
black_market_slots: BlackMarketSlots
|
black_market_slots: BlackMarketSlots
|
||||||
@@ -983,31 +1355,65 @@ class SA2BOptions(PerGameCommonOptions):
|
|||||||
slow_trap_weight: SlowTrapWeight
|
slow_trap_weight: SlowTrapWeight
|
||||||
cutscene_trap_weight: CutsceneTrapWeight
|
cutscene_trap_weight: CutsceneTrapWeight
|
||||||
reverse_trap_weight: ReverseTrapWeight
|
reverse_trap_weight: ReverseTrapWeight
|
||||||
|
literature_trap_weight: LiteratureTrapWeight
|
||||||
|
controller_drift_trap_weight: ControllerDriftTrapWeight
|
||||||
|
poison_trap_weight: PoisonTrapWeight
|
||||||
|
bee_trap_weight: BeeTrapWeight
|
||||||
pong_trap_weight: PongTrapWeight
|
pong_trap_weight: PongTrapWeight
|
||||||
|
breakout_trap_weight: BreakoutTrapWeight
|
||||||
|
fishing_trap_weight: FishingTrapWeight
|
||||||
|
trivia_trap_weight: TriviaTrapWeight
|
||||||
|
pokemon_trivia_trap_weight: PokemonTriviaTrapWeight
|
||||||
|
pokemon_count_trap_weight: PokemonCountTrapWeight
|
||||||
|
number_sequence_trap_weight: NumberSequenceTrapWeight
|
||||||
|
light_up_path_trap_weight: LightUpPathTrapWeight
|
||||||
|
pinball_trap_weight: PinballTrapWeight
|
||||||
|
math_quiz_trap_weight: MathQuizTrapWeight
|
||||||
|
snake_trap_weight: SnakeTrapWeight
|
||||||
|
input_sequence_trap_weight: InputSequenceTrapWeight
|
||||||
minigame_trap_difficulty: MinigameTrapDifficulty
|
minigame_trap_difficulty: MinigameTrapDifficulty
|
||||||
|
big_fishing_difficulty: BigFishingDifficulty
|
||||||
|
|
||||||
sadx_music: SADXMusic
|
sadx_music: SADXMusic
|
||||||
music_shuffle: MusicShuffle
|
music_shuffle: MusicShuffle
|
||||||
voice_shuffle: VoiceShuffle
|
voice_shuffle: VoiceShuffle
|
||||||
narrator: Narrator
|
narrator: Narrator
|
||||||
|
|
||||||
speed_mission_count: SpeedMissionCount
|
sonic_mission_count: SonicMissionCount
|
||||||
speed_mission_2: SpeedMission2
|
sonic_mission_2: SonicMission2
|
||||||
speed_mission_3: SpeedMission3
|
sonic_mission_3: SonicMission3
|
||||||
speed_mission_4: SpeedMission4
|
sonic_mission_4: SonicMission4
|
||||||
speed_mission_5: SpeedMission5
|
sonic_mission_5: SonicMission5
|
||||||
|
|
||||||
mech_mission_count: MechMissionCount
|
shadow_mission_count: ShadowMissionCount
|
||||||
mech_mission_2: MechMission2
|
shadow_mission_2: ShadowMission2
|
||||||
mech_mission_3: MechMission3
|
shadow_mission_3: ShadowMission3
|
||||||
mech_mission_4: MechMission4
|
shadow_mission_4: ShadowMission4
|
||||||
mech_mission_5: MechMission5
|
shadow_mission_5: ShadowMission5
|
||||||
|
|
||||||
hunt_mission_count: HuntMissionCount
|
tails_mission_count: TailsMissionCount
|
||||||
hunt_mission_2: HuntMission2
|
tails_mission_2: TailsMission2
|
||||||
hunt_mission_3: HuntMission3
|
tails_mission_3: TailsMission3
|
||||||
hunt_mission_4: HuntMission4
|
tails_mission_4: TailsMission4
|
||||||
hunt_mission_5: HuntMission5
|
tails_mission_5: TailsMission5
|
||||||
|
|
||||||
|
eggman_mission_count: EggmanMissionCount
|
||||||
|
eggman_mission_2: EggmanMission2
|
||||||
|
eggman_mission_3: EggmanMission3
|
||||||
|
eggman_mission_4: EggmanMission4
|
||||||
|
eggman_mission_5: EggmanMission5
|
||||||
|
|
||||||
|
knuckles_mission_count: KnucklesMissionCount
|
||||||
|
knuckles_mission_2: KnucklesMission2
|
||||||
|
knuckles_mission_3: KnucklesMission3
|
||||||
|
knuckles_mission_4: KnucklesMission4
|
||||||
|
knuckles_mission_5: KnucklesMission5
|
||||||
|
|
||||||
|
rouge_mission_count: RougeMissionCount
|
||||||
|
rouge_mission_2: RougeMission2
|
||||||
|
rouge_mission_3: RougeMission3
|
||||||
|
rouge_mission_4: RougeMission4
|
||||||
|
rouge_mission_5: RougeMission5
|
||||||
|
|
||||||
kart_mission_count: KartMissionCount
|
kart_mission_count: KartMissionCount
|
||||||
kart_mission_2: KartMission2
|
kart_mission_2: KartMission2
|
||||||
@@ -1022,4 +1428,5 @@ class SA2BOptions(PerGameCommonOptions):
|
|||||||
cannons_core_mission_5: CannonsCoreMission5
|
cannons_core_mission_5: CannonsCoreMission5
|
||||||
|
|
||||||
ring_link: RingLink
|
ring_link: RingLink
|
||||||
|
trap_link: TrapLink
|
||||||
death_link: DeathLink
|
death_link: DeathLink
|
||||||
|
502
worlds/sa2b/Presets.py
Normal file
502
worlds/sa2b/Presets.py
Normal file
@@ -0,0 +1,502 @@
|
|||||||
|
from typing import Dict, Any
|
||||||
|
|
||||||
|
from .Options import *
|
||||||
|
|
||||||
|
minsanity = {
|
||||||
|
"goal": Goal.option_chaos_chao,
|
||||||
|
"max_emblem_cap": MaximumEmblemCap.range_start,
|
||||||
|
|
||||||
|
"keysanity": False,
|
||||||
|
"whistlesanity": Whistlesanity.option_none,
|
||||||
|
"beetlesanity": False,
|
||||||
|
"omosanity": False,
|
||||||
|
"animalsanity": False,
|
||||||
|
"itemboxsanity": ItemBoxsanity.option_none,
|
||||||
|
"bigsanity": False,
|
||||||
|
"kart_race_checks": KartRaceChecks.option_none,
|
||||||
|
|
||||||
|
"junk_fill_percentage": 0,
|
||||||
|
|
||||||
|
"sonic_mission_count": BaseMissionCount.range_start,
|
||||||
|
"sonic_mission_2": False,
|
||||||
|
"sonic_mission_3": False,
|
||||||
|
"sonic_mission_4": False,
|
||||||
|
"sonic_mission_5": False,
|
||||||
|
|
||||||
|
"shadow_mission_count": BaseMissionCount.range_start,
|
||||||
|
"shadow_mission_2": False,
|
||||||
|
"shadow_mission_3": False,
|
||||||
|
"shadow_mission_4": False,
|
||||||
|
"shadow_mission_5": False,
|
||||||
|
|
||||||
|
"tails_mission_count": BaseMissionCount.range_start,
|
||||||
|
"tails_mission_2": False,
|
||||||
|
"tails_mission_3": False,
|
||||||
|
"tails_mission_4": False,
|
||||||
|
"tails_mission_5": False,
|
||||||
|
|
||||||
|
"eggman_mission_count": BaseMissionCount.range_start,
|
||||||
|
"eggman_mission_2": False,
|
||||||
|
"eggman_mission_3": False,
|
||||||
|
"eggman_mission_4": False,
|
||||||
|
"eggman_mission_5": False,
|
||||||
|
|
||||||
|
"knuckles_mission_count": BaseMissionCount.range_start,
|
||||||
|
"knuckles_mission_2": False,
|
||||||
|
"knuckles_mission_3": False,
|
||||||
|
"knuckles_mission_4": False,
|
||||||
|
"knuckles_mission_5": False,
|
||||||
|
|
||||||
|
"rouge_mission_count": BaseMissionCount.range_start,
|
||||||
|
"rouge_mission_2": False,
|
||||||
|
"rouge_mission_3": False,
|
||||||
|
"rouge_mission_4": False,
|
||||||
|
"rouge_mission_5": False,
|
||||||
|
|
||||||
|
"kart_mission_count": BaseMissionCount.range_start,
|
||||||
|
"kart_mission_2": False,
|
||||||
|
"kart_mission_3": False,
|
||||||
|
"kart_mission_4": False,
|
||||||
|
"kart_mission_5": False,
|
||||||
|
|
||||||
|
"cannons_core_mission_count": BaseMissionCount.range_start,
|
||||||
|
"cannons_core_mission_2": False,
|
||||||
|
"cannons_core_mission_3": False,
|
||||||
|
"cannons_core_mission_4": False,
|
||||||
|
"cannons_core_mission_5": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
chao_centric = {
|
||||||
|
"goal": Goal.option_chaos_chao,
|
||||||
|
|
||||||
|
"keysanity": False,
|
||||||
|
"whistlesanity": Whistlesanity.option_none,
|
||||||
|
"beetlesanity": False,
|
||||||
|
"omosanity": False,
|
||||||
|
"animalsanity": False,
|
||||||
|
"itemboxsanity": ItemBoxsanity.option_none,
|
||||||
|
"bigsanity": False,
|
||||||
|
"kart_race_checks": KartRaceChecks.option_none,
|
||||||
|
|
||||||
|
"black_market_slots": BlackMarketSlots.range_end,
|
||||||
|
"black_market_unlock_costs": BlackMarketUnlockCosts.option_high,
|
||||||
|
"chao_race_difficulty": ChaoRaceDifficulty.option_expert,
|
||||||
|
"chao_karate_difficulty": ChaoKarateDifficulty.option_super,
|
||||||
|
"chao_stadium_checks": ChaoStadiumChecks.option_all,
|
||||||
|
"chao_animal_parts": True,
|
||||||
|
"chao_stats": ChaoStats.range_end,
|
||||||
|
"chao_stats_frequency": 1,
|
||||||
|
"chao_stats_stamina": True,
|
||||||
|
"chao_stats_hidden": True,
|
||||||
|
"chao_kindergarten": ChaoKindergarten.option_full,
|
||||||
|
|
||||||
|
"junk_fill_percentage": 50,
|
||||||
|
|
||||||
|
"sonic_mission_count": BaseMissionCount.range_start,
|
||||||
|
"sonic_mission_2": False,
|
||||||
|
"sonic_mission_3": False,
|
||||||
|
"sonic_mission_4": False,
|
||||||
|
"sonic_mission_5": False,
|
||||||
|
|
||||||
|
"shadow_mission_count": BaseMissionCount.range_start,
|
||||||
|
"shadow_mission_2": False,
|
||||||
|
"shadow_mission_3": False,
|
||||||
|
"shadow_mission_4": False,
|
||||||
|
"shadow_mission_5": False,
|
||||||
|
|
||||||
|
"tails_mission_count": BaseMissionCount.range_start,
|
||||||
|
"tails_mission_2": False,
|
||||||
|
"tails_mission_3": False,
|
||||||
|
"tails_mission_4": False,
|
||||||
|
"tails_mission_5": False,
|
||||||
|
|
||||||
|
"eggman_mission_count": BaseMissionCount.range_start,
|
||||||
|
"eggman_mission_2": False,
|
||||||
|
"eggman_mission_3": False,
|
||||||
|
"eggman_mission_4": False,
|
||||||
|
"eggman_mission_5": False,
|
||||||
|
|
||||||
|
"knuckles_mission_count": BaseMissionCount.range_start,
|
||||||
|
"knuckles_mission_2": False,
|
||||||
|
"knuckles_mission_3": False,
|
||||||
|
"knuckles_mission_4": False,
|
||||||
|
"knuckles_mission_5": False,
|
||||||
|
|
||||||
|
"rouge_mission_count": BaseMissionCount.range_start,
|
||||||
|
"rouge_mission_2": False,
|
||||||
|
"rouge_mission_3": False,
|
||||||
|
"rouge_mission_4": False,
|
||||||
|
"rouge_mission_5": False,
|
||||||
|
|
||||||
|
"kart_mission_count": BaseMissionCount.range_start,
|
||||||
|
"kart_mission_2": False,
|
||||||
|
"kart_mission_3": False,
|
||||||
|
"kart_mission_4": False,
|
||||||
|
"kart_mission_5": False,
|
||||||
|
|
||||||
|
"cannons_core_mission_count": BaseMissionCount.range_start,
|
||||||
|
"cannons_core_mission_2": False,
|
||||||
|
"cannons_core_mission_3": False,
|
||||||
|
"cannons_core_mission_4": False,
|
||||||
|
"cannons_core_mission_5": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
allsanity_no_chao = {
|
||||||
|
"goal": Goal.option_cannons_core_boss_rush,
|
||||||
|
"boss_rush_shuffle": BossRushShuffle.option_chaos,
|
||||||
|
"minigame_madness_requirement": MinigameMadnessRequirement.range_end,
|
||||||
|
"minigame_madness_minimum": MinigameMadnessMinimum.range_end,
|
||||||
|
"max_emblem_cap": MaximumEmblemCap.range_end,
|
||||||
|
|
||||||
|
"mission_shuffle": True,
|
||||||
|
"required_cannons_core_missions": RequiredCannonsCoreMissions.option_all_active,
|
||||||
|
"emblem_percentage_for_cannons_core": EmblemPercentageForCannonsCore.range_end,
|
||||||
|
"number_of_level_gates": NumberOfLevelGates.range_end,
|
||||||
|
"level_gate_costs": LevelGateCosts.option_high,
|
||||||
|
|
||||||
|
"keysanity": True,
|
||||||
|
"whistlesanity": Whistlesanity.option_both,
|
||||||
|
"beetlesanity": True,
|
||||||
|
"omosanity": True,
|
||||||
|
"animalsanity": True,
|
||||||
|
"itemboxsanity": ItemBoxsanity.option_all,
|
||||||
|
"bigsanity": True,
|
||||||
|
"kart_race_checks": KartRaceChecks.option_full,
|
||||||
|
|
||||||
|
"junk_fill_percentage": 25,
|
||||||
|
"trap_fill_percentage": 25,
|
||||||
|
"omochao_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"timestop_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"confusion_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"tiny_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"gravity_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"exposition_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"ice_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"slow_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"cutscene_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"reverse_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"literature_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"controller_drift_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"poison_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"bee_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"pong_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"breakout_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"fishing_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"trivia_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"pokemon_trivia_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"pokemon_count_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"number_sequence_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"light_up_path_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"pinball_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"math_quiz_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"snake_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"input_sequence_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"minigame_trap_difficulty": MinigameTrapDifficulty.option_chaos,
|
||||||
|
"big_fishing_difficulty": BigFishingDifficulty.option_chaos,
|
||||||
|
|
||||||
|
"music_shuffle": MusicShuffle.option_full,
|
||||||
|
"voice_shuffle": VoiceShuffle.option_shuffled,
|
||||||
|
|
||||||
|
"sonic_mission_count": BaseMissionCount.range_end,
|
||||||
|
"sonic_mission_2": True,
|
||||||
|
"sonic_mission_3": True,
|
||||||
|
"sonic_mission_4": True,
|
||||||
|
"sonic_mission_5": True,
|
||||||
|
|
||||||
|
"shadow_mission_count": BaseMissionCount.range_end,
|
||||||
|
"shadow_mission_2": True,
|
||||||
|
"shadow_mission_3": True,
|
||||||
|
"shadow_mission_4": True,
|
||||||
|
"shadow_mission_5": True,
|
||||||
|
|
||||||
|
"tails_mission_count": BaseMissionCount.range_end,
|
||||||
|
"tails_mission_2": True,
|
||||||
|
"tails_mission_3": True,
|
||||||
|
"tails_mission_4": True,
|
||||||
|
"tails_mission_5": True,
|
||||||
|
|
||||||
|
"eggman_mission_count": BaseMissionCount.range_end,
|
||||||
|
"eggman_mission_2": True,
|
||||||
|
"eggman_mission_3": True,
|
||||||
|
"eggman_mission_4": True,
|
||||||
|
"eggman_mission_5": True,
|
||||||
|
|
||||||
|
"knuckles_mission_count": BaseMissionCount.range_end,
|
||||||
|
"knuckles_mission_2": True,
|
||||||
|
"knuckles_mission_3": True,
|
||||||
|
"knuckles_mission_4": True,
|
||||||
|
"knuckles_mission_5": True,
|
||||||
|
|
||||||
|
"rouge_mission_count": BaseMissionCount.range_end,
|
||||||
|
"rouge_mission_2": True,
|
||||||
|
"rouge_mission_3": True,
|
||||||
|
"rouge_mission_4": True,
|
||||||
|
"rouge_mission_5": True,
|
||||||
|
|
||||||
|
"kart_mission_count": BaseMissionCount.range_end,
|
||||||
|
"kart_mission_2": True,
|
||||||
|
"kart_mission_3": True,
|
||||||
|
"kart_mission_4": True,
|
||||||
|
"kart_mission_5": True,
|
||||||
|
|
||||||
|
"cannons_core_mission_count": BaseMissionCount.range_end,
|
||||||
|
"cannons_core_mission_2": True,
|
||||||
|
"cannons_core_mission_3": True,
|
||||||
|
"cannons_core_mission_4": True,
|
||||||
|
"cannons_core_mission_5": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
allsanity = {
|
||||||
|
"goal": Goal.option_cannons_core_boss_rush,
|
||||||
|
"boss_rush_shuffle": BossRushShuffle.option_chaos,
|
||||||
|
"minigame_madness_requirement": MinigameMadnessRequirement.range_end,
|
||||||
|
"minigame_madness_minimum": MinigameMadnessMinimum.range_end,
|
||||||
|
"max_emblem_cap": MaximumEmblemCap.range_end,
|
||||||
|
|
||||||
|
"mission_shuffle": True,
|
||||||
|
"required_cannons_core_missions": RequiredCannonsCoreMissions.option_all_active,
|
||||||
|
"emblem_percentage_for_cannons_core": EmblemPercentageForCannonsCore.range_end,
|
||||||
|
"number_of_level_gates": NumberOfLevelGates.range_end,
|
||||||
|
"level_gate_costs": LevelGateCosts.option_high,
|
||||||
|
|
||||||
|
"keysanity": True,
|
||||||
|
"whistlesanity": Whistlesanity.option_both,
|
||||||
|
"beetlesanity": True,
|
||||||
|
"omosanity": True,
|
||||||
|
"animalsanity": True,
|
||||||
|
"itemboxsanity": ItemBoxsanity.option_all,
|
||||||
|
"bigsanity": True,
|
||||||
|
"kart_race_checks": KartRaceChecks.option_full,
|
||||||
|
|
||||||
|
"black_market_slots": BlackMarketSlots.range_end,
|
||||||
|
"black_market_unlock_costs": BlackMarketUnlockCosts.option_high,
|
||||||
|
"chao_race_difficulty": ChaoRaceDifficulty.option_expert,
|
||||||
|
"chao_karate_difficulty": ChaoKarateDifficulty.option_super,
|
||||||
|
"chao_stadium_checks": ChaoStadiumChecks.option_all,
|
||||||
|
"chao_animal_parts": True,
|
||||||
|
"chao_stats": ChaoStats.range_end,
|
||||||
|
"chao_stats_frequency": 1,
|
||||||
|
"chao_stats_stamina": True,
|
||||||
|
"chao_stats_hidden": True,
|
||||||
|
"chao_kindergarten": ChaoKindergarten.option_full,
|
||||||
|
|
||||||
|
"junk_fill_percentage": 25,
|
||||||
|
"trap_fill_percentage": 25,
|
||||||
|
"omochao_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"timestop_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"confusion_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"tiny_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"gravity_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"exposition_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"ice_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"slow_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"cutscene_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"reverse_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"literature_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"controller_drift_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"poison_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"bee_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"pong_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"breakout_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"fishing_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"trivia_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"pokemon_trivia_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"pokemon_count_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"number_sequence_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"light_up_path_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"pinball_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"math_quiz_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"snake_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"input_sequence_trap_weight": BaseTrapWeight.option_high,
|
||||||
|
"minigame_trap_difficulty": MinigameTrapDifficulty.option_chaos,
|
||||||
|
"big_fishing_difficulty": BigFishingDifficulty.option_chaos,
|
||||||
|
|
||||||
|
"music_shuffle": MusicShuffle.option_full,
|
||||||
|
"voice_shuffle": VoiceShuffle.option_shuffled,
|
||||||
|
|
||||||
|
"sonic_mission_count": BaseMissionCount.range_end,
|
||||||
|
"sonic_mission_2": True,
|
||||||
|
"sonic_mission_3": True,
|
||||||
|
"sonic_mission_4": True,
|
||||||
|
"sonic_mission_5": True,
|
||||||
|
|
||||||
|
"shadow_mission_count": BaseMissionCount.range_end,
|
||||||
|
"shadow_mission_2": True,
|
||||||
|
"shadow_mission_3": True,
|
||||||
|
"shadow_mission_4": True,
|
||||||
|
"shadow_mission_5": True,
|
||||||
|
|
||||||
|
"tails_mission_count": BaseMissionCount.range_end,
|
||||||
|
"tails_mission_2": True,
|
||||||
|
"tails_mission_3": True,
|
||||||
|
"tails_mission_4": True,
|
||||||
|
"tails_mission_5": True,
|
||||||
|
|
||||||
|
"eggman_mission_count": BaseMissionCount.range_end,
|
||||||
|
"eggman_mission_2": True,
|
||||||
|
"eggman_mission_3": True,
|
||||||
|
"eggman_mission_4": True,
|
||||||
|
"eggman_mission_5": True,
|
||||||
|
|
||||||
|
"knuckles_mission_count": BaseMissionCount.range_end,
|
||||||
|
"knuckles_mission_2": True,
|
||||||
|
"knuckles_mission_3": True,
|
||||||
|
"knuckles_mission_4": True,
|
||||||
|
"knuckles_mission_5": True,
|
||||||
|
|
||||||
|
"rouge_mission_count": BaseMissionCount.range_end,
|
||||||
|
"rouge_mission_2": True,
|
||||||
|
"rouge_mission_3": True,
|
||||||
|
"rouge_mission_4": True,
|
||||||
|
"rouge_mission_5": True,
|
||||||
|
|
||||||
|
"kart_mission_count": BaseMissionCount.range_end,
|
||||||
|
"kart_mission_2": True,
|
||||||
|
"kart_mission_3": True,
|
||||||
|
"kart_mission_4": True,
|
||||||
|
"kart_mission_5": True,
|
||||||
|
|
||||||
|
"cannons_core_mission_count": BaseMissionCount.range_end,
|
||||||
|
"cannons_core_mission_2": True,
|
||||||
|
"cannons_core_mission_3": True,
|
||||||
|
"cannons_core_mission_4": True,
|
||||||
|
"cannons_core_mission_5": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
all_random = {
|
||||||
|
"goal": "random",
|
||||||
|
"boss_rush_shuffle": "random",
|
||||||
|
"minigame_madness_requirement": "random",
|
||||||
|
"minigame_madness_minimum": "random",
|
||||||
|
"logic_difficulty": "random",
|
||||||
|
"required_rank": "random",
|
||||||
|
"max_emblem_cap": "random",
|
||||||
|
"ring_loss": "random",
|
||||||
|
|
||||||
|
"mission_shuffle": "random",
|
||||||
|
"required_cannons_core_missions": "random",
|
||||||
|
"emblem_percentage_for_cannons_core": "random",
|
||||||
|
"number_of_level_gates": "random",
|
||||||
|
"level_gate_distribution": "random",
|
||||||
|
"level_gate_costs": "random",
|
||||||
|
|
||||||
|
"keysanity": "random",
|
||||||
|
"whistlesanity": "random",
|
||||||
|
"beetlesanity": "random",
|
||||||
|
"omosanity": "random",
|
||||||
|
"animalsanity": "random",
|
||||||
|
"itemboxsanity": "random",
|
||||||
|
"bigsanity": "random",
|
||||||
|
"kart_race_checks": "random",
|
||||||
|
|
||||||
|
"black_market_slots": "random",
|
||||||
|
"black_market_unlock_costs": "random",
|
||||||
|
"black_market_price_multiplier": "random",
|
||||||
|
"chao_race_difficulty": "random",
|
||||||
|
"chao_karate_difficulty": "random",
|
||||||
|
"chao_stadium_checks": "random",
|
||||||
|
"chao_animal_parts": "random",
|
||||||
|
"chao_stats": "random",
|
||||||
|
"chao_stats_frequency": "random",
|
||||||
|
"chao_stats_stamina": "random",
|
||||||
|
"chao_stats_hidden": "random",
|
||||||
|
"chao_kindergarten": "random",
|
||||||
|
"shuffle_starting_chao_eggs": "random",
|
||||||
|
"chao_entrance_randomization": "random",
|
||||||
|
|
||||||
|
"junk_fill_percentage": "random",
|
||||||
|
"trap_fill_percentage": "random",
|
||||||
|
"omochao_trap_weight": "random",
|
||||||
|
"timestop_trap_weight": "random",
|
||||||
|
"confusion_trap_weight": "random",
|
||||||
|
"tiny_trap_weight": "random",
|
||||||
|
"gravity_trap_weight": "random",
|
||||||
|
"exposition_trap_weight": "random",
|
||||||
|
"ice_trap_weight": "random",
|
||||||
|
"slow_trap_weight": "random",
|
||||||
|
"cutscene_trap_weight": "random",
|
||||||
|
"reverse_trap_weight": "random",
|
||||||
|
"literature_trap_weight": "random",
|
||||||
|
"controller_drift_trap_weight": "random",
|
||||||
|
"poison_trap_weight": "random",
|
||||||
|
"bee_trap_weight": "random",
|
||||||
|
"pong_trap_weight": "random",
|
||||||
|
"breakout_trap_weight": "random",
|
||||||
|
"fishing_trap_weight": "random",
|
||||||
|
"trivia_trap_weight": "random",
|
||||||
|
"pokemon_trivia_trap_weight": "random",
|
||||||
|
"pokemon_count_trap_weight": "random",
|
||||||
|
"number_sequence_trap_weight": "random",
|
||||||
|
"light_up_path_trap_weight": "random",
|
||||||
|
"pinball_trap_weight": "random",
|
||||||
|
"math_quiz_trap_weight": "random",
|
||||||
|
"snake_trap_weight": "random",
|
||||||
|
"input_sequence_trap_weight": "random",
|
||||||
|
"minigame_trap_difficulty": "random",
|
||||||
|
"big_fishing_difficulty": "random",
|
||||||
|
|
||||||
|
"sadx_music": "random",
|
||||||
|
"music_shuffle": "random",
|
||||||
|
"voice_shuffle": "random",
|
||||||
|
"narrator": "random",
|
||||||
|
|
||||||
|
"sonic_mission_count": "random",
|
||||||
|
"sonic_mission_2": "random",
|
||||||
|
"sonic_mission_3": "random",
|
||||||
|
"sonic_mission_4": "random",
|
||||||
|
"sonic_mission_5": "random",
|
||||||
|
|
||||||
|
"shadow_mission_count": "random",
|
||||||
|
"shadow_mission_2": "random",
|
||||||
|
"shadow_mission_3": "random",
|
||||||
|
"shadow_mission_4": "random",
|
||||||
|
"shadow_mission_5": "random",
|
||||||
|
|
||||||
|
"tails_mission_count": "random",
|
||||||
|
"tails_mission_2": "random",
|
||||||
|
"tails_mission_3": "random",
|
||||||
|
"tails_mission_4": "random",
|
||||||
|
"tails_mission_5": "random",
|
||||||
|
|
||||||
|
"eggman_mission_count": "random",
|
||||||
|
"eggman_mission_2": "random",
|
||||||
|
"eggman_mission_3": "random",
|
||||||
|
"eggman_mission_4": "random",
|
||||||
|
"eggman_mission_5": "random",
|
||||||
|
|
||||||
|
"knuckles_mission_count": "random",
|
||||||
|
"knuckles_mission_2": "random",
|
||||||
|
"knuckles_mission_3": "random",
|
||||||
|
"knuckles_mission_4": "random",
|
||||||
|
"knuckles_mission_5": "random",
|
||||||
|
|
||||||
|
"rouge_mission_count": "random",
|
||||||
|
"rouge_mission_2": "random",
|
||||||
|
"rouge_mission_3": "random",
|
||||||
|
"rouge_mission_4": "random",
|
||||||
|
"rouge_mission_5": "random",
|
||||||
|
|
||||||
|
"kart_mission_count": "random",
|
||||||
|
"kart_mission_2": "random",
|
||||||
|
"kart_mission_3": "random",
|
||||||
|
"kart_mission_4": "random",
|
||||||
|
"kart_mission_5": "random",
|
||||||
|
|
||||||
|
"cannons_core_mission_count": "random",
|
||||||
|
"cannons_core_mission_2": "random",
|
||||||
|
"cannons_core_mission_3": "random",
|
||||||
|
"cannons_core_mission_4": "random",
|
||||||
|
"cannons_core_mission_5": "random",
|
||||||
|
|
||||||
|
"ring_link": "random",
|
||||||
|
"trap_link": "random",
|
||||||
|
"death_link": "random",
|
||||||
|
}
|
||||||
|
|
||||||
|
sa2b_options_presets: Dict[str, Dict[str, Any]] = {
|
||||||
|
"Minsanity": minsanity,
|
||||||
|
"Chao-centric": chao_centric,
|
||||||
|
"Allsanity No Chao": allsanity_no_chao,
|
||||||
|
"Allsanity": allsanity,
|
||||||
|
"All Random": all_random,
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
2115
worlds/sa2b/Rules.py
2115
worlds/sa2b/Rules.py
File diff suppressed because it is too large
Load Diff
@@ -8,12 +8,13 @@ from worlds.AutoWorld import WebWorld, World
|
|||||||
from .AestheticData import chao_name_conversion, sample_chao_names, totally_real_item_names, \
|
from .AestheticData import chao_name_conversion, sample_chao_names, totally_real_item_names, \
|
||||||
all_exits, all_destinations, multi_rooms, single_rooms, room_to_exits_map, exit_to_room_map, valid_kindergarten_exits
|
all_exits, all_destinations, multi_rooms, single_rooms, room_to_exits_map, exit_to_room_map, valid_kindergarten_exits
|
||||||
from .GateBosses import get_gate_bosses, get_boss_rush_bosses, get_boss_name
|
from .GateBosses import get_gate_bosses, get_boss_rush_bosses, get_boss_name
|
||||||
from .Items import SA2BItem, ItemData, item_table, upgrades_table, emeralds_table, junk_table, trap_table, item_groups, \
|
from .Items import SA2BItem, ItemData, item_table, upgrades_table, emeralds_table, junk_table, minigame_trap_table, item_groups, \
|
||||||
eggs_table, fruits_table, seeds_table, hats_table, animals_table, chaos_drives_table
|
eggs_table, fruits_table, seeds_table, hats_table, animals_table, chaos_drives_table, event_table
|
||||||
from .Locations import SA2BLocation, all_locations, setup_locations, chao_animal_event_location_table, black_market_location_table
|
from .Locations import SA2BLocation, all_locations, location_groups, setup_locations, chao_animal_event_location_table, black_market_location_table
|
||||||
from .Missions import get_mission_table, get_mission_count_table, get_first_and_last_cannons_core_missions
|
from .Missions import get_mission_table, get_mission_count_table, get_first_and_last_cannons_core_missions, print_mission_orders_to_spoiler
|
||||||
from .Names import ItemName, LocationName
|
from .Names import ItemName, LocationName
|
||||||
from .Options import SA2BOptions, sa2b_option_groups
|
from .Options import SA2BOptions, sa2b_option_groups
|
||||||
|
from .Presets import sa2b_options_presets
|
||||||
from .Regions import create_regions, shuffleable_regions, connect_regions, LevelGate, gate_0_whitelist_regions, \
|
from .Regions import create_regions, shuffleable_regions, connect_regions, LevelGate, gate_0_whitelist_regions, \
|
||||||
gate_0_blacklist_regions
|
gate_0_blacklist_regions
|
||||||
from .Rules import set_rules
|
from .Rules import set_rules
|
||||||
@@ -33,6 +34,7 @@ class SA2BWeb(WebWorld):
|
|||||||
|
|
||||||
tutorials = [setup_en]
|
tutorials = [setup_en]
|
||||||
option_groups = sa2b_option_groups
|
option_groups = sa2b_option_groups
|
||||||
|
options_presets = sa2b_options_presets
|
||||||
|
|
||||||
|
|
||||||
def check_for_impossible_shuffle(shuffled_levels: typing.List[int], gate_0_range: int, multiworld: MultiWorld):
|
def check_for_impossible_shuffle(shuffled_levels: typing.List[int], gate_0_range: int, multiworld: MultiWorld):
|
||||||
@@ -60,11 +62,14 @@ class SA2BWorld(World):
|
|||||||
topology_present = False
|
topology_present = False
|
||||||
|
|
||||||
item_name_groups = item_groups
|
item_name_groups = item_groups
|
||||||
|
location_name_groups = location_groups
|
||||||
item_name_to_id = {name: data.code for name, data in item_table.items()}
|
item_name_to_id = {name: data.code for name, data in item_table.items()}
|
||||||
location_name_to_id = all_locations
|
location_name_to_id = all_locations
|
||||||
|
|
||||||
location_table: typing.Dict[str, int]
|
location_table: typing.Dict[str, int]
|
||||||
|
|
||||||
|
shuffled_region_list: typing.List[int]
|
||||||
|
levels_per_gate: typing.List[int]
|
||||||
mission_map: typing.Dict[int, int]
|
mission_map: typing.Dict[int, int]
|
||||||
mission_count_map: typing.Dict[int, int]
|
mission_count_map: typing.Dict[int, int]
|
||||||
emblems_for_cannons_core: int
|
emblems_for_cannons_core: int
|
||||||
@@ -78,7 +83,7 @@ class SA2BWorld(World):
|
|||||||
|
|
||||||
def fill_slot_data(self) -> dict:
|
def fill_slot_data(self) -> dict:
|
||||||
return {
|
return {
|
||||||
"ModVersion": 203,
|
"ModVersion": 204,
|
||||||
"Goal": self.options.goal.value,
|
"Goal": self.options.goal.value,
|
||||||
"MusicMap": self.generate_music_data(),
|
"MusicMap": self.generate_music_data(),
|
||||||
"VoiceMap": self.generate_voice_data(),
|
"VoiceMap": self.generate_voice_data(),
|
||||||
@@ -89,14 +94,20 @@ class SA2BWorld(World):
|
|||||||
"MusicShuffle": self.options.music_shuffle.value,
|
"MusicShuffle": self.options.music_shuffle.value,
|
||||||
"Narrator": self.options.narrator.value,
|
"Narrator": self.options.narrator.value,
|
||||||
"MinigameTrapDifficulty": self.options.minigame_trap_difficulty.value,
|
"MinigameTrapDifficulty": self.options.minigame_trap_difficulty.value,
|
||||||
|
"BigFishingDifficulty": self.options.big_fishing_difficulty.value,
|
||||||
"RingLoss": self.options.ring_loss.value,
|
"RingLoss": self.options.ring_loss.value,
|
||||||
"RingLink": self.options.ring_link.value,
|
"RingLink": self.options.ring_link.value,
|
||||||
|
"TrapLink": self.options.trap_link.value,
|
||||||
"RequiredRank": self.options.required_rank.value,
|
"RequiredRank": self.options.required_rank.value,
|
||||||
|
"MinigameMadnessAmount": self.options.minigame_madness_requirement.value,
|
||||||
|
"LogicDifficulty": self.options.logic_difficulty.value,
|
||||||
"ChaoKeys": self.options.keysanity.value,
|
"ChaoKeys": self.options.keysanity.value,
|
||||||
"Whistlesanity": self.options.whistlesanity.value,
|
"Whistlesanity": self.options.whistlesanity.value,
|
||||||
"GoldBeetles": self.options.beetlesanity.value,
|
"GoldBeetles": self.options.beetlesanity.value,
|
||||||
"OmochaoChecks": self.options.omosanity.value,
|
"OmochaoChecks": self.options.omosanity.value,
|
||||||
"AnimalChecks": self.options.animalsanity.value,
|
"AnimalChecks": self.options.animalsanity.value,
|
||||||
|
"ItemBoxChecks": self.options.itemboxsanity.value,
|
||||||
|
"BigChecks": self.options.bigsanity.value,
|
||||||
"KartRaceChecks": self.options.kart_race_checks.value,
|
"KartRaceChecks": self.options.kart_race_checks.value,
|
||||||
"ChaoStadiumChecks": self.options.chao_stadium_checks.value,
|
"ChaoStadiumChecks": self.options.chao_stadium_checks.value,
|
||||||
"ChaoRaceDifficulty": self.options.chao_race_difficulty.value,
|
"ChaoRaceDifficulty": self.options.chao_race_difficulty.value,
|
||||||
@@ -122,6 +133,7 @@ class SA2BWorld(World):
|
|||||||
"GateCosts": self.gate_costs,
|
"GateCosts": self.gate_costs,
|
||||||
"GateBosses": self.gate_bosses,
|
"GateBosses": self.gate_bosses,
|
||||||
"BossRushMap": self.boss_rush_map,
|
"BossRushMap": self.boss_rush_map,
|
||||||
|
"ActiveTraps": self.output_active_traps(),
|
||||||
"PlayerNum": self.player,
|
"PlayerNum": self.player,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,12 +163,42 @@ class SA2BWorld(World):
|
|||||||
|
|
||||||
valid_trap_weights = self.options.exposition_trap_weight.value + \
|
valid_trap_weights = self.options.exposition_trap_weight.value + \
|
||||||
self.options.reverse_trap_weight.value + \
|
self.options.reverse_trap_weight.value + \
|
||||||
self.options.pong_trap_weight.value
|
self.options.literature_trap_weight.value + \
|
||||||
|
self.options.controller_drift_trap_weight.value + \
|
||||||
|
self.options.poison_trap_weight.value + \
|
||||||
|
self.options.bee_trap_weight.value + \
|
||||||
|
self.options.pong_trap_weight.value + \
|
||||||
|
self.options.breakout_trap_weight.value + \
|
||||||
|
self.options.fishing_trap_weight.value + \
|
||||||
|
self.options.trivia_trap_weight.value + \
|
||||||
|
self.options.pokemon_trivia_trap_weight.value + \
|
||||||
|
self.options.pokemon_count_trap_weight.value + \
|
||||||
|
self.options.number_sequence_trap_weight.value + \
|
||||||
|
self.options.light_up_path_trap_weight.value + \
|
||||||
|
self.options.pinball_trap_weight.value + \
|
||||||
|
self.options.math_quiz_trap_weight.value + \
|
||||||
|
self.options.snake_trap_weight.value + \
|
||||||
|
self.options.input_sequence_trap_weight.value
|
||||||
|
|
||||||
if valid_trap_weights == 0:
|
if valid_trap_weights == 0:
|
||||||
self.options.exposition_trap_weight.value = 4
|
self.options.exposition_trap_weight.value = 4
|
||||||
self.options.reverse_trap_weight.value = 4
|
self.options.reverse_trap_weight.value = 4
|
||||||
|
self.options.literature_trap_weight.value = 4
|
||||||
|
self.options.controller_drift_trap_weight.value = 4
|
||||||
|
self.options.poison_trap_weight.value = 4
|
||||||
|
self.options.bee_trap_weight.value = 4
|
||||||
self.options.pong_trap_weight.value = 4
|
self.options.pong_trap_weight.value = 4
|
||||||
|
self.options.breakout_trap_weight.value = 4
|
||||||
|
self.options.fishing_trap_weight.value = 4
|
||||||
|
self.options.trivia_trap_weight.value = 4
|
||||||
|
self.options.pokemon_trivia_trap_weight.value = 4
|
||||||
|
self.options.pokemon_count_trap_weight.value = 4
|
||||||
|
self.options.number_sequence_trap_weight.value = 4
|
||||||
|
self.options.light_up_path_trap_weight.value = 4
|
||||||
|
self.options.pinball_trap_weight.value = 4
|
||||||
|
self.options.math_quiz_trap_weight.value = 4
|
||||||
|
self.options.snake_trap_weight.value = 4
|
||||||
|
self.options.input_sequence_trap_weight.value = 4
|
||||||
|
|
||||||
if self.options.kart_race_checks.value == 0:
|
if self.options.kart_race_checks.value == 0:
|
||||||
self.options.kart_race_checks.value = 2
|
self.options.kart_race_checks.value = 2
|
||||||
@@ -164,8 +206,8 @@ class SA2BWorld(World):
|
|||||||
self.gate_bosses = {}
|
self.gate_bosses = {}
|
||||||
self.boss_rush_map = {}
|
self.boss_rush_map = {}
|
||||||
else:
|
else:
|
||||||
self.gate_bosses = get_gate_bosses(self.multiworld, self)
|
self.gate_bosses = get_gate_bosses(self)
|
||||||
self.boss_rush_map = get_boss_rush_bosses(self.multiworld, self)
|
self.boss_rush_map = get_boss_rush_bosses(self)
|
||||||
|
|
||||||
def create_regions(self):
|
def create_regions(self):
|
||||||
self.mission_map = get_mission_table(self.multiworld, self, self.player)
|
self.mission_map = get_mission_table(self.multiworld, self, self.player)
|
||||||
@@ -177,7 +219,7 @@ class SA2BWorld(World):
|
|||||||
# Not Generate Basic
|
# Not Generate Basic
|
||||||
self.black_market_costs = dict()
|
self.black_market_costs = dict()
|
||||||
|
|
||||||
if self.options.goal.value in [0, 2, 4, 5, 6]:
|
if self.options.goal.value in [0, 2, 4, 5, 6, 8]:
|
||||||
self.multiworld.get_location(LocationName.finalhazard, self.player).place_locked_item(self.create_item(ItemName.maria))
|
self.multiworld.get_location(LocationName.finalhazard, self.player).place_locked_item(self.create_item(ItemName.maria))
|
||||||
elif self.options.goal.value == 1:
|
elif self.options.goal.value == 1:
|
||||||
self.multiworld.get_location(LocationName.green_hill, self.player).place_locked_item(self.create_item(ItemName.maria))
|
self.multiworld.get_location(LocationName.green_hill, self.player).place_locked_item(self.create_item(ItemName.maria))
|
||||||
@@ -202,7 +244,7 @@ class SA2BWorld(World):
|
|||||||
if self.options.goal.value != 3:
|
if self.options.goal.value != 3:
|
||||||
# Fill item pool with all required items
|
# Fill item pool with all required items
|
||||||
for item in {**upgrades_table}:
|
for item in {**upgrades_table}:
|
||||||
itempool += [self.create_item(item, False, self.options.goal.value)]
|
itempool += [self.create_item(item, None, self.options.goal.value)]
|
||||||
|
|
||||||
if self.options.goal.value in [1, 2, 6]:
|
if self.options.goal.value in [1, 2, 6]:
|
||||||
# Some flavor of Chaos Emerald Hunt
|
# Some flavor of Chaos Emerald Hunt
|
||||||
@@ -212,6 +254,25 @@ class SA2BWorld(World):
|
|||||||
# Black Market
|
# Black Market
|
||||||
itempool += [self.create_item(ItemName.market_token) for _ in range(self.options.black_market_slots.value)]
|
itempool += [self.create_item(ItemName.market_token) for _ in range(self.options.black_market_slots.value)]
|
||||||
|
|
||||||
|
if self.options.goal.value in [8]:
|
||||||
|
available_locations: int = total_required_locations - len(itempool) - self.options.number_of_level_gates.value
|
||||||
|
|
||||||
|
while (self.options.minigame_madness_requirement.value * len(minigame_trap_table)) > available_locations:
|
||||||
|
self.options.minigame_madness_requirement.value -= 1
|
||||||
|
|
||||||
|
while (self.options.minigame_madness_minimum.value * len(minigame_trap_table)) > available_locations:
|
||||||
|
self.options.minigame_madness_minimum.value -= 1
|
||||||
|
|
||||||
|
traps_to_create: int = max(self.options.minigame_madness_minimum.value, self.options.minigame_madness_requirement.value)
|
||||||
|
|
||||||
|
# Minigame Madness
|
||||||
|
for item in {**minigame_trap_table}:
|
||||||
|
for i in range(traps_to_create):
|
||||||
|
classification: ItemClassification = ItemClassification.trap
|
||||||
|
if i < self.options.minigame_madness_requirement.value:
|
||||||
|
classification |= ItemClassification.progression
|
||||||
|
itempool.append(self.create_item(item, classification))
|
||||||
|
|
||||||
black_market_unlock_mult = 1.0
|
black_market_unlock_mult = 1.0
|
||||||
if self.options.black_market_unlock_costs.value == 0:
|
if self.options.black_market_unlock_costs.value == 0:
|
||||||
black_market_unlock_mult = 0.5
|
black_market_unlock_mult = 0.5
|
||||||
@@ -235,12 +296,12 @@ class SA2BWorld(World):
|
|||||||
elif self.options.level_gate_costs.value == 1:
|
elif self.options.level_gate_costs.value == 1:
|
||||||
gate_cost_mult = 0.8
|
gate_cost_mult = 0.8
|
||||||
|
|
||||||
shuffled_region_list = list(range(30))
|
self.shuffled_region_list = list(range(30))
|
||||||
emblem_requirement_list = list()
|
emblem_requirement_list = list()
|
||||||
self.multiworld.random.shuffle(shuffled_region_list)
|
self.multiworld.random.shuffle(self.shuffled_region_list)
|
||||||
levels_per_gate = self.get_levels_per_gate()
|
self.levels_per_gate = self.get_levels_per_gate()
|
||||||
|
|
||||||
check_for_impossible_shuffle(shuffled_region_list, math.ceil(levels_per_gate[0]), self.multiworld)
|
check_for_impossible_shuffle(self.shuffled_region_list, math.ceil(self.levels_per_gate[0]), self.multiworld)
|
||||||
levels_added_to_gate = 0
|
levels_added_to_gate = 0
|
||||||
total_levels_added = 0
|
total_levels_added = 0
|
||||||
current_gate = 0
|
current_gate = 0
|
||||||
@@ -250,11 +311,11 @@ class SA2BWorld(World):
|
|||||||
gates = list()
|
gates = list()
|
||||||
gates.append(LevelGate(0))
|
gates.append(LevelGate(0))
|
||||||
for i in range(30):
|
for i in range(30):
|
||||||
gates[current_gate].gate_levels.append(shuffled_region_list[i])
|
gates[current_gate].gate_levels.append(self.shuffled_region_list[i])
|
||||||
emblem_requirement_list.append(current_gate_emblems)
|
emblem_requirement_list.append(current_gate_emblems)
|
||||||
levels_added_to_gate += 1
|
levels_added_to_gate += 1
|
||||||
total_levels_added += 1
|
total_levels_added += 1
|
||||||
if levels_added_to_gate >= levels_per_gate[current_gate]:
|
if levels_added_to_gate >= self.levels_per_gate[current_gate]:
|
||||||
current_gate += 1
|
current_gate += 1
|
||||||
if current_gate > self.options.number_of_level_gates.value:
|
if current_gate > self.options.number_of_level_gates.value:
|
||||||
current_gate = self.options.number_of_level_gates.value
|
current_gate = self.options.number_of_level_gates.value
|
||||||
@@ -265,18 +326,19 @@ class SA2BWorld(World):
|
|||||||
self.gate_costs[current_gate] = current_gate_emblems
|
self.gate_costs[current_gate] = current_gate_emblems
|
||||||
levels_added_to_gate = 0
|
levels_added_to_gate = 0
|
||||||
|
|
||||||
self.region_emblem_map = dict(zip(shuffled_region_list, emblem_requirement_list))
|
self.region_emblem_map = dict(zip(self.shuffled_region_list, emblem_requirement_list))
|
||||||
|
|
||||||
first_cannons_core_mission, final_cannons_core_mission = get_first_and_last_cannons_core_missions(self.mission_map, self.mission_count_map)
|
first_cannons_core_mission, final_cannons_core_mission = get_first_and_last_cannons_core_missions(self.mission_map, self.mission_count_map)
|
||||||
|
|
||||||
connect_regions(self.multiworld, self, self.player, gates, self.emblems_for_cannons_core, self.gate_bosses, self.boss_rush_map, first_cannons_core_mission, final_cannons_core_mission)
|
connect_regions(self.multiworld, self, self.player, gates, self.emblems_for_cannons_core, self.gate_bosses, self.boss_rush_map, first_cannons_core_mission, final_cannons_core_mission)
|
||||||
|
|
||||||
max_required_emblems = max(max(emblem_requirement_list), self.emblems_for_cannons_core)
|
max_required_emblems = max(max(emblem_requirement_list), self.emblems_for_cannons_core)
|
||||||
|
max_required_emblems = min(int(max_required_emblems * 1.1), total_emblem_count)
|
||||||
itempool += [self.create_item(ItemName.emblem) for _ in range(max_required_emblems)]
|
itempool += [self.create_item(ItemName.emblem) for _ in range(max_required_emblems)]
|
||||||
|
|
||||||
non_required_emblems = (total_emblem_count - max_required_emblems)
|
non_required_emblems = (total_emblem_count - max_required_emblems)
|
||||||
junk_count = math.floor(non_required_emblems * (self.options.junk_fill_percentage.value / 100.0))
|
junk_count = math.floor(non_required_emblems * (self.options.junk_fill_percentage.value / 100.0))
|
||||||
itempool += [self.create_item(ItemName.emblem, True) for _ in range(non_required_emblems - junk_count)]
|
itempool += [self.create_item(ItemName.emblem, ItemClassification.filler) for _ in range(non_required_emblems - junk_count)]
|
||||||
|
|
||||||
# Carve Traps out of junk_count
|
# Carve Traps out of junk_count
|
||||||
trap_weights = []
|
trap_weights = []
|
||||||
@@ -291,7 +353,22 @@ class SA2BWorld(World):
|
|||||||
trap_weights += ([ItemName.slow_trap] * self.options.slow_trap_weight.value)
|
trap_weights += ([ItemName.slow_trap] * self.options.slow_trap_weight.value)
|
||||||
trap_weights += ([ItemName.cutscene_trap] * self.options.cutscene_trap_weight.value)
|
trap_weights += ([ItemName.cutscene_trap] * self.options.cutscene_trap_weight.value)
|
||||||
trap_weights += ([ItemName.reverse_trap] * self.options.reverse_trap_weight.value)
|
trap_weights += ([ItemName.reverse_trap] * self.options.reverse_trap_weight.value)
|
||||||
|
trap_weights += ([ItemName.literature_trap] * self.options.literature_trap_weight.value)
|
||||||
|
trap_weights += ([ItemName.controller_drift_trap] * self.options.controller_drift_trap_weight.value)
|
||||||
|
trap_weights += ([ItemName.poison_trap] * self.options.poison_trap_weight.value)
|
||||||
|
trap_weights += ([ItemName.bee_trap] * self.options.bee_trap_weight.value)
|
||||||
trap_weights += ([ItemName.pong_trap] * self.options.pong_trap_weight.value)
|
trap_weights += ([ItemName.pong_trap] * self.options.pong_trap_weight.value)
|
||||||
|
trap_weights += ([ItemName.breakout_trap] * self.options.breakout_trap_weight.value)
|
||||||
|
trap_weights += ([ItemName.fishing_trap] * self.options.fishing_trap_weight.value)
|
||||||
|
trap_weights += ([ItemName.trivia_trap] * self.options.trivia_trap_weight.value)
|
||||||
|
trap_weights += ([ItemName.pokemon_trivia_trap] * self.options.pokemon_trivia_trap_weight.value)
|
||||||
|
trap_weights += ([ItemName.pokemon_count_trap] * self.options.pokemon_count_trap_weight.value)
|
||||||
|
trap_weights += ([ItemName.number_sequence_trap] * self.options.number_sequence_trap_weight.value)
|
||||||
|
trap_weights += ([ItemName.light_up_path_trap] * self.options.light_up_path_trap_weight.value)
|
||||||
|
trap_weights += ([ItemName.pinball_trap] * self.options.pinball_trap_weight.value)
|
||||||
|
trap_weights += ([ItemName.math_quiz_trap] * self.options.math_quiz_trap_weight.value)
|
||||||
|
trap_weights += ([ItemName.snake_trap] * self.options.snake_trap_weight.value)
|
||||||
|
trap_weights += ([ItemName.input_sequence_trap] * self.options.input_sequence_trap_weight.value)
|
||||||
|
|
||||||
junk_count += extra_junk_count
|
junk_count += extra_junk_count
|
||||||
trap_count = 0 if (len(trap_weights) == 0) else math.ceil(junk_count * (self.options.trap_fill_percentage.value / 100.0))
|
trap_count = 0 if (len(trap_weights) == 0) else math.ceil(junk_count * (self.options.trap_fill_percentage.value / 100.0))
|
||||||
@@ -347,11 +424,15 @@ class SA2BWorld(World):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def create_item(self, name: str, force_non_progression=False, goal=0) -> Item:
|
def create_item(self, name: str, force_classification=None, goal=0) -> Item:
|
||||||
data = item_table[name]
|
data = None
|
||||||
|
if name in event_table:
|
||||||
|
data = event_table[name]
|
||||||
|
else:
|
||||||
|
data = item_table[name]
|
||||||
|
|
||||||
if force_non_progression:
|
if force_classification is not None:
|
||||||
classification = ItemClassification.filler
|
classification = force_classification
|
||||||
elif name == ItemName.emblem or \
|
elif name == ItemName.emblem or \
|
||||||
name in emeralds_table.keys() or \
|
name in emeralds_table.keys() or \
|
||||||
(name == ItemName.knuckles_shovel_claws and goal in [4, 5]):
|
(name == ItemName.knuckles_shovel_claws and goal in [4, 5]):
|
||||||
@@ -380,9 +461,16 @@ class SA2BWorld(World):
|
|||||||
set_rules(self.multiworld, self, self.player, self.gate_bosses, self.boss_rush_map, self.mission_map, self.mission_count_map, self.black_market_costs)
|
set_rules(self.multiworld, self, self.player, self.gate_bosses, self.boss_rush_map, self.mission_map, self.mission_count_map, self.black_market_costs)
|
||||||
|
|
||||||
def write_spoiler(self, spoiler_handle: typing.TextIO):
|
def write_spoiler(self, spoiler_handle: typing.TextIO):
|
||||||
|
print_mission_orders_to_spoiler(self.mission_map,
|
||||||
|
self.mission_count_map,
|
||||||
|
self.shuffled_region_list,
|
||||||
|
self.levels_per_gate,
|
||||||
|
self.multiworld.player_name[self.player],
|
||||||
|
spoiler_handle)
|
||||||
|
|
||||||
if self.options.number_of_level_gates.value > 0 or self.options.goal.value in [4, 5, 6]:
|
if self.options.number_of_level_gates.value > 0 or self.options.goal.value in [4, 5, 6]:
|
||||||
spoiler_handle.write("\n")
|
spoiler_handle.write("\n")
|
||||||
header_text = "Sonic Adventure 2 Bosses for {}:\n"
|
header_text = "SA2 Bosses for {}:\n"
|
||||||
header_text = header_text.format(self.multiworld.player_name[self.player])
|
header_text = header_text.format(self.multiworld.player_name[self.player])
|
||||||
spoiler_handle.write(header_text)
|
spoiler_handle.write(header_text)
|
||||||
|
|
||||||
@@ -435,20 +523,20 @@ class SA2BWorld(World):
|
|||||||
continue
|
continue
|
||||||
level_region = exit.connected_region
|
level_region = exit.connected_region
|
||||||
for location in level_region.locations:
|
for location in level_region.locations:
|
||||||
er_hint_data[location.address] = gate_name
|
if location.address != None:
|
||||||
|
er_hint_data[location.address] = gate_name
|
||||||
|
|
||||||
for i in range(self.options.black_market_slots.value):
|
for i in range(self.options.black_market_slots.value):
|
||||||
location = self.multiworld.get_location(LocationName.chao_black_market_base + str(i + 1), self.player)
|
location = self.multiworld.get_location(LocationName.chao_black_market_base + str(i + 1), self.player)
|
||||||
er_hint_data[location.address] = str(self.black_market_costs[i]) + " " + str(ItemName.market_token)
|
er_hint_data[location.address] = str(self.black_market_costs[i]) + " " + str(ItemName.market_token)
|
||||||
|
|
||||||
|
|
||||||
hint_data[self.player] = er_hint_data
|
hint_data[self.player] = er_hint_data
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def stage_fill_hook(cls, multiworld: MultiWorld, progitempool, usefulitempool, filleritempool, fill_locations):
|
def stage_fill_hook(cls, multiworld: MultiWorld, progitempool, usefulitempool, filleritempool, fill_locations):
|
||||||
if multiworld.get_game_players("Sonic Adventure 2 Battle"):
|
if multiworld.get_game_players("Sonic Adventure 2 Battle"):
|
||||||
progitempool.sort(
|
progitempool.sort(
|
||||||
key=lambda item: 0 if (item.name != 'Emblem') else 1)
|
key=lambda item: 0 if ("Emblem" in item.name and item.game == "Sonic Adventure 2 Battle") else 1)
|
||||||
|
|
||||||
def get_levels_per_gate(self) -> list:
|
def get_levels_per_gate(self) -> list:
|
||||||
levels_per_gate = list()
|
levels_per_gate = list()
|
||||||
@@ -486,6 +574,39 @@ class SA2BWorld(World):
|
|||||||
|
|
||||||
return levels_per_gate
|
return levels_per_gate
|
||||||
|
|
||||||
|
def output_active_traps(self) -> typing.Dict[int, int]:
|
||||||
|
trap_data = {}
|
||||||
|
|
||||||
|
trap_data[0x30] = self.options.omochao_trap_weight.value
|
||||||
|
trap_data[0x31] = self.options.timestop_trap_weight.value
|
||||||
|
trap_data[0x32] = self.options.confusion_trap_weight.value
|
||||||
|
trap_data[0x33] = self.options.tiny_trap_weight.value
|
||||||
|
trap_data[0x34] = self.options.gravity_trap_weight.value
|
||||||
|
trap_data[0x35] = self.options.exposition_trap_weight.value
|
||||||
|
trap_data[0x37] = self.options.ice_trap_weight.value
|
||||||
|
trap_data[0x38] = self.options.slow_trap_weight.value
|
||||||
|
trap_data[0x39] = self.options.cutscene_trap_weight.value
|
||||||
|
trap_data[0x3A] = self.options.reverse_trap_weight.value
|
||||||
|
trap_data[0x3B] = self.options.literature_trap_weight.value
|
||||||
|
trap_data[0x3C] = self.options.controller_drift_trap_weight.value
|
||||||
|
trap_data[0x3D] = self.options.poison_trap_weight.value
|
||||||
|
trap_data[0x3E] = self.options.bee_trap_weight.value
|
||||||
|
|
||||||
|
trap_data[0x50] = self.options.pong_trap_weight.value
|
||||||
|
trap_data[0x51] = self.options.breakout_trap_weight.value
|
||||||
|
trap_data[0x52] = self.options.fishing_trap_weight.value
|
||||||
|
trap_data[0x53] = self.options.trivia_trap_weight.value
|
||||||
|
trap_data[0x54] = self.options.pokemon_trivia_trap_weight.value
|
||||||
|
trap_data[0x55] = self.options.pokemon_count_trap_weight.value
|
||||||
|
trap_data[0x56] = self.options.number_sequence_trap_weight.value
|
||||||
|
trap_data[0x57] = self.options.light_up_path_trap_weight.value
|
||||||
|
trap_data[0x58] = self.options.pinball_trap_weight.value
|
||||||
|
trap_data[0x59] = self.options.math_quiz_trap_weight.value
|
||||||
|
trap_data[0x5A] = self.options.snake_trap_weight.value
|
||||||
|
trap_data[0x5B] = self.options.input_sequence_trap_weight.value
|
||||||
|
|
||||||
|
return trap_data
|
||||||
|
|
||||||
def any_chao_locations_active(self) -> bool:
|
def any_chao_locations_active(self) -> bool:
|
||||||
if self.options.chao_race_difficulty.value > 0 or \
|
if self.options.chao_race_difficulty.value > 0 or \
|
||||||
self.options.chao_karate_difficulty.value > 0 or \
|
self.options.chao_karate_difficulty.value > 0 or \
|
||||||
@@ -686,7 +807,6 @@ class SA2BWorld(World):
|
|||||||
exit_choice = self.random.choice(valid_kindergarten_exits)
|
exit_choice = self.random.choice(valid_kindergarten_exits)
|
||||||
exit_room = exit_to_room_map[exit_choice]
|
exit_room = exit_to_room_map[exit_choice]
|
||||||
all_exits_copy.remove(exit_choice)
|
all_exits_copy.remove(exit_choice)
|
||||||
multi_rooms_copy.remove(exit_room)
|
|
||||||
|
|
||||||
destination = 0x06
|
destination = 0x06
|
||||||
single_rooms_copy.remove(destination)
|
single_rooms_copy.remove(destination)
|
||||||
@@ -723,7 +843,8 @@ class SA2BWorld(World):
|
|||||||
|
|
||||||
er_layout[exit_choice] = destination
|
er_layout[exit_choice] = destination
|
||||||
|
|
||||||
reverse_exit = self.random.choice(room_to_exits_map[destination])
|
possible_reverse_exits = [exit for exit in room_to_exits_map[destination] if exit in all_exits_copy]
|
||||||
|
reverse_exit = self.random.choice(possible_reverse_exits)
|
||||||
|
|
||||||
er_layout[reverse_exit] = exit_room
|
er_layout[reverse_exit] = exit_room
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user