SA2B: v2.3 - The Chao Update (#2277)
Changelog: Features: - New goal - Chaos Chao - Raise a Chaos Chao to win! - New optional Location Checks - Chao Animal Parts - Each body part from each type of animal is a location - Chao Stats - 0-99 levels of each of the 7 Chao stats can be locations - The frequency of Chao Stat locations can be set (every level, every 2nd level, etc) - Kindergartensanity - Classroom lessons are locations - Either all lessons or any one of each category can be set as locations - Shopsanity - A specified number of locations can be placed in the Chao Black Market - These locations are unlocked by acquiring `Chao Coin`s - Ring costs for these items can be adjusted - Chao Karate can now be set to one location per fight, instead of one per tournament - Items - If any Chao locations are active, the following will be in the item pool: - Chao Eggs - Garden Seeds - Garden Fruit - Chao Hats - Chaos Drives - The starting eggs in the garden can be a random color - Chao World entrances can be shuffled - Chao are given default names - New Traps - Reverse Trap Quality of Life: - Chao Save Data is now separate per-slot in addition to per-seed - This allows a single player to have multiple slots in the same seed, each having separate Chao progress - Chao Race/Karate progress is now displayed on Stage Select (when hovering over Chao World) - All Chao can now enter the Hero and Dark races - Chao Karate difficulty can be set separately from Chao Race difficulty - Chao Aging can be sped up at will, up to 15× - New mod `config` option to fine-tune Chao Stat multiplication - Note: This does not mix well with the Mod Manager "`Chao Stat Multiplier`" code - Pong Traps can now activate in Chao World - Maximum range for possible number of Emblems is now 1000 - General APWorld cleanup and optimization - Option access has moved to the new options system - An item group now exists for trap items Bug Fixes: - Dry Lagoon now has all 11 Animals - Eternal Engine - 2 (Standard and Hard Logic) now requires only `Tails - Booster` - Lost Colony - 2 (Hard Logic) now requires no upgrades - Lost Colony - Animal 9 (Hard Logic) now requires either `Eggman - Jet Engine` or `Eggman - Large Cannon`
This commit is contained in:
parent
829c664304
commit
85d02b2dc5
|
@ -0,0 +1,342 @@
|
||||||
|
|
||||||
|
chao_name_conversion = {
|
||||||
|
"!": 0x01,
|
||||||
|
"!": 0x02,
|
||||||
|
"#": 0x03,
|
||||||
|
"$": 0x04,
|
||||||
|
"%": 0x05,
|
||||||
|
"&": 0x06,
|
||||||
|
"\\": 0x07,
|
||||||
|
"(": 0x08,
|
||||||
|
")": 0x09,
|
||||||
|
"*": 0x0A,
|
||||||
|
"+": 0x0B,
|
||||||
|
",": 0x0C,
|
||||||
|
"-": 0x0D,
|
||||||
|
".": 0x0E,
|
||||||
|
"/": 0x0F,
|
||||||
|
|
||||||
|
"0": 0x10,
|
||||||
|
"1": 0x11,
|
||||||
|
"2": 0x12,
|
||||||
|
"3": 0x13,
|
||||||
|
"4": 0x14,
|
||||||
|
"5": 0x15,
|
||||||
|
"6": 0x16,
|
||||||
|
"7": 0x17,
|
||||||
|
"8": 0x18,
|
||||||
|
"9": 0x19,
|
||||||
|
":": 0x1A,
|
||||||
|
";": 0x1B,
|
||||||
|
"<": 0x1C,
|
||||||
|
"=": 0x1D,
|
||||||
|
">": 0x1E,
|
||||||
|
"?": 0x1F,
|
||||||
|
|
||||||
|
"@": 0x20,
|
||||||
|
"A": 0x21,
|
||||||
|
"B": 0x22,
|
||||||
|
"C": 0x23,
|
||||||
|
"D": 0x24,
|
||||||
|
"E": 0x25,
|
||||||
|
"F": 0x26,
|
||||||
|
"G": 0x27,
|
||||||
|
"H": 0x28,
|
||||||
|
"I": 0x29,
|
||||||
|
"J": 0x2A,
|
||||||
|
"K": 0x2B,
|
||||||
|
"L": 0x2C,
|
||||||
|
"M": 0x2D,
|
||||||
|
"N": 0x2E,
|
||||||
|
"O": 0x2F,
|
||||||
|
|
||||||
|
"P": 0x30,
|
||||||
|
"Q": 0x31,
|
||||||
|
"R": 0x32,
|
||||||
|
"S": 0x33,
|
||||||
|
"T": 0x34,
|
||||||
|
"U": 0x35,
|
||||||
|
"V": 0x36,
|
||||||
|
"W": 0x37,
|
||||||
|
"X": 0x38,
|
||||||
|
"Y": 0x39,
|
||||||
|
"Z": 0x3A,
|
||||||
|
"[": 0x3B,
|
||||||
|
"¥": 0x3C,
|
||||||
|
"]": 0x3D,
|
||||||
|
"^": 0x3E,
|
||||||
|
"_": 0x3F,
|
||||||
|
|
||||||
|
"`": 0x40,
|
||||||
|
"a": 0x41,
|
||||||
|
"b": 0x42,
|
||||||
|
"c": 0x43,
|
||||||
|
"d": 0x44,
|
||||||
|
"e": 0x45,
|
||||||
|
"f": 0x46,
|
||||||
|
"g": 0x47,
|
||||||
|
"h": 0x48,
|
||||||
|
"i": 0x49,
|
||||||
|
"j": 0x4A,
|
||||||
|
"k": 0x4B,
|
||||||
|
"l": 0x4C,
|
||||||
|
"m": 0x4D,
|
||||||
|
"n": 0x4E,
|
||||||
|
"o": 0x4F,
|
||||||
|
|
||||||
|
"p": 0x50,
|
||||||
|
"q": 0x51,
|
||||||
|
"r": 0x52,
|
||||||
|
"s": 0x53,
|
||||||
|
"t": 0x54,
|
||||||
|
"u": 0x55,
|
||||||
|
"v": 0x56,
|
||||||
|
"w": 0x57,
|
||||||
|
"x": 0x58,
|
||||||
|
"y": 0x59,
|
||||||
|
"z": 0x5A,
|
||||||
|
"{": 0x5B,
|
||||||
|
"|": 0x5C,
|
||||||
|
"}": 0x5D,
|
||||||
|
"~": 0x5E,
|
||||||
|
" ": 0x5F,
|
||||||
|
}
|
||||||
|
|
||||||
|
sample_chao_names = [
|
||||||
|
"Aginah",
|
||||||
|
"Biter",
|
||||||
|
"Steve",
|
||||||
|
"Ryley",
|
||||||
|
"Watcher",
|
||||||
|
"Acrid",
|
||||||
|
"Sheik",
|
||||||
|
"Lunais",
|
||||||
|
"Samus",
|
||||||
|
"The Kid",
|
||||||
|
"Jack",
|
||||||
|
"Sir Lee",
|
||||||
|
"Viridian",
|
||||||
|
"Rouhi",
|
||||||
|
"Toad",
|
||||||
|
"Merit",
|
||||||
|
"Ridley",
|
||||||
|
"Hornet",
|
||||||
|
"Carl",
|
||||||
|
"Raynor",
|
||||||
|
"Dixie",
|
||||||
|
"Wolnir",
|
||||||
|
"Mario",
|
||||||
|
"Gary",
|
||||||
|
"Wayne",
|
||||||
|
"Kevin",
|
||||||
|
"J.J.",
|
||||||
|
"Maxim",
|
||||||
|
"Redento",
|
||||||
|
"Caesar",
|
||||||
|
"Abigail",
|
||||||
|
"Link",
|
||||||
|
"Ninja",
|
||||||
|
"Roxas",
|
||||||
|
"Marin",
|
||||||
|
"Yorgle",
|
||||||
|
"DLC",
|
||||||
|
"Mina",
|
||||||
|
"Sans",
|
||||||
|
"Lan",
|
||||||
|
"Rin",
|
||||||
|
"Doomguy",
|
||||||
|
"Guide",
|
||||||
|
]
|
||||||
|
|
||||||
|
totally_real_item_names = [
|
||||||
|
"Mallet",
|
||||||
|
"Lava Rod",
|
||||||
|
"Master Knife",
|
||||||
|
"Slippers",
|
||||||
|
"Spade",
|
||||||
|
|
||||||
|
"Progressive Car Upgrade",
|
||||||
|
"Bonus Token",
|
||||||
|
|
||||||
|
"Shortnail",
|
||||||
|
"Runmaster",
|
||||||
|
|
||||||
|
"Courage Form",
|
||||||
|
"Auto Courage",
|
||||||
|
"Donald Defender",
|
||||||
|
"Goofy Blizzard",
|
||||||
|
"Ultimate Weapon",
|
||||||
|
|
||||||
|
"Song of the Sky Whale",
|
||||||
|
"Gryphon Shoes",
|
||||||
|
"Wing Key",
|
||||||
|
"Strength Anklet",
|
||||||
|
|
||||||
|
"Hairclip",
|
||||||
|
|
||||||
|
"Key of Wisdom",
|
||||||
|
|
||||||
|
"Baking",
|
||||||
|
"Progressive Block Mining",
|
||||||
|
|
||||||
|
"Jar",
|
||||||
|
"Whistle of Space",
|
||||||
|
"Rito Tunic",
|
||||||
|
|
||||||
|
"Kitchen Sink",
|
||||||
|
|
||||||
|
"Rock Badge",
|
||||||
|
"Key Card",
|
||||||
|
"Pikachu",
|
||||||
|
"Eevee",
|
||||||
|
"HM02 Strength",
|
||||||
|
|
||||||
|
"Progressive Astromancers",
|
||||||
|
"Progressive Chefs",
|
||||||
|
"The Living Safe",
|
||||||
|
"Lady Quinn",
|
||||||
|
|
||||||
|
"Dio's Worst Enemy",
|
||||||
|
|
||||||
|
"Pink Chaos Emerald",
|
||||||
|
"Black Chaos Emerald",
|
||||||
|
"Tails - Large Cannon",
|
||||||
|
"Eggman - Bazooka",
|
||||||
|
"Eggman - Booster",
|
||||||
|
"Knuckles - Shades",
|
||||||
|
"Sonic - Magic Shoes",
|
||||||
|
"Shadow - Bounce Bracelet",
|
||||||
|
"Rouge - Air Necklace",
|
||||||
|
"Big Key (Eggman's Pyramid)",
|
||||||
|
|
||||||
|
"Sensor Bunker",
|
||||||
|
"Phantom",
|
||||||
|
"Soldier",
|
||||||
|
|
||||||
|
"Plasma Suit",
|
||||||
|
"Gravity Beam",
|
||||||
|
"Hi-Jump Ball",
|
||||||
|
|
||||||
|
"Cannon Unlock LLL",
|
||||||
|
"Feather Cap",
|
||||||
|
|
||||||
|
"Progressive Yoshi",
|
||||||
|
"Purple Switch Palace",
|
||||||
|
"Cape Feather",
|
||||||
|
|
||||||
|
"Cane of Bryan",
|
||||||
|
|
||||||
|
"Van Repair",
|
||||||
|
"Autumn",
|
||||||
|
"Galaxy Knife",
|
||||||
|
"Green Cabbage Seeds",
|
||||||
|
|
||||||
|
"Timespinner Cog 1",
|
||||||
|
|
||||||
|
"Ladder",
|
||||||
|
|
||||||
|
"Visible Dots",
|
||||||
|
]
|
||||||
|
|
||||||
|
all_exits = [
|
||||||
|
0x00, # Lobby to Neutral
|
||||||
|
0x01, # Lobby to Hero
|
||||||
|
0x02, # Lobby to Dark
|
||||||
|
0x03, # Lobby to Kindergarten
|
||||||
|
0x04, # Neutral to Lobby
|
||||||
|
0x05, # Neutral to Cave
|
||||||
|
0x06, # Neutral to Transporter
|
||||||
|
0x07, # Hero to Lobby
|
||||||
|
0x08, # Hero to Transporter
|
||||||
|
0x09, # Dark to Lobby
|
||||||
|
0x0A, # Dark to Transporter
|
||||||
|
0x0B, # Cave to Neutral
|
||||||
|
0x0C, # Cave to Race
|
||||||
|
0x0D, # Cave to Karate
|
||||||
|
0x0E, # Race to Cave
|
||||||
|
0x0F, # Karate to Cave
|
||||||
|
0x10, # Transporter to Neutral
|
||||||
|
#0x11, # Transporter to Hero
|
||||||
|
#0x12, # Transporter to Dark
|
||||||
|
0x13, # Kindergarten to Lobby
|
||||||
|
]
|
||||||
|
|
||||||
|
all_destinations = [
|
||||||
|
0x07, # Lobby
|
||||||
|
0x07,
|
||||||
|
0x07,
|
||||||
|
0x07,
|
||||||
|
0x01, # Neutral
|
||||||
|
0x01,
|
||||||
|
0x01,
|
||||||
|
0x02, # Hero
|
||||||
|
0x02,
|
||||||
|
0x03, # Dark
|
||||||
|
0x03,
|
||||||
|
0x09, # Cave
|
||||||
|
0x09,
|
||||||
|
0x09,
|
||||||
|
0x05, # Chao Race
|
||||||
|
0x0A, # Chao Karate
|
||||||
|
0x0C, # Transporter
|
||||||
|
#0x0C,
|
||||||
|
#0x0C,
|
||||||
|
0x06, # Kindergarten
|
||||||
|
]
|
||||||
|
|
||||||
|
multi_rooms = [
|
||||||
|
0x07,
|
||||||
|
0x01,
|
||||||
|
0x02,
|
||||||
|
0x03,
|
||||||
|
0x09,
|
||||||
|
]
|
||||||
|
|
||||||
|
single_rooms = [
|
||||||
|
0x05,
|
||||||
|
0x0A,
|
||||||
|
0x0C,
|
||||||
|
0x06,
|
||||||
|
]
|
||||||
|
|
||||||
|
room_to_exits_map = {
|
||||||
|
0x07: [0x00, 0x01, 0x02, 0x03],
|
||||||
|
0x01: [0x04, 0x05, 0x06],
|
||||||
|
0x02: [0x07, 0x08],
|
||||||
|
0x03: [0x09, 0x0A],
|
||||||
|
0x09: [0x0B, 0x0C, 0x0D],
|
||||||
|
0x05: [0x0E],
|
||||||
|
0x0A: [0x0F],
|
||||||
|
0x0C: [0x10],#, 0x11, 0x12],
|
||||||
|
0x06: [0x13],
|
||||||
|
}
|
||||||
|
|
||||||
|
exit_to_room_map = {
|
||||||
|
0x00: 0x07, # Lobby to Neutral
|
||||||
|
0x01: 0x07, # Lobby to Hero
|
||||||
|
0x02: 0x07, # Lobby to Dark
|
||||||
|
0x03: 0x07, # Lobby to Kindergarten
|
||||||
|
0x04: 0x01, # Neutral to Lobby
|
||||||
|
0x05: 0x01, # Neutral to Cave
|
||||||
|
0x06: 0x01, # Neutral to Transporter
|
||||||
|
0x07: 0x02, # Hero to Lobby
|
||||||
|
0x08: 0x02, # Hero to Transporter
|
||||||
|
0x09: 0x03, # Dark to Lobby
|
||||||
|
0x0A: 0x03, # Dark to Transporter
|
||||||
|
0x0B: 0x09, # Cave to Neutral
|
||||||
|
0x0C: 0x09, # Cave to Race
|
||||||
|
0x0D: 0x09, # Cave to Karate
|
||||||
|
0x0E: 0x05, # Race to Cave
|
||||||
|
0x0F: 0x0A, # Karate to Cave
|
||||||
|
0x10: 0x0C, # Transporter to Neutral
|
||||||
|
#0x11: 0x0C, # Transporter to Hero
|
||||||
|
#0x12: 0x0C, # Transporter to Dark
|
||||||
|
0x13: 0x06, # Kindergarten to Lobby
|
||||||
|
}
|
||||||
|
|
||||||
|
valid_kindergarten_exits = [
|
||||||
|
0x04, # Neutral to Lobby
|
||||||
|
0x05, # Neutral to Cave
|
||||||
|
0x07, # Hero to Lobby
|
||||||
|
0x09, # Dark to Lobby
|
||||||
|
]
|
|
@ -1,4 +1,6 @@
|
||||||
import typing
|
import typing
|
||||||
|
from BaseClasses import MultiWorld
|
||||||
|
from worlds.AutoWorld import World
|
||||||
|
|
||||||
speed_characters_1 = "Sonic vs Shadow 1"
|
speed_characters_1 = "Sonic vs Shadow 1"
|
||||||
speed_characters_2 = "Sonic vs Shadow 2"
|
speed_characters_2 = "Sonic vs Shadow 2"
|
||||||
|
@ -59,17 +61,17 @@ def boss_has_requirement(boss: int):
|
||||||
return boss >= len(gate_bosses_no_requirements_table)
|
return boss >= len(gate_bosses_no_requirements_table)
|
||||||
|
|
||||||
|
|
||||||
def get_gate_bosses(world, player: int):
|
def get_gate_bosses(multiworld: MultiWorld, world: World):
|
||||||
selected_bosses: typing.List[int] = []
|
selected_bosses: typing.List[int] = []
|
||||||
boss_gates: typing.List[int] = []
|
boss_gates: typing.List[int] = []
|
||||||
available_bosses: typing.List[str] = list(gate_bosses_no_requirements_table.keys())
|
available_bosses: typing.List[str] = list(gate_bosses_no_requirements_table.keys())
|
||||||
world.random.shuffle(available_bosses)
|
multiworld.random.shuffle(available_bosses)
|
||||||
halfway = False
|
halfway = False
|
||||||
|
|
||||||
for x in range(world.number_of_level_gates[player]):
|
for x in range(world.options.number_of_level_gates):
|
||||||
if (not halfway) and ((x + 1) / world.number_of_level_gates[player]) > 0.5:
|
if (not halfway) and ((x + 1) / world.options.number_of_level_gates) > 0.5:
|
||||||
available_bosses.extend(gate_bosses_with_requirements_table)
|
available_bosses.extend(gate_bosses_with_requirements_table)
|
||||||
world.random.shuffle(available_bosses)
|
multiworld.random.shuffle(available_bosses)
|
||||||
halfway = True
|
halfway = True
|
||||||
selected_bosses.append(all_gate_bosses_table[available_bosses[0]])
|
selected_bosses.append(all_gate_bosses_table[available_bosses[0]])
|
||||||
boss_gates.append(x + 1)
|
boss_gates.append(x + 1)
|
||||||
|
@ -80,27 +82,27 @@ def get_gate_bosses(world, player: int):
|
||||||
return bosses
|
return bosses
|
||||||
|
|
||||||
|
|
||||||
def get_boss_rush_bosses(multiworld, player: int):
|
def get_boss_rush_bosses(multiworld: MultiWorld, world: World):
|
||||||
|
|
||||||
if multiworld.boss_rush_shuffle[player] == 0:
|
if world.options.boss_rush_shuffle == 0:
|
||||||
boss_list_o = list(range(0, 16))
|
boss_list_o = list(range(0, 16))
|
||||||
boss_list_s = [5, 2, 0, 10, 8, 4, 3, 1, 6, 13, 7, 11, 9, 15, 14, 12]
|
boss_list_s = [5, 2, 0, 10, 8, 4, 3, 1, 6, 13, 7, 11, 9, 15, 14, 12]
|
||||||
|
|
||||||
return dict(zip(boss_list_o, boss_list_s))
|
return dict(zip(boss_list_o, boss_list_s))
|
||||||
elif multiworld.boss_rush_shuffle[player] == 1:
|
elif world.options.boss_rush_shuffle == 1:
|
||||||
boss_list_o = list(range(0, 16))
|
boss_list_o = list(range(0, 16))
|
||||||
boss_list_s = boss_list_o.copy()
|
boss_list_s = boss_list_o.copy()
|
||||||
multiworld.random.shuffle(boss_list_s)
|
multiworld.random.shuffle(boss_list_s)
|
||||||
|
|
||||||
return dict(zip(boss_list_o, boss_list_s))
|
return dict(zip(boss_list_o, boss_list_s))
|
||||||
elif multiworld.boss_rush_shuffle[player] == 2:
|
elif world.options.boss_rush_shuffle == 2:
|
||||||
boss_list_o = list(range(0, 16))
|
boss_list_o = list(range(0, 16))
|
||||||
boss_list_s = [multiworld.random.choice(boss_list_o) for i in range(0, 16)]
|
boss_list_s = [multiworld.random.choice(boss_list_o) for i in range(0, 16)]
|
||||||
if 10 not in boss_list_s:
|
if 10 not in boss_list_s:
|
||||||
boss_list_s[multiworld.random.randint(0, 15)] = 10
|
boss_list_s[multiworld.random.randint(0, 15)] = 10
|
||||||
|
|
||||||
return dict(zip(boss_list_o, boss_list_s))
|
return dict(zip(boss_list_o, boss_list_s))
|
||||||
elif multiworld.boss_rush_shuffle[player] == 3:
|
elif world.options.boss_rush_shuffle == 3:
|
||||||
boss_list_o = list(range(0, 16))
|
boss_list_o = list(range(0, 16))
|
||||||
boss_list_s = [multiworld.random.choice(boss_list_o)] * len(boss_list_o)
|
boss_list_s = [multiworld.random.choice(boss_list_o)] * len(boss_list_o)
|
||||||
if 10 not in boss_list_s:
|
if 10 not in boss_list_s:
|
||||||
|
|
|
@ -23,6 +23,7 @@ class SA2BItem(Item):
|
||||||
# Separate tables for each type of item.
|
# Separate tables for each type of item.
|
||||||
emblems_table = {
|
emblems_table = {
|
||||||
ItemName.emblem: ItemData(0xFF0000, True),
|
ItemName.emblem: ItemData(0xFF0000, True),
|
||||||
|
ItemName.market_token: ItemData(0xFF001F, True),
|
||||||
}
|
}
|
||||||
|
|
||||||
upgrades_table = {
|
upgrades_table = {
|
||||||
|
@ -82,6 +83,7 @@ trap_table = {
|
||||||
ItemName.ice_trap: ItemData(0xFF0037, False, True),
|
ItemName.ice_trap: ItemData(0xFF0037, False, True),
|
||||||
ItemName.slow_trap: ItemData(0xFF0038, False, True),
|
ItemName.slow_trap: ItemData(0xFF0038, False, True),
|
||||||
ItemName.cutscene_trap: ItemData(0xFF0039, False, True),
|
ItemName.cutscene_trap: ItemData(0xFF0039, False, True),
|
||||||
|
ItemName.reverse_trap: ItemData(0xFF003A, False, True),
|
||||||
|
|
||||||
ItemName.pong_trap: ItemData(0xFF0050, False, True),
|
ItemName.pong_trap: ItemData(0xFF0050, False, True),
|
||||||
}
|
}
|
||||||
|
@ -96,6 +98,142 @@ emeralds_table = {
|
||||||
ItemName.blue_emerald: ItemData(0xFF0046, True),
|
ItemName.blue_emerald: ItemData(0xFF0046, True),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eggs_table = {
|
||||||
|
ItemName.normal_egg: ItemData(0xFF0100, False),
|
||||||
|
ItemName.yellow_monotone_egg: ItemData(0xFF0101, False),
|
||||||
|
ItemName.white_monotone_egg: ItemData(0xFF0102, False),
|
||||||
|
ItemName.brown_monotone_egg: ItemData(0xFF0103, False),
|
||||||
|
ItemName.sky_blue_monotone_egg: ItemData(0xFF0104, False),
|
||||||
|
ItemName.pink_monotone_egg: ItemData(0xFF0105, False),
|
||||||
|
ItemName.blue_monotone_egg: ItemData(0xFF0106, False),
|
||||||
|
ItemName.grey_monotone_egg: ItemData(0xFF0107, False),
|
||||||
|
ItemName.green_monotone_egg: ItemData(0xFF0108, False),
|
||||||
|
ItemName.red_monotone_egg: ItemData(0xFF0109, False),
|
||||||
|
ItemName.lime_green_monotone_egg: ItemData(0xFF010A, False),
|
||||||
|
ItemName.purple_monotone_egg: ItemData(0xFF010B, False),
|
||||||
|
ItemName.orange_monotone_egg: ItemData(0xFF010C, False),
|
||||||
|
ItemName.black_monotone_egg: ItemData(0xFF010D, False),
|
||||||
|
|
||||||
|
ItemName.yellow_twotone_egg: ItemData(0xFF010E, False),
|
||||||
|
ItemName.white_twotone_egg: ItemData(0xFF010F, False),
|
||||||
|
ItemName.brown_twotone_egg: ItemData(0xFF0110, False),
|
||||||
|
ItemName.sky_blue_twotone_egg: ItemData(0xFF0111, False),
|
||||||
|
ItemName.pink_twotone_egg: ItemData(0xFF0112, False),
|
||||||
|
ItemName.blue_twotone_egg: ItemData(0xFF0113, False),
|
||||||
|
ItemName.grey_twotone_egg: ItemData(0xFF0114, False),
|
||||||
|
ItemName.green_twotone_egg: ItemData(0xFF0115, False),
|
||||||
|
ItemName.red_twotone_egg: ItemData(0xFF0116, False),
|
||||||
|
ItemName.lime_green_twotone_egg: ItemData(0xFF0117, False),
|
||||||
|
ItemName.purple_twotone_egg: ItemData(0xFF0118, False),
|
||||||
|
ItemName.orange_twotone_egg: ItemData(0xFF0119, False),
|
||||||
|
ItemName.black_twotone_egg: ItemData(0xFF011A, False),
|
||||||
|
|
||||||
|
ItemName.normal_shiny_egg: ItemData(0xFF011B, False),
|
||||||
|
ItemName.yellow_shiny_egg: ItemData(0xFF011C, False),
|
||||||
|
ItemName.white_shiny_egg: ItemData(0xFF011D, False),
|
||||||
|
ItemName.brown_shiny_egg: ItemData(0xFF011E, False),
|
||||||
|
ItemName.sky_blue_shiny_egg: ItemData(0xFF011F, False),
|
||||||
|
ItemName.pink_shiny_egg: ItemData(0xFF0120, False),
|
||||||
|
ItemName.blue_shiny_egg: ItemData(0xFF0121, False),
|
||||||
|
ItemName.grey_shiny_egg: ItemData(0xFF0122, False),
|
||||||
|
ItemName.green_shiny_egg: ItemData(0xFF0123, False),
|
||||||
|
ItemName.red_shiny_egg: ItemData(0xFF0124, False),
|
||||||
|
ItemName.lime_green_shiny_egg: ItemData(0xFF0125, False),
|
||||||
|
ItemName.purple_shiny_egg: ItemData(0xFF0126, False),
|
||||||
|
ItemName.orange_shiny_egg: ItemData(0xFF0127, False),
|
||||||
|
ItemName.black_shiny_egg: ItemData(0xFF0128, False),
|
||||||
|
}
|
||||||
|
|
||||||
|
fruits_table = {
|
||||||
|
ItemName.chao_garden_fruit: ItemData(0xFF0200, False),
|
||||||
|
ItemName.hero_garden_fruit: ItemData(0xFF0201, False),
|
||||||
|
ItemName.dark_garden_fruit: ItemData(0xFF0202, False),
|
||||||
|
|
||||||
|
ItemName.strong_fruit: ItemData(0xFF0203, False),
|
||||||
|
ItemName.tasty_fruit: ItemData(0xFF0204, False),
|
||||||
|
ItemName.hero_fruit: ItemData(0xFF0205, False),
|
||||||
|
ItemName.dark_fruit: ItemData(0xFF0206, False),
|
||||||
|
ItemName.round_fruit: ItemData(0xFF0207, False),
|
||||||
|
ItemName.triangle_fruit: ItemData(0xFF0208, False),
|
||||||
|
ItemName.square_fruit: ItemData(0xFF0209, False),
|
||||||
|
ItemName.heart_fruit: ItemData(0xFF020A, False),
|
||||||
|
ItemName.chao_fruit: ItemData(0xFF020B, False),
|
||||||
|
ItemName.smart_fruit: ItemData(0xFF020C, False),
|
||||||
|
|
||||||
|
ItemName.orange_fruit: ItemData(0xFF020D, False),
|
||||||
|
ItemName.blue_fruit: ItemData(0xFF020E, False),
|
||||||
|
ItemName.pink_fruit: ItemData(0xFF020F, False),
|
||||||
|
ItemName.green_fruit: ItemData(0xFF0210, False),
|
||||||
|
ItemName.purple_fruit: ItemData(0xFF0211, False),
|
||||||
|
ItemName.yellow_fruit: ItemData(0xFF0212, False),
|
||||||
|
ItemName.red_fruit: ItemData(0xFF0213, False),
|
||||||
|
|
||||||
|
ItemName.mushroom_fruit: ItemData(0xFF0214, False),
|
||||||
|
ItemName.super_mushroom_fruit: ItemData(0xFF0215, False),
|
||||||
|
ItemName.mint_candy_fruit: ItemData(0xFF0216, False),
|
||||||
|
ItemName.grapes_fruit: ItemData(0xFF0217, False),
|
||||||
|
}
|
||||||
|
|
||||||
|
seeds_table = {
|
||||||
|
ItemName.strong_seed: ItemData(0xFF0300, False),
|
||||||
|
ItemName.tasty_seed: ItemData(0xFF0301, False),
|
||||||
|
ItemName.hero_seed: ItemData(0xFF0302, False),
|
||||||
|
ItemName.dark_seed: ItemData(0xFF0303, False),
|
||||||
|
ItemName.round_seed: ItemData(0xFF0304, False),
|
||||||
|
ItemName.triangle_seed: ItemData(0xFF0305, False),
|
||||||
|
ItemName.square_seed: ItemData(0xFF0306, False),
|
||||||
|
}
|
||||||
|
|
||||||
|
hats_table = {
|
||||||
|
ItemName.pumpkin_hat: ItemData(0xFF0401, False),
|
||||||
|
ItemName.skull_hat: ItemData(0xFF0402, False),
|
||||||
|
ItemName.apple_hat: ItemData(0xFF0403, False),
|
||||||
|
ItemName.bucket_hat: ItemData(0xFF0404, False),
|
||||||
|
ItemName.empty_can_hat: ItemData(0xFF0405, False),
|
||||||
|
ItemName.cardboard_box_hat: ItemData(0xFF0406, False),
|
||||||
|
ItemName.flower_pot_hat: ItemData(0xFF0407, False),
|
||||||
|
ItemName.paper_bag_hat: ItemData(0xFF0408, False),
|
||||||
|
ItemName.pan_hat: ItemData(0xFF0409, False),
|
||||||
|
ItemName.stump_hat: ItemData(0xFF040A, False),
|
||||||
|
ItemName.watermelon_hat: ItemData(0xFF040B, False),
|
||||||
|
|
||||||
|
ItemName.red_wool_beanie_hat: ItemData(0xFF040C, False),
|
||||||
|
ItemName.blue_wool_beanie_hat: ItemData(0xFF040D, False),
|
||||||
|
ItemName.black_wool_beanie_hat: ItemData(0xFF040E, False),
|
||||||
|
ItemName.pacifier_hat: ItemData(0xFF040F, False),
|
||||||
|
}
|
||||||
|
|
||||||
|
animals_table = {
|
||||||
|
ItemName.animal_penguin: ItemData(0xFF0500, False),
|
||||||
|
ItemName.animal_seal: ItemData(0xFF0501, False),
|
||||||
|
ItemName.animal_otter: ItemData(0xFF0502, False),
|
||||||
|
ItemName.animal_rabbit: ItemData(0xFF0503, False),
|
||||||
|
ItemName.animal_cheetah: ItemData(0xFF0504, False),
|
||||||
|
ItemName.animal_warthog: ItemData(0xFF0505, False),
|
||||||
|
ItemName.animal_bear: ItemData(0xFF0506, False),
|
||||||
|
ItemName.animal_tiger: ItemData(0xFF0507, False),
|
||||||
|
ItemName.animal_gorilla: ItemData(0xFF0508, False),
|
||||||
|
ItemName.animal_peacock: ItemData(0xFF0509, False),
|
||||||
|
ItemName.animal_parrot: ItemData(0xFF050A, False),
|
||||||
|
ItemName.animal_condor: ItemData(0xFF050B, False),
|
||||||
|
ItemName.animal_skunk: ItemData(0xFF050C, False),
|
||||||
|
ItemName.animal_sheep: ItemData(0xFF050D, False),
|
||||||
|
ItemName.animal_raccoon: ItemData(0xFF050E, False),
|
||||||
|
ItemName.animal_halffish: ItemData(0xFF050F, False),
|
||||||
|
ItemName.animal_skeleton_dog: ItemData(0xFF0510, False),
|
||||||
|
ItemName.animal_bat: ItemData(0xFF0511, False),
|
||||||
|
ItemName.animal_dragon: ItemData(0xFF0512, False),
|
||||||
|
ItemName.animal_unicorn: ItemData(0xFF0513, False),
|
||||||
|
ItemName.animal_phoenix: ItemData(0xFF0514, False),
|
||||||
|
}
|
||||||
|
|
||||||
|
chaos_drives_table = {
|
||||||
|
ItemName.chaos_drive_yellow: ItemData(0xFF0515, False),
|
||||||
|
ItemName.chaos_drive_green: ItemData(0xFF0516, False),
|
||||||
|
ItemName.chaos_drive_red: ItemData(0xFF0517, False),
|
||||||
|
ItemName.chaos_drive_purple: ItemData(0xFF0518, False),
|
||||||
|
}
|
||||||
|
|
||||||
event_table = {
|
event_table = {
|
||||||
ItemName.maria: ItemData(0xFF001D, True),
|
ItemName.maria: ItemData(0xFF001D, True),
|
||||||
}
|
}
|
||||||
|
@ -107,12 +245,25 @@ item_table = {
|
||||||
**junk_table,
|
**junk_table,
|
||||||
**trap_table,
|
**trap_table,
|
||||||
**emeralds_table,
|
**emeralds_table,
|
||||||
|
**eggs_table,
|
||||||
|
**fruits_table,
|
||||||
|
**seeds_table,
|
||||||
|
**hats_table,
|
||||||
|
**animals_table,
|
||||||
|
**chaos_drives_table,
|
||||||
**event_table,
|
**event_table,
|
||||||
}
|
}
|
||||||
|
|
||||||
lookup_id_to_name: typing.Dict[int, str] = {data.code: item_name for item_name, data in item_table.items() if data.code}
|
lookup_id_to_name: typing.Dict[int, str] = {data.code: item_name for item_name, data in item_table.items() if data.code}
|
||||||
|
|
||||||
item_groups: typing.Dict[str, str] = {"Chaos Emeralds": [item_name for item_name, data in emeralds_table.items()]}
|
item_groups: typing.Dict[str, str] = {
|
||||||
|
"Chaos Emeralds": list(emeralds_table.keys()),
|
||||||
|
"Eggs": list(eggs_table.keys()),
|
||||||
|
"Fruits": list(fruits_table.keys()),
|
||||||
|
"Seeds": list(seeds_table.keys()),
|
||||||
|
"Hats": list(hats_table.keys()),
|
||||||
|
"Traps": list(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.sonic_light_shoes].code] = "and the Soap Shoes"
|
||||||
ALTTPWorld.pedestal_credit_texts[item_table[ItemName.shadow_air_shoes].code] = "and the Soap Shoes"
|
ALTTPWorld.pedestal_credit_texts[item_table[ItemName.shadow_air_shoes].code] = "and the Soap Shoes"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
from BaseClasses import Location, MultiWorld
|
from BaseClasses import Location, MultiWorld
|
||||||
|
from worlds.AutoWorld import World
|
||||||
from .Names import LocationName
|
from .Names import LocationName
|
||||||
from .Missions import stage_name_prefixes, mission_orders
|
from .Missions import stage_name_prefixes, mission_orders
|
||||||
|
|
||||||
|
@ -1066,6 +1067,7 @@ animal_location_table = {
|
||||||
LocationName.final_rush_animal_11: 0xFF0C4F,
|
LocationName.final_rush_animal_11: 0xFF0C4F,
|
||||||
|
|
||||||
LocationName.iron_gate_animal_11: 0xFF0C50,
|
LocationName.iron_gate_animal_11: 0xFF0C50,
|
||||||
|
LocationName.dry_lagoon_animal_11: 0xFF0C51,
|
||||||
LocationName.sand_ocean_animal_11: 0xFF0C52,
|
LocationName.sand_ocean_animal_11: 0xFF0C52,
|
||||||
LocationName.radical_highway_animal_11: 0xFF0C53,
|
LocationName.radical_highway_animal_11: 0xFF0C53,
|
||||||
LocationName.lost_colony_animal_11: 0xFF0C55,
|
LocationName.lost_colony_animal_11: 0xFF0C55,
|
||||||
|
@ -1241,7 +1243,7 @@ boss_rush_location_table = {
|
||||||
LocationName.boss_rush_16: 0xFF0114,
|
LocationName.boss_rush_16: 0xFF0114,
|
||||||
}
|
}
|
||||||
|
|
||||||
chao_garden_beginner_location_table = {
|
chao_race_beginner_location_table = {
|
||||||
LocationName.chao_race_crab_pool_1: 0xFF0200,
|
LocationName.chao_race_crab_pool_1: 0xFF0200,
|
||||||
LocationName.chao_race_crab_pool_2: 0xFF0201,
|
LocationName.chao_race_crab_pool_2: 0xFF0201,
|
||||||
LocationName.chao_race_crab_pool_3: 0xFF0202,
|
LocationName.chao_race_crab_pool_3: 0xFF0202,
|
||||||
|
@ -1254,11 +1256,17 @@ chao_garden_beginner_location_table = {
|
||||||
LocationName.chao_race_block_canyon_1: 0xFF0209,
|
LocationName.chao_race_block_canyon_1: 0xFF0209,
|
||||||
LocationName.chao_race_block_canyon_2: 0xFF020A,
|
LocationName.chao_race_block_canyon_2: 0xFF020A,
|
||||||
LocationName.chao_race_block_canyon_3: 0xFF020B,
|
LocationName.chao_race_block_canyon_3: 0xFF020B,
|
||||||
|
|
||||||
LocationName.chao_beginner_karate: 0xFF0300,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chao_garden_intermediate_location_table = {
|
chao_karate_beginner_location_table = {
|
||||||
|
LocationName.chao_beginner_karate_1: 0xFF0300,
|
||||||
|
LocationName.chao_beginner_karate_2: 0xFF0301,
|
||||||
|
LocationName.chao_beginner_karate_3: 0xFF0302,
|
||||||
|
LocationName.chao_beginner_karate_4: 0xFF0303,
|
||||||
|
LocationName.chao_beginner_karate_5: 0xFF0304,
|
||||||
|
}
|
||||||
|
|
||||||
|
chao_race_intermediate_location_table = {
|
||||||
LocationName.chao_race_challenge_1: 0xFF022A,
|
LocationName.chao_race_challenge_1: 0xFF022A,
|
||||||
LocationName.chao_race_challenge_2: 0xFF022B,
|
LocationName.chao_race_challenge_2: 0xFF022B,
|
||||||
LocationName.chao_race_challenge_3: 0xFF022C,
|
LocationName.chao_race_challenge_3: 0xFF022C,
|
||||||
|
@ -1281,11 +1289,17 @@ chao_garden_intermediate_location_table = {
|
||||||
LocationName.chao_race_dark_2: 0xFF023B,
|
LocationName.chao_race_dark_2: 0xFF023B,
|
||||||
LocationName.chao_race_dark_3: 0xFF023C,
|
LocationName.chao_race_dark_3: 0xFF023C,
|
||||||
LocationName.chao_race_dark_4: 0xFF023D,
|
LocationName.chao_race_dark_4: 0xFF023D,
|
||||||
|
|
||||||
LocationName.chao_standard_karate: 0xFF0301,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chao_garden_expert_location_table = {
|
chao_karate_intermediate_location_table = {
|
||||||
|
LocationName.chao_standard_karate_1: 0xFF0305,
|
||||||
|
LocationName.chao_standard_karate_2: 0xFF0306,
|
||||||
|
LocationName.chao_standard_karate_3: 0xFF0307,
|
||||||
|
LocationName.chao_standard_karate_4: 0xFF0308,
|
||||||
|
LocationName.chao_standard_karate_5: 0xFF0309,
|
||||||
|
}
|
||||||
|
|
||||||
|
chao_race_expert_location_table = {
|
||||||
LocationName.chao_race_aquamarine_1: 0xFF020C,
|
LocationName.chao_race_aquamarine_1: 0xFF020C,
|
||||||
LocationName.chao_race_aquamarine_2: 0xFF020D,
|
LocationName.chao_race_aquamarine_2: 0xFF020D,
|
||||||
LocationName.chao_race_aquamarine_3: 0xFF020E,
|
LocationName.chao_race_aquamarine_3: 0xFF020E,
|
||||||
|
@ -1316,11 +1330,187 @@ chao_garden_expert_location_table = {
|
||||||
LocationName.chao_race_diamond_3: 0xFF0227,
|
LocationName.chao_race_diamond_3: 0xFF0227,
|
||||||
LocationName.chao_race_diamond_4: 0xFF0228,
|
LocationName.chao_race_diamond_4: 0xFF0228,
|
||||||
LocationName.chao_race_diamond_5: 0xFF0229,
|
LocationName.chao_race_diamond_5: 0xFF0229,
|
||||||
|
|
||||||
LocationName.chao_expert_karate: 0xFF0302,
|
|
||||||
LocationName.chao_super_karate: 0xFF0303,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chao_karate_expert_location_table = {
|
||||||
|
LocationName.chao_expert_karate_1: 0xFF030A,
|
||||||
|
LocationName.chao_expert_karate_2: 0xFF030B,
|
||||||
|
LocationName.chao_expert_karate_3: 0xFF030C,
|
||||||
|
LocationName.chao_expert_karate_4: 0xFF030D,
|
||||||
|
LocationName.chao_expert_karate_5: 0xFF030E,
|
||||||
|
}
|
||||||
|
|
||||||
|
chao_karate_super_location_table = {
|
||||||
|
LocationName.chao_super_karate_1: 0xFF030F,
|
||||||
|
LocationName.chao_super_karate_2: 0xFF0310,
|
||||||
|
LocationName.chao_super_karate_3: 0xFF0311,
|
||||||
|
LocationName.chao_super_karate_4: 0xFF0312,
|
||||||
|
LocationName.chao_super_karate_5: 0xFF0313,
|
||||||
|
}
|
||||||
|
|
||||||
|
chao_stat_swim_table = { LocationName.chao_stat_swim_base + str(index): (0xFF0E00 + index) for index in range(1,100) }
|
||||||
|
chao_stat_fly_table = { LocationName.chao_stat_fly_base + str(index): (0xFF0E80 + index) for index in range(1,100) }
|
||||||
|
chao_stat_run_table = { LocationName.chao_stat_run_base + str(index): (0xFF0F00 + index) for index in range(1,100) }
|
||||||
|
chao_stat_power_table = { LocationName.chao_stat_power_base + str(index): (0xFF0F80 + index) for index in range(1,100) }
|
||||||
|
chao_stat_stamina_table = { LocationName.chao_stat_stamina_base + str(index): (0xFF1000 + index) for index in range(1,100) }
|
||||||
|
chao_stat_luck_table = { LocationName.chao_stat_luck_base + str(index): (0xFF1080 + index) for index in range(1,100) }
|
||||||
|
chao_stat_intelligence_table = { LocationName.chao_stat_intelligence_base + str(index): (0xFF1100 + index) for index in range(1,100) }
|
||||||
|
|
||||||
|
chao_animal_event_location_table = {
|
||||||
|
LocationName.animal_penguin: None,
|
||||||
|
LocationName.animal_seal: None,
|
||||||
|
LocationName.animal_otter: None,
|
||||||
|
LocationName.animal_rabbit: None,
|
||||||
|
LocationName.animal_cheetah: None,
|
||||||
|
LocationName.animal_warthog: None,
|
||||||
|
LocationName.animal_bear: None,
|
||||||
|
LocationName.animal_tiger: None,
|
||||||
|
LocationName.animal_gorilla: None,
|
||||||
|
LocationName.animal_peacock: None,
|
||||||
|
LocationName.animal_parrot: None,
|
||||||
|
LocationName.animal_condor: None,
|
||||||
|
LocationName.animal_skunk: None,
|
||||||
|
LocationName.animal_sheep: None,
|
||||||
|
LocationName.animal_raccoon: None,
|
||||||
|
LocationName.animal_halffish: None,
|
||||||
|
LocationName.animal_skeleton_dog: None,
|
||||||
|
LocationName.animal_bat: None,
|
||||||
|
LocationName.animal_dragon: None,
|
||||||
|
LocationName.animal_unicorn: None,
|
||||||
|
LocationName.animal_phoenix: None,
|
||||||
|
}
|
||||||
|
|
||||||
|
chao_animal_part_location_table = {
|
||||||
|
LocationName.chao_penguin_arms: 0xFF1220,
|
||||||
|
LocationName.chao_penguin_forehead: 0xFF1222,
|
||||||
|
LocationName.chao_penguin_legs: 0xFF1224,
|
||||||
|
|
||||||
|
LocationName.chao_seal_arms: 0xFF1228,
|
||||||
|
LocationName.chao_seal_tail: 0xFF122E,
|
||||||
|
|
||||||
|
LocationName.chao_otter_arms: 0xFF1230,
|
||||||
|
LocationName.chao_otter_ears: 0xFF1231,
|
||||||
|
LocationName.chao_otter_face: 0xFF1233,
|
||||||
|
LocationName.chao_otter_legs: 0xFF1234,
|
||||||
|
LocationName.chao_otter_tail: 0xFF1236,
|
||||||
|
|
||||||
|
LocationName.chao_rabbit_arms: 0xFF1238,
|
||||||
|
LocationName.chao_rabbit_ears: 0xFF1239,
|
||||||
|
LocationName.chao_rabbit_legs: 0xFF123C,
|
||||||
|
LocationName.chao_rabbit_tail: 0xFF123E,
|
||||||
|
|
||||||
|
LocationName.chao_cheetah_arms: 0xFF1240,
|
||||||
|
LocationName.chao_cheetah_ears: 0xFF1241,
|
||||||
|
LocationName.chao_cheetah_legs: 0xFF1244,
|
||||||
|
LocationName.chao_cheetah_tail: 0xFF1246,
|
||||||
|
|
||||||
|
LocationName.chao_warthog_arms: 0xFF1248,
|
||||||
|
LocationName.chao_warthog_ears: 0xFF1249,
|
||||||
|
LocationName.chao_warthog_face: 0xFF124B,
|
||||||
|
LocationName.chao_warthog_legs: 0xFF124C,
|
||||||
|
LocationName.chao_warthog_tail: 0xFF124E,
|
||||||
|
|
||||||
|
LocationName.chao_bear_arms: 0xFF1250,
|
||||||
|
LocationName.chao_bear_ears: 0xFF1251,
|
||||||
|
LocationName.chao_bear_legs: 0xFF1254,
|
||||||
|
|
||||||
|
LocationName.chao_tiger_arms: 0xFF1258,
|
||||||
|
LocationName.chao_tiger_ears: 0xFF1259,
|
||||||
|
LocationName.chao_tiger_legs: 0xFF125C,
|
||||||
|
LocationName.chao_tiger_tail: 0xFF125E,
|
||||||
|
|
||||||
|
LocationName.chao_gorilla_arms: 0xFF1260,
|
||||||
|
LocationName.chao_gorilla_ears: 0xFF1261,
|
||||||
|
LocationName.chao_gorilla_forehead: 0xFF1262,
|
||||||
|
LocationName.chao_gorilla_legs: 0xFF1264,
|
||||||
|
|
||||||
|
LocationName.chao_peacock_forehead: 0xFF126A,
|
||||||
|
LocationName.chao_peacock_legs: 0xFF126C,
|
||||||
|
LocationName.chao_peacock_tail: 0xFF126E,
|
||||||
|
LocationName.chao_peacock_wings: 0xFF126F,
|
||||||
|
|
||||||
|
LocationName.chao_parrot_forehead: 0xFF1272,
|
||||||
|
LocationName.chao_parrot_legs: 0xFF1274,
|
||||||
|
LocationName.chao_parrot_tail: 0xFF1276,
|
||||||
|
LocationName.chao_parrot_wings: 0xFF1277,
|
||||||
|
|
||||||
|
LocationName.chao_condor_ears: 0xFF1279,
|
||||||
|
LocationName.chao_condor_legs: 0xFF127C,
|
||||||
|
LocationName.chao_condor_tail: 0xFF127E,
|
||||||
|
LocationName.chao_condor_wings: 0xFF127F,
|
||||||
|
|
||||||
|
LocationName.chao_skunk_arms: 0xFF1280,
|
||||||
|
LocationName.chao_skunk_forehead: 0xFF1282,
|
||||||
|
LocationName.chao_skunk_legs: 0xFF1284,
|
||||||
|
LocationName.chao_skunk_tail: 0xFF1286,
|
||||||
|
|
||||||
|
LocationName.chao_sheep_arms: 0xFF1288,
|
||||||
|
LocationName.chao_sheep_ears: 0xFF1289,
|
||||||
|
LocationName.chao_sheep_legs: 0xFF128C,
|
||||||
|
LocationName.chao_sheep_horn: 0xFF128D,
|
||||||
|
LocationName.chao_sheep_tail: 0xFF128E,
|
||||||
|
|
||||||
|
LocationName.chao_raccoon_arms: 0xFF1290,
|
||||||
|
LocationName.chao_raccoon_ears: 0xFF1291,
|
||||||
|
LocationName.chao_raccoon_legs: 0xFF1294,
|
||||||
|
|
||||||
|
LocationName.chao_dragon_arms: 0xFF12A0,
|
||||||
|
LocationName.chao_dragon_ears: 0xFF12A1,
|
||||||
|
LocationName.chao_dragon_legs: 0xFF12A4,
|
||||||
|
LocationName.chao_dragon_horn: 0xFF12A5,
|
||||||
|
LocationName.chao_dragon_tail: 0xFF12A6,
|
||||||
|
LocationName.chao_dragon_wings: 0xFF12A7,
|
||||||
|
|
||||||
|
LocationName.chao_unicorn_arms: 0xFF12A8,
|
||||||
|
LocationName.chao_unicorn_ears: 0xFF12A9,
|
||||||
|
LocationName.chao_unicorn_forehead: 0xFF12AA,
|
||||||
|
LocationName.chao_unicorn_legs: 0xFF12AC,
|
||||||
|
LocationName.chao_unicorn_tail: 0xFF12AE,
|
||||||
|
|
||||||
|
LocationName.chao_phoenix_forehead: 0xFF12B2,
|
||||||
|
LocationName.chao_phoenix_legs: 0xFF12B4,
|
||||||
|
LocationName.chao_phoenix_tail: 0xFF12B6,
|
||||||
|
LocationName.chao_phoenix_wings: 0xFF12B7,
|
||||||
|
}
|
||||||
|
|
||||||
|
chao_kindergarten_location_table = {
|
||||||
|
LocationName.chao_kindergarten_drawing_1: 0xFF12D0,
|
||||||
|
LocationName.chao_kindergarten_drawing_2: 0xFF12D1,
|
||||||
|
LocationName.chao_kindergarten_drawing_3: 0xFF12D2,
|
||||||
|
LocationName.chao_kindergarten_drawing_4: 0xFF12D3,
|
||||||
|
LocationName.chao_kindergarten_drawing_5: 0xFF12D4,
|
||||||
|
|
||||||
|
LocationName.chao_kindergarten_shake_dance: 0xFF12D8,
|
||||||
|
LocationName.chao_kindergarten_spin_dance: 0xFF12D9,
|
||||||
|
LocationName.chao_kindergarten_step_dance: 0xFF12DA,
|
||||||
|
LocationName.chao_kindergarten_gogo_dance: 0xFF12DB,
|
||||||
|
LocationName.chao_kindergarten_exercise: 0xFF12DC,
|
||||||
|
|
||||||
|
LocationName.chao_kindergarten_song_1: 0xFF12E0,
|
||||||
|
LocationName.chao_kindergarten_song_2: 0xFF12E1,
|
||||||
|
LocationName.chao_kindergarten_song_3: 0xFF12E2,
|
||||||
|
LocationName.chao_kindergarten_song_4: 0xFF12E3,
|
||||||
|
LocationName.chao_kindergarten_song_5: 0xFF12E4,
|
||||||
|
|
||||||
|
LocationName.chao_kindergarten_bell: 0xFF12E8,
|
||||||
|
LocationName.chao_kindergarten_castanets: 0xFF12E9,
|
||||||
|
LocationName.chao_kindergarten_cymbals: 0xFF12EA,
|
||||||
|
LocationName.chao_kindergarten_drum: 0xFF12EB,
|
||||||
|
LocationName.chao_kindergarten_flute: 0xFF12EC,
|
||||||
|
LocationName.chao_kindergarten_maracas: 0xFF12ED,
|
||||||
|
LocationName.chao_kindergarten_trumpet: 0xFF12EE,
|
||||||
|
LocationName.chao_kindergarten_tambourine: 0xFF12EF,
|
||||||
|
}
|
||||||
|
|
||||||
|
chao_kindergarten_basics_location_table = {
|
||||||
|
LocationName.chao_kindergarten_any_drawing: 0xFF12F0,
|
||||||
|
LocationName.chao_kindergarten_any_dance: 0xFF12F1,
|
||||||
|
LocationName.chao_kindergarten_any_song: 0xFF12F2,
|
||||||
|
LocationName.chao_kindergarten_any_instrument: 0xFF12F3,
|
||||||
|
}
|
||||||
|
|
||||||
|
black_market_location_table = { LocationName.chao_black_market_base + str(index): (0xFF1300 + index) for index in range(1,65) }
|
||||||
|
|
||||||
kart_race_beginner_location_table = {
|
kart_race_beginner_location_table = {
|
||||||
LocationName.kart_race_beginner_sonic: 0xFF0A00,
|
LocationName.kart_race_beginner_sonic: 0xFF0A00,
|
||||||
LocationName.kart_race_beginner_tails: 0xFF0A01,
|
LocationName.kart_race_beginner_tails: 0xFF0A01,
|
||||||
|
@ -1375,6 +1565,10 @@ grand_prix_location_table = {
|
||||||
LocationName.grand_prix: 0xFF007F,
|
LocationName.grand_prix: 0xFF007F,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chaos_chao_location_table = {
|
||||||
|
LocationName.chaos_chao: 0xFF009F,
|
||||||
|
}
|
||||||
|
|
||||||
all_locations = {
|
all_locations = {
|
||||||
**mission_location_table,
|
**mission_location_table,
|
||||||
**upgrade_location_table,
|
**upgrade_location_table,
|
||||||
|
@ -1386,9 +1580,13 @@ all_locations = {
|
||||||
**beetle_location_table,
|
**beetle_location_table,
|
||||||
**omochao_location_table,
|
**omochao_location_table,
|
||||||
**animal_location_table,
|
**animal_location_table,
|
||||||
**chao_garden_beginner_location_table,
|
**chao_race_beginner_location_table,
|
||||||
**chao_garden_intermediate_location_table,
|
**chao_karate_beginner_location_table,
|
||||||
**chao_garden_expert_location_table,
|
**chao_race_intermediate_location_table,
|
||||||
|
**chao_karate_intermediate_location_table,
|
||||||
|
**chao_race_expert_location_table,
|
||||||
|
**chao_karate_expert_location_table,
|
||||||
|
**chao_karate_super_location_table,
|
||||||
**kart_race_beginner_location_table,
|
**kart_race_beginner_location_table,
|
||||||
**kart_race_standard_location_table,
|
**kart_race_standard_location_table,
|
||||||
**kart_race_expert_location_table,
|
**kart_race_expert_location_table,
|
||||||
|
@ -1398,6 +1596,18 @@ all_locations = {
|
||||||
**green_hill_animal_location_table,
|
**green_hill_animal_location_table,
|
||||||
**final_boss_location_table,
|
**final_boss_location_table,
|
||||||
**grand_prix_location_table,
|
**grand_prix_location_table,
|
||||||
|
**chaos_chao_location_table,
|
||||||
|
**chao_stat_swim_table,
|
||||||
|
**chao_stat_fly_table,
|
||||||
|
**chao_stat_run_table,
|
||||||
|
**chao_stat_power_table,
|
||||||
|
**chao_stat_stamina_table,
|
||||||
|
**chao_stat_luck_table,
|
||||||
|
**chao_stat_intelligence_table,
|
||||||
|
**chao_animal_part_location_table,
|
||||||
|
**chao_kindergarten_location_table,
|
||||||
|
**chao_kindergarten_basics_location_table,
|
||||||
|
**black_market_location_table,
|
||||||
}
|
}
|
||||||
|
|
||||||
boss_gate_set = [
|
boss_gate_set = [
|
||||||
|
@ -1408,13 +1618,6 @@ boss_gate_set = [
|
||||||
LocationName.gate_5_boss,
|
LocationName.gate_5_boss,
|
||||||
]
|
]
|
||||||
|
|
||||||
chao_karate_set = [
|
|
||||||
LocationName.chao_beginner_karate,
|
|
||||||
LocationName.chao_standard_karate,
|
|
||||||
LocationName.chao_expert_karate,
|
|
||||||
LocationName.chao_super_karate,
|
|
||||||
]
|
|
||||||
|
|
||||||
chao_race_prize_set = [
|
chao_race_prize_set = [
|
||||||
LocationName.chao_race_crab_pool_3,
|
LocationName.chao_race_crab_pool_3,
|
||||||
LocationName.chao_race_stump_valley_3,
|
LocationName.chao_race_stump_valley_3,
|
||||||
|
@ -1437,19 +1640,24 @@ chao_race_prize_set = [
|
||||||
|
|
||||||
LocationName.chao_race_dark_2,
|
LocationName.chao_race_dark_2,
|
||||||
LocationName.chao_race_dark_4,
|
LocationName.chao_race_dark_4,
|
||||||
|
|
||||||
|
LocationName.chao_beginner_karate_5,
|
||||||
|
LocationName.chao_standard_karate_5,
|
||||||
|
LocationName.chao_expert_karate_5,
|
||||||
|
LocationName.chao_super_karate_5,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def setup_locations(world: MultiWorld, player: int, mission_map: typing.Dict[int, int], mission_count_map: typing.Dict[int, int]):
|
def setup_locations(world: World, player: int, mission_map: typing.Dict[int, int], mission_count_map: typing.Dict[int, int]):
|
||||||
location_table = {}
|
location_table = {}
|
||||||
chao_location_table = {}
|
chao_location_table = {}
|
||||||
|
|
||||||
if world.goal[player] == 3:
|
if world.options.goal == 3:
|
||||||
if world.kart_race_checks[player] == 2:
|
if world.options.kart_race_checks == 2:
|
||||||
location_table.update({**kart_race_beginner_location_table})
|
location_table.update({**kart_race_beginner_location_table})
|
||||||
location_table.update({**kart_race_standard_location_table})
|
location_table.update({**kart_race_standard_location_table})
|
||||||
location_table.update({**kart_race_expert_location_table})
|
location_table.update({**kart_race_expert_location_table})
|
||||||
elif world.kart_race_checks[player] == 1:
|
elif world.options.kart_race_checks == 1:
|
||||||
location_table.update({**kart_race_mini_location_table})
|
location_table.update({**kart_race_mini_location_table})
|
||||||
location_table.update({**grand_prix_location_table})
|
location_table.update({**grand_prix_location_table})
|
||||||
else:
|
else:
|
||||||
|
@ -1465,67 +1673,100 @@ def setup_locations(world: MultiWorld, player: int, mission_map: typing.Dict[int
|
||||||
|
|
||||||
location_table.update({**upgrade_location_table})
|
location_table.update({**upgrade_location_table})
|
||||||
|
|
||||||
if world.keysanity[player]:
|
if world.options.keysanity:
|
||||||
location_table.update({**chao_key_location_table})
|
location_table.update({**chao_key_location_table})
|
||||||
|
|
||||||
if world.whistlesanity[player].value == 1:
|
if world.options.whistlesanity.value == 1:
|
||||||
location_table.update({**pipe_location_table})
|
location_table.update({**pipe_location_table})
|
||||||
elif world.whistlesanity[player].value == 2:
|
elif world.options.whistlesanity.value == 2:
|
||||||
location_table.update({**hidden_whistle_location_table})
|
location_table.update({**hidden_whistle_location_table})
|
||||||
elif world.whistlesanity[player].value == 3:
|
elif world.options.whistlesanity.value == 3:
|
||||||
location_table.update({**pipe_location_table})
|
location_table.update({**pipe_location_table})
|
||||||
location_table.update({**hidden_whistle_location_table})
|
location_table.update({**hidden_whistle_location_table})
|
||||||
|
|
||||||
if world.beetlesanity[player]:
|
if world.options.beetlesanity:
|
||||||
location_table.update({**beetle_location_table})
|
location_table.update({**beetle_location_table})
|
||||||
|
|
||||||
if world.omosanity[player]:
|
if world.options.omosanity:
|
||||||
location_table.update({**omochao_location_table})
|
location_table.update({**omochao_location_table})
|
||||||
|
|
||||||
if world.animalsanity[player]:
|
if world.options.animalsanity:
|
||||||
location_table.update({**animal_location_table})
|
location_table.update({**animal_location_table})
|
||||||
|
|
||||||
if world.kart_race_checks[player] == 2:
|
if world.options.kart_race_checks == 2:
|
||||||
location_table.update({**kart_race_beginner_location_table})
|
location_table.update({**kart_race_beginner_location_table})
|
||||||
location_table.update({**kart_race_standard_location_table})
|
location_table.update({**kart_race_standard_location_table})
|
||||||
location_table.update({**kart_race_expert_location_table})
|
location_table.update({**kart_race_expert_location_table})
|
||||||
elif world.kart_race_checks[player] == 1:
|
elif world.options.kart_race_checks == 1:
|
||||||
location_table.update({**kart_race_mini_location_table})
|
location_table.update({**kart_race_mini_location_table})
|
||||||
|
|
||||||
if world.goal[player].value in [0, 2, 4, 5, 6]:
|
if world.options.goal.value in [0, 2, 4, 5, 6]:
|
||||||
location_table.update({**final_boss_location_table})
|
location_table.update({**final_boss_location_table})
|
||||||
|
elif world.options.goal.value in [7]:
|
||||||
|
location_table.update({**chaos_chao_location_table})
|
||||||
|
|
||||||
if world.goal[player].value in [1, 2]:
|
if world.options.goal.value in [1, 2]:
|
||||||
location_table.update({**green_hill_location_table})
|
location_table.update({**green_hill_location_table})
|
||||||
|
|
||||||
if world.keysanity[player]:
|
if world.options.keysanity:
|
||||||
location_table.update({**green_hill_chao_location_table})
|
location_table.update({**green_hill_chao_location_table})
|
||||||
|
|
||||||
if world.animalsanity[player]:
|
if world.options.animalsanity:
|
||||||
location_table.update({**green_hill_animal_location_table})
|
location_table.update({**green_hill_animal_location_table})
|
||||||
|
|
||||||
if world.goal[player].value in [4, 5, 6]:
|
if world.options.goal.value in [4, 5, 6]:
|
||||||
location_table.update({**boss_rush_location_table})
|
location_table.update({**boss_rush_location_table})
|
||||||
|
|
||||||
if world.chao_garden_difficulty[player].value >= 1:
|
if world.options.chao_race_difficulty.value >= 1:
|
||||||
chao_location_table.update({**chao_garden_beginner_location_table})
|
chao_location_table.update({**chao_race_beginner_location_table})
|
||||||
if world.chao_garden_difficulty[player].value >= 2:
|
if world.options.chao_race_difficulty.value >= 2:
|
||||||
chao_location_table.update({**chao_garden_intermediate_location_table})
|
chao_location_table.update({**chao_race_intermediate_location_table})
|
||||||
if world.chao_garden_difficulty[player].value >= 3:
|
if world.options.chao_race_difficulty.value >= 3:
|
||||||
chao_location_table.update({**chao_garden_expert_location_table})
|
chao_location_table.update({**chao_race_expert_location_table})
|
||||||
|
|
||||||
|
if world.options.chao_karate_difficulty.value >= 1:
|
||||||
|
chao_location_table.update({**chao_karate_beginner_location_table})
|
||||||
|
if world.options.chao_karate_difficulty.value >= 2:
|
||||||
|
chao_location_table.update({**chao_karate_intermediate_location_table})
|
||||||
|
if world.options.chao_karate_difficulty.value >= 3:
|
||||||
|
chao_location_table.update({**chao_karate_expert_location_table})
|
||||||
|
if world.options.chao_karate_difficulty.value >= 4:
|
||||||
|
chao_location_table.update({**chao_karate_super_location_table})
|
||||||
|
|
||||||
for key, value in chao_location_table.items():
|
for key, value in chao_location_table.items():
|
||||||
if key in chao_karate_set:
|
if key not in chao_race_prize_set:
|
||||||
if world.include_chao_karate[player]:
|
if world.options.chao_stadium_checks == "all":
|
||||||
location_table[key] = value
|
|
||||||
elif key not in chao_race_prize_set:
|
|
||||||
if world.chao_race_checks[player] == "all":
|
|
||||||
location_table[key] = value
|
location_table[key] = value
|
||||||
else:
|
else:
|
||||||
location_table[key] = value
|
location_table[key] = value
|
||||||
|
|
||||||
|
for index in range(1, world.options.chao_stats.value + 1):
|
||||||
|
if (index % world.options.chao_stats_frequency.value) == (world.options.chao_stats.value % world.options.chao_stats_frequency.value):
|
||||||
|
location_table[LocationName.chao_stat_swim_base + str(index)] = chao_stat_swim_table[ LocationName.chao_stat_swim_base + str(index)]
|
||||||
|
location_table[LocationName.chao_stat_fly_base + str(index)] = chao_stat_fly_table[ LocationName.chao_stat_fly_base + str(index)]
|
||||||
|
location_table[LocationName.chao_stat_run_base + str(index)] = chao_stat_run_table[ LocationName.chao_stat_run_base + str(index)]
|
||||||
|
location_table[LocationName.chao_stat_power_base + str(index)] = chao_stat_power_table[ LocationName.chao_stat_power_base + str(index)]
|
||||||
|
|
||||||
|
if world.options.chao_stats_stamina:
|
||||||
|
location_table[LocationName.chao_stat_stamina_base + str(index)] = chao_stat_stamina_table[LocationName.chao_stat_stamina_base + str(index)]
|
||||||
|
|
||||||
|
if world.options.chao_stats_hidden:
|
||||||
|
location_table[LocationName.chao_stat_luck_base + str(index)] = chao_stat_luck_table[ LocationName.chao_stat_luck_base + str(index)]
|
||||||
|
location_table[LocationName.chao_stat_intelligence_base + str(index)] = chao_stat_intelligence_table[LocationName.chao_stat_intelligence_base + str(index)]
|
||||||
|
|
||||||
|
if world.options.chao_animal_parts:
|
||||||
|
location_table.update({**chao_animal_part_location_table})
|
||||||
|
|
||||||
|
if world.options.chao_kindergarten.value == 1:
|
||||||
|
location_table.update({**chao_kindergarten_basics_location_table})
|
||||||
|
elif world.options.chao_kindergarten.value == 2:
|
||||||
|
location_table.update({**chao_kindergarten_location_table})
|
||||||
|
|
||||||
|
for index in range(1, world.options.black_market_slots.value + 1):
|
||||||
|
location_table[LocationName.chao_black_market_base + str(index)] = black_market_location_table[LocationName.chao_black_market_base + str(index)]
|
||||||
|
|
||||||
for x in range(len(boss_gate_set)):
|
for x in range(len(boss_gate_set)):
|
||||||
if x < world.number_of_level_gates[player].value:
|
if x < world.options.number_of_level_gates.value:
|
||||||
location_table[boss_gate_set[x]] = boss_gate_location_table[boss_gate_set[x]]
|
location_table[boss_gate_set[x]] = boss_gate_location_table[boss_gate_set[x]]
|
||||||
|
|
||||||
return location_table
|
return location_table
|
||||||
|
|
|
@ -2,6 +2,7 @@ import typing
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
from BaseClasses import MultiWorld
|
from BaseClasses import MultiWorld
|
||||||
|
from worlds.AutoWorld import World
|
||||||
|
|
||||||
|
|
||||||
mission_orders: typing.List[typing.List[int]] = [
|
mission_orders: typing.List[typing.List[int]] = [
|
||||||
|
@ -193,10 +194,10 @@ stage_name_prefixes: typing.List[str] = [
|
||||||
"Cannon's Core - ",
|
"Cannon's Core - ",
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_mission_count_table(multiworld: MultiWorld, player: int):
|
def get_mission_count_table(multiworld: MultiWorld, world: World, player: int):
|
||||||
mission_count_table: typing.Dict[int, int] = {}
|
mission_count_table: typing.Dict[int, int] = {}
|
||||||
|
|
||||||
if multiworld.goal[player] == 3:
|
if world.options.goal == 3:
|
||||||
for level in range(31):
|
for level in range(31):
|
||||||
mission_count_table[level] = 0
|
mission_count_table[level] = 0
|
||||||
else:
|
else:
|
||||||
|
@ -207,26 +208,26 @@ def get_mission_count_table(multiworld: MultiWorld, player: int):
|
||||||
cannons_core_active_missions = 1
|
cannons_core_active_missions = 1
|
||||||
|
|
||||||
for i in range(2,6):
|
for i in range(2,6):
|
||||||
if getattr(multiworld, "speed_mission_" + str(i), None)[player]:
|
if getattr(world.options, "speed_mission_" + str(i), None):
|
||||||
speed_active_missions += 1
|
speed_active_missions += 1
|
||||||
|
|
||||||
if getattr(multiworld, "mech_mission_" + str(i), None)[player]:
|
if getattr(world.options, "mech_mission_" + str(i), None):
|
||||||
mech_active_missions += 1
|
mech_active_missions += 1
|
||||||
|
|
||||||
if getattr(multiworld, "hunt_mission_" + str(i), None)[player]:
|
if getattr(world.options, "hunt_mission_" + str(i), None):
|
||||||
hunt_active_missions += 1
|
hunt_active_missions += 1
|
||||||
|
|
||||||
if getattr(multiworld, "kart_mission_" + str(i), None)[player]:
|
if getattr(world.options, "kart_mission_" + str(i), None):
|
||||||
kart_active_missions += 1
|
kart_active_missions += 1
|
||||||
|
|
||||||
if getattr(multiworld, "cannons_core_mission_" + str(i), None)[player]:
|
if getattr(world.options, "cannons_core_mission_" + str(i), None):
|
||||||
cannons_core_active_missions += 1
|
cannons_core_active_missions += 1
|
||||||
|
|
||||||
speed_active_missions = min(speed_active_missions, multiworld.speed_mission_count[player].value)
|
speed_active_missions = min(speed_active_missions, world.options.speed_mission_count.value)
|
||||||
mech_active_missions = min(mech_active_missions, multiworld.mech_mission_count[player].value)
|
mech_active_missions = min(mech_active_missions, world.options.mech_mission_count.value)
|
||||||
hunt_active_missions = min(hunt_active_missions, multiworld.hunt_mission_count[player].value)
|
hunt_active_missions = min(hunt_active_missions, world.options.hunt_mission_count.value)
|
||||||
kart_active_missions = min(kart_active_missions, multiworld.kart_mission_count[player].value)
|
kart_active_missions = min(kart_active_missions, world.options.kart_mission_count.value)
|
||||||
cannons_core_active_missions = min(cannons_core_active_missions, multiworld.cannons_core_mission_count[player].value)
|
cannons_core_active_missions = min(cannons_core_active_missions, world.options.cannons_core_mission_count.value)
|
||||||
|
|
||||||
active_missions: typing.List[typing.List[int]] = [
|
active_missions: typing.List[typing.List[int]] = [
|
||||||
speed_active_missions,
|
speed_active_missions,
|
||||||
|
@ -244,10 +245,10 @@ def get_mission_count_table(multiworld: MultiWorld, player: int):
|
||||||
return mission_count_table
|
return mission_count_table
|
||||||
|
|
||||||
|
|
||||||
def get_mission_table(multiworld: MultiWorld, player: int):
|
def get_mission_table(multiworld: MultiWorld, world: World, player: int):
|
||||||
mission_table: typing.Dict[int, int] = {}
|
mission_table: typing.Dict[int, int] = {}
|
||||||
|
|
||||||
if multiworld.goal[player] == 3:
|
if world.options.goal == 3:
|
||||||
for level in range(31):
|
for level in range(31):
|
||||||
mission_table[level] = 0
|
mission_table[level] = 0
|
||||||
else:
|
else:
|
||||||
|
@ -259,19 +260,19 @@ def get_mission_table(multiworld: MultiWorld, player: int):
|
||||||
|
|
||||||
# Add included missions
|
# Add included missions
|
||||||
for i in range(2,6):
|
for i in range(2,6):
|
||||||
if getattr(multiworld, "speed_mission_" + str(i), None)[player]:
|
if getattr(world.options, "speed_mission_" + str(i), None):
|
||||||
speed_active_missions.append(i)
|
speed_active_missions.append(i)
|
||||||
|
|
||||||
if getattr(multiworld, "mech_mission_" + str(i), None)[player]:
|
if getattr(world.options, "mech_mission_" + str(i), None):
|
||||||
mech_active_missions.append(i)
|
mech_active_missions.append(i)
|
||||||
|
|
||||||
if getattr(multiworld, "hunt_mission_" + str(i), None)[player]:
|
if getattr(world.options, "hunt_mission_" + str(i), None):
|
||||||
hunt_active_missions.append(i)
|
hunt_active_missions.append(i)
|
||||||
|
|
||||||
if getattr(multiworld, "kart_mission_" + str(i), None)[player]:
|
if getattr(world.options, "kart_mission_" + str(i), None):
|
||||||
kart_active_missions.append(i)
|
kart_active_missions.append(i)
|
||||||
|
|
||||||
if getattr(multiworld, "cannons_core_mission_" + str(i), None)[player]:
|
if getattr(world.options, "cannons_core_mission_" + str(i), None):
|
||||||
cannons_core_active_missions.append(i)
|
cannons_core_active_missions.append(i)
|
||||||
|
|
||||||
active_missions: typing.List[typing.List[int]] = [
|
active_missions: typing.List[typing.List[int]] = [
|
||||||
|
@ -292,10 +293,10 @@ def get_mission_table(multiworld: MultiWorld, player: int):
|
||||||
first_mission = 1
|
first_mission = 1
|
||||||
first_mission_options = [1, 2, 3]
|
first_mission_options = [1, 2, 3]
|
||||||
|
|
||||||
if not multiworld.animalsanity[player]:
|
if not world.options.animalsanity:
|
||||||
first_mission_options.append(4)
|
first_mission_options.append(4)
|
||||||
|
|
||||||
if multiworld.mission_shuffle[player]:
|
if world.options.mission_shuffle:
|
||||||
first_mission = multiworld.random.choice([mission for mission in level_active_missions if mission in first_mission_options])
|
first_mission = multiworld.random.choice([mission for mission in level_active_missions if mission in first_mission_options])
|
||||||
|
|
||||||
level_active_missions.remove(first_mission)
|
level_active_missions.remove(first_mission)
|
||||||
|
@ -305,7 +306,7 @@ def get_mission_table(multiworld: MultiWorld, player: int):
|
||||||
if mission not in level_chosen_missions:
|
if mission not in level_chosen_missions:
|
||||||
level_chosen_missions.append(mission)
|
level_chosen_missions.append(mission)
|
||||||
|
|
||||||
if multiworld.mission_shuffle[player]:
|
if world.options.mission_shuffle:
|
||||||
multiworld.random.shuffle(level_chosen_missions)
|
multiworld.random.shuffle(level_chosen_missions)
|
||||||
|
|
||||||
level_chosen_missions.insert(0, first_mission)
|
level_chosen_missions.insert(0, first_mission)
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
# Emblem Definition
|
# Emblem Definition
|
||||||
emblem = "Emblem"
|
emblem = "Emblem"
|
||||||
|
|
||||||
|
# Market Token Definition
|
||||||
|
market_token = "Chao Coin"
|
||||||
|
|
||||||
# Upgrade Definitions
|
# Upgrade Definitions
|
||||||
sonic_gloves = "Sonic - Magic Glove"
|
sonic_gloves = "Sonic - Magic Glove"
|
||||||
sonic_light_shoes = "Sonic - Light Shoes"
|
sonic_light_shoes = "Sonic - Light Shoes"
|
||||||
|
@ -36,6 +39,8 @@ rouge_pick_nails = "Rouge - Pick Nails"
|
||||||
rouge_treasure_scope = "Rouge - Treasure Scope"
|
rouge_treasure_scope = "Rouge - Treasure Scope"
|
||||||
rouge_iron_boots = "Rouge - Iron Boots"
|
rouge_iron_boots = "Rouge - Iron Boots"
|
||||||
|
|
||||||
|
|
||||||
|
# Junk
|
||||||
five_rings = "Five Rings"
|
five_rings = "Five Rings"
|
||||||
ten_rings = "Ten Rings"
|
ten_rings = "Ten Rings"
|
||||||
twenty_rings = "Twenty Rings"
|
twenty_rings = "Twenty Rings"
|
||||||
|
@ -44,6 +49,8 @@ shield = "Shield"
|
||||||
magnetic_shield = "Magnetic Shield"
|
magnetic_shield = "Magnetic Shield"
|
||||||
invincibility = "Invincibility"
|
invincibility = "Invincibility"
|
||||||
|
|
||||||
|
|
||||||
|
# Traps
|
||||||
omochao_trap = "OmoTrap"
|
omochao_trap = "OmoTrap"
|
||||||
timestop_trap = "Chaos Control Trap"
|
timestop_trap = "Chaos Control Trap"
|
||||||
confuse_trap = "Confusion Trap"
|
confuse_trap = "Confusion Trap"
|
||||||
|
@ -54,9 +61,12 @@ darkness_trap = "Darkness Trap"
|
||||||
ice_trap = "Ice Trap"
|
ice_trap = "Ice Trap"
|
||||||
slow_trap = "Slow Trap"
|
slow_trap = "Slow Trap"
|
||||||
cutscene_trap = "Cutscene Trap"
|
cutscene_trap = "Cutscene Trap"
|
||||||
|
reverse_trap = "Reverse Trap"
|
||||||
|
|
||||||
pong_trap = "Pong Trap"
|
pong_trap = "Pong Trap"
|
||||||
|
|
||||||
|
|
||||||
|
# Chaos Emeralds
|
||||||
white_emerald = "White Chaos Emerald"
|
white_emerald = "White Chaos Emerald"
|
||||||
red_emerald = "Red Chaos Emerald"
|
red_emerald = "Red Chaos Emerald"
|
||||||
cyan_emerald = "Cyan Chaos Emerald"
|
cyan_emerald = "Cyan Chaos Emerald"
|
||||||
|
@ -65,4 +75,140 @@ green_emerald = "Green Chaos Emerald"
|
||||||
yellow_emerald = "Yellow Chaos Emerald"
|
yellow_emerald = "Yellow Chaos Emerald"
|
||||||
blue_emerald = "Blue Chaos Emerald"
|
blue_emerald = "Blue Chaos Emerald"
|
||||||
|
|
||||||
|
|
||||||
|
# Chao Eggs
|
||||||
|
normal_egg = "Normal Egg"
|
||||||
|
yellow_monotone_egg = "Yellow Mono-Tone Egg"
|
||||||
|
white_monotone_egg = "White Mono-Tone Egg"
|
||||||
|
brown_monotone_egg = "Brown Mono-Tone Egg"
|
||||||
|
sky_blue_monotone_egg = "Sky Blue Mono-Tone Egg"
|
||||||
|
pink_monotone_egg = "Pink Mono-Tone Egg"
|
||||||
|
blue_monotone_egg = "Blue Mono-Tone Egg"
|
||||||
|
grey_monotone_egg = "Grey Mono-Tone Egg"
|
||||||
|
green_monotone_egg = "Green Mono-Tone Egg"
|
||||||
|
red_monotone_egg = "Red Mono-Tone Egg"
|
||||||
|
lime_green_monotone_egg = "Lime Green Mono-Tone Egg"
|
||||||
|
purple_monotone_egg = "Purple Mono-Tone Egg"
|
||||||
|
orange_monotone_egg = "Orange Mono-Tone Egg"
|
||||||
|
black_monotone_egg = "Black Mono-Tone Egg"
|
||||||
|
|
||||||
|
yellow_twotone_egg = "Yellow Two-Tone Egg"
|
||||||
|
white_twotone_egg = "White Two-Tone Egg"
|
||||||
|
brown_twotone_egg = "Brown Two-Tone Egg"
|
||||||
|
sky_blue_twotone_egg = "Sky Blue Two-Tone Egg"
|
||||||
|
pink_twotone_egg = "Pink Two-Tone Egg"
|
||||||
|
blue_twotone_egg = "Blue Two-Tone Egg"
|
||||||
|
grey_twotone_egg = "Grey Two-Tone Egg"
|
||||||
|
green_twotone_egg = "Green Two-Tone Egg"
|
||||||
|
red_twotone_egg = "Red Two-Tone Egg"
|
||||||
|
lime_green_twotone_egg = "Lime Green Two-Tone Egg"
|
||||||
|
purple_twotone_egg = "Purple Two-Tone Egg"
|
||||||
|
orange_twotone_egg = "Orange Two-Tone Egg"
|
||||||
|
black_twotone_egg = "Black Two-Tone Egg"
|
||||||
|
|
||||||
|
normal_shiny_egg = "Normal Shiny Egg"
|
||||||
|
yellow_shiny_egg = "Yellow Shiny Egg"
|
||||||
|
white_shiny_egg = "White Shiny Egg"
|
||||||
|
brown_shiny_egg = "Brown Shiny Egg"
|
||||||
|
sky_blue_shiny_egg = "Sky Blue Shiny Egg"
|
||||||
|
pink_shiny_egg = "Pink Shiny Egg"
|
||||||
|
blue_shiny_egg = "Blue Shiny Egg"
|
||||||
|
grey_shiny_egg = "Grey Shiny Egg"
|
||||||
|
green_shiny_egg = "Green Shiny Egg"
|
||||||
|
red_shiny_egg = "Red Shiny Egg"
|
||||||
|
lime_green_shiny_egg = "Lime Green Shiny Egg"
|
||||||
|
purple_shiny_egg = "Purple Shiny Egg"
|
||||||
|
orange_shiny_egg = "Orange Shiny Egg"
|
||||||
|
black_shiny_egg = "Black Shiny Egg"
|
||||||
|
|
||||||
|
|
||||||
|
# Chao Fruit
|
||||||
|
chao_garden_fruit = "Chao Garden Fruit"
|
||||||
|
hero_garden_fruit = "Hero Garden Fruit"
|
||||||
|
dark_garden_fruit = "Dark Garden Fruit"
|
||||||
|
|
||||||
|
strong_fruit = "Strong Fruit"
|
||||||
|
tasty_fruit = "Tasty Fruit"
|
||||||
|
hero_fruit = "Hero Fruit"
|
||||||
|
dark_fruit = "Dark Fruit"
|
||||||
|
round_fruit = "Round Fruit"
|
||||||
|
triangle_fruit = "Triangle Fruit"
|
||||||
|
square_fruit = "Square Fruit"
|
||||||
|
heart_fruit = "Heart Fruit"
|
||||||
|
chao_fruit = "Chao Fruit"
|
||||||
|
smart_fruit = "Smart Fruit"
|
||||||
|
|
||||||
|
orange_fruit = "Orange Fruit"
|
||||||
|
blue_fruit = "Blue Fruit"
|
||||||
|
pink_fruit = "Pink Fruit"
|
||||||
|
green_fruit = "Green Fruit"
|
||||||
|
purple_fruit = "Purple Fruit"
|
||||||
|
yellow_fruit = "Yellow Fruit"
|
||||||
|
red_fruit = "Red Fruit"
|
||||||
|
|
||||||
|
mushroom_fruit = "Mushroom"
|
||||||
|
super_mushroom_fruit = "Super Mushroom"
|
||||||
|
mint_candy_fruit = "Mint Candy"
|
||||||
|
grapes_fruit = "Grapes"
|
||||||
|
|
||||||
|
|
||||||
|
# Chao Seeds
|
||||||
|
strong_seed = "Strong Seed"
|
||||||
|
tasty_seed = "Tasty Seed"
|
||||||
|
hero_seed = "Hero Seed"
|
||||||
|
dark_seed = "Dark Seed"
|
||||||
|
round_seed = "Round Seed"
|
||||||
|
triangle_seed = "Triangle Seed"
|
||||||
|
square_seed = "Square Seed"
|
||||||
|
|
||||||
|
|
||||||
|
# Chao Hats
|
||||||
|
pumpkin_hat = "Pumpkin"
|
||||||
|
skull_hat = "Skull"
|
||||||
|
apple_hat = "Apple"
|
||||||
|
bucket_hat = "Bucket"
|
||||||
|
empty_can_hat = "Empty Can"
|
||||||
|
cardboard_box_hat = "Cardboard Box"
|
||||||
|
flower_pot_hat = "Flower Pot"
|
||||||
|
paper_bag_hat = "Paper Bag"
|
||||||
|
pan_hat = "Pan"
|
||||||
|
stump_hat = "Stump"
|
||||||
|
watermelon_hat = "Watermelon"
|
||||||
|
|
||||||
|
red_wool_beanie_hat = "Red Wool Beanie"
|
||||||
|
blue_wool_beanie_hat = "Blue Wool Beanie"
|
||||||
|
black_wool_beanie_hat = "Black Wool Beanie"
|
||||||
|
pacifier_hat = "Pacifier"
|
||||||
|
|
||||||
|
|
||||||
|
# Animal Items
|
||||||
|
animal_penguin = "Penguin"
|
||||||
|
animal_seal = "Seal"
|
||||||
|
animal_otter = "Otter"
|
||||||
|
animal_rabbit = "Rabbit"
|
||||||
|
animal_cheetah = "Cheetah"
|
||||||
|
animal_warthog = "Warthog"
|
||||||
|
animal_bear = "Bear"
|
||||||
|
animal_tiger = "Tiger"
|
||||||
|
animal_gorilla = "Gorilla"
|
||||||
|
animal_peacock = "Peacock"
|
||||||
|
animal_parrot = "Parrot"
|
||||||
|
animal_condor = "Condor"
|
||||||
|
animal_skunk = "Skunk"
|
||||||
|
animal_sheep = "Sheep"
|
||||||
|
animal_raccoon = "Raccoon"
|
||||||
|
animal_halffish = "HalfFish"
|
||||||
|
animal_skeleton_dog = "Skeleton Dog"
|
||||||
|
animal_bat = "Bat"
|
||||||
|
animal_dragon = "Dragon"
|
||||||
|
animal_unicorn = "Unicorn"
|
||||||
|
animal_phoenix = "Phoenix"
|
||||||
|
|
||||||
|
chaos_drive_yellow = "Yellow Chaos Drive"
|
||||||
|
chaos_drive_green = "Green Chaos Drive"
|
||||||
|
chaos_drive_red = "Red Chaos Drive"
|
||||||
|
chaos_drive_purple = "Purple Chaos Drive"
|
||||||
|
|
||||||
|
|
||||||
|
# Goal Item
|
||||||
maria = "What Maria Wanted"
|
maria = "What Maria Wanted"
|
||||||
|
|
|
@ -909,6 +909,7 @@ dry_lagoon_animal_7 = "Dry Lagoon - 7 Animals"
|
||||||
dry_lagoon_animal_8 = "Dry Lagoon - 8 Animals"
|
dry_lagoon_animal_8 = "Dry Lagoon - 8 Animals"
|
||||||
dry_lagoon_animal_9 = "Dry Lagoon - 9 Animals"
|
dry_lagoon_animal_9 = "Dry Lagoon - 9 Animals"
|
||||||
dry_lagoon_animal_10 = "Dry Lagoon - 10 Animals"
|
dry_lagoon_animal_10 = "Dry Lagoon - 10 Animals"
|
||||||
|
dry_lagoon_animal_11 = "Dry Lagoon - 11 Animals"
|
||||||
dry_lagoon_upgrade = "Dry Lagoon - Upgrade"
|
dry_lagoon_upgrade = "Dry Lagoon - Upgrade"
|
||||||
egg_quarters_1 = "Egg Quarters - 1"
|
egg_quarters_1 = "Egg Quarters - 1"
|
||||||
egg_quarters_2 = "Egg Quarters - 2"
|
egg_quarters_2 = "Egg Quarters - 2"
|
||||||
|
@ -1150,10 +1151,190 @@ chao_race_dark_2 = "Chao Race - Dark 2"
|
||||||
chao_race_dark_3 = "Chao Race - Dark 3"
|
chao_race_dark_3 = "Chao Race - Dark 3"
|
||||||
chao_race_dark_4 = "Chao Race - Dark 4"
|
chao_race_dark_4 = "Chao Race - Dark 4"
|
||||||
|
|
||||||
chao_beginner_karate = "Chao Karate - Beginner"
|
chao_beginner_karate_1 = "Chao Karate - Beginner 1"
|
||||||
chao_standard_karate = "Chao Karate - Standard"
|
chao_beginner_karate_2 = "Chao Karate - Beginner 2"
|
||||||
chao_expert_karate = "Chao Karate - Expert"
|
chao_beginner_karate_3 = "Chao Karate - Beginner 3"
|
||||||
chao_super_karate = "Chao Karate - Super"
|
chao_beginner_karate_4 = "Chao Karate - Beginner 4"
|
||||||
|
chao_beginner_karate_5 = "Chao Karate - Beginner 5"
|
||||||
|
chao_standard_karate_1 = "Chao Karate - Standard 1"
|
||||||
|
chao_standard_karate_2 = "Chao Karate - Standard 2"
|
||||||
|
chao_standard_karate_3 = "Chao Karate - Standard 3"
|
||||||
|
chao_standard_karate_4 = "Chao Karate - Standard 4"
|
||||||
|
chao_standard_karate_5 = "Chao Karate - Standard 5"
|
||||||
|
chao_expert_karate_1 = "Chao Karate - Expert 1"
|
||||||
|
chao_expert_karate_2 = "Chao Karate - Expert 2"
|
||||||
|
chao_expert_karate_3 = "Chao Karate - Expert 3"
|
||||||
|
chao_expert_karate_4 = "Chao Karate - Expert 4"
|
||||||
|
chao_expert_karate_5 = "Chao Karate - Expert 5"
|
||||||
|
chao_super_karate_1 = "Chao Karate - Super 1"
|
||||||
|
chao_super_karate_2 = "Chao Karate - Super 2"
|
||||||
|
chao_super_karate_3 = "Chao Karate - Super 3"
|
||||||
|
chao_super_karate_4 = "Chao Karate - Super 4"
|
||||||
|
chao_super_karate_5 = "Chao Karate - Super 5"
|
||||||
|
|
||||||
|
chao_stat_swim_base = "Chao Stat - Swim - "
|
||||||
|
chao_stat_fly_base = "Chao Stat - Fly - "
|
||||||
|
chao_stat_run_base = "Chao Stat - Run - "
|
||||||
|
chao_stat_power_base = "Chao Stat - Power - "
|
||||||
|
chao_stat_stamina_base = "Chao Stat - Stamina - "
|
||||||
|
chao_stat_luck_base = "Chao Stat - Luck - "
|
||||||
|
chao_stat_intelligence_base = "Chao Stat - Intelligence - "
|
||||||
|
|
||||||
|
chao_black_market_base = "Black Market - "
|
||||||
|
|
||||||
|
# Animal Event Locations
|
||||||
|
animal_penguin = "Penguin Behavior"
|
||||||
|
animal_seal = "Seal Behavior"
|
||||||
|
animal_otter = "Otter Behavior"
|
||||||
|
animal_rabbit = "Rabbit Behavior"
|
||||||
|
animal_cheetah = "Cheetah Behavior"
|
||||||
|
animal_warthog = "Warthog Behavior"
|
||||||
|
animal_bear = "Bear Behavior"
|
||||||
|
animal_tiger = "Tiger Behavior"
|
||||||
|
animal_gorilla = "Gorilla Behavior"
|
||||||
|
animal_peacock = "Peacock Behavior"
|
||||||
|
animal_parrot = "Parrot Behavior"
|
||||||
|
animal_condor = "Condor Behavior"
|
||||||
|
animal_skunk = "Skunk Behavior"
|
||||||
|
animal_sheep = "Sheep Behavior"
|
||||||
|
animal_raccoon = "Raccoon Behavior"
|
||||||
|
animal_halffish = "HalfFish Behavior"
|
||||||
|
animal_skeleton_dog = "Skeleton Dog Behavior"
|
||||||
|
animal_bat = "Bat Behavior"
|
||||||
|
animal_dragon = "Dragon Behavior"
|
||||||
|
animal_unicorn = "Unicorn Behavior"
|
||||||
|
animal_phoenix = "Phoenix Behavior"
|
||||||
|
|
||||||
|
# Animal Body Part Locations
|
||||||
|
chao_penguin_arms = "Chao - Penguin Arms"
|
||||||
|
chao_penguin_forehead = "Chao - Penguin Forehead"
|
||||||
|
chao_penguin_legs = "Chao - Penguin Legs"
|
||||||
|
|
||||||
|
chao_seal_arms = "Chao - Seal Arms"
|
||||||
|
chao_seal_tail = "Chao - Seal Tail"
|
||||||
|
|
||||||
|
chao_otter_arms = "Chao - Otter Arms"
|
||||||
|
chao_otter_ears = "Chao - Otter Ears"
|
||||||
|
chao_otter_face = "Chao - Otter Face"
|
||||||
|
chao_otter_legs = "Chao - Otter Legs"
|
||||||
|
chao_otter_tail = "Chao - Otter Tail"
|
||||||
|
|
||||||
|
chao_rabbit_arms = "Chao - Rabbit Arms"
|
||||||
|
chao_rabbit_ears = "Chao - Rabbit Ears"
|
||||||
|
chao_rabbit_legs = "Chao - Rabbit Legs"
|
||||||
|
chao_rabbit_tail = "Chao - Rabbit Tail"
|
||||||
|
|
||||||
|
chao_cheetah_arms = "Chao - Cheetah Arms"
|
||||||
|
chao_cheetah_ears = "Chao - Cheetah Ears"
|
||||||
|
chao_cheetah_legs = "Chao - Cheetah Legs"
|
||||||
|
chao_cheetah_tail = "Chao - Cheetah Tail"
|
||||||
|
|
||||||
|
chao_warthog_arms = "Chao - Warthog Arms"
|
||||||
|
chao_warthog_ears = "Chao - Warthog Ears"
|
||||||
|
chao_warthog_face = "Chao - Warthog Face"
|
||||||
|
chao_warthog_legs = "Chao - Warthog Legs"
|
||||||
|
chao_warthog_tail = "Chao - Warthog Tail"
|
||||||
|
|
||||||
|
chao_bear_arms = "Chao - Bear Arms"
|
||||||
|
chao_bear_ears = "Chao - Bear Ears"
|
||||||
|
chao_bear_legs = "Chao - Bear Legs"
|
||||||
|
|
||||||
|
chao_tiger_arms = "Chao - Tiger Arms"
|
||||||
|
chao_tiger_ears = "Chao - Tiger Ears"
|
||||||
|
chao_tiger_legs = "Chao - Tiger Legs"
|
||||||
|
chao_tiger_tail = "Chao - Tiger Tail"
|
||||||
|
|
||||||
|
chao_gorilla_arms = "Chao - Gorilla Arms"
|
||||||
|
chao_gorilla_ears = "Chao - Gorilla Ears"
|
||||||
|
chao_gorilla_forehead = "Chao - Gorilla Forehead"
|
||||||
|
chao_gorilla_legs = "Chao - Gorilla Legs"
|
||||||
|
|
||||||
|
chao_peacock_forehead = "Chao - Peacock Forehead"
|
||||||
|
chao_peacock_legs = "Chao - Peacock Legs"
|
||||||
|
chao_peacock_tail = "Chao - Peacock Tail"
|
||||||
|
chao_peacock_wings = "Chao - Peacock Wings"
|
||||||
|
|
||||||
|
chao_parrot_forehead = "Chao - Parrot Forehead"
|
||||||
|
chao_parrot_legs = "Chao - Parrot Legs"
|
||||||
|
chao_parrot_tail = "Chao - Parrot Tail"
|
||||||
|
chao_parrot_wings = "Chao - Parrot Wings"
|
||||||
|
|
||||||
|
chao_condor_ears = "Chao - Condor Ears"
|
||||||
|
chao_condor_legs = "Chao - Condor Legs"
|
||||||
|
chao_condor_tail = "Chao - Condor Tail"
|
||||||
|
chao_condor_wings = "Chao - Condor Wings"
|
||||||
|
|
||||||
|
chao_skunk_arms = "Chao - Skunk Arms"
|
||||||
|
chao_skunk_forehead = "Chao - Skunk Forehead"
|
||||||
|
chao_skunk_legs = "Chao - Skunk Legs"
|
||||||
|
chao_skunk_tail = "Chao - Skunk Tail"
|
||||||
|
|
||||||
|
chao_sheep_arms = "Chao - Sheep Arms"
|
||||||
|
chao_sheep_ears = "Chao - Sheep Ears"
|
||||||
|
chao_sheep_legs = "Chao - Sheep Legs"
|
||||||
|
chao_sheep_horn = "Chao - Sheep Horn"
|
||||||
|
chao_sheep_tail = "Chao - Sheep Tail"
|
||||||
|
|
||||||
|
chao_raccoon_arms = "Chao - Raccoon Arms"
|
||||||
|
chao_raccoon_ears = "Chao - Raccoon Ears"
|
||||||
|
chao_raccoon_legs = "Chao - Raccoon Legs"
|
||||||
|
|
||||||
|
chao_dragon_arms = "Chao - Dragon Arms"
|
||||||
|
chao_dragon_ears = "Chao - Dragon Ears"
|
||||||
|
chao_dragon_legs = "Chao - Dragon Legs"
|
||||||
|
chao_dragon_horn = "Chao - Dragon Horn"
|
||||||
|
chao_dragon_tail = "Chao - Dragon Tail"
|
||||||
|
chao_dragon_wings = "Chao - Dragon Wings"
|
||||||
|
|
||||||
|
chao_unicorn_arms = "Chao - Unicorn Arms"
|
||||||
|
chao_unicorn_ears = "Chao - Unicorn Ears"
|
||||||
|
chao_unicorn_forehead = "Chao - Unicorn Forehead"
|
||||||
|
chao_unicorn_legs = "Chao - Unicorn Legs"
|
||||||
|
chao_unicorn_tail = "Chao - Unicorn Tail"
|
||||||
|
|
||||||
|
chao_phoenix_forehead = "Chao - Phoenix Forehead"
|
||||||
|
chao_phoenix_legs = "Chao - Phoenix Legs"
|
||||||
|
chao_phoenix_tail = "Chao - Phoenix Tail"
|
||||||
|
chao_phoenix_wings = "Chao - Phoenix Wings"
|
||||||
|
|
||||||
|
# Chao Kindergarten Locations
|
||||||
|
chao_kindergarten_drawing_1 = "Chao Kindergarten - Drawing 1"
|
||||||
|
chao_kindergarten_drawing_2 = "Chao Kindergarten - Drawing 2"
|
||||||
|
chao_kindergarten_drawing_3 = "Chao Kindergarten - Drawing 3"
|
||||||
|
chao_kindergarten_drawing_4 = "Chao Kindergarten - Drawing 4"
|
||||||
|
chao_kindergarten_drawing_5 = "Chao Kindergarten - Drawing 5"
|
||||||
|
|
||||||
|
chao_kindergarten_shake_dance = "Chao Kindergarten - Shake Dance"
|
||||||
|
chao_kindergarten_spin_dance = "Chao Kindergarten - Spin Dance"
|
||||||
|
chao_kindergarten_step_dance = "Chao Kindergarten - Step Dance"
|
||||||
|
chao_kindergarten_gogo_dance = "Chao Kindergarten - Go-Go Dance"
|
||||||
|
chao_kindergarten_exercise = "Chao Kindergarten - Exercise"
|
||||||
|
|
||||||
|
chao_kindergarten_song_1 = "Chao Kindergarten - Song 1"
|
||||||
|
chao_kindergarten_song_2 = "Chao Kindergarten - Song 2"
|
||||||
|
chao_kindergarten_song_3 = "Chao Kindergarten - Song 3"
|
||||||
|
chao_kindergarten_song_4 = "Chao Kindergarten - Song 4"
|
||||||
|
chao_kindergarten_song_5 = "Chao Kindergarten - Song 5"
|
||||||
|
|
||||||
|
chao_kindergarten_bell = "Chao Kindergarten - Bell"
|
||||||
|
chao_kindergarten_castanets = "Chao Kindergarten - Castanets"
|
||||||
|
chao_kindergarten_cymbals = "Chao Kindergarten - Cymbals"
|
||||||
|
chao_kindergarten_drum = "Chao Kindergarten - Drum"
|
||||||
|
chao_kindergarten_flute = "Chao Kindergarten - Flute"
|
||||||
|
chao_kindergarten_maracas = "Chao Kindergarten - Maracas"
|
||||||
|
chao_kindergarten_trumpet = "Chao Kindergarten - Trumpet"
|
||||||
|
chao_kindergarten_tambourine = "Chao Kindergarten - Tambourine"
|
||||||
|
|
||||||
|
chao_kindergarten_any_drawing = "Chao Kindergarten - Any Drawing"
|
||||||
|
chao_kindergarten_any_dance = "Chao Kindergarten - Any Dance"
|
||||||
|
chao_kindergarten_any_song = "Chao Kindergarten - Any Song"
|
||||||
|
chao_kindergarten_any_instrument = "Chao Kindergarten - Any Instrument"
|
||||||
|
|
||||||
|
|
||||||
|
# Chao Goal Locations
|
||||||
|
chaos_chao = "Chaos Chao"
|
||||||
|
chaos_chao_region = "Chaos Chao"
|
||||||
|
|
||||||
|
|
||||||
# Kart Race Definitions
|
# Kart Race Definitions
|
||||||
kart_race_beginner_sonic = "Kart Race - Beginner - Sonic"
|
kart_race_beginner_sonic = "Kart Race - Beginner - Sonic"
|
||||||
|
@ -1261,9 +1442,18 @@ green_hill_region = "Green Hill"
|
||||||
grand_prix = "Grand Prix"
|
grand_prix = "Grand Prix"
|
||||||
grand_prix_region = "Grand Prix"
|
grand_prix_region = "Grand Prix"
|
||||||
|
|
||||||
chao_garden_beginner_region = "Chao Garden - Beginner"
|
chao_race_beginner_region = "Chao Race - Beginner"
|
||||||
chao_garden_intermediate_region = "Chao Garden - Intermediate"
|
chao_race_intermediate_region = "Chao Race - Intermediate"
|
||||||
chao_garden_expert_region = "Chao Garden - Expert"
|
chao_race_expert_region = "Chao Race - Expert"
|
||||||
|
|
||||||
|
chao_karate_beginner_region = "Chao Karate - Beginner"
|
||||||
|
chao_karate_intermediate_region = "Chao Karate - Standard"
|
||||||
|
chao_karate_expert_region = "Chao Karate - Expert"
|
||||||
|
chao_karate_super_region = "Chao Karate - Super"
|
||||||
|
|
||||||
|
chao_kindergarten_region = "Chao Kindergarten"
|
||||||
|
|
||||||
|
black_market_region = "Black Market"
|
||||||
|
|
||||||
kart_race_beginner_region = "Kart Race - Beginner"
|
kart_race_beginner_region = "Kart Race - Beginner"
|
||||||
kart_race_standard_region = "Kart Race - Intermediate"
|
kart_race_standard_region = "Kart Race - Intermediate"
|
||||||
|
|
|
@ -13,6 +13,7 @@ class Goal(Choice):
|
||||||
Boss Rush: Beat all of the bosses in the Boss Rush, ending with Finalhazard
|
Boss Rush: Beat all of the bosses in the Boss Rush, ending with Finalhazard
|
||||||
Cannon's Core Boss Rush: Beat Cannon's Core, then beat all of the bosses in the Boss Rush, ending with Finalhazard
|
Cannon's Core Boss Rush: Beat Cannon's Core, then beat all of the bosses in the Boss Rush, ending with Finalhazard
|
||||||
Boss Rush Chaos Emerald Hunt: Find the Seven Chaos Emeralds, then beat all of the bosses in the Boss Rush, ending with Finalhazard
|
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
|
||||||
"""
|
"""
|
||||||
display_name = "Goal"
|
display_name = "Goal"
|
||||||
option_biolizard = 0
|
option_biolizard = 0
|
||||||
|
@ -22,6 +23,7 @@ class Goal(Choice):
|
||||||
option_boss_rush = 4
|
option_boss_rush = 4
|
||||||
option_cannons_core_boss_rush = 5
|
option_cannons_core_boss_rush = 5
|
||||||
option_boss_rush_chaos_emerald_hunt = 6
|
option_boss_rush_chaos_emerald_hunt = 6
|
||||||
|
option_chaos_chao = 7
|
||||||
default = 0
|
default = 0
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -70,74 +72,81 @@ class BaseTrapWeight(Choice):
|
||||||
|
|
||||||
class OmochaoTrapWeight(BaseTrapWeight):
|
class OmochaoTrapWeight(BaseTrapWeight):
|
||||||
"""
|
"""
|
||||||
Likelihood of a receiving a trap which spawns several Omochao around the player
|
Likelihood of receiving a trap which spawns several Omochao around the player
|
||||||
"""
|
"""
|
||||||
display_name = "OmoTrap Weight"
|
display_name = "OmoTrap Weight"
|
||||||
|
|
||||||
|
|
||||||
class TimestopTrapWeight(BaseTrapWeight):
|
class TimestopTrapWeight(BaseTrapWeight):
|
||||||
"""
|
"""
|
||||||
Likelihood of a receiving a trap which briefly stops time
|
Likelihood of receiving a trap which briefly stops time
|
||||||
"""
|
"""
|
||||||
display_name = "Chaos Control Trap Weight"
|
display_name = "Chaos Control Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
class ConfusionTrapWeight(BaseTrapWeight):
|
class ConfusionTrapWeight(BaseTrapWeight):
|
||||||
"""
|
"""
|
||||||
Likelihood of a receiving a trap which causes the controls to be skewed for a period of time
|
Likelihood of receiving a trap which causes the controls to be skewed for a period of time
|
||||||
"""
|
"""
|
||||||
display_name = "Confusion Trap Weight"
|
display_name = "Confusion Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
class TinyTrapWeight(BaseTrapWeight):
|
class TinyTrapWeight(BaseTrapWeight):
|
||||||
"""
|
"""
|
||||||
Likelihood of a receiving a trap which causes the player to become tiny
|
Likelihood of receiving a trap which causes the player to become tiny
|
||||||
"""
|
"""
|
||||||
display_name = "Tiny Trap Weight"
|
display_name = "Tiny Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
class GravityTrapWeight(BaseTrapWeight):
|
class GravityTrapWeight(BaseTrapWeight):
|
||||||
"""
|
"""
|
||||||
Likelihood of a receiving a trap which increases gravity
|
Likelihood of receiving a trap which increases gravity
|
||||||
"""
|
"""
|
||||||
display_name = "Gravity Trap Weight"
|
display_name = "Gravity Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
class ExpositionTrapWeight(BaseTrapWeight):
|
class ExpositionTrapWeight(BaseTrapWeight):
|
||||||
"""
|
"""
|
||||||
Likelihood of a receiving a trap which tells you the story
|
Likelihood of receiving a trap which tells you the story
|
||||||
"""
|
"""
|
||||||
display_name = "Exposition Trap Weight"
|
display_name = "Exposition Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
class DarknessTrapWeight(BaseTrapWeight):
|
class DarknessTrapWeight(BaseTrapWeight):
|
||||||
"""
|
"""
|
||||||
Likelihood of a receiving a trap which makes the world dark
|
Likelihood of receiving a trap which makes the world dark
|
||||||
"""
|
"""
|
||||||
display_name = "Darkness Trap Weight"
|
display_name = "Darkness Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
class IceTrapWeight(BaseTrapWeight):
|
class IceTrapWeight(BaseTrapWeight):
|
||||||
"""
|
"""
|
||||||
Likelihood of a receiving a trap which makes the world slippery
|
Likelihood of receiving a trap which makes the world slippery
|
||||||
"""
|
"""
|
||||||
display_name = "Ice Trap Weight"
|
display_name = "Ice Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
class SlowTrapWeight(BaseTrapWeight):
|
class SlowTrapWeight(BaseTrapWeight):
|
||||||
"""
|
"""
|
||||||
Likelihood of a receiving a trap which makes you gotta go slow
|
Likelihood of receiving a trap which makes you gotta go slow
|
||||||
"""
|
"""
|
||||||
display_name = "Slow Trap Weight"
|
display_name = "Slow Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
class CutsceneTrapWeight(BaseTrapWeight):
|
class CutsceneTrapWeight(BaseTrapWeight):
|
||||||
"""
|
"""
|
||||||
Likelihood of a receiving a trap which makes you watch an unskippable cutscene
|
Likelihood of receiving a trap which makes you watch an unskippable cutscene
|
||||||
"""
|
"""
|
||||||
display_name = "Cutscene Trap Weight"
|
display_name = "Cutscene Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
|
class ReverseTrapWeight(BaseTrapWeight):
|
||||||
|
"""
|
||||||
|
Likelihood of receiving a trap which reverses your controls
|
||||||
|
"""
|
||||||
|
display_name = "Reverse Trap Weight"
|
||||||
|
|
||||||
|
|
||||||
class PongTrapWeight(BaseTrapWeight):
|
class PongTrapWeight(BaseTrapWeight):
|
||||||
"""
|
"""
|
||||||
Likelihood of receiving a trap which forces you to play a Pong minigame
|
Likelihood of receiving a trap which forces you to play a Pong minigame
|
||||||
|
@ -219,7 +228,7 @@ class Omosanity(Toggle):
|
||||||
class Animalsanity(Toggle):
|
class Animalsanity(Toggle):
|
||||||
"""
|
"""
|
||||||
Determines whether picking up counted small animals grants checks
|
Determines whether picking up counted small animals grants checks
|
||||||
(420 Locations)
|
(421 Locations)
|
||||||
"""
|
"""
|
||||||
display_name = "Animalsanity"
|
display_name = "Animalsanity"
|
||||||
|
|
||||||
|
@ -291,7 +300,7 @@ class MaximumEmblemCap(Range):
|
||||||
"""
|
"""
|
||||||
display_name = "Max Emblem Cap"
|
display_name = "Max Emblem Cap"
|
||||||
range_start = 50
|
range_start = 50
|
||||||
range_end = 500
|
range_end = 1000
|
||||||
default = 180
|
default = 180
|
||||||
|
|
||||||
|
|
||||||
|
@ -308,15 +317,15 @@ class RequiredRank(Choice):
|
||||||
default = 0
|
default = 0
|
||||||
|
|
||||||
|
|
||||||
class ChaoGardenDifficulty(Choice):
|
class ChaoRaceDifficulty(Choice):
|
||||||
"""
|
"""
|
||||||
Determines the number of chao garden difficulty levels included. Easier difficulty settings means fewer chao garden checks
|
Determines the number of Chao Race difficulty levels included. Easier difficulty settings means fewer Chao Race checks
|
||||||
None: No Chao Garden Activities have checks
|
None: No Chao Races have checks
|
||||||
Beginner: Beginner Races
|
Beginner: Beginner Races
|
||||||
Intermediate: Beginner, Challenge, Hero, and Dark Races
|
Intermediate: Beginner, Challenge, Hero, and Dark Races
|
||||||
Expert: Beginner, Challenge, Hero, Dark and Jewel Races
|
Expert: Beginner, Challenge, Hero, Dark and Jewel Races
|
||||||
"""
|
"""
|
||||||
display_name = "Chao Garden Difficulty"
|
display_name = "Chao Race Difficulty"
|
||||||
option_none = 0
|
option_none = 0
|
||||||
option_beginner = 1
|
option_beginner = 1
|
||||||
option_intermediate = 2
|
option_intermediate = 2
|
||||||
|
@ -324,26 +333,138 @@ class ChaoGardenDifficulty(Choice):
|
||||||
default = 0
|
default = 0
|
||||||
|
|
||||||
|
|
||||||
class IncludeChaoKarate(Toggle):
|
class ChaoKarateDifficulty(Choice):
|
||||||
"""
|
"""
|
||||||
Determines whether the Chao Karate should be included as checks (Note: This setting requires purchase of the "Battle" DLC)
|
Determines the number of Chao Karate difficulty levels included. (Note: This setting requires purchase of the "Battle" DLC)
|
||||||
"""
|
"""
|
||||||
display_name = "Include Chao Karate"
|
display_name = "Chao Karate Difficulty"
|
||||||
|
option_none = 0
|
||||||
|
option_beginner = 1
|
||||||
|
option_standard = 2
|
||||||
|
option_expert = 3
|
||||||
|
option_super = 4
|
||||||
|
default = 0
|
||||||
|
|
||||||
|
|
||||||
class ChaoRaceChecks(Choice):
|
class ChaoStadiumChecks(Choice):
|
||||||
"""
|
"""
|
||||||
Determines which Chao Races grant checks
|
Determines which Chao Stadium activities grant checks
|
||||||
All: Each individual race grants a check
|
All: Each individual race and karate fight grants a check
|
||||||
Prize: Only the races which grant Chao Toys grant checks (final race of each Beginner and Jewel cup, 4th, 8th, and
|
Prize: Only the races which grant Chao Toys grant checks (final race of each Beginner and Jewel cup, 4th, 8th, and
|
||||||
12th Challenge Races, 2nd and 4th Hero and Dark Races)
|
12th Challenge Races, 2nd and 4th Hero and Dark Races, final fight of each Karate difficulty)
|
||||||
"""
|
"""
|
||||||
display_name = "Chao Race Checks"
|
display_name = "Chao Stadium Checks"
|
||||||
option_all = 0
|
option_all = 0
|
||||||
option_prize = 1
|
option_prize = 1
|
||||||
default = 0
|
default = 0
|
||||||
|
|
||||||
|
|
||||||
|
class ChaoStats(Range):
|
||||||
|
"""
|
||||||
|
Determines the highest level in each Chao Stat that grants checks
|
||||||
|
(Swim, Fly, Run, Power)
|
||||||
|
"""
|
||||||
|
display_name = "Chao Stats"
|
||||||
|
range_start = 0
|
||||||
|
range_end = 99
|
||||||
|
default = 0
|
||||||
|
|
||||||
|
|
||||||
|
class ChaoStatsFrequency(Range):
|
||||||
|
"""
|
||||||
|
Determines how many levels in each Chao Stat grant checks (up to the maximum set in the `chao_stats` option)
|
||||||
|
`1` means every level is included, `2` means every other level is included, `3` means every third, and so on
|
||||||
|
"""
|
||||||
|
display_name = "Chao Stats Frequency"
|
||||||
|
range_start = 1
|
||||||
|
range_end = 20
|
||||||
|
default = 5
|
||||||
|
|
||||||
|
|
||||||
|
class ChaoStatsStamina(Toggle):
|
||||||
|
"""
|
||||||
|
Determines whether Stamina is included in the `chao_stats` option
|
||||||
|
"""
|
||||||
|
display_name = "Chao Stats - Stamina"
|
||||||
|
|
||||||
|
|
||||||
|
class ChaoStatsHidden(Toggle):
|
||||||
|
"""
|
||||||
|
Determines whether the hidden stats (Luck and Intelligence) are included in the `chao_stats` option
|
||||||
|
"""
|
||||||
|
display_name = "Chao Stats - Luck and Intelligence"
|
||||||
|
|
||||||
|
|
||||||
|
class ChaoAnimalParts(Toggle):
|
||||||
|
"""
|
||||||
|
Determines whether giving Chao various animal parts grants checks
|
||||||
|
(73 Locations)
|
||||||
|
"""
|
||||||
|
display_name = "Chao Animal Parts"
|
||||||
|
|
||||||
|
|
||||||
|
class ChaoKindergarten(Choice):
|
||||||
|
"""
|
||||||
|
Determines whether learning the lessons from the Kindergarten Classroom grants checks
|
||||||
|
(WARNING: VERY SLOW)
|
||||||
|
None: No Kindergarten classes have checks
|
||||||
|
Basics: One class from each category (Drawing, Dance, Song, and Instrument) is a check (4 Locations)
|
||||||
|
Full: Every class is a check (23 Locations)
|
||||||
|
"""
|
||||||
|
display_name = "Chao Kindergarten Checks"
|
||||||
|
option_none = 0
|
||||||
|
option_basics = 1
|
||||||
|
option_full = 2
|
||||||
|
default = 0
|
||||||
|
|
||||||
|
|
||||||
|
class BlackMarketSlots(Range):
|
||||||
|
"""
|
||||||
|
Determines how many multiworld items are available to purchase from the Black Market
|
||||||
|
"""
|
||||||
|
display_name = "Black Market Slots"
|
||||||
|
range_start = 0
|
||||||
|
range_end = 64
|
||||||
|
default = 0
|
||||||
|
|
||||||
|
|
||||||
|
class BlackMarketUnlockCosts(Choice):
|
||||||
|
"""
|
||||||
|
Determines how many Chao Coins are required to unlock sets of Black Market items
|
||||||
|
"""
|
||||||
|
display_name = "Black Market Unlock Costs"
|
||||||
|
option_low = 0
|
||||||
|
option_medium = 1
|
||||||
|
option_high = 2
|
||||||
|
default = 1
|
||||||
|
|
||||||
|
|
||||||
|
class BlackMarketPriceMultiplier(Range):
|
||||||
|
"""
|
||||||
|
Determines how many rings the Black Market items cost
|
||||||
|
The base ring costs of items in the Black Market range from 50-100,
|
||||||
|
and are then multiplied by this value
|
||||||
|
"""
|
||||||
|
display_name = "Black Market Price Multiplier"
|
||||||
|
range_start = 0
|
||||||
|
range_end = 40
|
||||||
|
default = 1
|
||||||
|
|
||||||
|
|
||||||
|
class ShuffleStartingChaoEggs(DefaultOnToggle):
|
||||||
|
"""
|
||||||
|
Determines whether the starting Chao eggs in the gardens are random
|
||||||
|
"""
|
||||||
|
display_name = "Shuffle Starting Chao Eggs"
|
||||||
|
|
||||||
|
|
||||||
|
class ChaoEntranceRandomization(Toggle):
|
||||||
|
"""
|
||||||
|
Determines whether entrances in Chao World are randomized
|
||||||
|
"""
|
||||||
|
display_name = "Chao Entrance Randomization"
|
||||||
|
|
||||||
|
|
||||||
class RequiredCannonsCoreMissions(Choice):
|
class RequiredCannonsCoreMissions(Choice):
|
||||||
"""
|
"""
|
||||||
Determines how many Cannon's Core missions must be completed (for Biolizard or Cannon's Core goals)
|
Determines how many Cannon's Core missions must be completed (for Biolizard or Cannon's Core goals)
|
||||||
|
@ -657,24 +778,42 @@ class LogicDifficulty(Choice):
|
||||||
|
|
||||||
sa2b_options: typing.Dict[str, type(Option)] = {
|
sa2b_options: typing.Dict[str, type(Option)] = {
|
||||||
"goal": Goal,
|
"goal": Goal,
|
||||||
|
|
||||||
"mission_shuffle": MissionShuffle,
|
"mission_shuffle": MissionShuffle,
|
||||||
"boss_rush_shuffle": BossRushShuffle,
|
"boss_rush_shuffle": BossRushShuffle,
|
||||||
|
|
||||||
"keysanity": Keysanity,
|
"keysanity": Keysanity,
|
||||||
"whistlesanity": Whistlesanity,
|
"whistlesanity": Whistlesanity,
|
||||||
"beetlesanity": Beetlesanity,
|
"beetlesanity": Beetlesanity,
|
||||||
"omosanity": Omosanity,
|
"omosanity": Omosanity,
|
||||||
"animalsanity": Animalsanity,
|
"animalsanity": Animalsanity,
|
||||||
"kart_race_checks": KartRaceChecks,
|
"kart_race_checks": KartRaceChecks,
|
||||||
|
|
||||||
|
"logic_difficulty": LogicDifficulty,
|
||||||
"required_rank": RequiredRank,
|
"required_rank": RequiredRank,
|
||||||
"emblem_percentage_for_cannons_core": EmblemPercentageForCannonsCore,
|
|
||||||
"required_cannons_core_missions": RequiredCannonsCoreMissions,
|
"required_cannons_core_missions": RequiredCannonsCoreMissions,
|
||||||
|
|
||||||
|
"emblem_percentage_for_cannons_core": EmblemPercentageForCannonsCore,
|
||||||
"number_of_level_gates": NumberOfLevelGates,
|
"number_of_level_gates": NumberOfLevelGates,
|
||||||
"level_gate_distribution": LevelGateDistribution,
|
"level_gate_distribution": LevelGateDistribution,
|
||||||
"level_gate_costs": LevelGateCosts,
|
"level_gate_costs": LevelGateCosts,
|
||||||
"max_emblem_cap": MaximumEmblemCap,
|
"max_emblem_cap": MaximumEmblemCap,
|
||||||
"chao_garden_difficulty": ChaoGardenDifficulty,
|
|
||||||
"include_chao_karate": IncludeChaoKarate,
|
"chao_race_difficulty": ChaoRaceDifficulty,
|
||||||
"chao_race_checks": ChaoRaceChecks,
|
"chao_karate_difficulty": ChaoKarateDifficulty,
|
||||||
|
"chao_stadium_checks": ChaoStadiumChecks,
|
||||||
|
"chao_stats": ChaoStats,
|
||||||
|
"chao_stats_frequency": ChaoStatsFrequency,
|
||||||
|
"chao_stats_stamina": ChaoStatsStamina,
|
||||||
|
"chao_stats_hidden": ChaoStatsHidden,
|
||||||
|
"chao_animal_parts": ChaoAnimalParts,
|
||||||
|
"chao_kindergarten": ChaoKindergarten,
|
||||||
|
"black_market_slots": BlackMarketSlots,
|
||||||
|
"black_market_unlock_costs": BlackMarketUnlockCosts,
|
||||||
|
"black_market_price_multiplier": BlackMarketPriceMultiplier,
|
||||||
|
"shuffle_starting_chao_eggs": ShuffleStartingChaoEggs,
|
||||||
|
"chao_entrance_randomization": ChaoEntranceRandomization,
|
||||||
|
|
||||||
"junk_fill_percentage": JunkFillPercentage,
|
"junk_fill_percentage": JunkFillPercentage,
|
||||||
"trap_fill_percentage": TrapFillPercentage,
|
"trap_fill_percentage": TrapFillPercentage,
|
||||||
"omochao_trap_weight": OmochaoTrapWeight,
|
"omochao_trap_weight": OmochaoTrapWeight,
|
||||||
|
@ -687,39 +826,46 @@ sa2b_options: typing.Dict[str, type(Option)] = {
|
||||||
"ice_trap_weight": IceTrapWeight,
|
"ice_trap_weight": IceTrapWeight,
|
||||||
"slow_trap_weight": SlowTrapWeight,
|
"slow_trap_weight": SlowTrapWeight,
|
||||||
"cutscene_trap_weight": CutsceneTrapWeight,
|
"cutscene_trap_weight": CutsceneTrapWeight,
|
||||||
|
"reverse_trap_weight": ReverseTrapWeight,
|
||||||
"pong_trap_weight": PongTrapWeight,
|
"pong_trap_weight": PongTrapWeight,
|
||||||
"minigame_trap_difficulty": MinigameTrapDifficulty,
|
"minigame_trap_difficulty": MinigameTrapDifficulty,
|
||||||
"ring_loss": RingLoss,
|
|
||||||
"ring_link": RingLink,
|
|
||||||
"sadx_music": SADXMusic,
|
"sadx_music": SADXMusic,
|
||||||
"music_shuffle": MusicShuffle,
|
"music_shuffle": MusicShuffle,
|
||||||
"voice_shuffle": VoiceShuffle,
|
"voice_shuffle": VoiceShuffle,
|
||||||
"narrator": Narrator,
|
"narrator": Narrator,
|
||||||
"logic_difficulty": LogicDifficulty,
|
"ring_loss": RingLoss,
|
||||||
|
|
||||||
"speed_mission_count": SpeedMissionCount,
|
"speed_mission_count": SpeedMissionCount,
|
||||||
"speed_mission_2": SpeedMission2,
|
"speed_mission_2": SpeedMission2,
|
||||||
"speed_mission_3": SpeedMission3,
|
"speed_mission_3": SpeedMission3,
|
||||||
"speed_mission_4": SpeedMission4,
|
"speed_mission_4": SpeedMission4,
|
||||||
"speed_mission_5": SpeedMission5,
|
"speed_mission_5": SpeedMission5,
|
||||||
|
|
||||||
"mech_mission_count": MechMissionCount,
|
"mech_mission_count": MechMissionCount,
|
||||||
"mech_mission_2": MechMission2,
|
"mech_mission_2": MechMission2,
|
||||||
"mech_mission_3": MechMission3,
|
"mech_mission_3": MechMission3,
|
||||||
"mech_mission_4": MechMission4,
|
"mech_mission_4": MechMission4,
|
||||||
"mech_mission_5": MechMission5,
|
"mech_mission_5": MechMission5,
|
||||||
|
|
||||||
"hunt_mission_count": HuntMissionCount,
|
"hunt_mission_count": HuntMissionCount,
|
||||||
"hunt_mission_2": HuntMission2,
|
"hunt_mission_2": HuntMission2,
|
||||||
"hunt_mission_3": HuntMission3,
|
"hunt_mission_3": HuntMission3,
|
||||||
"hunt_mission_4": HuntMission4,
|
"hunt_mission_4": HuntMission4,
|
||||||
"hunt_mission_5": HuntMission5,
|
"hunt_mission_5": HuntMission5,
|
||||||
|
|
||||||
"kart_mission_count": KartMissionCount,
|
"kart_mission_count": KartMissionCount,
|
||||||
"kart_mission_2": KartMission2,
|
"kart_mission_2": KartMission2,
|
||||||
"kart_mission_3": KartMission3,
|
"kart_mission_3": KartMission3,
|
||||||
"kart_mission_4": KartMission4,
|
"kart_mission_4": KartMission4,
|
||||||
"kart_mission_5": KartMission5,
|
"kart_mission_5": KartMission5,
|
||||||
|
|
||||||
"cannons_core_mission_count": CannonsCoreMissionCount,
|
"cannons_core_mission_count": CannonsCoreMissionCount,
|
||||||
"cannons_core_mission_2": CannonsCoreMission2,
|
"cannons_core_mission_2": CannonsCoreMission2,
|
||||||
"cannons_core_mission_3": CannonsCoreMission3,
|
"cannons_core_mission_3": CannonsCoreMission3,
|
||||||
"cannons_core_mission_4": CannonsCoreMission4,
|
"cannons_core_mission_4": CannonsCoreMission4,
|
||||||
"cannons_core_mission_5": CannonsCoreMission5,
|
"cannons_core_mission_5": CannonsCoreMission5,
|
||||||
|
|
||||||
|
"ring_link": RingLink,
|
||||||
"death_link": DeathLink,
|
"death_link": DeathLink,
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
1575
worlds/sa2b/Rules.py
1575
worlds/sa2b/Rules.py
File diff suppressed because it is too large
Load Diff
|
@ -1,14 +1,18 @@
|
||||||
import typing
|
import typing
|
||||||
import math
|
import math
|
||||||
|
import logging
|
||||||
|
|
||||||
from BaseClasses import Item, MultiWorld, Tutorial, ItemClassification
|
from BaseClasses import Item, MultiWorld, Tutorial, ItemClassification
|
||||||
from .Items import SA2BItem, ItemData, item_table, upgrades_table, emeralds_table, junk_table, trap_table, item_groups
|
from .Items import SA2BItem, ItemData, item_table, upgrades_table, emeralds_table, junk_table, trap_table, item_groups, \
|
||||||
from .Locations import SA2BLocation, all_locations, setup_locations
|
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 .Options import sa2b_options
|
from .Options import sa2b_options
|
||||||
from .Regions import create_regions, shuffleable_regions, connect_regions, LevelGate, gate_0_whitelist_regions, \
|
from .Regions import create_regions, shuffleable_regions, connect_regions, LevelGate, gate_0_whitelist_regions, \
|
||||||
gate_0_blacklist_regions
|
gate_0_blacklist_regions
|
||||||
from .Rules import set_rules
|
from .Rules import set_rules
|
||||||
from .Names import ItemName, LocationName
|
from .Names import ItemName, LocationName
|
||||||
|
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 worlds.AutoWorld import WebWorld, World
|
from worlds.AutoWorld import WebWorld, World
|
||||||
from .GateBosses import get_gate_bosses, get_boss_rush_bosses, get_boss_name
|
from .GateBosses import get_gate_bosses, get_boss_rush_bosses, get_boss_name
|
||||||
from .Missions import get_mission_table, get_mission_count_table, get_first_and_last_cannons_core_missions
|
from .Missions import get_mission_table, get_mission_count_table, get_first_and_last_cannons_core_missions
|
||||||
|
@ -52,7 +56,7 @@ class SA2BWorld(World):
|
||||||
game: str = "Sonic Adventure 2 Battle"
|
game: str = "Sonic Adventure 2 Battle"
|
||||||
option_definitions = sa2b_options
|
option_definitions = sa2b_options
|
||||||
topology_present = False
|
topology_present = False
|
||||||
data_version = 6
|
data_version = 7
|
||||||
|
|
||||||
item_name_groups = item_groups
|
item_name_groups = item_groups
|
||||||
item_name_to_id = {name: data.code for name, data in item_table.items()}
|
item_name_to_id = {name: data.code for name, data in item_table.items()}
|
||||||
|
@ -60,8 +64,6 @@ class SA2BWorld(World):
|
||||||
|
|
||||||
location_table: typing.Dict[str, int]
|
location_table: typing.Dict[str, int]
|
||||||
|
|
||||||
music_map: typing.Dict[int, int]
|
|
||||||
voice_map: typing.Dict[int, int]
|
|
||||||
mission_map: typing.Dict[int, int]
|
mission_map: typing.Dict[int, int]
|
||||||
mission_count_map: typing.Dict[int, int]
|
mission_count_map: typing.Dict[int, int]
|
||||||
emblems_for_cannons_core: int
|
emblems_for_cannons_core: int
|
||||||
|
@ -69,138 +71,126 @@ class SA2BWorld(World):
|
||||||
gate_costs: typing.Dict[int, int]
|
gate_costs: typing.Dict[int, int]
|
||||||
gate_bosses: typing.Dict[int, int]
|
gate_bosses: typing.Dict[int, int]
|
||||||
boss_rush_map: typing.Dict[int, int]
|
boss_rush_map: typing.Dict[int, int]
|
||||||
|
black_market_costs: typing.Dict[int, int]
|
||||||
|
|
||||||
web = SA2BWeb()
|
web = SA2BWeb()
|
||||||
|
|
||||||
def _get_slot_data(self):
|
def fill_slot_data(self) -> dict:
|
||||||
return {
|
return {
|
||||||
"ModVersion": 202,
|
"ModVersion": 203,
|
||||||
"Goal": self.multiworld.goal[self.player].value,
|
"Goal": self.options.goal.value,
|
||||||
"MusicMap": self.music_map,
|
"MusicMap": self.generate_music_data(),
|
||||||
"VoiceMap": self.voice_map,
|
"VoiceMap": self.generate_voice_data(),
|
||||||
|
"DefaultEggMap": self.generate_chao_egg_data(),
|
||||||
|
"DefaultChaoNameMap": self.generate_chao_name_data(),
|
||||||
"MissionMap": self.mission_map,
|
"MissionMap": self.mission_map,
|
||||||
"MissionCountMap": self.mission_count_map,
|
"MissionCountMap": self.mission_count_map,
|
||||||
"MusicShuffle": self.multiworld.music_shuffle[self.player].value,
|
"MusicShuffle": self.options.music_shuffle.value,
|
||||||
"Narrator": self.multiworld.narrator[self.player].value,
|
"Narrator": self.options.narrator.value,
|
||||||
"MinigameTrapDifficulty": self.multiworld.minigame_trap_difficulty[self.player].value,
|
"MinigameTrapDifficulty": self.options.minigame_trap_difficulty.value,
|
||||||
"RingLoss": self.multiworld.ring_loss[self.player].value,
|
"RingLoss": self.options.ring_loss.value,
|
||||||
"RingLink": self.multiworld.ring_link[self.player].value,
|
"RingLink": self.options.ring_link.value,
|
||||||
"RequiredRank": self.multiworld.required_rank[self.player].value,
|
"RequiredRank": self.options.required_rank.value,
|
||||||
"ChaoKeys": self.multiworld.keysanity[self.player].value,
|
"ChaoKeys": self.options.keysanity.value,
|
||||||
"Whistlesanity": self.multiworld.whistlesanity[self.player].value,
|
"Whistlesanity": self.options.whistlesanity.value,
|
||||||
"GoldBeetles": self.multiworld.beetlesanity[self.player].value,
|
"GoldBeetles": self.options.beetlesanity.value,
|
||||||
"OmochaoChecks": self.multiworld.omosanity[self.player].value,
|
"OmochaoChecks": self.options.omosanity.value,
|
||||||
"AnimalChecks": self.multiworld.animalsanity[self.player].value,
|
"AnimalChecks": self.options.animalsanity.value,
|
||||||
"KartRaceChecks": self.multiworld.kart_race_checks[self.player].value,
|
"KartRaceChecks": self.options.kart_race_checks.value,
|
||||||
"ChaoRaceChecks": self.multiworld.chao_race_checks[self.player].value,
|
"ChaoStadiumChecks": self.options.chao_stadium_checks.value,
|
||||||
"ChaoGardenDifficulty": self.multiworld.chao_garden_difficulty[self.player].value,
|
"ChaoRaceDifficulty": self.options.chao_race_difficulty.value,
|
||||||
"DeathLink": self.multiworld.death_link[self.player].value,
|
"ChaoKarateDifficulty": self.options.chao_karate_difficulty.value,
|
||||||
"EmblemPercentageForCannonsCore": self.multiworld.emblem_percentage_for_cannons_core[self.player].value,
|
"ChaoStats": self.options.chao_stats.value,
|
||||||
"RequiredCannonsCoreMissions": self.multiworld.required_cannons_core_missions[self.player].value,
|
"ChaoStatsFrequency": self.options.chao_stats_frequency.value,
|
||||||
"NumberOfLevelGates": self.multiworld.number_of_level_gates[self.player].value,
|
"ChaoStatsStamina": self.options.chao_stats_stamina.value,
|
||||||
"LevelGateDistribution": self.multiworld.level_gate_distribution[self.player].value,
|
"ChaoStatsHidden": self.options.chao_stats_hidden.value,
|
||||||
|
"ChaoAnimalParts": self.options.chao_animal_parts.value,
|
||||||
|
"ChaoKindergarten": self.options.chao_kindergarten.value,
|
||||||
|
"BlackMarketSlots": self.options.black_market_slots.value,
|
||||||
|
"BlackMarketData": self.generate_black_market_data(),
|
||||||
|
"BlackMarketUnlockCosts": self.black_market_costs,
|
||||||
|
"BlackMarketUnlockSetting": self.options.black_market_unlock_costs.value,
|
||||||
|
"ChaoERLayout": self.generate_er_layout(),
|
||||||
|
"DeathLink": self.options.death_link.value,
|
||||||
|
"EmblemPercentageForCannonsCore": self.options.emblem_percentage_for_cannons_core.value,
|
||||||
|
"RequiredCannonsCoreMissions": self.options.required_cannons_core_missions.value,
|
||||||
|
"NumberOfLevelGates": self.options.number_of_level_gates.value,
|
||||||
|
"LevelGateDistribution": self.options.level_gate_distribution.value,
|
||||||
"EmblemsForCannonsCore": self.emblems_for_cannons_core,
|
"EmblemsForCannonsCore": self.emblems_for_cannons_core,
|
||||||
"RegionEmblemMap": self.region_emblem_map,
|
"RegionEmblemMap": self.region_emblem_map,
|
||||||
"GateCosts": self.gate_costs,
|
"GateCosts": self.gate_costs,
|
||||||
"GateBosses": self.gate_bosses,
|
"GateBosses": self.gate_bosses,
|
||||||
"BossRushMap": self.boss_rush_map,
|
"BossRushMap": self.boss_rush_map,
|
||||||
|
"PlayerNum": self.player,
|
||||||
}
|
}
|
||||||
|
|
||||||
def _create_items(self, name: str):
|
|
||||||
data = item_table[name]
|
|
||||||
return [self.create_item(name) for _ in range(data.quantity)]
|
|
||||||
|
|
||||||
def fill_slot_data(self) -> dict:
|
|
||||||
slot_data = self._get_slot_data()
|
|
||||||
slot_data["MusicMap"] = self.music_map
|
|
||||||
for option_name in sa2b_options:
|
|
||||||
option = getattr(self.multiworld, option_name)[self.player]
|
|
||||||
slot_data[option_name] = option.value
|
|
||||||
|
|
||||||
return slot_data
|
|
||||||
|
|
||||||
def get_levels_per_gate(self) -> list:
|
|
||||||
levels_per_gate = list()
|
|
||||||
max_gate_index = self.multiworld.number_of_level_gates[self.player]
|
|
||||||
average_level_count = 30 / (max_gate_index + 1)
|
|
||||||
levels_added = 0
|
|
||||||
|
|
||||||
for i in range(max_gate_index + 1):
|
|
||||||
levels_per_gate.append(average_level_count)
|
|
||||||
levels_added += average_level_count
|
|
||||||
additional_count_iterator = 0
|
|
||||||
while levels_added < 30:
|
|
||||||
levels_per_gate[additional_count_iterator] += 1
|
|
||||||
levels_added += 1
|
|
||||||
additional_count_iterator += 1 if additional_count_iterator < max_gate_index else -max_gate_index
|
|
||||||
|
|
||||||
if self.multiworld.level_gate_distribution[self.player] == 0 or self.multiworld.level_gate_distribution[self.player] == 2:
|
|
||||||
early_distribution = self.multiworld.level_gate_distribution[self.player] == 0
|
|
||||||
levels_to_distribute = 5
|
|
||||||
gate_index_offset = 0
|
|
||||||
while levels_to_distribute > 0:
|
|
||||||
if levels_per_gate[0 + gate_index_offset] == 1 or \
|
|
||||||
levels_per_gate[max_gate_index - gate_index_offset] == 1:
|
|
||||||
break
|
|
||||||
if early_distribution:
|
|
||||||
levels_per_gate[0 + gate_index_offset] += 1
|
|
||||||
levels_per_gate[max_gate_index - gate_index_offset] -= 1
|
|
||||||
else:
|
|
||||||
levels_per_gate[0 + gate_index_offset] -= 1
|
|
||||||
levels_per_gate[max_gate_index - gate_index_offset] += 1
|
|
||||||
gate_index_offset += 1
|
|
||||||
if gate_index_offset > math.floor(max_gate_index / 2):
|
|
||||||
gate_index_offset = 0
|
|
||||||
levels_to_distribute -= 1
|
|
||||||
|
|
||||||
return levels_per_gate
|
|
||||||
|
|
||||||
def generate_early(self):
|
def generate_early(self):
|
||||||
if self.multiworld.goal[self.player].value == 3:
|
if self.options.goal.value == 3:
|
||||||
# Turn off everything else for Grand Prix goal
|
# Turn off everything else for Grand Prix goal
|
||||||
self.multiworld.number_of_level_gates[self.player].value = 0
|
self.options.number_of_level_gates.value = 0
|
||||||
self.multiworld.emblem_percentage_for_cannons_core[self.player].value = 0
|
self.options.emblem_percentage_for_cannons_core.value = 0
|
||||||
self.multiworld.junk_fill_percentage[self.player].value = 100
|
|
||||||
self.multiworld.trap_fill_percentage[self.player].value = 100
|
|
||||||
self.multiworld.omochao_trap_weight[self.player].value = 0
|
|
||||||
self.multiworld.timestop_trap_weight[self.player].value = 0
|
|
||||||
self.multiworld.confusion_trap_weight[self.player].value = 0
|
|
||||||
self.multiworld.tiny_trap_weight[self.player].value = 0
|
|
||||||
self.multiworld.gravity_trap_weight[self.player].value = 0
|
|
||||||
self.multiworld.ice_trap_weight[self.player].value = 0
|
|
||||||
self.multiworld.slow_trap_weight[self.player].value = 0
|
|
||||||
|
|
||||||
valid_trap_weights = self.multiworld.exposition_trap_weight[self.player].value + \
|
self.options.chao_race_difficulty.value = 0
|
||||||
self.multiworld.cutscene_trap_weight[self.player].value + \
|
self.options.chao_karate_difficulty.value = 0
|
||||||
self.multiworld.pong_trap_weight[self.player].value
|
self.options.chao_stats.value = 0
|
||||||
|
self.options.chao_animal_parts.value = 0
|
||||||
|
self.options.chao_kindergarten.value = 0
|
||||||
|
self.options.black_market_slots.value = 0
|
||||||
|
|
||||||
|
self.options.junk_fill_percentage.value = 100
|
||||||
|
self.options.trap_fill_percentage.value = 100
|
||||||
|
self.options.omochao_trap_weight.value = 0
|
||||||
|
self.options.timestop_trap_weight.value = 0
|
||||||
|
self.options.confusion_trap_weight.value = 0
|
||||||
|
self.options.tiny_trap_weight.value = 0
|
||||||
|
self.options.gravity_trap_weight.value = 0
|
||||||
|
self.options.ice_trap_weight.value = 0
|
||||||
|
self.options.slow_trap_weight.value = 0
|
||||||
|
self.options.cutscene_trap_weight.value = 0
|
||||||
|
|
||||||
|
valid_trap_weights = self.options.exposition_trap_weight.value + \
|
||||||
|
self.options.reverse_trap_weight.value + \
|
||||||
|
self.options.pong_trap_weight.value
|
||||||
|
|
||||||
if valid_trap_weights == 0:
|
if valid_trap_weights == 0:
|
||||||
self.multiworld.exposition_trap_weight[self.player].value = 4
|
self.options.exposition_trap_weight.value = 4
|
||||||
self.multiworld.cutscene_trap_weight[self.player].value = 4
|
self.options.reverse_trap_weight.value = 4
|
||||||
self.multiworld.pong_trap_weight[self.player].value = 4
|
self.options.pong_trap_weight.value = 4
|
||||||
|
|
||||||
if self.multiworld.kart_race_checks[self.player].value == 0:
|
if self.options.kart_race_checks.value == 0:
|
||||||
self.multiworld.kart_race_checks[self.player].value = 2
|
self.options.kart_race_checks.value = 2
|
||||||
|
|
||||||
self.gate_bosses = {}
|
self.gate_bosses = {}
|
||||||
self.boss_rush_map = {}
|
self.boss_rush_map = {}
|
||||||
else:
|
else:
|
||||||
self.gate_bosses = get_gate_bosses(self.multiworld, self.player)
|
self.gate_bosses = get_gate_bosses(self.multiworld, self)
|
||||||
self.boss_rush_map = get_boss_rush_bosses(self.multiworld, self.player)
|
self.boss_rush_map = get_boss_rush_bosses(self.multiworld, self)
|
||||||
|
|
||||||
def create_regions(self):
|
def create_regions(self):
|
||||||
self.mission_map = get_mission_table(self.multiworld, self.player)
|
self.mission_map = get_mission_table(self.multiworld, self, self.player)
|
||||||
self.mission_count_map = get_mission_count_table(self.multiworld, self.player)
|
self.mission_count_map = get_mission_count_table(self.multiworld, self, self.player)
|
||||||
|
|
||||||
self.location_table = setup_locations(self.multiworld, self.player, self.mission_map, self.mission_count_map)
|
self.location_table = setup_locations(self, self.player, self.mission_map, self.mission_count_map)
|
||||||
create_regions(self.multiworld, self.player, self.location_table)
|
create_regions(self.multiworld, self, self.player, self.location_table)
|
||||||
|
|
||||||
# Not Generate Basic
|
# Not Generate Basic
|
||||||
if self.multiworld.goal[self.player].value in [0, 2, 4, 5, 6]:
|
self.black_market_costs = dict()
|
||||||
|
|
||||||
|
if self.options.goal.value in [0, 2, 4, 5, 6]:
|
||||||
self.multiworld.get_location(LocationName.finalhazard, self.player).place_locked_item(self.create_item(ItemName.maria))
|
self.multiworld.get_location(LocationName.finalhazard, self.player).place_locked_item(self.create_item(ItemName.maria))
|
||||||
elif self.multiworld.goal[self.player].value == 1:
|
elif self.options.goal.value == 1:
|
||||||
self.multiworld.get_location(LocationName.green_hill, self.player).place_locked_item(self.create_item(ItemName.maria))
|
self.multiworld.get_location(LocationName.green_hill, self.player).place_locked_item(self.create_item(ItemName.maria))
|
||||||
elif self.multiworld.goal[self.player].value == 3:
|
elif self.options.goal.value == 3:
|
||||||
self.multiworld.get_location(LocationName.grand_prix, self.player).place_locked_item(self.create_item(ItemName.maria))
|
self.multiworld.get_location(LocationName.grand_prix, self.player).place_locked_item(self.create_item(ItemName.maria))
|
||||||
|
elif self.options.goal.value == 7:
|
||||||
|
self.multiworld.get_location(LocationName.chaos_chao, self.player).place_locked_item(self.create_item(ItemName.maria))
|
||||||
|
|
||||||
|
for animal_name in chao_animal_event_location_table.keys():
|
||||||
|
animal_region = self.multiworld.get_region(animal_name, self.player)
|
||||||
|
animal_event_location = SA2BLocation(self.player, animal_name, None, animal_region)
|
||||||
|
animal_region.locations.append(animal_event_location)
|
||||||
|
animal_event_item = SA2BItem(animal_name, ItemClassification.progression, None, self.player)
|
||||||
|
self.multiworld.get_location(animal_name, self.player).place_locked_item(animal_event_item)
|
||||||
|
|
||||||
itempool: typing.List[SA2BItem] = []
|
itempool: typing.List[SA2BItem] = []
|
||||||
|
|
||||||
|
@ -208,28 +198,40 @@ class SA2BWorld(World):
|
||||||
total_required_locations = len(self.location_table)
|
total_required_locations = len(self.location_table)
|
||||||
total_required_locations -= 1; # Locked Victory Location
|
total_required_locations -= 1; # Locked Victory Location
|
||||||
|
|
||||||
if self.multiworld.goal[self.player].value != 3:
|
if self.options.goal.value != 3:
|
||||||
# Fill item pool with all required items
|
# Fill item pool with all required items
|
||||||
for item in {**upgrades_table}:
|
for item in {**upgrades_table}:
|
||||||
itempool += [self.create_item(item, False, self.multiworld.goal[self.player].value)]
|
itempool += [self.create_item(item, False, self.options.goal.value)]
|
||||||
|
|
||||||
if self.multiworld.goal[self.player].value in [1, 2, 6]:
|
if self.options.goal.value in [1, 2, 6]:
|
||||||
# Some flavor of Chaos Emerald Hunt
|
# Some flavor of Chaos Emerald Hunt
|
||||||
for item in {**emeralds_table}:
|
for item in {**emeralds_table}:
|
||||||
itempool += self._create_items(item)
|
itempool.append(self.create_item(item))
|
||||||
|
|
||||||
|
# Black Market
|
||||||
|
itempool += [self.create_item(ItemName.market_token) for _ in range(self.options.black_market_slots.value)]
|
||||||
|
|
||||||
|
black_market_unlock_mult = 1.0
|
||||||
|
if self.options.black_market_unlock_costs.value == 0:
|
||||||
|
black_market_unlock_mult = 0.5
|
||||||
|
elif self.options.black_market_unlock_costs.value == 1:
|
||||||
|
black_market_unlock_mult = 0.75
|
||||||
|
|
||||||
|
for i in range(self.options.black_market_slots.value):
|
||||||
|
self.black_market_costs[i] = math.floor((i + 1) * black_market_unlock_mult)
|
||||||
|
|
||||||
# Cap at player-specified Emblem count
|
# Cap at player-specified Emblem count
|
||||||
raw_emblem_count = total_required_locations - len(itempool)
|
raw_emblem_count = total_required_locations - len(itempool)
|
||||||
total_emblem_count = min(raw_emblem_count, self.multiworld.max_emblem_cap[self.player].value)
|
total_emblem_count = min(raw_emblem_count, self.options.max_emblem_cap.value)
|
||||||
extra_junk_count = raw_emblem_count - total_emblem_count
|
extra_junk_count = raw_emblem_count - total_emblem_count
|
||||||
|
|
||||||
self.emblems_for_cannons_core = math.floor(
|
self.emblems_for_cannons_core = math.floor(
|
||||||
total_emblem_count * (self.multiworld.emblem_percentage_for_cannons_core[self.player].value / 100.0))
|
total_emblem_count * (self.options.emblem_percentage_for_cannons_core.value / 100.0))
|
||||||
|
|
||||||
gate_cost_mult = 1.0
|
gate_cost_mult = 1.0
|
||||||
if self.multiworld.level_gate_costs[self.player].value == 0:
|
if self.options.level_gate_costs.value == 0:
|
||||||
gate_cost_mult = 0.6
|
gate_cost_mult = 0.6
|
||||||
elif self.multiworld.level_gate_costs[self.player].value == 1:
|
elif self.options.level_gate_costs.value == 1:
|
||||||
gate_cost_mult = 0.8
|
gate_cost_mult = 0.8
|
||||||
|
|
||||||
shuffled_region_list = list(range(30))
|
shuffled_region_list = list(range(30))
|
||||||
|
@ -253,8 +255,8 @@ class SA2BWorld(World):
|
||||||
total_levels_added += 1
|
total_levels_added += 1
|
||||||
if levels_added_to_gate >= levels_per_gate[current_gate]:
|
if levels_added_to_gate >= levels_per_gate[current_gate]:
|
||||||
current_gate += 1
|
current_gate += 1
|
||||||
if current_gate > self.multiworld.number_of_level_gates[self.player].value:
|
if current_gate > self.options.number_of_level_gates.value:
|
||||||
current_gate = self.multiworld.number_of_level_gates[self.player].value
|
current_gate = self.options.number_of_level_gates.value
|
||||||
else:
|
else:
|
||||||
current_gate_emblems = max(
|
current_gate_emblems = max(
|
||||||
math.floor(total_emblem_count * math.pow(total_levels_added / 30.0, 2.0) * gate_cost_mult), current_gate)
|
math.floor(total_emblem_count * math.pow(total_levels_added / 30.0, 2.0) * gate_cost_mult), current_gate)
|
||||||
|
@ -266,36 +268,68 @@ class SA2BWorld(World):
|
||||||
|
|
||||||
first_cannons_core_mission, final_cannons_core_mission = get_first_and_last_cannons_core_missions(self.mission_map, self.mission_count_map)
|
first_cannons_core_mission, final_cannons_core_mission = get_first_and_last_cannons_core_missions(self.mission_map, self.mission_count_map)
|
||||||
|
|
||||||
connect_regions(self.multiworld, self.player, gates, self.emblems_for_cannons_core, self.gate_bosses, self.boss_rush_map, first_cannons_core_mission, final_cannons_core_mission)
|
connect_regions(self.multiworld, self, self.player, gates, self.emblems_for_cannons_core, self.gate_bosses, self.boss_rush_map, first_cannons_core_mission, final_cannons_core_mission)
|
||||||
|
|
||||||
max_required_emblems = max(max(emblem_requirement_list), self.emblems_for_cannons_core)
|
max_required_emblems = max(max(emblem_requirement_list), self.emblems_for_cannons_core)
|
||||||
itempool += [self.create_item(ItemName.emblem) for _ in range(max_required_emblems)]
|
itempool += [self.create_item(ItemName.emblem) for _ in range(max_required_emblems)]
|
||||||
|
|
||||||
non_required_emblems = (total_emblem_count - max_required_emblems)
|
non_required_emblems = (total_emblem_count - max_required_emblems)
|
||||||
junk_count = math.floor(non_required_emblems * (self.multiworld.junk_fill_percentage[self.player].value / 100.0))
|
junk_count = math.floor(non_required_emblems * (self.options.junk_fill_percentage.value / 100.0))
|
||||||
itempool += [self.create_item(ItemName.emblem, True) for _ in range(non_required_emblems - junk_count)]
|
itempool += [self.create_item(ItemName.emblem, True) for _ in range(non_required_emblems - junk_count)]
|
||||||
|
|
||||||
# Carve Traps out of junk_count
|
# Carve Traps out of junk_count
|
||||||
trap_weights = []
|
trap_weights = []
|
||||||
trap_weights += ([ItemName.omochao_trap] * self.multiworld.omochao_trap_weight[self.player].value)
|
trap_weights += ([ItemName.omochao_trap] * self.options.omochao_trap_weight.value)
|
||||||
trap_weights += ([ItemName.timestop_trap] * self.multiworld.timestop_trap_weight[self.player].value)
|
trap_weights += ([ItemName.timestop_trap] * self.options.timestop_trap_weight.value)
|
||||||
trap_weights += ([ItemName.confuse_trap] * self.multiworld.confusion_trap_weight[self.player].value)
|
trap_weights += ([ItemName.confuse_trap] * self.options.confusion_trap_weight.value)
|
||||||
trap_weights += ([ItemName.tiny_trap] * self.multiworld.tiny_trap_weight[self.player].value)
|
trap_weights += ([ItemName.tiny_trap] * self.options.tiny_trap_weight.value)
|
||||||
trap_weights += ([ItemName.gravity_trap] * self.multiworld.gravity_trap_weight[self.player].value)
|
trap_weights += ([ItemName.gravity_trap] * self.options.gravity_trap_weight.value)
|
||||||
trap_weights += ([ItemName.exposition_trap] * self.multiworld.exposition_trap_weight[self.player].value)
|
trap_weights += ([ItemName.exposition_trap] * self.options.exposition_trap_weight.value)
|
||||||
#trap_weights += ([ItemName.darkness_trap] * self.multiworld.darkness_trap_weight[self.player].value)
|
#trap_weights += ([ItemName.darkness_trap] * self.options.darkness_trap_weight.value)
|
||||||
trap_weights += ([ItemName.ice_trap] * self.multiworld.ice_trap_weight[self.player].value)
|
trap_weights += ([ItemName.ice_trap] * self.options.ice_trap_weight.value)
|
||||||
trap_weights += ([ItemName.slow_trap] * self.multiworld.slow_trap_weight[self.player].value)
|
trap_weights += ([ItemName.slow_trap] * self.options.slow_trap_weight.value)
|
||||||
trap_weights += ([ItemName.cutscene_trap] * self.multiworld.cutscene_trap_weight[self.player].value)
|
trap_weights += ([ItemName.cutscene_trap] * self.options.cutscene_trap_weight.value)
|
||||||
trap_weights += ([ItemName.pong_trap] * self.multiworld.pong_trap_weight[self.player].value)
|
trap_weights += ([ItemName.reverse_trap] * self.options.reverse_trap_weight.value)
|
||||||
|
trap_weights += ([ItemName.pong_trap] * self.options.pong_trap_weight.value)
|
||||||
|
|
||||||
junk_count += extra_junk_count
|
junk_count += extra_junk_count
|
||||||
trap_count = 0 if (len(trap_weights) == 0) else math.ceil(junk_count * (self.multiworld.trap_fill_percentage[self.player].value / 100.0))
|
trap_count = 0 if (len(trap_weights) == 0) else math.ceil(junk_count * (self.options.trap_fill_percentage.value / 100.0))
|
||||||
junk_count -= trap_count
|
junk_count -= trap_count
|
||||||
|
|
||||||
|
chao_active = self.any_chao_locations_active()
|
||||||
junk_pool = []
|
junk_pool = []
|
||||||
junk_keys = list(junk_table.keys())
|
junk_keys = list(junk_table.keys())
|
||||||
|
|
||||||
|
# Chao Junk
|
||||||
|
if chao_active:
|
||||||
|
junk_keys += list(chaos_drives_table.keys())
|
||||||
|
eggs_keys = list(eggs_table.keys())
|
||||||
|
fruits_keys = list(fruits_table.keys())
|
||||||
|
seeds_keys = list(seeds_table.keys())
|
||||||
|
hats_keys = list(hats_table.keys())
|
||||||
|
eggs_count = 0
|
||||||
|
seeds_count = 0
|
||||||
|
hats_count = 0
|
||||||
|
|
||||||
for i in range(junk_count):
|
for i in range(junk_count):
|
||||||
|
junk_type = self.random.randint(0, len(junk_keys) + 3)
|
||||||
|
|
||||||
|
if chao_active and junk_type == len(junk_keys) + 0 and eggs_count < 20:
|
||||||
|
junk_item = self.multiworld.random.choice(eggs_keys)
|
||||||
|
junk_pool.append(self.create_item(junk_item))
|
||||||
|
eggs_count += 1
|
||||||
|
elif chao_active and junk_type == len(junk_keys) + 1:
|
||||||
|
junk_item = self.multiworld.random.choice(fruits_keys)
|
||||||
|
junk_pool.append(self.create_item(junk_item))
|
||||||
|
elif chao_active and junk_type == len(junk_keys) + 2 and seeds_count < 12:
|
||||||
|
junk_item = self.multiworld.random.choice(seeds_keys)
|
||||||
|
junk_pool.append(self.create_item(junk_item))
|
||||||
|
seeds_count += 1
|
||||||
|
elif chao_active and junk_type == len(junk_keys) + 3 and hats_count < 20:
|
||||||
|
junk_item = self.multiworld.random.choice(hats_keys)
|
||||||
|
junk_pool.append(self.create_item(junk_item))
|
||||||
|
hats_count += 1
|
||||||
|
else:
|
||||||
junk_item = self.multiworld.random.choice(junk_keys)
|
junk_item = self.multiworld.random.choice(junk_keys)
|
||||||
junk_pool.append(self.create_item(junk_item))
|
junk_pool.append(self.create_item(junk_item))
|
||||||
|
|
||||||
|
@ -310,95 +344,6 @@ class SA2BWorld(World):
|
||||||
|
|
||||||
self.multiworld.itempool += itempool
|
self.multiworld.itempool += itempool
|
||||||
|
|
||||||
# Music Shuffle
|
|
||||||
if self.multiworld.music_shuffle[self.player] == "levels":
|
|
||||||
musiclist_o = list(range(0, 47))
|
|
||||||
musiclist_s = musiclist_o.copy()
|
|
||||||
self.multiworld.random.shuffle(musiclist_s)
|
|
||||||
musiclist_o.extend(range(47, 78))
|
|
||||||
musiclist_s.extend(range(47, 78))
|
|
||||||
|
|
||||||
if self.multiworld.sadx_music[self.player].value == 1:
|
|
||||||
musiclist_s = [x+100 for x in musiclist_s]
|
|
||||||
elif self.multiworld.sadx_music[self.player].value == 2:
|
|
||||||
for i in range(len(musiclist_s)):
|
|
||||||
if self.multiworld.random.randint(0,1):
|
|
||||||
musiclist_s[i] += 100
|
|
||||||
|
|
||||||
self.music_map = dict(zip(musiclist_o, musiclist_s))
|
|
||||||
elif self.multiworld.music_shuffle[self.player] == "full":
|
|
||||||
musiclist_o = list(range(0, 78))
|
|
||||||
musiclist_s = musiclist_o.copy()
|
|
||||||
self.multiworld.random.shuffle(musiclist_s)
|
|
||||||
|
|
||||||
if self.multiworld.sadx_music[self.player].value == 1:
|
|
||||||
musiclist_s = [x+100 for x in musiclist_s]
|
|
||||||
elif self.multiworld.sadx_music[self.player].value == 2:
|
|
||||||
for i in range(len(musiclist_s)):
|
|
||||||
if self.multiworld.random.randint(0,1):
|
|
||||||
musiclist_s[i] += 100
|
|
||||||
|
|
||||||
self.music_map = dict(zip(musiclist_o, musiclist_s))
|
|
||||||
elif self.multiworld.music_shuffle[self.player] == "singularity":
|
|
||||||
musiclist_o = list(range(0, 78))
|
|
||||||
musiclist_s = [self.multiworld.random.choice(musiclist_o)] * len(musiclist_o)
|
|
||||||
|
|
||||||
if self.multiworld.sadx_music[self.player].value == 1:
|
|
||||||
musiclist_s = [x+100 for x in musiclist_s]
|
|
||||||
elif self.multiworld.sadx_music[self.player].value == 2:
|
|
||||||
if self.multiworld.random.randint(0,1):
|
|
||||||
musiclist_s = [x+100 for x in musiclist_s]
|
|
||||||
|
|
||||||
self.music_map = dict(zip(musiclist_o, musiclist_s))
|
|
||||||
else:
|
|
||||||
musiclist_o = list(range(0, 78))
|
|
||||||
musiclist_s = musiclist_o.copy()
|
|
||||||
|
|
||||||
if self.multiworld.sadx_music[self.player].value == 1:
|
|
||||||
musiclist_s = [x+100 for x in musiclist_s]
|
|
||||||
elif self.multiworld.sadx_music[self.player].value == 2:
|
|
||||||
for i in range(len(musiclist_s)):
|
|
||||||
if self.multiworld.random.randint(0,1):
|
|
||||||
musiclist_s[i] += 100
|
|
||||||
|
|
||||||
self.music_map = dict(zip(musiclist_o, musiclist_s))
|
|
||||||
|
|
||||||
# Voice Shuffle
|
|
||||||
if self.multiworld.voice_shuffle[self.player] == "shuffled":
|
|
||||||
voicelist_o = list(range(0, 2623))
|
|
||||||
voicelist_s = voicelist_o.copy()
|
|
||||||
self.multiworld.random.shuffle(voicelist_s)
|
|
||||||
|
|
||||||
self.voice_map = dict(zip(voicelist_o, voicelist_s))
|
|
||||||
elif self.multiworld.voice_shuffle[self.player] == "rude":
|
|
||||||
voicelist_o = list(range(0, 2623))
|
|
||||||
voicelist_s = voicelist_o.copy()
|
|
||||||
self.multiworld.random.shuffle(voicelist_s)
|
|
||||||
|
|
||||||
for i in range(len(voicelist_s)):
|
|
||||||
if self.multiworld.random.randint(1,100) > 80:
|
|
||||||
voicelist_s[i] = 17
|
|
||||||
|
|
||||||
self.voice_map = dict(zip(voicelist_o, voicelist_s))
|
|
||||||
elif self.multiworld.voice_shuffle[self.player] == "chao":
|
|
||||||
voicelist_o = list(range(0, 2623))
|
|
||||||
voicelist_s = voicelist_o.copy()
|
|
||||||
self.multiworld.random.shuffle(voicelist_s)
|
|
||||||
|
|
||||||
for i in range(len(voicelist_s)):
|
|
||||||
voicelist_s[i] = self.multiworld.random.choice(range(2586, 2608))
|
|
||||||
|
|
||||||
self.voice_map = dict(zip(voicelist_o, voicelist_s))
|
|
||||||
elif self.multiworld.voice_shuffle[self.player] == "singularity":
|
|
||||||
voicelist_o = list(range(0, 2623))
|
|
||||||
voicelist_s = [self.multiworld.random.choice(voicelist_o)] * len(voicelist_o)
|
|
||||||
|
|
||||||
self.voice_map = dict(zip(voicelist_o, voicelist_s))
|
|
||||||
else:
|
|
||||||
voicelist_o = list(range(0, 2623))
|
|
||||||
voicelist_s = voicelist_o.copy()
|
|
||||||
|
|
||||||
self.voice_map = dict(zip(voicelist_o, voicelist_s))
|
|
||||||
|
|
||||||
|
|
||||||
def create_item(self, name: str, force_non_progression=False, goal=0) -> Item:
|
def create_item(self, name: str, force_non_progression=False, goal=0) -> Item:
|
||||||
|
@ -422,26 +367,32 @@ class SA2BWorld(World):
|
||||||
return created_item
|
return created_item
|
||||||
|
|
||||||
def get_filler_item_name(self) -> str:
|
def get_filler_item_name(self) -> str:
|
||||||
return self.multiworld.random.choice(list(junk_table.keys()))
|
junk_keys = list(junk_table.keys())
|
||||||
|
|
||||||
|
# Chao Junk
|
||||||
|
if self.any_chao_locations_active():
|
||||||
|
junk_keys += list(chaos_drives_table.keys())
|
||||||
|
|
||||||
|
return self.multiworld.random.choice(junk_keys)
|
||||||
|
|
||||||
def set_rules(self):
|
def set_rules(self):
|
||||||
set_rules(self.multiworld, self.player, self.gate_bosses, self.boss_rush_map, self.mission_map, self.mission_count_map)
|
set_rules(self.multiworld, self, self.player, self.gate_bosses, self.boss_rush_map, self.mission_map, self.mission_count_map, self.black_market_costs)
|
||||||
|
|
||||||
def write_spoiler(self, spoiler_handle: typing.TextIO):
|
def write_spoiler(self, spoiler_handle: typing.TextIO):
|
||||||
if self.multiworld.number_of_level_gates[self.player].value > 0 or self.multiworld.goal[self.player].value in [4, 5, 6]:
|
if self.options.number_of_level_gates.value > 0 or self.options.goal.value in [4, 5, 6]:
|
||||||
spoiler_handle.write("\n")
|
spoiler_handle.write("\n")
|
||||||
header_text = "Sonic Adventure 2 Bosses for {}:\n"
|
header_text = "Sonic Adventure 2 Bosses for {}:\n"
|
||||||
header_text = header_text.format(self.multiworld.player_name[self.player])
|
header_text = header_text.format(self.multiworld.player_name[self.player])
|
||||||
spoiler_handle.write(header_text)
|
spoiler_handle.write(header_text)
|
||||||
|
|
||||||
if self.multiworld.number_of_level_gates[self.player].value > 0:
|
if self.options.number_of_level_gates.value > 0:
|
||||||
for x in range(len(self.gate_bosses.values())):
|
for x in range(len(self.gate_bosses.values())):
|
||||||
text = "Gate {0} Boss: {1}\n"
|
text = "Gate {0} Boss: {1}\n"
|
||||||
text = text.format((x + 1), get_boss_name(self.gate_bosses[x + 1]))
|
text = text.format((x + 1), get_boss_name(self.gate_bosses[x + 1]))
|
||||||
spoiler_handle.writelines(text)
|
spoiler_handle.writelines(text)
|
||||||
spoiler_handle.write("\n")
|
spoiler_handle.write("\n")
|
||||||
|
|
||||||
if self.multiworld.goal[self.player].value in [4, 5, 6]:
|
if self.options.goal.value in [4, 5, 6]:
|
||||||
for x in range(len(self.boss_rush_map.values())):
|
for x in range(len(self.boss_rush_map.values())):
|
||||||
text = "Boss Rush Boss {0}: {1}\n"
|
text = "Boss Rush Boss {0}: {1}\n"
|
||||||
text = text.format((x + 1), get_boss_name(self.boss_rush_map[x]))
|
text = text.format((x + 1), get_boss_name(self.boss_rush_map[x]))
|
||||||
|
@ -459,12 +410,21 @@ class SA2BWorld(World):
|
||||||
]
|
]
|
||||||
no_hint_region_names = [
|
no_hint_region_names = [
|
||||||
LocationName.cannon_core_region,
|
LocationName.cannon_core_region,
|
||||||
LocationName.chao_garden_beginner_region,
|
LocationName.chao_race_beginner_region,
|
||||||
LocationName.chao_garden_intermediate_region,
|
LocationName.chao_race_intermediate_region,
|
||||||
LocationName.chao_garden_expert_region,
|
LocationName.chao_race_expert_region,
|
||||||
|
LocationName.chao_karate_beginner_region,
|
||||||
|
LocationName.chao_karate_intermediate_region,
|
||||||
|
LocationName.chao_karate_expert_region,
|
||||||
|
LocationName.chao_karate_super_region,
|
||||||
|
LocationName.kart_race_beginner_region,
|
||||||
|
LocationName.kart_race_standard_region,
|
||||||
|
LocationName.kart_race_expert_region,
|
||||||
|
LocationName.chao_kindergarten_region,
|
||||||
|
LocationName.black_market_region,
|
||||||
]
|
]
|
||||||
er_hint_data = {}
|
er_hint_data = {}
|
||||||
for i in range(self.multiworld.number_of_level_gates[self.player].value + 1):
|
for i in range(self.options.number_of_level_gates.value + 1):
|
||||||
gate_name = gate_names[i]
|
gate_name = gate_names[i]
|
||||||
gate_region = self.multiworld.get_region(gate_name, self.player)
|
gate_region = self.multiworld.get_region(gate_name, self.player)
|
||||||
if not gate_region:
|
if not gate_region:
|
||||||
|
@ -476,10 +436,353 @@ class SA2BWorld(World):
|
||||||
for location in level_region.locations:
|
for location in level_region.locations:
|
||||||
er_hint_data[location.address] = gate_name
|
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
|
hint_data[self.player] = er_hint_data
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def stage_fill_hook(cls, world, progitempool, usefulitempool, filleritempool, fill_locations):
|
def stage_fill_hook(cls, multiworld: MultiWorld, progitempool, usefulitempool, filleritempool, fill_locations):
|
||||||
if world.get_game_players("Sonic Adventure 2 Battle"):
|
if multiworld.get_game_players("Sonic Adventure 2 Battle"):
|
||||||
progitempool.sort(
|
progitempool.sort(
|
||||||
key=lambda item: 0 if (item.name != 'Emblem') else 1)
|
key=lambda item: 0 if (item.name != 'Emblem') else 1)
|
||||||
|
|
||||||
|
def get_levels_per_gate(self) -> list:
|
||||||
|
levels_per_gate = list()
|
||||||
|
max_gate_index = self.options.number_of_level_gates
|
||||||
|
average_level_count = 30 / (max_gate_index + 1)
|
||||||
|
levels_added = 0
|
||||||
|
|
||||||
|
for i in range(max_gate_index + 1):
|
||||||
|
levels_per_gate.append(average_level_count)
|
||||||
|
levels_added += average_level_count
|
||||||
|
additional_count_iterator = 0
|
||||||
|
while levels_added < 30:
|
||||||
|
levels_per_gate[additional_count_iterator] += 1
|
||||||
|
levels_added += 1
|
||||||
|
additional_count_iterator += 1 if additional_count_iterator < max_gate_index else -max_gate_index
|
||||||
|
|
||||||
|
if self.options.level_gate_distribution == 0 or self.options.level_gate_distribution == 2:
|
||||||
|
early_distribution = self.options.level_gate_distribution == 0
|
||||||
|
levels_to_distribute = 5
|
||||||
|
gate_index_offset = 0
|
||||||
|
while levels_to_distribute > 0:
|
||||||
|
if levels_per_gate[0 + gate_index_offset] == 1 or \
|
||||||
|
levels_per_gate[max_gate_index - gate_index_offset] == 1:
|
||||||
|
break
|
||||||
|
if early_distribution:
|
||||||
|
levels_per_gate[0 + gate_index_offset] += 1
|
||||||
|
levels_per_gate[max_gate_index - gate_index_offset] -= 1
|
||||||
|
else:
|
||||||
|
levels_per_gate[0 + gate_index_offset] -= 1
|
||||||
|
levels_per_gate[max_gate_index - gate_index_offset] += 1
|
||||||
|
gate_index_offset += 1
|
||||||
|
if gate_index_offset > math.floor(max_gate_index / 2):
|
||||||
|
gate_index_offset = 0
|
||||||
|
levels_to_distribute -= 1
|
||||||
|
|
||||||
|
return levels_per_gate
|
||||||
|
|
||||||
|
def any_chao_locations_active(self) -> bool:
|
||||||
|
if self.options.chao_race_difficulty.value > 0 or \
|
||||||
|
self.options.chao_karate_difficulty.value > 0 or \
|
||||||
|
self.options.chao_stats.value > 0 or \
|
||||||
|
self.options.chao_animal_parts or \
|
||||||
|
self.options.chao_kindergarten or \
|
||||||
|
self.options.black_market_slots.value > 0:
|
||||||
|
return True;
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def generate_music_data(self) -> typing.Dict[int, int]:
|
||||||
|
if self.options.music_shuffle == "levels":
|
||||||
|
musiclist_o = list(range(0, 47))
|
||||||
|
musiclist_s = musiclist_o.copy()
|
||||||
|
self.random.shuffle(musiclist_s)
|
||||||
|
musiclist_o.extend(range(47, 78))
|
||||||
|
musiclist_s.extend(range(47, 78))
|
||||||
|
|
||||||
|
if self.options.sadx_music.value == 1:
|
||||||
|
musiclist_s = [x+100 for x in musiclist_s]
|
||||||
|
elif self.options.sadx_music.value == 2:
|
||||||
|
for i in range(len(musiclist_s)):
|
||||||
|
if self.random.randint(0,1):
|
||||||
|
musiclist_s[i] += 100
|
||||||
|
|
||||||
|
return dict(zip(musiclist_o, musiclist_s))
|
||||||
|
elif self.options.music_shuffle == "full":
|
||||||
|
musiclist_o = list(range(0, 78))
|
||||||
|
musiclist_s = musiclist_o.copy()
|
||||||
|
self.random.shuffle(musiclist_s)
|
||||||
|
|
||||||
|
if self.options.sadx_music.value == 1:
|
||||||
|
musiclist_s = [x+100 for x in musiclist_s]
|
||||||
|
elif self.options.sadx_music.value == 2:
|
||||||
|
for i in range(len(musiclist_s)):
|
||||||
|
if self.random.randint(0,1):
|
||||||
|
musiclist_s[i] += 100
|
||||||
|
|
||||||
|
return dict(zip(musiclist_o, musiclist_s))
|
||||||
|
elif self.options.music_shuffle == "singularity":
|
||||||
|
musiclist_o = list(range(0, 78))
|
||||||
|
musiclist_s = [self.random.choice(musiclist_o)] * len(musiclist_o)
|
||||||
|
|
||||||
|
if self.options.sadx_music.value == 1:
|
||||||
|
musiclist_s = [x+100 for x in musiclist_s]
|
||||||
|
elif self.options.sadx_music.value == 2:
|
||||||
|
if self.random.randint(0,1):
|
||||||
|
musiclist_s = [x+100 for x in musiclist_s]
|
||||||
|
|
||||||
|
return dict(zip(musiclist_o, musiclist_s))
|
||||||
|
else:
|
||||||
|
musiclist_o = list(range(0, 78))
|
||||||
|
musiclist_s = musiclist_o.copy()
|
||||||
|
|
||||||
|
if self.options.sadx_music.value == 1:
|
||||||
|
musiclist_s = [x+100 for x in musiclist_s]
|
||||||
|
elif self.options.sadx_music.value == 2:
|
||||||
|
for i in range(len(musiclist_s)):
|
||||||
|
if self.random.randint(0,1):
|
||||||
|
musiclist_s[i] += 100
|
||||||
|
|
||||||
|
return dict(zip(musiclist_o, musiclist_s))
|
||||||
|
|
||||||
|
def generate_voice_data(self) -> typing.Dict[int, int]:
|
||||||
|
if self.options.voice_shuffle == "shuffled":
|
||||||
|
voicelist_o = list(range(0, 2623))
|
||||||
|
voicelist_s = voicelist_o.copy()
|
||||||
|
self.random.shuffle(voicelist_s)
|
||||||
|
|
||||||
|
return dict(zip(voicelist_o, voicelist_s))
|
||||||
|
elif self.options.voice_shuffle == "rude":
|
||||||
|
voicelist_o = list(range(0, 2623))
|
||||||
|
voicelist_s = voicelist_o.copy()
|
||||||
|
self.random.shuffle(voicelist_s)
|
||||||
|
|
||||||
|
for i in range(len(voicelist_s)):
|
||||||
|
if self.random.randint(1,100) > 80:
|
||||||
|
voicelist_s[i] = 17
|
||||||
|
|
||||||
|
return dict(zip(voicelist_o, voicelist_s))
|
||||||
|
elif self.options.voice_shuffle == "chao":
|
||||||
|
voicelist_o = list(range(0, 2623))
|
||||||
|
voicelist_s = voicelist_o.copy()
|
||||||
|
self.random.shuffle(voicelist_s)
|
||||||
|
|
||||||
|
for i in range(len(voicelist_s)):
|
||||||
|
voicelist_s[i] = self.random.choice(range(2586, 2608))
|
||||||
|
|
||||||
|
return dict(zip(voicelist_o, voicelist_s))
|
||||||
|
elif self.options.voice_shuffle == "singularity":
|
||||||
|
voicelist_o = list(range(0, 2623))
|
||||||
|
voicelist_s = [self.random.choice(voicelist_o)] * len(voicelist_o)
|
||||||
|
|
||||||
|
return dict(zip(voicelist_o, voicelist_s))
|
||||||
|
else:
|
||||||
|
voicelist_o = list(range(0, 2623))
|
||||||
|
voicelist_s = voicelist_o.copy()
|
||||||
|
|
||||||
|
return dict(zip(voicelist_o, voicelist_s))
|
||||||
|
|
||||||
|
def generate_chao_egg_data(self) -> typing.Dict[int, int]:
|
||||||
|
if self.options.shuffle_starting_chao_eggs:
|
||||||
|
egglist_o = list(range(0, 4))
|
||||||
|
egglist_s = self.random.sample(range(0,54), 4)
|
||||||
|
|
||||||
|
return dict(zip(egglist_o, egglist_s))
|
||||||
|
else:
|
||||||
|
# Indicate these are not shuffled
|
||||||
|
egglist_o = [0, 1, 2, 3]
|
||||||
|
egglist_s = [255, 255, 255, 255]
|
||||||
|
|
||||||
|
return dict(zip(egglist_o, egglist_s))
|
||||||
|
|
||||||
|
def generate_chao_name_data(self) -> typing.Dict[int, int]:
|
||||||
|
number_of_names = 30
|
||||||
|
name_list_o = list(range(number_of_names * 7))
|
||||||
|
name_list_s = []
|
||||||
|
|
||||||
|
name_list_base = []
|
||||||
|
name_list_copy = list(self.multiworld.player_name.values())
|
||||||
|
name_list_copy.remove(self.multiworld.player_name[self.player])
|
||||||
|
|
||||||
|
if len(name_list_copy) >= number_of_names:
|
||||||
|
name_list_base = self.random.sample(name_list_copy, number_of_names)
|
||||||
|
else:
|
||||||
|
name_list_base = name_list_copy
|
||||||
|
self.random.shuffle(name_list_base)
|
||||||
|
|
||||||
|
name_list_base += self.random.sample(sample_chao_names, number_of_names - len(name_list_base))
|
||||||
|
|
||||||
|
for name in name_list_base:
|
||||||
|
for char_idx in range(7):
|
||||||
|
if char_idx < len(name):
|
||||||
|
name_list_s.append(chao_name_conversion[name[char_idx]])
|
||||||
|
else:
|
||||||
|
name_list_s.append(0x00)
|
||||||
|
|
||||||
|
return dict(zip(name_list_o, name_list_s))
|
||||||
|
|
||||||
|
def generate_black_market_data(self) -> typing.Dict[int, int]:
|
||||||
|
if self.options.black_market_slots.value == 0:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
ring_costs = [50, 75, 100]
|
||||||
|
|
||||||
|
market_data = {}
|
||||||
|
item_names = []
|
||||||
|
player_names = []
|
||||||
|
progression_flags = []
|
||||||
|
totally_real_item_names_copy = totally_real_item_names.copy()
|
||||||
|
location_names = [(LocationName.chao_black_market_base + str(i)) for i in range(1, self.options.black_market_slots.value + 1)]
|
||||||
|
locations = [self.multiworld.get_location(location_name, self.player) for location_name in location_names]
|
||||||
|
for location in locations:
|
||||||
|
if location.item.classification & ItemClassification.trap:
|
||||||
|
item_name = self.random.choice(totally_real_item_names_copy)
|
||||||
|
totally_real_item_names_copy.remove(item_name)
|
||||||
|
item_names.append(item_name)
|
||||||
|
else:
|
||||||
|
item_names.append(location.item.name)
|
||||||
|
player_names.append(self.multiworld.player_name[location.item.player])
|
||||||
|
|
||||||
|
if location.item.classification & ItemClassification.progression or location.item.classification & ItemClassification.trap:
|
||||||
|
progression_flags.append(2)
|
||||||
|
elif location.item.classification & ItemClassification.useful:
|
||||||
|
progression_flags.append(1)
|
||||||
|
else:
|
||||||
|
progression_flags.append(0)
|
||||||
|
|
||||||
|
for item_idx in range(self.options.black_market_slots.value):
|
||||||
|
for chr_idx in range(len(item_names[item_idx][:26])):
|
||||||
|
market_data[(item_idx * 46) + chr_idx] = ord(item_names[item_idx][chr_idx])
|
||||||
|
for chr_idx in range(len(player_names[item_idx][:16])):
|
||||||
|
market_data[(item_idx * 46) + 26 + chr_idx] = ord(player_names[item_idx][chr_idx])
|
||||||
|
|
||||||
|
market_data[(item_idx * 46) + 42] = ring_costs[progression_flags[item_idx]] * self.options.black_market_price_multiplier.value
|
||||||
|
|
||||||
|
return market_data
|
||||||
|
|
||||||
|
def generate_er_layout(self) -> typing.Dict[int, int]:
|
||||||
|
if not self.options.chao_entrance_randomization:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
er_layout = {}
|
||||||
|
|
||||||
|
start_exit = self.random.randint(0, 3)
|
||||||
|
accessible_rooms = []
|
||||||
|
|
||||||
|
multi_rooms_copy = multi_rooms.copy()
|
||||||
|
single_rooms_copy = single_rooms.copy()
|
||||||
|
all_exits_copy = all_exits.copy()
|
||||||
|
all_destinations_copy = all_destinations.copy()
|
||||||
|
|
||||||
|
multi_rooms_copy.remove(0x07)
|
||||||
|
accessible_rooms.append(0x07)
|
||||||
|
|
||||||
|
# Place Kindergarten somewhere sane
|
||||||
|
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)
|
||||||
|
all_destinations_copy.remove(destination)
|
||||||
|
|
||||||
|
er_layout[exit_choice] = destination
|
||||||
|
|
||||||
|
reverse_exit = self.random.choice(room_to_exits_map[destination])
|
||||||
|
|
||||||
|
er_layout[reverse_exit] = exit_to_room_map[exit_choice]
|
||||||
|
|
||||||
|
all_exits_copy.remove(reverse_exit)
|
||||||
|
all_destinations_copy.remove(exit_room)
|
||||||
|
|
||||||
|
# Connect multi-exit rooms
|
||||||
|
loop_guard = 0
|
||||||
|
while len(multi_rooms_copy) > 0:
|
||||||
|
loop_guard += 1
|
||||||
|
if loop_guard > 2000:
|
||||||
|
logging.warning(f"Failed to generate Chao Entrance Randomization for player: {self.multiworld.player_name[self.player]}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
exit_room = self.random.choice(accessible_rooms)
|
||||||
|
possible_exits = [exit for exit in room_to_exits_map[exit_room] if exit in all_exits_copy]
|
||||||
|
if len(possible_exits) == 0:
|
||||||
|
continue
|
||||||
|
exit_choice = self.random.choice(possible_exits)
|
||||||
|
all_exits_copy.remove(exit_choice)
|
||||||
|
|
||||||
|
destination = self.random.choice(multi_rooms_copy)
|
||||||
|
multi_rooms_copy.remove(destination)
|
||||||
|
all_destinations_copy.remove(destination)
|
||||||
|
accessible_rooms.append(destination)
|
||||||
|
|
||||||
|
er_layout[exit_choice] = destination
|
||||||
|
|
||||||
|
reverse_exit = self.random.choice(room_to_exits_map[destination])
|
||||||
|
|
||||||
|
er_layout[reverse_exit] = exit_room
|
||||||
|
|
||||||
|
all_exits_copy.remove(reverse_exit)
|
||||||
|
all_destinations_copy.remove(exit_room)
|
||||||
|
|
||||||
|
# Connect dead-end rooms
|
||||||
|
loop_guard = 0
|
||||||
|
while len(single_rooms_copy) > 0:
|
||||||
|
loop_guard += 1
|
||||||
|
if loop_guard > 2000:
|
||||||
|
logging.warning(f"Failed to generate Chao Entrance Randomization for player: {self.multiworld.player_name[self.player]}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
exit_room = self.random.choice(accessible_rooms)
|
||||||
|
possible_exits = [exit for exit in room_to_exits_map[exit_room] if exit in all_exits_copy]
|
||||||
|
if len(possible_exits) == 0:
|
||||||
|
continue
|
||||||
|
exit_choice = self.random.choice(possible_exits)
|
||||||
|
all_exits_copy.remove(exit_choice)
|
||||||
|
|
||||||
|
destination = self.random.choice(single_rooms_copy)
|
||||||
|
single_rooms_copy.remove(destination)
|
||||||
|
all_destinations_copy.remove(destination)
|
||||||
|
|
||||||
|
er_layout[exit_choice] = destination
|
||||||
|
|
||||||
|
reverse_exit = self.random.choice(room_to_exits_map[destination])
|
||||||
|
|
||||||
|
er_layout[reverse_exit] = exit_room
|
||||||
|
|
||||||
|
all_exits_copy.remove(reverse_exit)
|
||||||
|
all_destinations_copy.remove(exit_room)
|
||||||
|
|
||||||
|
# Connect remaining exits
|
||||||
|
loop_guard = 0
|
||||||
|
while len(all_exits_copy) > 0:
|
||||||
|
loop_guard += 1
|
||||||
|
if loop_guard > 2000:
|
||||||
|
logging.warning(f"Failed to generate Chao Entrance Randomization for player: {self.multiworld.player_name[self.player]}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
exit_room = self.random.choice(all_destinations_copy)
|
||||||
|
possible_exits = [exit for exit in room_to_exits_map[exit_room] if exit in all_exits_copy]
|
||||||
|
if len(possible_exits) == 0:
|
||||||
|
continue
|
||||||
|
exit_choice = self.random.choice(possible_exits)
|
||||||
|
all_exits_copy.remove(exit_choice)
|
||||||
|
all_destinations_copy.remove(exit_room)
|
||||||
|
|
||||||
|
destination = self.random.choice(all_destinations_copy)
|
||||||
|
all_destinations_copy.remove(destination)
|
||||||
|
|
||||||
|
er_layout[exit_choice] = 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
|
||||||
|
|
||||||
|
all_exits_copy.remove(reverse_exit)
|
||||||
|
|
||||||
|
return er_layout
|
||||||
|
|
|
@ -127,9 +127,6 @@ If you wish to use the `SADX Music` option of the Randomizer, you must own a cop
|
||||||
- Mission 1 is missing a texture in the stage select UI.
|
- Mission 1 is missing a texture in the stage select UI.
|
||||||
- Most likely another mod is conflicting and overwriting the texture pack. It is recommeded to have the SA2B Archipelago mod load last in the mod loader.
|
- Most likely another mod is conflicting and overwriting the texture pack. It is recommeded to have the SA2B Archipelago mod load last in the mod loader.
|
||||||
|
|
||||||
- Received Cutscene Traps don't play after beating a level.
|
|
||||||
- Make sure you don't have the "`Skip Intro`" option enabled in the mod manager.
|
|
||||||
|
|
||||||
## Save File Safeguard (Advanced Option)
|
## Save File Safeguard (Advanced Option)
|
||||||
|
|
||||||
The mod contains a save file safeguard which associates a savefile to a specific Archipelago seed. By default, save files can only connect to Archipelago servers that match their seed. The safeguard can be disabled in the mod config.ini by setting `IgnoreFileSafety` to true. This is NOT recommended for the standard user as it will allow any save file to connect and send items to the Archipelago server.
|
The mod contains a save file safeguard which associates a savefile to a specific Archipelago seed. By default, save files can only connect to Archipelago servers that match their seed. The safeguard can be disabled in the mod config.ini by setting `IgnoreFileSafety` to true. This is NOT recommended for the standard user as it will allow any save file to connect and send items to the Archipelago server.
|
||||||
|
|
Loading…
Reference in New Issue