mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 12:11:33 -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",
|
||||
"Corvus",
|
||||
"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 = [
|
||||
@@ -240,6 +260,35 @@ totally_real_item_names = [
|
||||
"Ladder",
|
||||
|
||||
"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 = [
|
||||
|
@@ -1,6 +1,82 @@
|
||||
# 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
|
||||
|
||||
### Features:
|
||||
|
@@ -1,18 +1,23 @@
|
||||
import typing
|
||||
|
||||
from BaseClasses import MultiWorld
|
||||
from worlds.AutoWorld import World
|
||||
|
||||
speed_characters_1 = "Sonic vs Shadow 1"
|
||||
speed_characters_2 = "Sonic vs Shadow 2"
|
||||
mech_characters_1 = "Tails vs Eggman 1"
|
||||
mech_characters_2 = "Tails vs Eggman 2"
|
||||
hunt_characters_1 = "Knuckles vs Rouge 1"
|
||||
big_foot = "F-6t BIG FOOT"
|
||||
hot_shot = "B-3x HOT SHOT"
|
||||
flying_dog = "R-1/A FLYING DOG"
|
||||
egg_golem_sonic = "Egg Golem (Sonic)"
|
||||
egg_golem_eggman = "Egg Golem (Eggman)"
|
||||
king_boom_boo = "King Boom Boo"
|
||||
from .Names import LocationName
|
||||
from .Options import GateBossPlando
|
||||
|
||||
|
||||
speed_characters_1 = "sonic vs shadow 1"
|
||||
speed_characters_2 = "sonic vs shadow 2"
|
||||
mech_characters_1 = "tails vs eggman 1"
|
||||
mech_characters_2 = "tails vs eggman 2"
|
||||
hunt_characters_1 = "knuckles vs rouge 1"
|
||||
big_foot = "big foot"
|
||||
hot_shot = "hot shot"
|
||||
flying_dog = "flying dog"
|
||||
egg_golem_sonic = "egg golem (sonic)"
|
||||
egg_golem_eggman = "egg golem (eggman)"
|
||||
king_boom_boo = "king boom boo"
|
||||
|
||||
gate_bosses_no_requirements_table = {
|
||||
speed_characters_1: 0,
|
||||
@@ -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):
|
||||
for key, value in gate_bosses_no_requirements_table.items():
|
||||
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
|
||||
return boss_id_to_name[boss]
|
||||
|
||||
|
||||
def boss_has_requirement(boss: int):
|
||||
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] = []
|
||||
boss_gates: typing.List[int] = []
|
||||
available_bosses: typing.List[str] = list(gate_bosses_no_requirements_table.keys())
|
||||
multiworld.random.shuffle(available_bosses)
|
||||
halfway = False
|
||||
world.random.shuffle(available_bosses)
|
||||
|
||||
gate_boss_plando: typing.Union[int, str] = world.options.gate_boss_plando.value
|
||||
plando_bosses = ["None", "None", "None", "None", "None"]
|
||||
if isinstance(gate_boss_plando, str):
|
||||
# boss plando
|
||||
options = gate_boss_plando.split(";")
|
||||
gate_boss_plando = GateBossPlando.options[options.pop()]
|
||||
for option in options:
|
||||
if "-" in option:
|
||||
loc, boss = option.split("-")
|
||||
boss_num = LocationName.boss_gate_names[loc]
|
||||
|
||||
if boss_num >= world.options.number_of_level_gates.value:
|
||||
# Don't reject bosses plando'd into gate bosses that won't exist
|
||||
pass
|
||||
|
||||
if boss in plando_bosses:
|
||||
# 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):
|
||||
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)
|
||||
multiworld.random.shuffle(available_bosses)
|
||||
halfway = True
|
||||
selected_bosses.append(all_gate_bosses_table[available_bosses[0]])
|
||||
world.random.shuffle(available_bosses)
|
||||
|
||||
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)
|
||||
available_bosses.remove(available_bosses[0])
|
||||
available_bosses.remove(chosen_boss)
|
||||
|
||||
bosses: typing.Dict[int, int] = dict(zip(boss_gates, selected_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:
|
||||
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:
|
||||
boss_list_o = list(range(0, 16))
|
||||
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))
|
||||
elif world.options.boss_rush_shuffle == 2:
|
||||
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:
|
||||
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))
|
||||
elif world.options.boss_rush_shuffle == 3:
|
||||
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:
|
||||
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))
|
||||
else:
|
||||
|
@@ -2,7 +2,6 @@ import typing
|
||||
|
||||
from BaseClasses import Item, ItemClassification
|
||||
from .Names import ItemName
|
||||
from worlds.alttp import ALTTPWorld
|
||||
|
||||
|
||||
class ItemData(typing.NamedTuple):
|
||||
@@ -14,7 +13,7 @@ class ItemData(typing.NamedTuple):
|
||||
|
||||
|
||||
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):
|
||||
super(SA2BItem, self).__init__(name, classification, code, player)
|
||||
@@ -73,19 +72,36 @@ junk_table = {
|
||||
}
|
||||
|
||||
trap_table = {
|
||||
ItemName.omochao_trap: ItemData(0xFF0030, False, True),
|
||||
ItemName.timestop_trap: ItemData(0xFF0031, False, True),
|
||||
ItemName.confuse_trap: ItemData(0xFF0032, False, True),
|
||||
ItemName.tiny_trap: ItemData(0xFF0033, False, True),
|
||||
ItemName.gravity_trap: ItemData(0xFF0034, False, True),
|
||||
ItemName.exposition_trap: ItemData(0xFF0035, False, True),
|
||||
#ItemName.darkness_trap: ItemData(0xFF0036, False, True),
|
||||
ItemName.ice_trap: ItemData(0xFF0037, False, True),
|
||||
ItemName.slow_trap: ItemData(0xFF0038, False, True),
|
||||
ItemName.cutscene_trap: ItemData(0xFF0039, False, True),
|
||||
ItemName.reverse_trap: ItemData(0xFF003A, False, True),
|
||||
ItemName.omochao_trap: ItemData(0xFF0030, False, True),
|
||||
ItemName.timestop_trap: ItemData(0xFF0031, False, True),
|
||||
ItemName.confuse_trap: ItemData(0xFF0032, False, True),
|
||||
ItemName.tiny_trap: ItemData(0xFF0033, False, True),
|
||||
ItemName.gravity_trap: ItemData(0xFF0034, False, True),
|
||||
ItemName.exposition_trap: ItemData(0xFF0035, False, True),
|
||||
#ItemName.darkness_trap: ItemData(0xFF0036, False, True),
|
||||
ItemName.ice_trap: ItemData(0xFF0037, False, True),
|
||||
ItemName.slow_trap: ItemData(0xFF0038, False, True),
|
||||
ItemName.cutscene_trap: ItemData(0xFF0039, 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 = {
|
||||
@@ -235,7 +251,7 @@ chaos_drives_table = {
|
||||
}
|
||||
|
||||
event_table = {
|
||||
ItemName.maria: ItemData(0xFF001D, True),
|
||||
ItemName.maria: ItemData(None, True),
|
||||
}
|
||||
|
||||
# Complete item table.
|
||||
@@ -244,6 +260,7 @@ item_table = {
|
||||
**upgrades_table,
|
||||
**junk_table,
|
||||
**trap_table,
|
||||
**minigame_trap_table,
|
||||
**emeralds_table,
|
||||
**eggs_table,
|
||||
**fruits_table,
|
||||
@@ -251,7 +268,6 @@ item_table = {
|
||||
**hats_table,
|
||||
**animals_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}
|
||||
@@ -263,7 +279,12 @@ item_groups: typing.Dict[str, str] = {
|
||||
"Seeds": list(seeds_table.keys()),
|
||||
"Hats": list(hats_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"
|
||||
ALTTPWorld.pedestal_credit_texts[item_table[ItemName.shadow_air_shoes].code] = "and the Soap Shoes"
|
||||
try:
|
||||
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],
|
||||
]
|
||||
|
||||
### 0: Speed
|
||||
### 1: Mech
|
||||
### 2: Hunt
|
||||
### 3: Kart
|
||||
### 4: Cannon's Core
|
||||
### 0: Sonic
|
||||
### 1: Tails
|
||||
### 2: Knuckles
|
||||
### 3: Shadow
|
||||
### 4: Eggman
|
||||
### 5: Rouge
|
||||
### 6: Kart
|
||||
### 7: Cannon's Core
|
||||
level_styles: typing.List[int] = [
|
||||
0,
|
||||
2,
|
||||
@@ -133,7 +136,7 @@ level_styles: typing.List[int] = [
|
||||
2,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
6,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
@@ -142,22 +145,22 @@ level_styles: typing.List[int] = [
|
||||
0,
|
||||
0,
|
||||
|
||||
1,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
3,
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
|
||||
4,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
5,
|
||||
4,
|
||||
4,
|
||||
5,
|
||||
3,
|
||||
6,
|
||||
3,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
|
||||
7,
|
||||
]
|
||||
|
||||
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):
|
||||
mission_count_table[level] = 0
|
||||
else:
|
||||
speed_active_missions = 1
|
||||
mech_active_missions = 1
|
||||
hunt_active_missions = 1
|
||||
sonic_active_missions = 1
|
||||
tails_active_missions = 1
|
||||
knuckles_active_missions = 1
|
||||
shadow_active_missions = 1
|
||||
eggman_active_missions = 1
|
||||
rouge_active_missions = 1
|
||||
kart_active_missions = 1
|
||||
cannons_core_active_missions = 1
|
||||
|
||||
for i in range(2,6):
|
||||
if getattr(world.options, "speed_mission_" + str(i), None):
|
||||
speed_active_missions += 1
|
||||
if getattr(world.options, "sonic_mission_" + str(i), None):
|
||||
sonic_active_missions += 1
|
||||
|
||||
if getattr(world.options, "mech_mission_" + str(i), None):
|
||||
mech_active_missions += 1
|
||||
if getattr(world.options, "tails_mission_" + str(i), None):
|
||||
tails_active_missions += 1
|
||||
|
||||
if getattr(world.options, "hunt_mission_" + str(i), None):
|
||||
hunt_active_missions += 1
|
||||
if getattr(world.options, "knuckles_mission_" + str(i), None):
|
||||
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):
|
||||
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):
|
||||
cannons_core_active_missions += 1
|
||||
|
||||
speed_active_missions = min(speed_active_missions, world.options.speed_mission_count.value)
|
||||
mech_active_missions = min(mech_active_missions, world.options.mech_mission_count.value)
|
||||
hunt_active_missions = min(hunt_active_missions, world.options.hunt_mission_count.value)
|
||||
sonic_active_missions = min(sonic_active_missions, world.options.sonic_mission_count.value)
|
||||
tails_active_missions = min(tails_active_missions, world.options.tails_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)
|
||||
cannons_core_active_missions = min(cannons_core_active_missions, world.options.cannons_core_mission_count.value)
|
||||
|
||||
active_missions: typing.List[typing.List[int]] = [
|
||||
speed_active_missions,
|
||||
mech_active_missions,
|
||||
hunt_active_missions,
|
||||
sonic_active_missions,
|
||||
tails_active_missions,
|
||||
knuckles_active_missions,
|
||||
shadow_active_missions,
|
||||
eggman_active_missions,
|
||||
rouge_active_missions,
|
||||
kart_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):
|
||||
mission_table[level] = 0
|
||||
else:
|
||||
speed_active_missions: typing.List[int] = [1]
|
||||
mech_active_missions: typing.List[int] = [1]
|
||||
hunt_active_missions: typing.List[int] = [1]
|
||||
sonic_active_missions: typing.List[int] = [1]
|
||||
tails_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]
|
||||
cannons_core_active_missions: typing.List[int] = [1]
|
||||
|
||||
# Add included missions
|
||||
for i in range(2,6):
|
||||
if getattr(world.options, "speed_mission_" + str(i), None):
|
||||
speed_active_missions.append(i)
|
||||
if getattr(world.options, "sonic_mission_" + str(i), None):
|
||||
sonic_active_missions.append(i)
|
||||
|
||||
if getattr(world.options, "mech_mission_" + str(i), None):
|
||||
mech_active_missions.append(i)
|
||||
if getattr(world.options, "tails_mission_" + str(i), None):
|
||||
tails_active_missions.append(i)
|
||||
|
||||
if getattr(world.options, "hunt_mission_" + str(i), None):
|
||||
hunt_active_missions.append(i)
|
||||
if getattr(world.options, "knuckles_mission_" + str(i), None):
|
||||
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):
|
||||
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)
|
||||
|
||||
active_missions: typing.List[typing.List[int]] = [
|
||||
speed_active_missions,
|
||||
mech_active_missions,
|
||||
hunt_active_missions,
|
||||
sonic_active_missions,
|
||||
tails_active_missions,
|
||||
knuckles_active_missions,
|
||||
shadow_active_missions,
|
||||
eggman_active_missions,
|
||||
rouge_active_missions,
|
||||
kart_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]):
|
||||
mission_count = mission_count_map[30]
|
||||
mission_order: typing.List[int] = mission_orders[mission_map[30]]
|
||||
stage_prefix: str = stage_name_prefixes[30]
|
||||
mission_count = mission_count_map[30]
|
||||
mission_order: typing.List[int] = mission_orders[mission_map[30]]
|
||||
stage_prefix: str = stage_name_prefixes[30]
|
||||
|
||||
first_mission_number = mission_order[0]
|
||||
last_mission_number = mission_order[mission_count - 1]
|
||||
first_location_name: str = stage_prefix + str(first_mission_number)
|
||||
last_location_name: str = stage_prefix + str(last_mission_number)
|
||||
first_mission_number = mission_order[0]
|
||||
last_mission_number = mission_order[mission_count - 1]
|
||||
first_location_name: str = stage_prefix + str(first_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"
|
||||
|
||||
# Upgrade Definitions
|
||||
sonic_gloves = "Sonic - Magic Glove"
|
||||
sonic_gloves = "Sonic - Magic Gloves"
|
||||
sonic_light_shoes = "Sonic - Light Shoes"
|
||||
sonic_ancient_light = "Sonic - Ancient Light"
|
||||
sonic_bounce_bracelet = "Sonic - Bounce Bracelet"
|
||||
@@ -51,19 +51,34 @@ invincibility = "Invincibility"
|
||||
|
||||
|
||||
# Traps
|
||||
omochao_trap = "OmoTrap"
|
||||
timestop_trap = "Chaos Control Trap"
|
||||
confuse_trap = "Confusion Trap"
|
||||
tiny_trap = "Tiny Trap"
|
||||
gravity_trap = "Gravity Trap"
|
||||
exposition_trap = "Exposition Trap"
|
||||
darkness_trap = "Darkness Trap"
|
||||
ice_trap = "Ice Trap"
|
||||
slow_trap = "Slow Trap"
|
||||
cutscene_trap = "Cutscene Trap"
|
||||
reverse_trap = "Reverse Trap"
|
||||
omochao_trap = "OmoTrap"
|
||||
timestop_trap = "Chaos Control Trap"
|
||||
confuse_trap = "Confusion Trap"
|
||||
tiny_trap = "Tiny Trap"
|
||||
gravity_trap = "Gravity Trap"
|
||||
exposition_trap = "Exposition Trap"
|
||||
darkness_trap = "Darkness Trap"
|
||||
ice_trap = "Ice Trap"
|
||||
slow_trap = "Slow Trap"
|
||||
cutscene_trap = "Cutscene 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
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,8 @@
|
||||
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):
|
||||
@@ -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
|
||||
|
||||
Chaos Chao: Raise a Chaos Chao to win
|
||||
|
||||
Minigame Madness: Win a certain amount of each Minigame Trap, then defeat Finalhazard
|
||||
"""
|
||||
display_name = "Goal"
|
||||
option_biolizard = 0
|
||||
@@ -32,6 +36,7 @@ class Goal(Choice):
|
||||
option_cannons_core_boss_rush = 5
|
||||
option_boss_rush_chaos_emerald_hunt = 6
|
||||
option_chaos_chao = 7
|
||||
option_minigame_madness = 8
|
||||
default = 0
|
||||
|
||||
@classmethod
|
||||
@@ -71,6 +76,66 @@ class BossRushShuffle(Choice):
|
||||
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):
|
||||
"""
|
||||
Base Class for Trap Weights
|
||||
@@ -159,6 +224,34 @@ class ReverseTrapWeight(BaseTrapWeight):
|
||||
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):
|
||||
"""
|
||||
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"
|
||||
|
||||
|
||||
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):
|
||||
"""
|
||||
How difficult any Minigame-style traps are
|
||||
Chaos causes the difficulty to be random per-minigame
|
||||
"""
|
||||
display_name = "Minigame Trap Difficulty"
|
||||
option_easy = 0
|
||||
option_medium = 1
|
||||
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
|
||||
|
||||
|
||||
@@ -197,7 +382,7 @@ class TrapFillPercentage(Range):
|
||||
default = 0
|
||||
|
||||
|
||||
class Keysanity(Toggle):
|
||||
class Keysanity(DefaultOnToggle):
|
||||
"""
|
||||
Determines whether picking up Chao Keys grants checks
|
||||
(86 Locations)
|
||||
@@ -225,7 +410,7 @@ class Whistlesanity(Choice):
|
||||
default = 0
|
||||
|
||||
|
||||
class Beetlesanity(Toggle):
|
||||
class Beetlesanity(DefaultOnToggle):
|
||||
"""
|
||||
Determines whether destroying Gold Beetles grants checks
|
||||
(27 Locations)
|
||||
@@ -244,13 +429,35 @@ class Omosanity(Toggle):
|
||||
class Animalsanity(Toggle):
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
Determines whether Kart Race Mode grants checks
|
||||
@@ -313,7 +520,7 @@ class LevelGateCosts(Choice):
|
||||
option_low = 0
|
||||
option_medium = 1
|
||||
option_high = 2
|
||||
default = 2
|
||||
default = 0
|
||||
|
||||
|
||||
class MaximumEmblemCap(Range):
|
||||
@@ -523,109 +730,214 @@ class BaseMissionCount(Range):
|
||||
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):
|
||||
@@ -706,7 +1018,7 @@ class RingLoss(Choice):
|
||||
|
||||
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"
|
||||
option_classic = 0
|
||||
@@ -729,6 +1041,16 @@ class RingLink(Toggle):
|
||||
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):
|
||||
"""
|
||||
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
|
||||
|
||||
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"
|
||||
option_standard = 0
|
||||
option_hard = 1
|
||||
option_expert = 2
|
||||
default = 0
|
||||
|
||||
|
||||
@@ -835,6 +1160,8 @@ sa2b_option_groups = [
|
||||
OptionGroup("General Options", [
|
||||
Goal,
|
||||
BossRushShuffle,
|
||||
MinigameMadnessRequirement,
|
||||
MinigameMadnessMinimum,
|
||||
LogicDifficulty,
|
||||
RequiredRank,
|
||||
MaximumEmblemCap,
|
||||
@@ -854,6 +1181,8 @@ sa2b_option_groups = [
|
||||
Beetlesanity,
|
||||
Omosanity,
|
||||
Animalsanity,
|
||||
ItemBoxsanity,
|
||||
Bigsanity,
|
||||
KartRaceChecks,
|
||||
]),
|
||||
OptionGroup("Chao", [
|
||||
@@ -885,29 +1214,68 @@ sa2b_option_groups = [
|
||||
SlowTrapWeight,
|
||||
CutsceneTrapWeight,
|
||||
ReverseTrapWeight,
|
||||
LiteratureTrapWeight,
|
||||
ControllerDriftTrapWeight,
|
||||
PoisonTrapWeight,
|
||||
BeeTrapWeight,
|
||||
]),
|
||||
OptionGroup("Minigames", [
|
||||
PongTrapWeight,
|
||||
BreakoutTrapWeight,
|
||||
FishingTrapWeight,
|
||||
TriviaTrapWeight,
|
||||
PokemonTriviaTrapWeight,
|
||||
PokemonCountTrapWeight,
|
||||
NumberSequenceTrapWeight,
|
||||
LightUpPathTrapWeight,
|
||||
PinballTrapWeight,
|
||||
MathQuizTrapWeight,
|
||||
SnakeTrapWeight,
|
||||
InputSequenceTrapWeight,
|
||||
MinigameTrapDifficulty,
|
||||
BigFishingDifficulty,
|
||||
]),
|
||||
OptionGroup("Speed Missions", [
|
||||
SpeedMissionCount,
|
||||
SpeedMission2,
|
||||
SpeedMission3,
|
||||
SpeedMission4,
|
||||
SpeedMission5,
|
||||
OptionGroup("Sonic Missions", [
|
||||
SonicMissionCount,
|
||||
SonicMission2,
|
||||
SonicMission3,
|
||||
SonicMission4,
|
||||
SonicMission5,
|
||||
]),
|
||||
OptionGroup("Mech Missions", [
|
||||
MechMissionCount,
|
||||
MechMission2,
|
||||
MechMission3,
|
||||
MechMission4,
|
||||
MechMission5,
|
||||
OptionGroup("Shadow Missions", [
|
||||
ShadowMissionCount,
|
||||
ShadowMission2,
|
||||
ShadowMission3,
|
||||
ShadowMission4,
|
||||
ShadowMission5,
|
||||
]),
|
||||
OptionGroup("Hunt Missions", [
|
||||
HuntMissionCount,
|
||||
HuntMission2,
|
||||
HuntMission3,
|
||||
HuntMission4,
|
||||
HuntMission5,
|
||||
OptionGroup("Tails Missions", [
|
||||
TailsMissionCount,
|
||||
TailsMission2,
|
||||
TailsMission3,
|
||||
TailsMission4,
|
||||
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", [
|
||||
KartMissionCount,
|
||||
@@ -931,11 +1299,13 @@ sa2b_option_groups = [
|
||||
]),
|
||||
]
|
||||
|
||||
|
||||
@dataclass
|
||||
class SA2BOptions(PerGameCommonOptions):
|
||||
goal: Goal
|
||||
boss_rush_shuffle: BossRushShuffle
|
||||
minigame_madness_requirement: MinigameMadnessRequirement
|
||||
minigame_madness_minimum: MinigameMadnessMinimum
|
||||
gate_boss_plando: GateBossPlando
|
||||
logic_difficulty: LogicDifficulty
|
||||
required_rank: RequiredRank
|
||||
max_emblem_cap: MaximumEmblemCap
|
||||
@@ -953,6 +1323,8 @@ class SA2BOptions(PerGameCommonOptions):
|
||||
beetlesanity: Beetlesanity
|
||||
omosanity: Omosanity
|
||||
animalsanity: Animalsanity
|
||||
itemboxsanity: ItemBoxsanity
|
||||
bigsanity: Bigsanity
|
||||
kart_race_checks: KartRaceChecks
|
||||
|
||||
black_market_slots: BlackMarketSlots
|
||||
@@ -983,31 +1355,65 @@ class SA2BOptions(PerGameCommonOptions):
|
||||
slow_trap_weight: SlowTrapWeight
|
||||
cutscene_trap_weight: CutsceneTrapWeight
|
||||
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
|
||||
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
|
||||
big_fishing_difficulty: BigFishingDifficulty
|
||||
|
||||
sadx_music: SADXMusic
|
||||
music_shuffle: MusicShuffle
|
||||
voice_shuffle: VoiceShuffle
|
||||
narrator: Narrator
|
||||
|
||||
speed_mission_count: SpeedMissionCount
|
||||
speed_mission_2: SpeedMission2
|
||||
speed_mission_3: SpeedMission3
|
||||
speed_mission_4: SpeedMission4
|
||||
speed_mission_5: SpeedMission5
|
||||
sonic_mission_count: SonicMissionCount
|
||||
sonic_mission_2: SonicMission2
|
||||
sonic_mission_3: SonicMission3
|
||||
sonic_mission_4: SonicMission4
|
||||
sonic_mission_5: SonicMission5
|
||||
|
||||
mech_mission_count: MechMissionCount
|
||||
mech_mission_2: MechMission2
|
||||
mech_mission_3: MechMission3
|
||||
mech_mission_4: MechMission4
|
||||
mech_mission_5: MechMission5
|
||||
shadow_mission_count: ShadowMissionCount
|
||||
shadow_mission_2: ShadowMission2
|
||||
shadow_mission_3: ShadowMission3
|
||||
shadow_mission_4: ShadowMission4
|
||||
shadow_mission_5: ShadowMission5
|
||||
|
||||
hunt_mission_count: HuntMissionCount
|
||||
hunt_mission_2: HuntMission2
|
||||
hunt_mission_3: HuntMission3
|
||||
hunt_mission_4: HuntMission4
|
||||
hunt_mission_5: HuntMission5
|
||||
tails_mission_count: TailsMissionCount
|
||||
tails_mission_2: TailsMission2
|
||||
tails_mission_3: TailsMission3
|
||||
tails_mission_4: TailsMission4
|
||||
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_2: KartMission2
|
||||
@@ -1022,4 +1428,5 @@ class SA2BOptions(PerGameCommonOptions):
|
||||
cannons_core_mission_5: CannonsCoreMission5
|
||||
|
||||
ring_link: RingLink
|
||||
trap_link: TrapLink
|
||||
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, \
|
||||
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 .Items import SA2BItem, ItemData, item_table, upgrades_table, emeralds_table, junk_table, trap_table, item_groups, \
|
||||
eggs_table, fruits_table, seeds_table, hats_table, animals_table, chaos_drives_table
|
||||
from .Locations import SA2BLocation, all_locations, 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 .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, event_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, print_mission_orders_to_spoiler
|
||||
from .Names import ItemName, LocationName
|
||||
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, \
|
||||
gate_0_blacklist_regions
|
||||
from .Rules import set_rules
|
||||
@@ -33,6 +34,7 @@ class SA2BWeb(WebWorld):
|
||||
|
||||
tutorials = [setup_en]
|
||||
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):
|
||||
@@ -60,11 +62,14 @@ class SA2BWorld(World):
|
||||
topology_present = False
|
||||
|
||||
item_name_groups = item_groups
|
||||
location_name_groups = location_groups
|
||||
item_name_to_id = {name: data.code for name, data in item_table.items()}
|
||||
location_name_to_id = all_locations
|
||||
|
||||
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_count_map: typing.Dict[int, int]
|
||||
emblems_for_cannons_core: int
|
||||
@@ -78,7 +83,7 @@ class SA2BWorld(World):
|
||||
|
||||
def fill_slot_data(self) -> dict:
|
||||
return {
|
||||
"ModVersion": 203,
|
||||
"ModVersion": 204,
|
||||
"Goal": self.options.goal.value,
|
||||
"MusicMap": self.generate_music_data(),
|
||||
"VoiceMap": self.generate_voice_data(),
|
||||
@@ -89,14 +94,20 @@ class SA2BWorld(World):
|
||||
"MusicShuffle": self.options.music_shuffle.value,
|
||||
"Narrator": self.options.narrator.value,
|
||||
"MinigameTrapDifficulty": self.options.minigame_trap_difficulty.value,
|
||||
"BigFishingDifficulty": self.options.big_fishing_difficulty.value,
|
||||
"RingLoss": self.options.ring_loss.value,
|
||||
"RingLink": self.options.ring_link.value,
|
||||
"TrapLink": self.options.trap_link.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,
|
||||
"Whistlesanity": self.options.whistlesanity.value,
|
||||
"GoldBeetles": self.options.beetlesanity.value,
|
||||
"OmochaoChecks": self.options.omosanity.value,
|
||||
"AnimalChecks": self.options.animalsanity.value,
|
||||
"ItemBoxChecks": self.options.itemboxsanity.value,
|
||||
"BigChecks": self.options.bigsanity.value,
|
||||
"KartRaceChecks": self.options.kart_race_checks.value,
|
||||
"ChaoStadiumChecks": self.options.chao_stadium_checks.value,
|
||||
"ChaoRaceDifficulty": self.options.chao_race_difficulty.value,
|
||||
@@ -122,6 +133,7 @@ class SA2BWorld(World):
|
||||
"GateCosts": self.gate_costs,
|
||||
"GateBosses": self.gate_bosses,
|
||||
"BossRushMap": self.boss_rush_map,
|
||||
"ActiveTraps": self.output_active_traps(),
|
||||
"PlayerNum": self.player,
|
||||
}
|
||||
|
||||
@@ -151,12 +163,42 @@ class SA2BWorld(World):
|
||||
|
||||
valid_trap_weights = self.options.exposition_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:
|
||||
self.options.exposition_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.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:
|
||||
self.options.kart_race_checks.value = 2
|
||||
@@ -164,8 +206,8 @@ class SA2BWorld(World):
|
||||
self.gate_bosses = {}
|
||||
self.boss_rush_map = {}
|
||||
else:
|
||||
self.gate_bosses = get_gate_bosses(self.multiworld, self)
|
||||
self.boss_rush_map = get_boss_rush_bosses(self.multiworld, self)
|
||||
self.gate_bosses = get_gate_bosses(self)
|
||||
self.boss_rush_map = get_boss_rush_bosses(self)
|
||||
|
||||
def create_regions(self):
|
||||
self.mission_map = get_mission_table(self.multiworld, self, self.player)
|
||||
@@ -177,7 +219,7 @@ class SA2BWorld(World):
|
||||
# Not Generate Basic
|
||||
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))
|
||||
elif self.options.goal.value == 1:
|
||||
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:
|
||||
# Fill item pool with all required items
|
||||
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]:
|
||||
# Some flavor of Chaos Emerald Hunt
|
||||
@@ -212,6 +254,25 @@ class SA2BWorld(World):
|
||||
# Black Market
|
||||
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
|
||||
if self.options.black_market_unlock_costs.value == 0:
|
||||
black_market_unlock_mult = 0.5
|
||||
@@ -235,12 +296,12 @@ class SA2BWorld(World):
|
||||
elif self.options.level_gate_costs.value == 1:
|
||||
gate_cost_mult = 0.8
|
||||
|
||||
shuffled_region_list = list(range(30))
|
||||
self.shuffled_region_list = list(range(30))
|
||||
emblem_requirement_list = list()
|
||||
self.multiworld.random.shuffle(shuffled_region_list)
|
||||
levels_per_gate = self.get_levels_per_gate()
|
||||
self.multiworld.random.shuffle(self.shuffled_region_list)
|
||||
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
|
||||
total_levels_added = 0
|
||||
current_gate = 0
|
||||
@@ -250,11 +311,11 @@ class SA2BWorld(World):
|
||||
gates = list()
|
||||
gates.append(LevelGate(0))
|
||||
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)
|
||||
levels_added_to_gate += 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
|
||||
if 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
|
||||
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)
|
||||
|
||||
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 = min(int(max_required_emblems * 1.1), total_emblem_count)
|
||||
itempool += [self.create_item(ItemName.emblem) for _ in range(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))
|
||||
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
|
||||
trap_weights = []
|
||||
@@ -291,7 +353,22 @@ class SA2BWorld(World):
|
||||
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.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.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
|
||||
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:
|
||||
data = item_table[name]
|
||||
def create_item(self, name: str, force_classification=None, goal=0) -> Item:
|
||||
data = None
|
||||
if name in event_table:
|
||||
data = event_table[name]
|
||||
else:
|
||||
data = item_table[name]
|
||||
|
||||
if force_non_progression:
|
||||
classification = ItemClassification.filler
|
||||
if force_classification is not None:
|
||||
classification = force_classification
|
||||
elif name == ItemName.emblem or \
|
||||
name in emeralds_table.keys() or \
|
||||
(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)
|
||||
|
||||
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]:
|
||||
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])
|
||||
spoiler_handle.write(header_text)
|
||||
|
||||
@@ -435,20 +523,20 @@ class SA2BWorld(World):
|
||||
continue
|
||||
level_region = exit.connected_region
|
||||
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):
|
||||
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)
|
||||
|
||||
|
||||
hint_data[self.player] = er_hint_data
|
||||
|
||||
@classmethod
|
||||
def stage_fill_hook(cls, multiworld: MultiWorld, progitempool, usefulitempool, filleritempool, fill_locations):
|
||||
if multiworld.get_game_players("Sonic Adventure 2 Battle"):
|
||||
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:
|
||||
levels_per_gate = list()
|
||||
@@ -486,6 +574,39 @@ class SA2BWorld(World):
|
||||
|
||||
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:
|
||||
if self.options.chao_race_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_room = exit_to_room_map[exit_choice]
|
||||
all_exits_copy.remove(exit_choice)
|
||||
multi_rooms_copy.remove(exit_room)
|
||||
|
||||
destination = 0x06
|
||||
single_rooms_copy.remove(destination)
|
||||
@@ -723,7 +843,8 @@ class SA2BWorld(World):
|
||||
|
||||
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
|
||||
|
||||
|
Reference in New Issue
Block a user