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
|
||||
from BaseClasses import MultiWorld
|
||||
from worlds.AutoWorld import World
|
||||
|
||||
speed_characters_1 = "Sonic vs Shadow 1"
|
||||
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)
|
||||
|
||||
|
||||
def get_gate_bosses(world, player: int):
|
||||
def get_gate_bosses(multiworld: MultiWorld, world: World):
|
||||
selected_bosses: typing.List[int] = []
|
||||
boss_gates: typing.List[int] = []
|
||||
available_bosses: typing.List[str] = list(gate_bosses_no_requirements_table.keys())
|
||||
world.random.shuffle(available_bosses)
|
||||
multiworld.random.shuffle(available_bosses)
|
||||
halfway = False
|
||||
|
||||
for x in range(world.number_of_level_gates[player]):
|
||||
if (not halfway) and ((x + 1) / world.number_of_level_gates[player]) > 0.5:
|
||||
for x in range(world.options.number_of_level_gates):
|
||||
if (not halfway) and ((x + 1) / world.options.number_of_level_gates) > 0.5:
|
||||
available_bosses.extend(gate_bosses_with_requirements_table)
|
||||
world.random.shuffle(available_bosses)
|
||||
multiworld.random.shuffle(available_bosses)
|
||||
halfway = True
|
||||
selected_bosses.append(all_gate_bosses_table[available_bosses[0]])
|
||||
boss_gates.append(x + 1)
|
||||
|
@ -80,27 +82,27 @@ def get_gate_bosses(world, player: int):
|
|||
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_s = [5, 2, 0, 10, 8, 4, 3, 1, 6, 13, 7, 11, 9, 15, 14, 12]
|
||||
|
||||
return dict(zip(boss_list_o, boss_list_s))
|
||||
elif multiworld.boss_rush_shuffle[player] == 1:
|
||||
elif world.options.boss_rush_shuffle == 1:
|
||||
boss_list_o = list(range(0, 16))
|
||||
boss_list_s = boss_list_o.copy()
|
||||
multiworld.random.shuffle(boss_list_s)
|
||||
|
||||
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_s = [multiworld.random.choice(boss_list_o) for i in range(0, 16)]
|
||||
if 10 not in boss_list_s:
|
||||
boss_list_s[multiworld.random.randint(0, 15)] = 10
|
||||
|
||||
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_s = [multiworld.random.choice(boss_list_o)] * len(boss_list_o)
|
||||
if 10 not in boss_list_s:
|
||||
|
|
|
@ -22,7 +22,8 @@ class SA2BItem(Item):
|
|||
|
||||
# Separate tables for each type of item.
|
||||
emblems_table = {
|
||||
ItemName.emblem: ItemData(0xFF0000, True),
|
||||
ItemName.emblem: ItemData(0xFF0000, True),
|
||||
ItemName.market_token: ItemData(0xFF001F, True),
|
||||
}
|
||||
|
||||
upgrades_table = {
|
||||
|
@ -82,6 +83,7 @@ trap_table = {
|
|||
ItemName.ice_trap: ItemData(0xFF0037, False, True),
|
||||
ItemName.slow_trap: ItemData(0xFF0038, False, True),
|
||||
ItemName.cutscene_trap: ItemData(0xFF0039, False, True),
|
||||
ItemName.reverse_trap: ItemData(0xFF003A, False, True),
|
||||
|
||||
ItemName.pong_trap: ItemData(0xFF0050, False, True),
|
||||
}
|
||||
|
@ -96,6 +98,142 @@ emeralds_table = {
|
|||
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 = {
|
||||
ItemName.maria: ItemData(0xFF001D, True),
|
||||
}
|
||||
|
@ -107,12 +245,25 @@ item_table = {
|
|||
**junk_table,
|
||||
**trap_table,
|
||||
**emeralds_table,
|
||||
**eggs_table,
|
||||
**fruits_table,
|
||||
**seeds_table,
|
||||
**hats_table,
|
||||
**animals_table,
|
||||
**chaos_drives_table,
|
||||
**event_table,
|
||||
}
|
||||
|
||||
lookup_id_to_name: typing.Dict[int, str] = {data.code: item_name for item_name, data in item_table.items() if data.code}
|
||||
|
||||
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.shadow_air_shoes].code] = "and the Soap Shoes"
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import typing
|
||||
|
||||
from BaseClasses import Location, MultiWorld
|
||||
from worlds.AutoWorld import World
|
||||
from .Names import LocationName
|
||||
from .Missions import stage_name_prefixes, mission_orders
|
||||
|
||||
|
@ -1066,6 +1067,7 @@ animal_location_table = {
|
|||
LocationName.final_rush_animal_11: 0xFF0C4F,
|
||||
|
||||
LocationName.iron_gate_animal_11: 0xFF0C50,
|
||||
LocationName.dry_lagoon_animal_11: 0xFF0C51,
|
||||
LocationName.sand_ocean_animal_11: 0xFF0C52,
|
||||
LocationName.radical_highway_animal_11: 0xFF0C53,
|
||||
LocationName.lost_colony_animal_11: 0xFF0C55,
|
||||
|
@ -1241,7 +1243,7 @@ boss_rush_location_table = {
|
|||
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_2: 0xFF0201,
|
||||
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_2: 0xFF020A,
|
||||
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_2: 0xFF022B,
|
||||
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_3: 0xFF023C,
|
||||
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_2: 0xFF020D,
|
||||
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_4: 0xFF0228,
|
||||
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 = {
|
||||
LocationName.kart_race_beginner_sonic: 0xFF0A00,
|
||||
LocationName.kart_race_beginner_tails: 0xFF0A01,
|
||||
|
@ -1375,6 +1565,10 @@ grand_prix_location_table = {
|
|||
LocationName.grand_prix: 0xFF007F,
|
||||
}
|
||||
|
||||
chaos_chao_location_table = {
|
||||
LocationName.chaos_chao: 0xFF009F,
|
||||
}
|
||||
|
||||
all_locations = {
|
||||
**mission_location_table,
|
||||
**upgrade_location_table,
|
||||
|
@ -1386,9 +1580,13 @@ all_locations = {
|
|||
**beetle_location_table,
|
||||
**omochao_location_table,
|
||||
**animal_location_table,
|
||||
**chao_garden_beginner_location_table,
|
||||
**chao_garden_intermediate_location_table,
|
||||
**chao_garden_expert_location_table,
|
||||
**chao_race_beginner_location_table,
|
||||
**chao_karate_beginner_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_standard_location_table,
|
||||
**kart_race_expert_location_table,
|
||||
|
@ -1398,6 +1596,18 @@ all_locations = {
|
|||
**green_hill_animal_location_table,
|
||||
**final_boss_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 = [
|
||||
|
@ -1408,13 +1618,6 @@ boss_gate_set = [
|
|||
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 = [
|
||||
LocationName.chao_race_crab_pool_3,
|
||||
LocationName.chao_race_stump_valley_3,
|
||||
|
@ -1437,19 +1640,24 @@ chao_race_prize_set = [
|
|||
|
||||
LocationName.chao_race_dark_2,
|
||||
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 = {}
|
||||
chao_location_table = {}
|
||||
|
||||
if world.goal[player] == 3:
|
||||
if world.kart_race_checks[player] == 2:
|
||||
if world.options.goal == 3:
|
||||
if world.options.kart_race_checks == 2:
|
||||
location_table.update({**kart_race_beginner_location_table})
|
||||
location_table.update({**kart_race_standard_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({**grand_prix_location_table})
|
||||
else:
|
||||
|
@ -1465,67 +1673,100 @@ def setup_locations(world: MultiWorld, player: int, mission_map: typing.Dict[int
|
|||
|
||||
location_table.update({**upgrade_location_table})
|
||||
|
||||
if world.keysanity[player]:
|
||||
if world.options.keysanity:
|
||||
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})
|
||||
elif world.whistlesanity[player].value == 2:
|
||||
elif world.options.whistlesanity.value == 2:
|
||||
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({**hidden_whistle_location_table})
|
||||
|
||||
if world.beetlesanity[player]:
|
||||
if world.options.beetlesanity:
|
||||
location_table.update({**beetle_location_table})
|
||||
|
||||
if world.omosanity[player]:
|
||||
if world.options.omosanity:
|
||||
location_table.update({**omochao_location_table})
|
||||
|
||||
if world.animalsanity[player]:
|
||||
if world.options.animalsanity:
|
||||
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_standard_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})
|
||||
|
||||
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})
|
||||
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})
|
||||
|
||||
if world.keysanity[player]:
|
||||
if world.options.keysanity:
|
||||
location_table.update({**green_hill_chao_location_table})
|
||||
|
||||
if world.animalsanity[player]:
|
||||
if world.options.animalsanity:
|
||||
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})
|
||||
|
||||
if world.chao_garden_difficulty[player].value >= 1:
|
||||
chao_location_table.update({**chao_garden_beginner_location_table})
|
||||
if world.chao_garden_difficulty[player].value >= 2:
|
||||
chao_location_table.update({**chao_garden_intermediate_location_table})
|
||||
if world.chao_garden_difficulty[player].value >= 3:
|
||||
chao_location_table.update({**chao_garden_expert_location_table})
|
||||
if world.options.chao_race_difficulty.value >= 1:
|
||||
chao_location_table.update({**chao_race_beginner_location_table})
|
||||
if world.options.chao_race_difficulty.value >= 2:
|
||||
chao_location_table.update({**chao_race_intermediate_location_table})
|
||||
if world.options.chao_race_difficulty.value >= 3:
|
||||
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():
|
||||
if key in chao_karate_set:
|
||||
if world.include_chao_karate[player]:
|
||||
location_table[key] = value
|
||||
elif key not in chao_race_prize_set:
|
||||
if world.chao_race_checks[player] == "all":
|
||||
if key not in chao_race_prize_set:
|
||||
if world.options.chao_stadium_checks == "all":
|
||||
location_table[key] = value
|
||||
else:
|
||||
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)):
|
||||
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]]
|
||||
|
||||
return location_table
|
||||
|
|
|
@ -2,6 +2,7 @@ import typing
|
|||
import copy
|
||||
|
||||
from BaseClasses import MultiWorld
|
||||
from worlds.AutoWorld import World
|
||||
|
||||
|
||||
mission_orders: typing.List[typing.List[int]] = [
|
||||
|
@ -193,10 +194,10 @@ stage_name_prefixes: typing.List[str] = [
|
|||
"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] = {}
|
||||
|
||||
if multiworld.goal[player] == 3:
|
||||
if world.options.goal == 3:
|
||||
for level in range(31):
|
||||
mission_count_table[level] = 0
|
||||
else:
|
||||
|
@ -207,26 +208,26 @@ def get_mission_count_table(multiworld: MultiWorld, player: int):
|
|||
cannons_core_active_missions = 1
|
||||
|
||||
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
|
||||
|
||||
if getattr(multiworld, "mech_mission_" + str(i), None)[player]:
|
||||
if getattr(world.options, "mech_mission_" + str(i), None):
|
||||
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
|
||||
|
||||
if getattr(multiworld, "kart_mission_" + str(i), None)[player]:
|
||||
if getattr(world.options, "kart_mission_" + str(i), None):
|
||||
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
|
||||
|
||||
speed_active_missions = min(speed_active_missions, multiworld.speed_mission_count[player].value)
|
||||
mech_active_missions = min(mech_active_missions, multiworld.mech_mission_count[player].value)
|
||||
hunt_active_missions = min(hunt_active_missions, multiworld.hunt_mission_count[player].value)
|
||||
kart_active_missions = min(kart_active_missions, multiworld.kart_mission_count[player].value)
|
||||
cannons_core_active_missions = min(cannons_core_active_missions, multiworld.cannons_core_mission_count[player].value)
|
||||
speed_active_missions = min(speed_active_missions, world.options.speed_mission_count.value)
|
||||
mech_active_missions = min(mech_active_missions, world.options.mech_mission_count.value)
|
||||
hunt_active_missions = min(hunt_active_missions, world.options.hunt_mission_count.value)
|
||||
kart_active_missions = min(kart_active_missions, world.options.kart_mission_count.value)
|
||||
cannons_core_active_missions = min(cannons_core_active_missions, world.options.cannons_core_mission_count.value)
|
||||
|
||||
active_missions: typing.List[typing.List[int]] = [
|
||||
speed_active_missions,
|
||||
|
@ -244,10 +245,10 @@ def get_mission_count_table(multiworld: MultiWorld, player: int):
|
|||
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] = {}
|
||||
|
||||
if multiworld.goal[player] == 3:
|
||||
if world.options.goal == 3:
|
||||
for level in range(31):
|
||||
mission_table[level] = 0
|
||||
else:
|
||||
|
@ -259,19 +260,19 @@ def get_mission_table(multiworld: MultiWorld, player: int):
|
|||
|
||||
# Add included missions
|
||||
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)
|
||||
|
||||
if getattr(multiworld, "mech_mission_" + str(i), None)[player]:
|
||||
if getattr(world.options, "mech_mission_" + str(i), None):
|
||||
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)
|
||||
|
||||
if getattr(multiworld, "kart_mission_" + str(i), None)[player]:
|
||||
if getattr(world.options, "kart_mission_" + str(i), None):
|
||||
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)
|
||||
|
||||
active_missions: typing.List[typing.List[int]] = [
|
||||
|
@ -292,10 +293,10 @@ def get_mission_table(multiworld: MultiWorld, player: int):
|
|||
first_mission = 1
|
||||
first_mission_options = [1, 2, 3]
|
||||
|
||||
if not multiworld.animalsanity[player]:
|
||||
if not world.options.animalsanity:
|
||||
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])
|
||||
|
||||
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:
|
||||
level_chosen_missions.append(mission)
|
||||
|
||||
if multiworld.mission_shuffle[player]:
|
||||
if world.options.mission_shuffle:
|
||||
multiworld.random.shuffle(level_chosen_missions)
|
||||
|
||||
level_chosen_missions.insert(0, first_mission)
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
# Emblem Definition
|
||||
emblem = "Emblem"
|
||||
|
||||
# Market Token Definition
|
||||
market_token = "Chao Coin"
|
||||
|
||||
# Upgrade Definitions
|
||||
sonic_gloves = "Sonic - Magic Glove"
|
||||
sonic_light_shoes = "Sonic - Light Shoes"
|
||||
|
@ -36,6 +39,8 @@ rouge_pick_nails = "Rouge - Pick Nails"
|
|||
rouge_treasure_scope = "Rouge - Treasure Scope"
|
||||
rouge_iron_boots = "Rouge - Iron Boots"
|
||||
|
||||
|
||||
# Junk
|
||||
five_rings = "Five Rings"
|
||||
ten_rings = "Ten Rings"
|
||||
twenty_rings = "Twenty Rings"
|
||||
|
@ -44,6 +49,8 @@ shield = "Shield"
|
|||
magnetic_shield = "Magnetic Shield"
|
||||
invincibility = "Invincibility"
|
||||
|
||||
|
||||
# Traps
|
||||
omochao_trap = "OmoTrap"
|
||||
timestop_trap = "Chaos Control Trap"
|
||||
confuse_trap = "Confusion Trap"
|
||||
|
@ -54,9 +61,12 @@ darkness_trap = "Darkness Trap"
|
|||
ice_trap = "Ice Trap"
|
||||
slow_trap = "Slow Trap"
|
||||
cutscene_trap = "Cutscene Trap"
|
||||
reverse_trap = "Reverse Trap"
|
||||
|
||||
pong_trap = "Pong Trap"
|
||||
|
||||
|
||||
# Chaos Emeralds
|
||||
white_emerald = "White Chaos Emerald"
|
||||
red_emerald = "Red Chaos Emerald"
|
||||
cyan_emerald = "Cyan Chaos Emerald"
|
||||
|
@ -65,4 +75,140 @@ green_emerald = "Green Chaos Emerald"
|
|||
yellow_emerald = "Yellow 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"
|
||||
|
|
|
@ -909,6 +909,7 @@ dry_lagoon_animal_7 = "Dry Lagoon - 7 Animals"
|
|||
dry_lagoon_animal_8 = "Dry Lagoon - 8 Animals"
|
||||
dry_lagoon_animal_9 = "Dry Lagoon - 9 Animals"
|
||||
dry_lagoon_animal_10 = "Dry Lagoon - 10 Animals"
|
||||
dry_lagoon_animal_11 = "Dry Lagoon - 11 Animals"
|
||||
dry_lagoon_upgrade = "Dry Lagoon - Upgrade"
|
||||
egg_quarters_1 = "Egg Quarters - 1"
|
||||
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_4 = "Chao Race - Dark 4"
|
||||
|
||||
chao_beginner_karate = "Chao Karate - Beginner"
|
||||
chao_standard_karate = "Chao Karate - Standard"
|
||||
chao_expert_karate = "Chao Karate - Expert"
|
||||
chao_super_karate = "Chao Karate - Super"
|
||||
chao_beginner_karate_1 = "Chao Karate - Beginner 1"
|
||||
chao_beginner_karate_2 = "Chao Karate - Beginner 2"
|
||||
chao_beginner_karate_3 = "Chao Karate - Beginner 3"
|
||||
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_beginner_sonic = "Kart Race - Beginner - Sonic"
|
||||
|
@ -1261,9 +1442,18 @@ green_hill_region = "Green Hill"
|
|||
grand_prix = "Grand Prix"
|
||||
grand_prix_region = "Grand Prix"
|
||||
|
||||
chao_garden_beginner_region = "Chao Garden - Beginner"
|
||||
chao_garden_intermediate_region = "Chao Garden - Intermediate"
|
||||
chao_garden_expert_region = "Chao Garden - Expert"
|
||||
chao_race_beginner_region = "Chao Race - Beginner"
|
||||
chao_race_intermediate_region = "Chao Race - Intermediate"
|
||||
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_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
|
||||
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
|
||||
Chaos Chao: Raise a Chaos Chao to win
|
||||
"""
|
||||
display_name = "Goal"
|
||||
option_biolizard = 0
|
||||
|
@ -22,6 +23,7 @@ class Goal(Choice):
|
|||
option_boss_rush = 4
|
||||
option_cannons_core_boss_rush = 5
|
||||
option_boss_rush_chaos_emerald_hunt = 6
|
||||
option_chaos_chao = 7
|
||||
default = 0
|
||||
|
||||
@classmethod
|
||||
|
@ -70,74 +72,81 @@ class BaseTrapWeight(Choice):
|
|||
|
||||
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"
|
||||
|
||||
|
||||
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"
|
||||
|
||||
|
||||
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"
|
||||
|
||||
|
||||
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"
|
||||
|
||||
|
||||
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"
|
||||
|
||||
|
||||
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"
|
||||
|
||||
|
||||
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"
|
||||
|
||||
|
||||
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"
|
||||
|
||||
|
||||
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"
|
||||
|
||||
|
||||
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"
|
||||
|
||||
|
||||
class ReverseTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of receiving a trap which reverses your controls
|
||||
"""
|
||||
display_name = "Reverse Trap Weight"
|
||||
|
||||
|
||||
class PongTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of receiving a trap which forces you to play a Pong minigame
|
||||
|
@ -219,7 +228,7 @@ class Omosanity(Toggle):
|
|||
class Animalsanity(Toggle):
|
||||
"""
|
||||
Determines whether picking up counted small animals grants checks
|
||||
(420 Locations)
|
||||
(421 Locations)
|
||||
"""
|
||||
display_name = "Animalsanity"
|
||||
|
||||
|
@ -291,7 +300,7 @@ class MaximumEmblemCap(Range):
|
|||
"""
|
||||
display_name = "Max Emblem Cap"
|
||||
range_start = 50
|
||||
range_end = 500
|
||||
range_end = 1000
|
||||
default = 180
|
||||
|
||||
|
||||
|
@ -308,15 +317,15 @@ class RequiredRank(Choice):
|
|||
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
|
||||
None: No Chao Garden Activities have checks
|
||||
Determines the number of Chao Race difficulty levels included. Easier difficulty settings means fewer Chao Race checks
|
||||
None: No Chao Races have checks
|
||||
Beginner: Beginner Races
|
||||
Intermediate: Beginner, Challenge, Hero, and Dark Races
|
||||
Expert: Beginner, Challenge, Hero, Dark and Jewel Races
|
||||
"""
|
||||
display_name = "Chao Garden Difficulty"
|
||||
display_name = "Chao Race Difficulty"
|
||||
option_none = 0
|
||||
option_beginner = 1
|
||||
option_intermediate = 2
|
||||
|
@ -324,26 +333,138 @@ class ChaoGardenDifficulty(Choice):
|
|||
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
|
||||
All: Each individual race grants a check
|
||||
Determines which Chao Stadium activities grant checks
|
||||
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
|
||||
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_prize = 1
|
||||
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):
|
||||
"""
|
||||
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)] = {
|
||||
"goal": Goal,
|
||||
|
||||
"mission_shuffle": MissionShuffle,
|
||||
"boss_rush_shuffle": BossRushShuffle,
|
||||
|
||||
"keysanity": Keysanity,
|
||||
"whistlesanity": Whistlesanity,
|
||||
"beetlesanity": Beetlesanity,
|
||||
"omosanity": Omosanity,
|
||||
"animalsanity": Animalsanity,
|
||||
"kart_race_checks": KartRaceChecks,
|
||||
|
||||
"logic_difficulty": LogicDifficulty,
|
||||
"required_rank": RequiredRank,
|
||||
"emblem_percentage_for_cannons_core": EmblemPercentageForCannonsCore,
|
||||
"required_cannons_core_missions": RequiredCannonsCoreMissions,
|
||||
|
||||
"emblem_percentage_for_cannons_core": EmblemPercentageForCannonsCore,
|
||||
"number_of_level_gates": NumberOfLevelGates,
|
||||
"level_gate_distribution": LevelGateDistribution,
|
||||
"level_gate_costs": LevelGateCosts,
|
||||
"max_emblem_cap": MaximumEmblemCap,
|
||||
"chao_garden_difficulty": ChaoGardenDifficulty,
|
||||
"include_chao_karate": IncludeChaoKarate,
|
||||
"chao_race_checks": ChaoRaceChecks,
|
||||
|
||||
"chao_race_difficulty": ChaoRaceDifficulty,
|
||||
"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,
|
||||
"trap_fill_percentage": TrapFillPercentage,
|
||||
"omochao_trap_weight": OmochaoTrapWeight,
|
||||
|
@ -687,39 +826,46 @@ sa2b_options: typing.Dict[str, type(Option)] = {
|
|||
"ice_trap_weight": IceTrapWeight,
|
||||
"slow_trap_weight": SlowTrapWeight,
|
||||
"cutscene_trap_weight": CutsceneTrapWeight,
|
||||
"reverse_trap_weight": ReverseTrapWeight,
|
||||
"pong_trap_weight": PongTrapWeight,
|
||||
"minigame_trap_difficulty": MinigameTrapDifficulty,
|
||||
"ring_loss": RingLoss,
|
||||
"ring_link": RingLink,
|
||||
|
||||
"sadx_music": SADXMusic,
|
||||
"music_shuffle": MusicShuffle,
|
||||
"voice_shuffle": VoiceShuffle,
|
||||
"narrator": Narrator,
|
||||
"logic_difficulty": LogicDifficulty,
|
||||
"ring_loss": RingLoss,
|
||||
|
||||
"speed_mission_count": SpeedMissionCount,
|
||||
"speed_mission_2": SpeedMission2,
|
||||
"speed_mission_3": SpeedMission3,
|
||||
"speed_mission_4": SpeedMission4,
|
||||
"speed_mission_5": SpeedMission5,
|
||||
|
||||
"mech_mission_count": MechMissionCount,
|
||||
"mech_mission_2": MechMission2,
|
||||
"mech_mission_3": MechMission3,
|
||||
"mech_mission_4": MechMission4,
|
||||
"mech_mission_5": MechMission5,
|
||||
|
||||
"hunt_mission_count": HuntMissionCount,
|
||||
"hunt_mission_2": HuntMission2,
|
||||
"hunt_mission_3": HuntMission3,
|
||||
"hunt_mission_4": HuntMission4,
|
||||
"hunt_mission_5": HuntMission5,
|
||||
|
||||
"kart_mission_count": KartMissionCount,
|
||||
"kart_mission_2": KartMission2,
|
||||
"kart_mission_3": KartMission3,
|
||||
"kart_mission_4": KartMission4,
|
||||
"kart_mission_5": KartMission5,
|
||||
|
||||
"cannons_core_mission_count": CannonsCoreMissionCount,
|
||||
"cannons_core_mission_2": CannonsCoreMission2,
|
||||
"cannons_core_mission_3": CannonsCoreMission3,
|
||||
"cannons_core_mission_4": CannonsCoreMission4,
|
||||
"cannons_core_mission_5": CannonsCoreMission5,
|
||||
|
||||
"ring_link": RingLink,
|
||||
"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 math
|
||||
import logging
|
||||
|
||||
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 .Locations import SA2BLocation, all_locations, setup_locations
|
||||
from .Items import SA2BItem, ItemData, item_table, upgrades_table, emeralds_table, junk_table, trap_table, item_groups, \
|
||||
eggs_table, fruits_table, seeds_table, hats_table, animals_table, chaos_drives_table
|
||||
from .Locations import SA2BLocation, all_locations, setup_locations, chao_animal_event_location_table, black_market_location_table
|
||||
from .Options import sa2b_options
|
||||
from .Regions import create_regions, shuffleable_regions, connect_regions, LevelGate, gate_0_whitelist_regions, \
|
||||
gate_0_blacklist_regions
|
||||
from .Rules import set_rules
|
||||
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 .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
|
||||
|
@ -52,7 +56,7 @@ class SA2BWorld(World):
|
|||
game: str = "Sonic Adventure 2 Battle"
|
||||
option_definitions = sa2b_options
|
||||
topology_present = False
|
||||
data_version = 6
|
||||
data_version = 7
|
||||
|
||||
item_name_groups = item_groups
|
||||
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]
|
||||
|
||||
music_map: typing.Dict[int, int]
|
||||
voice_map: typing.Dict[int, int]
|
||||
mission_map: typing.Dict[int, int]
|
||||
mission_count_map: typing.Dict[int, int]
|
||||
emblems_for_cannons_core: int
|
||||
|
@ -69,138 +71,126 @@ class SA2BWorld(World):
|
|||
gate_costs: typing.Dict[int, int]
|
||||
gate_bosses: typing.Dict[int, int]
|
||||
boss_rush_map: typing.Dict[int, int]
|
||||
black_market_costs: typing.Dict[int, int]
|
||||
|
||||
web = SA2BWeb()
|
||||
|
||||
def _get_slot_data(self):
|
||||
def fill_slot_data(self) -> dict:
|
||||
return {
|
||||
"ModVersion": 202,
|
||||
"Goal": self.multiworld.goal[self.player].value,
|
||||
"MusicMap": self.music_map,
|
||||
"VoiceMap": self.voice_map,
|
||||
"ModVersion": 203,
|
||||
"Goal": self.options.goal.value,
|
||||
"MusicMap": self.generate_music_data(),
|
||||
"VoiceMap": self.generate_voice_data(),
|
||||
"DefaultEggMap": self.generate_chao_egg_data(),
|
||||
"DefaultChaoNameMap": self.generate_chao_name_data(),
|
||||
"MissionMap": self.mission_map,
|
||||
"MissionCountMap": self.mission_count_map,
|
||||
"MusicShuffle": self.multiworld.music_shuffle[self.player].value,
|
||||
"Narrator": self.multiworld.narrator[self.player].value,
|
||||
"MinigameTrapDifficulty": self.multiworld.minigame_trap_difficulty[self.player].value,
|
||||
"RingLoss": self.multiworld.ring_loss[self.player].value,
|
||||
"RingLink": self.multiworld.ring_link[self.player].value,
|
||||
"RequiredRank": self.multiworld.required_rank[self.player].value,
|
||||
"ChaoKeys": self.multiworld.keysanity[self.player].value,
|
||||
"Whistlesanity": self.multiworld.whistlesanity[self.player].value,
|
||||
"GoldBeetles": self.multiworld.beetlesanity[self.player].value,
|
||||
"OmochaoChecks": self.multiworld.omosanity[self.player].value,
|
||||
"AnimalChecks": self.multiworld.animalsanity[self.player].value,
|
||||
"KartRaceChecks": self.multiworld.kart_race_checks[self.player].value,
|
||||
"ChaoRaceChecks": self.multiworld.chao_race_checks[self.player].value,
|
||||
"ChaoGardenDifficulty": self.multiworld.chao_garden_difficulty[self.player].value,
|
||||
"DeathLink": self.multiworld.death_link[self.player].value,
|
||||
"EmblemPercentageForCannonsCore": self.multiworld.emblem_percentage_for_cannons_core[self.player].value,
|
||||
"RequiredCannonsCoreMissions": self.multiworld.required_cannons_core_missions[self.player].value,
|
||||
"NumberOfLevelGates": self.multiworld.number_of_level_gates[self.player].value,
|
||||
"LevelGateDistribution": self.multiworld.level_gate_distribution[self.player].value,
|
||||
"MusicShuffle": self.options.music_shuffle.value,
|
||||
"Narrator": self.options.narrator.value,
|
||||
"MinigameTrapDifficulty": self.options.minigame_trap_difficulty.value,
|
||||
"RingLoss": self.options.ring_loss.value,
|
||||
"RingLink": self.options.ring_link.value,
|
||||
"RequiredRank": self.options.required_rank.value,
|
||||
"ChaoKeys": self.options.keysanity.value,
|
||||
"Whistlesanity": self.options.whistlesanity.value,
|
||||
"GoldBeetles": self.options.beetlesanity.value,
|
||||
"OmochaoChecks": self.options.omosanity.value,
|
||||
"AnimalChecks": self.options.animalsanity.value,
|
||||
"KartRaceChecks": self.options.kart_race_checks.value,
|
||||
"ChaoStadiumChecks": self.options.chao_stadium_checks.value,
|
||||
"ChaoRaceDifficulty": self.options.chao_race_difficulty.value,
|
||||
"ChaoKarateDifficulty": self.options.chao_karate_difficulty.value,
|
||||
"ChaoStats": self.options.chao_stats.value,
|
||||
"ChaoStatsFrequency": self.options.chao_stats_frequency.value,
|
||||
"ChaoStatsStamina": self.options.chao_stats_stamina.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,
|
||||
"RegionEmblemMap": self.region_emblem_map,
|
||||
"GateCosts": self.gate_costs,
|
||||
"GateBosses": self.gate_bosses,
|
||||
"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):
|
||||
if self.multiworld.goal[self.player].value == 3:
|
||||
if self.options.goal.value == 3:
|
||||
# Turn off everything else for Grand Prix goal
|
||||
self.multiworld.number_of_level_gates[self.player].value = 0
|
||||
self.multiworld.emblem_percentage_for_cannons_core[self.player].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
|
||||
self.options.number_of_level_gates.value = 0
|
||||
self.options.emblem_percentage_for_cannons_core.value = 0
|
||||
|
||||
valid_trap_weights = self.multiworld.exposition_trap_weight[self.player].value + \
|
||||
self.multiworld.cutscene_trap_weight[self.player].value + \
|
||||
self.multiworld.pong_trap_weight[self.player].value
|
||||
self.options.chao_race_difficulty.value = 0
|
||||
self.options.chao_karate_difficulty.value = 0
|
||||
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:
|
||||
self.multiworld.exposition_trap_weight[self.player].value = 4
|
||||
self.multiworld.cutscene_trap_weight[self.player].value = 4
|
||||
self.multiworld.pong_trap_weight[self.player].value = 4
|
||||
self.options.exposition_trap_weight.value = 4
|
||||
self.options.reverse_trap_weight.value = 4
|
||||
self.options.pong_trap_weight.value = 4
|
||||
|
||||
if self.multiworld.kart_race_checks[self.player].value == 0:
|
||||
self.multiworld.kart_race_checks[self.player].value = 2
|
||||
if self.options.kart_race_checks.value == 0:
|
||||
self.options.kart_race_checks.value = 2
|
||||
|
||||
self.gate_bosses = {}
|
||||
self.boss_rush_map = {}
|
||||
else:
|
||||
self.gate_bosses = get_gate_bosses(self.multiworld, self.player)
|
||||
self.boss_rush_map = get_boss_rush_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)
|
||||
|
||||
def create_regions(self):
|
||||
self.mission_map = get_mission_table(self.multiworld, self.player)
|
||||
self.mission_count_map = get_mission_count_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, self.player)
|
||||
|
||||
self.location_table = setup_locations(self.multiworld, self.player, self.mission_map, self.mission_count_map)
|
||||
create_regions(self.multiworld, self.player, self.location_table)
|
||||
self.location_table = setup_locations(self, self.player, self.mission_map, self.mission_count_map)
|
||||
create_regions(self.multiworld, self, self.player, self.location_table)
|
||||
|
||||
# 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))
|
||||
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))
|
||||
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))
|
||||
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] = []
|
||||
|
||||
|
@ -208,28 +198,40 @@ class SA2BWorld(World):
|
|||
total_required_locations = len(self.location_table)
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
if self.multiworld.level_gate_costs[self.player].value == 0:
|
||||
if self.options.level_gate_costs.value == 0:
|
||||
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
|
||||
|
||||
shuffled_region_list = list(range(30))
|
||||
|
@ -253,8 +255,8 @@ class SA2BWorld(World):
|
|||
total_levels_added += 1
|
||||
if levels_added_to_gate >= levels_per_gate[current_gate]:
|
||||
current_gate += 1
|
||||
if current_gate > self.multiworld.number_of_level_gates[self.player].value:
|
||||
current_gate = self.multiworld.number_of_level_gates[self.player].value
|
||||
if current_gate > self.options.number_of_level_gates.value:
|
||||
current_gate = self.options.number_of_level_gates.value
|
||||
else:
|
||||
current_gate_emblems = max(
|
||||
math.floor(total_emblem_count * math.pow(total_levels_added / 30.0, 2.0) * gate_cost_mult), current_gate)
|
||||
|
@ -266,38 +268,70 @@ 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)
|
||||
|
||||
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)
|
||||
itempool += [self.create_item(ItemName.emblem) for _ in range(max_required_emblems)]
|
||||
|
||||
non_required_emblems = (total_emblem_count - max_required_emblems)
|
||||
junk_count = math.floor(non_required_emblems * (self.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)]
|
||||
|
||||
# Carve Traps out of junk_count
|
||||
trap_weights = []
|
||||
trap_weights += ([ItemName.omochao_trap] * self.multiworld.omochao_trap_weight[self.player].value)
|
||||
trap_weights += ([ItemName.timestop_trap] * self.multiworld.timestop_trap_weight[self.player].value)
|
||||
trap_weights += ([ItemName.confuse_trap] * self.multiworld.confusion_trap_weight[self.player].value)
|
||||
trap_weights += ([ItemName.tiny_trap] * self.multiworld.tiny_trap_weight[self.player].value)
|
||||
trap_weights += ([ItemName.gravity_trap] * self.multiworld.gravity_trap_weight[self.player].value)
|
||||
trap_weights += ([ItemName.exposition_trap] * self.multiworld.exposition_trap_weight[self.player].value)
|
||||
#trap_weights += ([ItemName.darkness_trap] * self.multiworld.darkness_trap_weight[self.player].value)
|
||||
trap_weights += ([ItemName.ice_trap] * self.multiworld.ice_trap_weight[self.player].value)
|
||||
trap_weights += ([ItemName.slow_trap] * self.multiworld.slow_trap_weight[self.player].value)
|
||||
trap_weights += ([ItemName.cutscene_trap] * self.multiworld.cutscene_trap_weight[self.player].value)
|
||||
trap_weights += ([ItemName.pong_trap] * self.multiworld.pong_trap_weight[self.player].value)
|
||||
trap_weights += ([ItemName.omochao_trap] * self.options.omochao_trap_weight.value)
|
||||
trap_weights += ([ItemName.timestop_trap] * self.options.timestop_trap_weight.value)
|
||||
trap_weights += ([ItemName.confuse_trap] * self.options.confusion_trap_weight.value)
|
||||
trap_weights += ([ItemName.tiny_trap] * self.options.tiny_trap_weight.value)
|
||||
trap_weights += ([ItemName.gravity_trap] * self.options.gravity_trap_weight.value)
|
||||
trap_weights += ([ItemName.exposition_trap] * self.options.exposition_trap_weight.value)
|
||||
#trap_weights += ([ItemName.darkness_trap] * self.options.darkness_trap_weight.value)
|
||||
trap_weights += ([ItemName.ice_trap] * self.options.ice_trap_weight.value)
|
||||
trap_weights += ([ItemName.slow_trap] * self.options.slow_trap_weight.value)
|
||||
trap_weights += ([ItemName.cutscene_trap] * self.options.cutscene_trap_weight.value)
|
||||
trap_weights += ([ItemName.reverse_trap] * self.options.reverse_trap_weight.value)
|
||||
trap_weights += ([ItemName.pong_trap] * self.options.pong_trap_weight.value)
|
||||
|
||||
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
|
||||
|
||||
chao_active = self.any_chao_locations_active()
|
||||
junk_pool = []
|
||||
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):
|
||||
junk_item = self.multiworld.random.choice(junk_keys)
|
||||
junk_pool.append(self.create_item(junk_item))
|
||||
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_pool.append(self.create_item(junk_item))
|
||||
|
||||
itempool += junk_pool
|
||||
|
||||
|
@ -310,95 +344,6 @@ class SA2BWorld(World):
|
|||
|
||||
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:
|
||||
|
@ -422,26 +367,32 @@ class SA2BWorld(World):
|
|||
return created_item
|
||||
|
||||
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):
|
||||
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):
|
||||
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")
|
||||
header_text = "Sonic Adventure 2 Bosses for {}:\n"
|
||||
header_text = header_text.format(self.multiworld.player_name[self.player])
|
||||
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())):
|
||||
text = "Gate {0} Boss: {1}\n"
|
||||
text = text.format((x + 1), get_boss_name(self.gate_bosses[x + 1]))
|
||||
spoiler_handle.writelines(text)
|
||||
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())):
|
||||
text = "Boss Rush Boss {0}: {1}\n"
|
||||
text = text.format((x + 1), get_boss_name(self.boss_rush_map[x]))
|
||||
|
@ -459,12 +410,21 @@ class SA2BWorld(World):
|
|||
]
|
||||
no_hint_region_names = [
|
||||
LocationName.cannon_core_region,
|
||||
LocationName.chao_garden_beginner_region,
|
||||
LocationName.chao_garden_intermediate_region,
|
||||
LocationName.chao_garden_expert_region,
|
||||
LocationName.chao_race_beginner_region,
|
||||
LocationName.chao_race_intermediate_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 = {}
|
||||
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_region = self.multiworld.get_region(gate_name, self.player)
|
||||
if not gate_region:
|
||||
|
@ -476,10 +436,353 @@ class SA2BWorld(World):
|
|||
for location in level_region.locations:
|
||||
er_hint_data[location.address] = gate_name
|
||||
|
||||
for i in range(self.options.black_market_slots.value):
|
||||
location = self.multiworld.get_location(LocationName.chao_black_market_base + str(i + 1), self.player)
|
||||
er_hint_data[location.address] = str(self.black_market_costs[i]) + " " + str(ItemName.market_token)
|
||||
|
||||
|
||||
hint_data[self.player] = er_hint_data
|
||||
|
||||
@classmethod
|
||||
def stage_fill_hook(cls, world, progitempool, usefulitempool, filleritempool, fill_locations):
|
||||
if world.get_game_players("Sonic Adventure 2 Battle"):
|
||||
def stage_fill_hook(cls, multiworld: MultiWorld, progitempool, usefulitempool, filleritempool, fill_locations):
|
||||
if multiworld.get_game_players("Sonic Adventure 2 Battle"):
|
||||
progitempool.sort(
|
||||
key=lambda item: 0 if (item.name != 'Emblem') else 1)
|
||||
|
||||
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.
|
||||
- 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)
|
||||
|
||||
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