mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 04:01:32 -06:00
Kirby's Dream Land 3: Implement New Game (#2119)
Co-authored-by: Alchav <59858495+Alchav@users.noreply.github.com> Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com> Co-authored-by: Doug Hoskisson <beauxq@yahoo.com> Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
This commit is contained in:
@@ -59,6 +59,7 @@ Currently, the following games are supported:
|
||||
* Landstalker: The Treasures of King Nole
|
||||
* Final Fantasy Mystic Quest
|
||||
* TUNIC
|
||||
* Kirby's Dream Land 3
|
||||
|
||||
For setup and instructions check out our [tutorials page](https://archipelago.gg/tutorial/).
|
||||
Downloads can be found at [Releases](https://github.com/ArchipelagoMW/Archipelago/releases), including compiled
|
||||
|
@@ -67,6 +67,9 @@
|
||||
# Hylics 2
|
||||
/worlds/hylics2/ @TRPG0
|
||||
|
||||
# Kirby's Dream Land 3
|
||||
/worlds/kdl3/ @Silvris
|
||||
|
||||
# Kingdom Hearts 2
|
||||
/worlds/kh2/ @JaredWeakStrike
|
||||
|
||||
|
@@ -131,6 +131,11 @@ Root: HKCR; Subkey: "{#MyAppName}l2acpatch"; ValueData: "Arc
|
||||
Root: HKCR; Subkey: "{#MyAppName}l2acpatch\DefaultIcon"; ValueData: "{app}\ArchipelagoSNIClient.exe,0"; ValueType: string; ValueName: "";
|
||||
Root: HKCR; Subkey: "{#MyAppName}l2acpatch\shell\open\command"; ValueData: """{app}\ArchipelagoSNIClient.exe"" ""%1"""; ValueType: string; ValueName: "";
|
||||
|
||||
Root: HKCR; Subkey: ".apkdl3"; ValueData: "{#MyAppName}kdl3patch"; Flags: uninsdeletevalue; ValueType: string; ValueName: ""; Components: client/sni
|
||||
Root: HKCR; Subkey: "{#MyAppName}kdl3patch"; ValueData: "Archipelago Kirby's Dream Land 3 Patch"; Flags: uninsdeletekey; ValueType: string; ValueName: ""; Components: client/sni
|
||||
Root: HKCR; Subkey: "{#MyAppName}kdl3patch\DefaultIcon"; ValueData: "{app}\ArchipelagoSNIClient.exe,0"; ValueType: string; ValueName: ""; Components: client/sni
|
||||
Root: HKCR; Subkey: "{#MyAppName}kdl3patch\shell\open\command"; ValueData: """{app}\ArchipelagoSNIClient.exe"" ""%1"""; ValueType: string; ValueName: ""; Components: client/sni
|
||||
|
||||
Root: HKCR; Subkey: ".apmc"; ValueData: "{#MyAppName}mcdata"; Flags: uninsdeletevalue; ValueType: string; ValueName: "";
|
||||
Root: HKCR; Subkey: "{#MyAppName}mcdata"; ValueData: "Archipelago Minecraft Data"; Flags: uninsdeletekey; ValueType: string; ValueName: "";
|
||||
Root: HKCR; Subkey: "{#MyAppName}mcdata\DefaultIcon"; ValueData: "{app}\ArchipelagoMinecraftClient.exe,0"; ValueType: string; ValueName: "";
|
||||
|
@@ -88,7 +88,7 @@ components: List[Component] = [
|
||||
# SNI
|
||||
Component('SNI Client', 'SNIClient',
|
||||
file_identifier=SuffixIdentifier('.apz3', '.apm3', '.apsoe', '.aplttp', '.apsm', '.apsmz3', '.apdkc3',
|
||||
'.apsmw', '.apl2ac')),
|
||||
'.apsmw', '.apl2ac', '.apkdl3')),
|
||||
Component('Links Awakening DX Client', 'LinksAwakeningClient',
|
||||
file_identifier=SuffixIdentifier('.apladx')),
|
||||
Component('LttP Adjuster', 'LttPAdjuster'),
|
||||
|
@@ -161,8 +161,40 @@ into any locations within the game slots named BobsSlaytheSpire and BobsRogueLeg
|
||||
|
||||
## Boss Plando
|
||||
|
||||
As this is currently only supported by A Link to the Past, instead of finding an explanation here, please refer to the
|
||||
relevant guide: [A Link to the Past Plando Guide](/tutorial/A%20Link%20to%20the%20Past/plando/en)
|
||||
This is currently only supported by A Link to the Past and Kirby's Dream Land 3. Boss plando allows a player to place a
|
||||
given boss within an arena. More specific information for boss plando in A Link to the Past can be found in
|
||||
its [plando guide](/tutorial/A%20Link%20to%20the%20Past/plando/en).
|
||||
|
||||
Boss plando takes in a list of instructions for placing bosses, separated by a semicolon `;`.
|
||||
There are three types of placement: direct, full, and shuffle.
|
||||
* Direct placement takes both an arena and a boss, and places the boss into that arena.
|
||||
* `Eastern Palace-Trinexx`
|
||||
* Full placement will take a boss, and place it into as many remaining arenas as possible.
|
||||
* `King Dedede`
|
||||
* Shuffle will fill any remaining arenas using a given boss shuffle option, typically to be used as the last instruction.
|
||||
* `full`
|
||||
|
||||
### Examples
|
||||
|
||||
```yaml
|
||||
A Link to the Past:
|
||||
boss_shuffle:
|
||||
# Basic boss shuffle, but prevent Trinexx from being outside Turtle Rock
|
||||
Turtle Rock-Trinexx;basic: 1
|
||||
# Place as many Arrghus as possible, then let the rest be random
|
||||
Arrghus;chaos: 1
|
||||
|
||||
Kirby's Dream Land 3:
|
||||
boss_shuffle:
|
||||
# Ensure Iceberg's boss will be King Dedede, but randomize the rest
|
||||
Iceberg-King Dedede;full: 1
|
||||
# Have all bosses be Whispy Woods
|
||||
Whispy Woods: 1
|
||||
# Ensure Ripple Field's boss is Pon & Con, but let the method others
|
||||
# are placed with be random
|
||||
Ripple Field-Pon & Con;random: 1
|
||||
```
|
||||
|
||||
|
||||
## Text Plando
|
||||
|
||||
@@ -184,7 +216,7 @@ its [plando guide](/tutorial/A%20Link%20to%20the%20Past/plando/en#connections).
|
||||
|
||||
[A Link to the Past connections](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/alttp/EntranceShuffle.py#L3852)
|
||||
|
||||
[Minecraft connections](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/minecraft/Regions.py#L62)
|
||||
[Minecraft connections](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/minecraft/data/regions.json#L18****)
|
||||
|
||||
### Examples
|
||||
|
||||
|
434
worlds/kdl3/Aesthetics.py
Normal file
434
worlds/kdl3/Aesthetics.py
Normal file
@@ -0,0 +1,434 @@
|
||||
import struct
|
||||
from .Options import KirbyFlavorPreset, GooeyFlavorPreset
|
||||
|
||||
kirby_flavor_presets = {
|
||||
1: {
|
||||
"1": "B50029",
|
||||
"2": "FF91C6",
|
||||
"3": "B0123B",
|
||||
"4": "630F0F",
|
||||
"5": "D60052",
|
||||
"6": "DE4873",
|
||||
"7": "D07880",
|
||||
"8": "000000",
|
||||
"9": "F770A5",
|
||||
"10": "E01784",
|
||||
"11": "CA4C74",
|
||||
"12": "A7443F",
|
||||
"13": "FF1784",
|
||||
"14": "FFA1DE",
|
||||
"15": "B03830",
|
||||
},
|
||||
2: {
|
||||
"1": "C70057",
|
||||
"2": "FF3554",
|
||||
"3": "AA0040",
|
||||
"4": "C02D47",
|
||||
"5": "E02068",
|
||||
"6": "C2183F",
|
||||
"7": "D03F80",
|
||||
"8": "872939",
|
||||
"9": "E82B47",
|
||||
"10": "E80067",
|
||||
"11": "D52F40",
|
||||
"12": "9F1C33",
|
||||
"13": "FD187F",
|
||||
"14": "F85068",
|
||||
"15": "D2386F",
|
||||
},
|
||||
3: {
|
||||
"1": "5858e2",
|
||||
"2": "e6e6fa",
|
||||
"3": "bcbcf2",
|
||||
"4": "8484e6",
|
||||
"5": "2929ec",
|
||||
"6": "b5b5f0",
|
||||
"7": "847bd6",
|
||||
"8": "3232d6",
|
||||
"9": "d6d6ef",
|
||||
"10": "4a52ef",
|
||||
"11": "c6c6e6",
|
||||
"12": "4343ad",
|
||||
"13": "6767ff",
|
||||
"14": "f6f6fd",
|
||||
"15": "3139b6",
|
||||
},
|
||||
4: {
|
||||
"1": "B01810",
|
||||
"2": "F0E08D",
|
||||
"3": "C8A060",
|
||||
"4": "A87043",
|
||||
"5": "E03700",
|
||||
"6": "EFC063",
|
||||
"7": "D07818",
|
||||
"8": "A8501C",
|
||||
"9": "E8D070",
|
||||
"10": "E2501E",
|
||||
"11": "E8C55C",
|
||||
"12": "B08833",
|
||||
"13": "E8783B",
|
||||
"14": "F8F8A5",
|
||||
"15": "B03800",
|
||||
},
|
||||
5: {
|
||||
"1": "9F4410",
|
||||
"2": "88F27B",
|
||||
"3": "57A044",
|
||||
"4": "227029",
|
||||
"5": "C75418",
|
||||
"6": "57BA23",
|
||||
"7": "1C6B00",
|
||||
"8": "2D6823",
|
||||
"9": "3FD744",
|
||||
"10": "E06C16",
|
||||
"11": "54C053",
|
||||
"12": "1A541E",
|
||||
"13": "F06B10",
|
||||
"14": "98F89A",
|
||||
"15": "B05830",
|
||||
},
|
||||
6: {
|
||||
"1": "7C1060",
|
||||
"2": "CA8AE8",
|
||||
"3": "8250A5",
|
||||
"4": "604B7B",
|
||||
"5": "A52068",
|
||||
"6": "8D64B8",
|
||||
"7": "B73B80",
|
||||
"8": "672D9A",
|
||||
"9": "BA82D5",
|
||||
"10": "B55098",
|
||||
"11": "9F5CCF",
|
||||
"12": "632B74",
|
||||
"13": "CF78B5",
|
||||
"14": "DA98F8",
|
||||
"15": "8D3863",
|
||||
},
|
||||
7: {
|
||||
"1": "6F1410",
|
||||
"2": "C2735C",
|
||||
"3": "5C351C",
|
||||
"4": "875440",
|
||||
"5": "9F2F0C",
|
||||
"6": "874C3B",
|
||||
"7": "88534C",
|
||||
"8": "4C1E00",
|
||||
"9": "B06458",
|
||||
"10": "921C16",
|
||||
"11": "9F5C54",
|
||||
"12": "5B3125",
|
||||
"13": "C01A14",
|
||||
"14": "CF785B",
|
||||
"15": "6B3125",
|
||||
},
|
||||
8: {
|
||||
"1": "a6a6a6",
|
||||
"2": "e6e6e6",
|
||||
"3": "bcbcbc",
|
||||
"4": "848484",
|
||||
"5": "909090",
|
||||
"6": "b5b5b5",
|
||||
"7": "848484",
|
||||
"8": "646464",
|
||||
"9": "d6d6d6",
|
||||
"10": "525252",
|
||||
"11": "c6c6c6",
|
||||
"12": "737373",
|
||||
"13": "949494",
|
||||
"14": "f6f6f6",
|
||||
"15": "545454",
|
||||
},
|
||||
9: {
|
||||
"1": "400000",
|
||||
"2": "6B6B6B",
|
||||
"3": "2B2B2B",
|
||||
"4": "181818",
|
||||
"5": "640000",
|
||||
"6": "3D3D3D",
|
||||
"7": "878787",
|
||||
"8": "020202",
|
||||
"9": "606060",
|
||||
"10": "980000",
|
||||
"11": "505050",
|
||||
"12": "474747",
|
||||
"13": "C80000",
|
||||
"14": "808080",
|
||||
"15": "AF0000",
|
||||
},
|
||||
10: {
|
||||
"1": "2B4B10",
|
||||
"2": "EF8A9D",
|
||||
"3": "C84F6B",
|
||||
"4": "B74F54",
|
||||
"5": "126018",
|
||||
"6": "D85F6F",
|
||||
"7": "D06870",
|
||||
"8": "A24858",
|
||||
"9": "E77B8D",
|
||||
"10": "168025",
|
||||
"11": "DF5C68",
|
||||
"12": "9D4353",
|
||||
"13": "48953F",
|
||||
"14": "F897AD",
|
||||
"15": "B03830",
|
||||
},
|
||||
11: {
|
||||
"1": "7B290C",
|
||||
"2": "FF9A00",
|
||||
"3": "B05C1C",
|
||||
"4": "8F3F0E",
|
||||
"5": "D23B0C",
|
||||
"6": "E08200",
|
||||
"7": "D05800",
|
||||
"8": "8A2B16",
|
||||
"9": "EF970A",
|
||||
"10": "E24800",
|
||||
"11": "E58F00",
|
||||
"12": "A03700",
|
||||
"13": "ED3B00",
|
||||
"14": "FFAF27",
|
||||
"15": "A84700",
|
||||
},
|
||||
12: {
|
||||
"1": "AFA810",
|
||||
"2": "4FF29D",
|
||||
"3": "2BA04C",
|
||||
"4": "007043",
|
||||
"5": "C7C218",
|
||||
"6": "33BA5F",
|
||||
"7": "006B40",
|
||||
"8": "2D6823",
|
||||
"9": "1CD773",
|
||||
"10": "E0CF16",
|
||||
"11": "2DC06C",
|
||||
"12": "00543F",
|
||||
"13": "F0F010",
|
||||
"14": "43F8B2",
|
||||
"15": "B0A230",
|
||||
},
|
||||
13: {
|
||||
"1": "7C73B0",
|
||||
"2": "CACAE7",
|
||||
"3": "7B7BA8",
|
||||
"4": "5F5FA7",
|
||||
"5": "B57EDC",
|
||||
"6": "8585C5",
|
||||
"7": "5B5B82",
|
||||
"8": "474796",
|
||||
"9": "B2B2D8",
|
||||
"10": "B790EF",
|
||||
"11": "9898C2",
|
||||
"12": "6B6BB7",
|
||||
"13": "CDADFA",
|
||||
"14": "E6E6FA",
|
||||
"15": "976FBD",
|
||||
},
|
||||
}
|
||||
|
||||
gooey_flavor_presets = {
|
||||
1: {
|
||||
"1": "CD539D",
|
||||
"2": "D270AD",
|
||||
"3": "F27CBF",
|
||||
"4": "FF91C6",
|
||||
"5": "FFA1DE",
|
||||
"6": "B51810",
|
||||
"7": "EF524A",
|
||||
"8": "D6C6C6",
|
||||
"9": "FFFFFF",
|
||||
},
|
||||
2: {
|
||||
"1": "161600",
|
||||
"2": "592910",
|
||||
"3": "5A3118",
|
||||
"4": "AB3918",
|
||||
"5": "EB3918",
|
||||
"6": "B51810",
|
||||
"7": "EF524A",
|
||||
"8": "D6C6C6",
|
||||
"9": "FFFFFF",
|
||||
},
|
||||
3: {
|
||||
"1": "001616",
|
||||
"2": "102959",
|
||||
"3": "18315A",
|
||||
"4": "1839AB",
|
||||
"5": "1839EB",
|
||||
"6": "B51810",
|
||||
"7": "EF524A",
|
||||
"8": "D6C6C6",
|
||||
"9": "FFFFFF",
|
||||
},
|
||||
4: {
|
||||
"1": "C8A031",
|
||||
"2": "C5BD38",
|
||||
"3": "D2CD48",
|
||||
"4": "E2E040",
|
||||
"5": "EAE2A0",
|
||||
"6": "B51810",
|
||||
"7": "EF524A",
|
||||
"8": "D6C6C6",
|
||||
"9": "FFFFFF",
|
||||
},
|
||||
5: {
|
||||
"1": "54A208",
|
||||
"2": "5CB021",
|
||||
"3": "6CB206",
|
||||
"4": "8AC54C",
|
||||
"5": "8DD554",
|
||||
"6": "B51810",
|
||||
"7": "EF524A",
|
||||
"8": "D6C6C6",
|
||||
"9": "FFFFFF",
|
||||
},
|
||||
6: {
|
||||
"1": "3D083D",
|
||||
"2": "4B024B",
|
||||
"3": "4C104C",
|
||||
"4": "5F0A5F",
|
||||
"5": "9F1D9F",
|
||||
"6": "B51810",
|
||||
"7": "EF524A",
|
||||
"8": "D6C6C6",
|
||||
"9": "FFFFFF",
|
||||
},
|
||||
7: {
|
||||
"1": "270C08",
|
||||
"2": "481C10",
|
||||
"3": "581E10",
|
||||
"4": "5B2712",
|
||||
"5": "743316",
|
||||
"6": "B51810",
|
||||
"7": "EF524A",
|
||||
"8": "D6C6C6",
|
||||
"9": "FFFFFF",
|
||||
},
|
||||
8: {
|
||||
"1": "7F7F7F",
|
||||
"2": "909090",
|
||||
"3": "9D9D9D",
|
||||
"4": "BFBFBF",
|
||||
"5": "D2D2D2",
|
||||
"6": "B51810",
|
||||
"7": "EF524A",
|
||||
"8": "D6C6C6",
|
||||
"9": "FFFFFF",
|
||||
},
|
||||
9: {
|
||||
"1": "141414",
|
||||
"2": "2D2D2D",
|
||||
"3": "404040",
|
||||
"4": "585858",
|
||||
"5": "7F7F7F",
|
||||
"6": "B51810",
|
||||
"7": "EF524A",
|
||||
"8": "D6C6C6",
|
||||
"9": "FFFFFF",
|
||||
},
|
||||
10: {
|
||||
"1": "954353",
|
||||
"2": "AF4F68",
|
||||
"3": "CD6073",
|
||||
"4": "E06774",
|
||||
"5": "E587A2",
|
||||
"6": "17AF10",
|
||||
"7": "4FE748",
|
||||
"8": "D6C6C6",
|
||||
"9": "FFFFFF",
|
||||
},
|
||||
11: {
|
||||
"1": "CF4700",
|
||||
"2": "D85C08",
|
||||
"3": "E26C04",
|
||||
"4": "EA7B16",
|
||||
"5": "EF8506",
|
||||
"6": "B51810",
|
||||
"7": "EF524A",
|
||||
"8": "D6C6C6",
|
||||
"9": "FFFFFF",
|
||||
},
|
||||
12: {
|
||||
"1": "1C4708",
|
||||
"2": "105B1C",
|
||||
"3": "186827",
|
||||
"4": "187C3B",
|
||||
"5": "188831",
|
||||
"6": "B51810",
|
||||
"7": "EF524A",
|
||||
"8": "D6C6C6",
|
||||
"9": "FFFFFF",
|
||||
},
|
||||
13: {
|
||||
"1": "501E70",
|
||||
"2": "673B87",
|
||||
"3": "7848A7",
|
||||
"4": "9067C7",
|
||||
"5": "B57EDC",
|
||||
"6": "B51810",
|
||||
"7": "EF524A",
|
||||
"8": "D6C6C6",
|
||||
"9": "FFFFFF",
|
||||
},
|
||||
}
|
||||
|
||||
kirby_target_palettes = {
|
||||
0x64646: (["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], 0, 1),
|
||||
0x64846: (["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], 0, 1),
|
||||
0x1E007E: (["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], 0, 1),
|
||||
0x1E009C: (["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], 0, 0.5),
|
||||
0x1E00F6: (["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], 0, 1),
|
||||
0x1E0114: (["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], 0, 0.5),
|
||||
0x1E0216: (["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], 0, 1),
|
||||
0x1E0234: (["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], 0, 0.5),
|
||||
0x1E0486: (["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], 0, 1),
|
||||
0x1E04A4: (["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], 0, 0.5),
|
||||
}
|
||||
|
||||
gooey_target_palettes = {
|
||||
0x604C2: (["1", "2", "3", "4", "5", "6", "7", "8", "9"], 0, 1),
|
||||
0x64592: (["1", "2", "3", "4", "5", "6", "7", "8", "9"], 0, 1),
|
||||
0x64692: (["1", "2", "3", "4", "5", "6", "7", "8", "9"], 0, 1),
|
||||
0x64892: (["1", "2", "3", "4", "5", "6", "7", "8", "9"], 0, 1),
|
||||
0x1E02CA: (["1", "2", "3", "4", "5", "6", "7", "8", "9"], 0, 1),
|
||||
0x1E0342: (["1", "2", "3", "4", "5", "6", "7", "8", "9"], 0, 1),
|
||||
0x1E05A6: (["1", "2", "3", "4", "5", "6", "7", "8", "9"], 0, 1),
|
||||
0x1E05B8: (["1", "2", "3", "4", "5", "6", "7", "8", "9"], 0, 0.5),
|
||||
0x1E0636: (["1", "2", "3", "4", "5", "6", "7", "8", "9"], 0, 1),
|
||||
0x1E065A: (["1", "2", "3", "4", "5", "6", "7", "8", "9"], 0, 1.5),
|
||||
}
|
||||
|
||||
|
||||
def get_kirby_palette(world):
|
||||
palette = world.options.kirby_flavor_preset.value
|
||||
if palette == KirbyFlavorPreset.option_custom:
|
||||
return world.options.kirby_flavor.value
|
||||
return kirby_flavor_presets.get(palette, None)
|
||||
|
||||
|
||||
def get_gooey_palette(world):
|
||||
palette = world.options.gooey_flavor_preset.value
|
||||
if palette == GooeyFlavorPreset.option_custom:
|
||||
return world.options.gooey_flavor.value
|
||||
return gooey_flavor_presets.get(palette, None)
|
||||
|
||||
|
||||
def rgb888_to_bgr555(red, green, blue) -> bytes:
|
||||
red = red >> 3
|
||||
green = green >> 3
|
||||
blue = blue >> 3
|
||||
outcol = (blue << 10) + (green << 5) + red
|
||||
return struct.pack("H", outcol)
|
||||
|
||||
|
||||
def get_palette_bytes(palette, target, offset, factor):
|
||||
output_data = bytearray()
|
||||
for color in target:
|
||||
hexcol = palette[color]
|
||||
if hexcol.startswith("#"):
|
||||
hexcol = hexcol.replace("#", "")
|
||||
colint = int(hexcol, 16)
|
||||
col = ((colint & 0xFF0000) >> 16, (colint & 0xFF00) >> 8, colint & 0xFF)
|
||||
col = tuple(int(int(factor*x) + offset) for x in col)
|
||||
byte_data = rgb888_to_bgr555(col[0], col[1], col[2])
|
||||
output_data.extend(bytearray(byte_data))
|
||||
return output_data
|
417
worlds/kdl3/Client.py
Normal file
417
worlds/kdl3/Client.py
Normal file
@@ -0,0 +1,417 @@
|
||||
import logging
|
||||
import struct
|
||||
import time
|
||||
import typing
|
||||
import uuid
|
||||
from struct import unpack, pack
|
||||
from collections import defaultdict
|
||||
import random
|
||||
|
||||
from MultiServer import mark_raw
|
||||
from NetUtils import ClientStatus, color
|
||||
from Utils import async_start
|
||||
from worlds.AutoSNIClient import SNIClient
|
||||
from .Locations import boss_locations
|
||||
from .Gifting import kdl3_gifting_options, kdl3_trap_gifts, kdl3_gifts, update_object, pop_object, initialize_giftboxes
|
||||
from .ClientAddrs import consumable_addrs, star_addrs
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from SNIClient import SNIClientCommandProcessor
|
||||
|
||||
snes_logger = logging.getLogger("SNES")
|
||||
|
||||
# FXPAK Pro protocol memory mapping used by SNI
|
||||
ROM_START = 0x000000
|
||||
SRAM_1_START = 0xE00000
|
||||
|
||||
# KDL3
|
||||
KDL3_HALKEN = SRAM_1_START + 0x80F0
|
||||
KDL3_NINTEN = SRAM_1_START + 0x8FF0
|
||||
KDL3_ROMNAME = SRAM_1_START + 0x8100
|
||||
KDL3_DEATH_LINK_ADDR = SRAM_1_START + 0x9010
|
||||
KDL3_GOAL_ADDR = SRAM_1_START + 0x9012
|
||||
KDL3_CONSUMABLE_FLAG = SRAM_1_START + 0x9018
|
||||
KDL3_STARS_FLAG = SRAM_1_START + 0x901A
|
||||
KDL3_GIFTING_FLAG = SRAM_1_START + 0x901C
|
||||
KDL3_LEVEL_ADDR = SRAM_1_START + 0x9020
|
||||
KDL3_IS_DEMO = SRAM_1_START + 0x5AD5
|
||||
KDL3_GAME_STATE = SRAM_1_START + 0x36D0
|
||||
KDL3_GAME_SAVE = SRAM_1_START + 0x3617
|
||||
KDL3_LIFE_COUNT = SRAM_1_START + 0x39CF
|
||||
KDL3_KIRBY_HP = SRAM_1_START + 0x39D1
|
||||
KDL3_BOSS_HP = SRAM_1_START + 0x39D5
|
||||
KDL3_STAR_COUNT = SRAM_1_START + 0x39D7
|
||||
KDL3_LIFE_VISUAL = SRAM_1_START + 0x39E3
|
||||
KDL3_HEART_STARS = SRAM_1_START + 0x53A7
|
||||
KDL3_WORLD_UNLOCK = SRAM_1_START + 0x53CB
|
||||
KDL3_LEVEL_UNLOCK = SRAM_1_START + 0x53CD
|
||||
KDL3_CURRENT_WORLD = SRAM_1_START + 0x53CF
|
||||
KDL3_CURRENT_LEVEL = SRAM_1_START + 0x53D3
|
||||
KDL3_BOSS_STATUS = SRAM_1_START + 0x53D5
|
||||
KDL3_INVINCIBILITY_TIMER = SRAM_1_START + 0x54B1
|
||||
KDL3_MG5_STATUS = SRAM_1_START + 0x5EE4
|
||||
KDL3_BOSS_BUTCH_STATUS = SRAM_1_START + 0x5EEA
|
||||
KDL3_JUMPING_STATUS = SRAM_1_START + 0x5EF0
|
||||
KDL3_CURRENT_BGM = SRAM_1_START + 0x733E
|
||||
KDL3_SOUND_FX = SRAM_1_START + 0x7F62
|
||||
KDL3_ANIMAL_FRIENDS = SRAM_1_START + 0x8000
|
||||
KDL3_ABILITY_ARRAY = SRAM_1_START + 0x8020
|
||||
KDL3_RECV_COUNT = SRAM_1_START + 0x8050
|
||||
KDL3_HEART_STAR_COUNT = SRAM_1_START + 0x8070
|
||||
KDL3_GOOEY_TRAP = SRAM_1_START + 0x8080
|
||||
KDL3_SLOWNESS_TRAP = SRAM_1_START + 0x8082
|
||||
KDL3_ABILITY_TRAP = SRAM_1_START + 0x8084
|
||||
KDL3_GIFTING_SEND = SRAM_1_START + 0x8086
|
||||
KDL3_COMPLETED_STAGES = SRAM_1_START + 0x8200
|
||||
KDL3_CONSUMABLES = SRAM_1_START + 0xA000
|
||||
KDL3_STARS = SRAM_1_START + 0xB000
|
||||
KDL3_ITEM_QUEUE = SRAM_1_START + 0xC000
|
||||
|
||||
deathlink_messages = defaultdict(lambda: " was defeated.", {
|
||||
0x0200: " was bonked by apples from Whispy Woods.",
|
||||
0x0201: " was out-maneuvered by Acro.",
|
||||
0x0202: " was out-numbered by Pon & Con.",
|
||||
0x0203: " was defeated by Ado's powerful paintings.",
|
||||
0x0204: " was clobbered by King Dedede.",
|
||||
0x0205: " lost their battle against Dark Matter."
|
||||
})
|
||||
|
||||
|
||||
@mark_raw
|
||||
def cmd_gift(self: "SNIClientCommandProcessor"):
|
||||
"""Toggles gifting for the current game."""
|
||||
if not getattr(self.ctx, "gifting", None):
|
||||
self.ctx.gifting = True
|
||||
else:
|
||||
self.ctx.gifting = not self.ctx.gifting
|
||||
self.output(f"Gifting set to {self.ctx.gifting}")
|
||||
async_start(update_object(self.ctx, f"Giftboxes;{self.ctx.team}", {
|
||||
f"{self.ctx.slot}":
|
||||
{
|
||||
"IsOpen": self.ctx.gifting,
|
||||
**kdl3_gifting_options
|
||||
}
|
||||
}))
|
||||
|
||||
|
||||
class KDL3SNIClient(SNIClient):
|
||||
game = "Kirby's Dream Land 3"
|
||||
levels = None
|
||||
consumables = None
|
||||
stars = None
|
||||
item_queue: typing.List = []
|
||||
initialize_gifting = False
|
||||
giftbox_key: str = ""
|
||||
motherbox_key: str = ""
|
||||
client_random: random.Random = random.Random()
|
||||
|
||||
async def deathlink_kill_player(self, ctx) -> None:
|
||||
from SNIClient import DeathState, snes_buffered_write, snes_flush_writes, snes_read
|
||||
game_state = await snes_read(ctx, KDL3_GAME_STATE, 1)
|
||||
if game_state[0] == 0xFF:
|
||||
return # despite how funny it is, don't try to kill Kirby in a menu
|
||||
|
||||
current_stage = await snes_read(ctx, KDL3_CURRENT_LEVEL, 1)
|
||||
if current_stage[0] == 0x7: # boss stage
|
||||
boss_hp = await snes_read(ctx, KDL3_BOSS_HP, 1)
|
||||
if boss_hp[0] == 0:
|
||||
return # receiving a deathlink after defeating a boss has softlock potential
|
||||
|
||||
current_hp = await snes_read(ctx, KDL3_KIRBY_HP, 1)
|
||||
if current_hp[0] == 0:
|
||||
return # don't kill Kirby while he's already dead
|
||||
snes_buffered_write(ctx, KDL3_KIRBY_HP, bytes([0x00]))
|
||||
|
||||
await snes_flush_writes(ctx)
|
||||
|
||||
ctx.death_state = DeathState.dead
|
||||
ctx.last_death_link = time.time()
|
||||
|
||||
async def validate_rom(self, ctx) -> bool:
|
||||
from SNIClient import snes_read
|
||||
rom_name = await snes_read(ctx, KDL3_ROMNAME, 0x15)
|
||||
if rom_name is None or rom_name == bytes([0] * 0x15) or rom_name[:4] != b"KDL3":
|
||||
if "gift" in ctx.command_processor.commands:
|
||||
ctx.command_processor.commands.pop("gift")
|
||||
return False
|
||||
|
||||
ctx.game = self.game
|
||||
ctx.rom = rom_name
|
||||
ctx.items_handling = 0b111 # always remote items
|
||||
ctx.allow_collect = True
|
||||
if "gift" not in ctx.command_processor.commands:
|
||||
ctx.command_processor.commands["gift"] = cmd_gift
|
||||
|
||||
death_link = await snes_read(ctx, KDL3_DEATH_LINK_ADDR, 1)
|
||||
if death_link:
|
||||
await ctx.update_death_link(bool(death_link[0] & 0b1))
|
||||
return True
|
||||
|
||||
async def pop_item(self, ctx, in_stage):
|
||||
from SNIClient import snes_buffered_write, snes_read
|
||||
if len(self.item_queue) > 0:
|
||||
item = self.item_queue.pop()
|
||||
if not in_stage and item & 0xC0:
|
||||
# can't handle this item right now, send it to the back and return to handle the rest
|
||||
self.item_queue.append(item)
|
||||
return
|
||||
ingame_queue = list(unpack("HHHHHHHH", await snes_read(ctx, KDL3_ITEM_QUEUE, 16)))
|
||||
for i in range(len(ingame_queue)):
|
||||
if ingame_queue[i] == 0x00:
|
||||
ingame_queue[i] = item
|
||||
snes_buffered_write(ctx, KDL3_ITEM_QUEUE, pack("HHHHHHHH", *ingame_queue))
|
||||
break
|
||||
else:
|
||||
self.item_queue.append(item) # no more slots, get it next go around
|
||||
|
||||
async def pop_gift(self, ctx):
|
||||
if ctx.stored_data[self.giftbox_key]:
|
||||
from SNIClient import snes_read, snes_buffered_write
|
||||
key, gift = ctx.stored_data[self.giftbox_key].popitem()
|
||||
await pop_object(ctx, self.giftbox_key, key)
|
||||
# first, special cases
|
||||
traits = [trait["Trait"] for trait in gift["Traits"]]
|
||||
if "Candy" in traits or "Invincible" in traits:
|
||||
# apply invincibility candy
|
||||
self.item_queue.append(0x43)
|
||||
elif "Tomato" in traits or "tomato" in gift["ItemName"].lower():
|
||||
# apply maxim tomato
|
||||
# only want tomatos here, no other vegetable is that good
|
||||
self.item_queue.append(0x42)
|
||||
elif "Life" in traits:
|
||||
# Apply 1-Up
|
||||
self.item_queue.append(0x41)
|
||||
elif "Currency" in traits or "Star" in traits:
|
||||
value = gift["ItemValue"]
|
||||
if value >= 50000:
|
||||
self.item_queue.append(0x46)
|
||||
elif value >= 30000:
|
||||
self.item_queue.append(0x45)
|
||||
else:
|
||||
self.item_queue.append(0x44)
|
||||
elif "Trap" in traits:
|
||||
# find the best trap to apply
|
||||
if "Goo" in traits or "Gel" in traits:
|
||||
self.item_queue.append(0x80)
|
||||
elif "Slow" in traits or "Slowness" in traits:
|
||||
self.item_queue.append(0x81)
|
||||
elif "Eject" in traits or "Removal" in traits:
|
||||
self.item_queue.append(0x82)
|
||||
else:
|
||||
# just deal damage to Kirby
|
||||
kirby_hp = struct.unpack("H", await snes_read(ctx, KDL3_KIRBY_HP, 2))[0]
|
||||
snes_buffered_write(ctx, KDL3_KIRBY_HP, struct.pack("H", max(kirby_hp - 1, 0)))
|
||||
else:
|
||||
# check if it's tasty
|
||||
if any(x in traits for x in ["Consumable", "Food", "Drink", "Heal", "Health"]):
|
||||
# it's tasty!, use quality to decide how much to heal
|
||||
quality = max((trait["Quality"] for trait in gift["Traits"]
|
||||
if trait["Trait"] in ["Consumable", "Food", "Drink", "Heal", "Health"]))
|
||||
quality = min(10, quality * 2)
|
||||
else:
|
||||
# it's not really edible, but he'll eat it anyway
|
||||
quality = self.client_random.choices(range(0, 2), {0: 75, 1: 25})[0]
|
||||
kirby_hp = await snes_read(ctx, KDL3_KIRBY_HP, 1)
|
||||
gooey_hp = await snes_read(ctx, KDL3_KIRBY_HP + 2, 1)
|
||||
snes_buffered_write(ctx, KDL3_SOUND_FX, bytes([0x26]))
|
||||
if gooey_hp[0] > 0x00:
|
||||
snes_buffered_write(ctx, KDL3_KIRBY_HP, struct.pack("H", min(kirby_hp[0] + quality // 2, 8)))
|
||||
snes_buffered_write(ctx, KDL3_KIRBY_HP + 2, struct.pack("H", min(gooey_hp[0] + quality // 2, 8)))
|
||||
else:
|
||||
snes_buffered_write(ctx, KDL3_KIRBY_HP, struct.pack("H", min(kirby_hp[0] + quality, 10)))
|
||||
|
||||
async def pick_gift_recipient(self, ctx, gift):
|
||||
if gift != 4:
|
||||
gift_base = kdl3_gifts[gift]
|
||||
else:
|
||||
gift_base = kdl3_trap_gifts[self.client_random.randint(0, 3)]
|
||||
most_applicable = -1
|
||||
most_applicable_slot = ctx.slot
|
||||
for slot, info in ctx.stored_data[self.motherbox_key].items():
|
||||
if int(slot) == ctx.slot and len(ctx.stored_data[self.motherbox_key]) > 1:
|
||||
continue
|
||||
desire = len(set(info["DesiredTraits"]).intersection([trait["Trait"] for trait in gift_base["Traits"]]))
|
||||
if desire > most_applicable:
|
||||
most_applicable = desire
|
||||
most_applicable_slot = int(slot)
|
||||
elif most_applicable_slot == ctx.slot and info["AcceptsAnyGift"]:
|
||||
# only send to ourselves if no one else will take it
|
||||
most_applicable_slot = int(slot)
|
||||
# print(most_applicable, most_applicable_slot)
|
||||
item_uuid = uuid.uuid4().hex
|
||||
item = {
|
||||
**gift_base,
|
||||
"ID": item_uuid,
|
||||
"Sender": ctx.player_names[ctx.slot],
|
||||
"Receiver": ctx.player_names[most_applicable_slot],
|
||||
"SenderTeam": ctx.team,
|
||||
"ReceiverTeam": ctx.team, # for the moment
|
||||
"IsRefund": False
|
||||
}
|
||||
# print(item)
|
||||
await update_object(ctx, f"Giftbox;{ctx.team};{most_applicable_slot}", {
|
||||
item_uuid: item,
|
||||
})
|
||||
|
||||
async def game_watcher(self, ctx) -> None:
|
||||
try:
|
||||
from SNIClient import snes_buffered_write, snes_flush_writes, snes_read
|
||||
rom = await snes_read(ctx, KDL3_ROMNAME, 0x15)
|
||||
if rom != ctx.rom:
|
||||
ctx.rom = None
|
||||
halken = await snes_read(ctx, KDL3_HALKEN, 6)
|
||||
if halken != b"halken":
|
||||
return
|
||||
ninten = await snes_read(ctx, KDL3_NINTEN, 6)
|
||||
if ninten != b"ninten":
|
||||
return
|
||||
if not ctx.slot:
|
||||
return
|
||||
if not self.initialize_gifting:
|
||||
self.giftbox_key = f"Giftbox;{ctx.team};{ctx.slot}"
|
||||
self.motherbox_key = f"Giftboxes;{ctx.team}"
|
||||
enable_gifting = await snes_read(ctx, KDL3_GIFTING_FLAG, 0x01)
|
||||
await initialize_giftboxes(ctx, self.giftbox_key, self.motherbox_key, bool(enable_gifting[0]))
|
||||
self.initialize_gifting = True
|
||||
# can't check debug anymore, without going and copying the value. might be important later.
|
||||
if self.levels is None:
|
||||
self.levels = dict()
|
||||
for i in range(5):
|
||||
level_data = await snes_read(ctx, KDL3_LEVEL_ADDR + (14 * i), 14)
|
||||
self.levels[i] = unpack("HHHHHHH", level_data)
|
||||
|
||||
if self.consumables is None:
|
||||
consumables = await snes_read(ctx, KDL3_CONSUMABLE_FLAG, 1)
|
||||
self.consumables = consumables[0] == 0x01
|
||||
if self.stars is None:
|
||||
stars = await snes_read(ctx, KDL3_STARS_FLAG, 1)
|
||||
self.stars = stars[0] == 0x01
|
||||
is_demo = await snes_read(ctx, KDL3_IS_DEMO, 1)
|
||||
# 1 - recording a demo, 2 - playing back recorded, 3+ is a demo
|
||||
if is_demo[0] > 0x00:
|
||||
return
|
||||
current_save = await snes_read(ctx, KDL3_GAME_SAVE, 1)
|
||||
goal = await snes_read(ctx, KDL3_GOAL_ADDR, 1)
|
||||
boss_butch_status = await snes_read(ctx, KDL3_BOSS_BUTCH_STATUS + (current_save[0] * 2), 1)
|
||||
mg5_status = await snes_read(ctx, KDL3_MG5_STATUS + (current_save[0] * 2), 1)
|
||||
jumping_status = await snes_read(ctx, KDL3_JUMPING_STATUS + (current_save[0] * 2), 1)
|
||||
if boss_butch_status[0] == 0xFF:
|
||||
return # save file is not created, ignore
|
||||
if (goal[0] == 0x00 and boss_butch_status[0] == 0x01) \
|
||||
or (goal[0] == 0x01 and boss_butch_status[0] == 0x03) \
|
||||
or (goal[0] == 0x02 and mg5_status[0] == 0x03) \
|
||||
or (goal[0] == 0x03 and jumping_status[0] == 0x03):
|
||||
await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}])
|
||||
ctx.finished_game = True
|
||||
current_bgm = await snes_read(ctx, KDL3_CURRENT_BGM, 1)
|
||||
if current_bgm[0] in (0x00, 0x21, 0x22, 0x23, 0x25, 0x2A, 0x2B):
|
||||
return # null, title screen, opening, save select, true and false endings
|
||||
game_state = await snes_read(ctx, KDL3_GAME_STATE, 1)
|
||||
current_hp = await snes_read(ctx, KDL3_KIRBY_HP, 1)
|
||||
if "DeathLink" in ctx.tags and game_state[0] == 0x00 and ctx.last_death_link + 1 < time.time():
|
||||
currently_dead = current_hp[0] == 0x00
|
||||
await ctx.handle_deathlink_state(currently_dead)
|
||||
|
||||
recv_count = await snes_read(ctx, KDL3_RECV_COUNT, 2)
|
||||
recv_amount = unpack("H", recv_count)[0]
|
||||
if recv_amount < len(ctx.items_received):
|
||||
item = ctx.items_received[recv_amount]
|
||||
recv_amount += 1
|
||||
logging.info('Received %s from %s (%s) (%d/%d in list)' % (
|
||||
color(ctx.item_names[item.item], 'red', 'bold'),
|
||||
color(ctx.player_names[item.player], 'yellow'),
|
||||
ctx.location_names[item.location], recv_amount, len(ctx.items_received)))
|
||||
|
||||
snes_buffered_write(ctx, KDL3_RECV_COUNT, pack("H", recv_amount))
|
||||
item_idx = item.item & 0x00000F
|
||||
if item.item & 0x000070 == 0:
|
||||
self.item_queue.append(item_idx | 0x10)
|
||||
elif item.item & 0x000010 > 0:
|
||||
self.item_queue.append(item_idx | 0x20)
|
||||
elif item.item & 0x000020 > 0:
|
||||
# Positive
|
||||
self.item_queue.append(item_idx | 0x40)
|
||||
elif item.item & 0x000040 > 0:
|
||||
self.item_queue.append(item_idx | 0x80)
|
||||
|
||||
# handle gifts here
|
||||
gifting_status = await snes_read(ctx, KDL3_GIFTING_FLAG, 0x01)
|
||||
if hasattr(ctx, "gifting") and ctx.gifting:
|
||||
if gifting_status[0]:
|
||||
gift = await snes_read(ctx, KDL3_GIFTING_SEND, 0x01)
|
||||
if gift[0]:
|
||||
# we have a gift to send
|
||||
await self.pick_gift_recipient(ctx, gift[0])
|
||||
snes_buffered_write(ctx, KDL3_GIFTING_SEND, bytes([0x00]))
|
||||
else:
|
||||
snes_buffered_write(ctx, KDL3_GIFTING_FLAG, bytes([0x01]))
|
||||
else:
|
||||
if gifting_status[0]:
|
||||
snes_buffered_write(ctx, KDL3_GIFTING_FLAG, bytes([0x00]))
|
||||
|
||||
await snes_flush_writes(ctx)
|
||||
|
||||
new_checks = []
|
||||
# level completion status
|
||||
world_unlocks = await snes_read(ctx, KDL3_WORLD_UNLOCK, 1)
|
||||
if world_unlocks[0] > 0x06:
|
||||
return # save is not loaded, ignore
|
||||
stages_raw = await snes_read(ctx, KDL3_COMPLETED_STAGES, 60)
|
||||
stages = struct.unpack("HHHHHHHHHHHHHHHHHHHHHHHHHHHHHH", stages_raw)
|
||||
for i in range(30):
|
||||
loc_id = 0x770000 + i + 1
|
||||
if stages[i] == 1 and loc_id not in ctx.checked_locations:
|
||||
new_checks.append(loc_id)
|
||||
elif loc_id in ctx.checked_locations:
|
||||
snes_buffered_write(ctx, KDL3_COMPLETED_STAGES + (i * 2), struct.pack("H", 1))
|
||||
|
||||
# heart star status
|
||||
heart_stars = await snes_read(ctx, KDL3_HEART_STARS, 35)
|
||||
for i in range(5):
|
||||
start_ind = i * 7
|
||||
for j in range(1, 7):
|
||||
level_ind = start_ind + j - 1
|
||||
loc_id = 0x770100 + (6 * i) + j
|
||||
if heart_stars[level_ind] and loc_id not in ctx.checked_locations:
|
||||
new_checks.append(loc_id)
|
||||
elif loc_id in ctx.checked_locations:
|
||||
snes_buffered_write(ctx, KDL3_HEART_STARS + level_ind, bytes([0x01]))
|
||||
if self.consumables:
|
||||
consumables = await snes_read(ctx, KDL3_CONSUMABLES, 1920)
|
||||
for consumable in consumable_addrs:
|
||||
# TODO: see if this can be sped up in any way
|
||||
loc_id = 0x770300 + consumable
|
||||
if loc_id not in ctx.checked_locations and consumables[consumable_addrs[consumable]] == 0x01:
|
||||
new_checks.append(loc_id)
|
||||
if self.stars:
|
||||
stars = await snes_read(ctx, KDL3_STARS, 1920)
|
||||
for star in star_addrs:
|
||||
if star not in ctx.checked_locations and stars[star_addrs[star]] == 0x01:
|
||||
new_checks.append(star)
|
||||
|
||||
if game_state[0] != 0xFF:
|
||||
await self.pop_gift(ctx)
|
||||
await self.pop_item(ctx, game_state[0] != 0xFF)
|
||||
await snes_flush_writes(ctx)
|
||||
|
||||
# boss status
|
||||
boss_flag_bytes = await snes_read(ctx, KDL3_BOSS_STATUS, 2)
|
||||
boss_flag = unpack("H", boss_flag_bytes)[0]
|
||||
for bitmask, boss in zip(range(1, 11, 2), boss_locations.keys()):
|
||||
if boss_flag & (1 << bitmask) > 0 and boss not in ctx.checked_locations:
|
||||
new_checks.append(boss)
|
||||
|
||||
for new_check_id in new_checks:
|
||||
ctx.locations_checked.add(new_check_id)
|
||||
location = ctx.location_names[new_check_id]
|
||||
snes_logger.info(
|
||||
f'New Check: {location} ({len(ctx.locations_checked)}/{len(ctx.missing_locations) + len(ctx.checked_locations)})')
|
||||
await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": [new_check_id]}])
|
||||
except Exception as ex:
|
||||
# we crashed, so print log and clean up
|
||||
snes_logger.error("", exc_info=ex)
|
||||
if "gift" in ctx.command_processor.commands:
|
||||
ctx.command_processor.commands.pop("gift")
|
||||
ctx.rom = None
|
||||
ctx.game = None
|
816
worlds/kdl3/ClientAddrs.py
Normal file
816
worlds/kdl3/ClientAddrs.py
Normal file
@@ -0,0 +1,816 @@
|
||||
consumable_addrs = {
|
||||
0: 14,
|
||||
1: 15,
|
||||
2: 84,
|
||||
3: 138,
|
||||
4: 139,
|
||||
5: 204,
|
||||
6: 214,
|
||||
7: 215,
|
||||
8: 224,
|
||||
9: 330,
|
||||
10: 353,
|
||||
11: 458,
|
||||
12: 459,
|
||||
13: 522,
|
||||
14: 525,
|
||||
15: 605,
|
||||
16: 606,
|
||||
17: 630,
|
||||
18: 671,
|
||||
19: 672,
|
||||
20: 693,
|
||||
21: 791,
|
||||
22: 851,
|
||||
23: 883,
|
||||
24: 971,
|
||||
25: 985,
|
||||
26: 986,
|
||||
27: 1024,
|
||||
28: 1035,
|
||||
29: 1036,
|
||||
30: 1038,
|
||||
31: 1039,
|
||||
32: 1170,
|
||||
33: 1171,
|
||||
34: 1377,
|
||||
35: 1378,
|
||||
36: 1413,
|
||||
37: 1494,
|
||||
38: 1666,
|
||||
39: 1808,
|
||||
40: 1809,
|
||||
41: 1816,
|
||||
42: 1856,
|
||||
43: 1857,
|
||||
}
|
||||
|
||||
star_addrs = {
|
||||
0x770401: 0,
|
||||
0x770402: 1,
|
||||
0x770403: 2,
|
||||
0x770404: 3,
|
||||
0x770405: 4,
|
||||
0x770406: 5,
|
||||
0x770407: 7,
|
||||
0x770408: 8,
|
||||
0x770409: 9,
|
||||
0x77040a: 10,
|
||||
0x77040b: 11,
|
||||
0x77040c: 12,
|
||||
0x77040d: 13,
|
||||
0x77040e: 16,
|
||||
0x77040f: 17,
|
||||
0x770410: 19,
|
||||
0x770411: 20,
|
||||
0x770412: 21,
|
||||
0x770413: 22,
|
||||
0x770414: 23,
|
||||
0x770415: 24,
|
||||
0x770416: 25,
|
||||
0x770417: 26,
|
||||
0x770418: 65,
|
||||
0x770419: 66,
|
||||
0x77041a: 67,
|
||||
0x77041b: 68,
|
||||
0x77041c: 69,
|
||||
0x77041d: 70,
|
||||
0x77041e: 71,
|
||||
0x77041f: 72,
|
||||
0x770420: 73,
|
||||
0x770421: 74,
|
||||
0x770422: 76,
|
||||
0x770423: 77,
|
||||
0x770424: 78,
|
||||
0x770425: 79,
|
||||
0x770426: 80,
|
||||
0x770427: 81,
|
||||
0x770428: 82,
|
||||
0x770429: 83,
|
||||
0x77042a: 85,
|
||||
0x77042b: 86,
|
||||
0x77042c: 87,
|
||||
0x77042d: 128,
|
||||
0x77042e: 129,
|
||||
0x77042f: 130,
|
||||
0x770430: 131,
|
||||
0x770431: 132,
|
||||
0x770432: 133,
|
||||
0x770433: 134,
|
||||
0x770434: 135,
|
||||
0x770435: 136,
|
||||
0x770436: 137,
|
||||
0x770437: 140,
|
||||
0x770438: 141,
|
||||
0x770439: 142,
|
||||
0x77043a: 143,
|
||||
0x77043b: 144,
|
||||
0x77043c: 145,
|
||||
0x77043d: 146,
|
||||
0x77043e: 147,
|
||||
0x77043f: 148,
|
||||
0x770440: 149,
|
||||
0x770441: 150,
|
||||
0x770442: 151,
|
||||
0x770443: 152,
|
||||
0x770444: 153,
|
||||
0x770445: 154,
|
||||
0x770446: 155,
|
||||
0x770447: 156,
|
||||
0x770448: 157,
|
||||
0x770449: 158,
|
||||
0x77044a: 159,
|
||||
0x77044b: 160,
|
||||
0x77044c: 192,
|
||||
0x77044d: 193,
|
||||
0x77044e: 194,
|
||||
0x77044f: 195,
|
||||
0x770450: 197,
|
||||
0x770451: 198,
|
||||
0x770452: 199,
|
||||
0x770453: 200,
|
||||
0x770454: 201,
|
||||
0x770455: 203,
|
||||
0x770456: 205,
|
||||
0x770457: 206,
|
||||
0x770458: 207,
|
||||
0x770459: 208,
|
||||
0x77045a: 209,
|
||||
0x77045b: 210,
|
||||
0x77045c: 211,
|
||||
0x77045d: 212,
|
||||
0x77045e: 213,
|
||||
0x77045f: 216,
|
||||
0x770460: 217,
|
||||
0x770461: 218,
|
||||
0x770462: 219,
|
||||
0x770463: 220,
|
||||
0x770464: 221,
|
||||
0x770465: 222,
|
||||
0x770466: 225,
|
||||
0x770467: 227,
|
||||
0x770468: 228,
|
||||
0x770469: 229,
|
||||
0x77046a: 230,
|
||||
0x77046b: 231,
|
||||
0x77046c: 232,
|
||||
0x77046d: 233,
|
||||
0x77046e: 234,
|
||||
0x77046f: 235,
|
||||
0x770470: 236,
|
||||
0x770471: 257,
|
||||
0x770472: 258,
|
||||
0x770473: 259,
|
||||
0x770474: 260,
|
||||
0x770475: 261,
|
||||
0x770476: 262,
|
||||
0x770477: 263,
|
||||
0x770478: 264,
|
||||
0x770479: 265,
|
||||
0x77047a: 266,
|
||||
0x77047b: 267,
|
||||
0x77047c: 268,
|
||||
0x77047d: 270,
|
||||
0x77047e: 271,
|
||||
0x77047f: 272,
|
||||
0x770480: 273,
|
||||
0x770481: 275,
|
||||
0x770482: 276,
|
||||
0x770483: 277,
|
||||
0x770484: 278,
|
||||
0x770485: 279,
|
||||
0x770486: 280,
|
||||
0x770487: 281,
|
||||
0x770488: 282,
|
||||
0x770489: 283,
|
||||
0x77048a: 284,
|
||||
0x77048b: 285,
|
||||
0x77048c: 286,
|
||||
0x77048d: 287,
|
||||
0x77048e: 321,
|
||||
0x77048f: 322,
|
||||
0x770490: 323,
|
||||
0x770491: 324,
|
||||
0x770492: 325,
|
||||
0x770493: 326,
|
||||
0x770494: 327,
|
||||
0x770495: 328,
|
||||
0x770496: 329,
|
||||
0x770497: 332,
|
||||
0x770498: 334,
|
||||
0x770499: 335,
|
||||
0x77049a: 336,
|
||||
0x77049b: 337,
|
||||
0x77049c: 340,
|
||||
0x77049d: 341,
|
||||
0x77049e: 342,
|
||||
0x77049f: 343,
|
||||
0x7704a0: 345,
|
||||
0x7704a1: 346,
|
||||
0x7704a2: 347,
|
||||
0x7704a3: 348,
|
||||
0x7704a4: 349,
|
||||
0x7704a5: 350,
|
||||
0x7704a6: 351,
|
||||
0x7704a7: 354,
|
||||
0x7704a8: 355,
|
||||
0x7704a9: 356,
|
||||
0x7704aa: 357,
|
||||
0x7704ab: 384,
|
||||
0x7704ac: 385,
|
||||
0x7704ad: 386,
|
||||
0x7704ae: 387,
|
||||
0x7704af: 388,
|
||||
0x7704b0: 389,
|
||||
0x7704b1: 391,
|
||||
0x7704b2: 392,
|
||||
0x7704b3: 393,
|
||||
0x7704b4: 394,
|
||||
0x7704b5: 396,
|
||||
0x7704b6: 397,
|
||||
0x7704b7: 398,
|
||||
0x7704b8: 399,
|
||||
0x7704b9: 400,
|
||||
0x7704ba: 401,
|
||||
0x7704bb: 402,
|
||||
0x7704bc: 403,
|
||||
0x7704bd: 404,
|
||||
0x7704be: 449,
|
||||
0x7704bf: 450,
|
||||
0x7704c0: 451,
|
||||
0x7704c1: 453,
|
||||
0x7704c2: 454,
|
||||
0x7704c3: 455,
|
||||
0x7704c4: 456,
|
||||
0x7704c5: 457,
|
||||
0x7704c6: 460,
|
||||
0x7704c7: 461,
|
||||
0x7704c8: 462,
|
||||
0x7704c9: 463,
|
||||
0x7704ca: 464,
|
||||
0x7704cb: 465,
|
||||
0x7704cc: 466,
|
||||
0x7704cd: 467,
|
||||
0x7704ce: 468,
|
||||
0x7704cf: 513,
|
||||
0x7704d0: 514,
|
||||
0x7704d1: 515,
|
||||
0x7704d2: 516,
|
||||
0x7704d3: 517,
|
||||
0x7704d4: 518,
|
||||
0x7704d5: 519,
|
||||
0x7704d6: 520,
|
||||
0x7704d7: 521,
|
||||
0x7704d8: 523,
|
||||
0x7704d9: 524,
|
||||
0x7704da: 527,
|
||||
0x7704db: 528,
|
||||
0x7704dc: 529,
|
||||
0x7704dd: 531,
|
||||
0x7704de: 532,
|
||||
0x7704df: 533,
|
||||
0x7704e0: 534,
|
||||
0x7704e1: 535,
|
||||
0x7704e2: 536,
|
||||
0x7704e3: 537,
|
||||
0x7704e4: 576,
|
||||
0x7704e5: 577,
|
||||
0x7704e6: 578,
|
||||
0x7704e7: 579,
|
||||
0x7704e8: 580,
|
||||
0x7704e9: 582,
|
||||
0x7704ea: 583,
|
||||
0x7704eb: 584,
|
||||
0x7704ec: 585,
|
||||
0x7704ed: 586,
|
||||
0x7704ee: 587,
|
||||
0x7704ef: 588,
|
||||
0x7704f0: 589,
|
||||
0x7704f1: 590,
|
||||
0x7704f2: 591,
|
||||
0x7704f3: 592,
|
||||
0x7704f4: 593,
|
||||
0x7704f5: 594,
|
||||
0x7704f6: 595,
|
||||
0x7704f7: 596,
|
||||
0x7704f8: 597,
|
||||
0x7704f9: 598,
|
||||
0x7704fa: 599,
|
||||
0x7704fb: 600,
|
||||
0x7704fc: 601,
|
||||
0x7704fd: 602,
|
||||
0x7704fe: 603,
|
||||
0x7704ff: 604,
|
||||
0x770500: 607,
|
||||
0x770501: 608,
|
||||
0x770502: 609,
|
||||
0x770503: 610,
|
||||
0x770504: 611,
|
||||
0x770505: 612,
|
||||
0x770506: 613,
|
||||
0x770507: 614,
|
||||
0x770508: 615,
|
||||
0x770509: 616,
|
||||
0x77050a: 617,
|
||||
0x77050b: 618,
|
||||
0x77050c: 619,
|
||||
0x77050d: 620,
|
||||
0x77050e: 621,
|
||||
0x77050f: 622,
|
||||
0x770510: 623,
|
||||
0x770511: 624,
|
||||
0x770512: 625,
|
||||
0x770513: 626,
|
||||
0x770514: 627,
|
||||
0x770515: 628,
|
||||
0x770516: 629,
|
||||
0x770517: 640,
|
||||
0x770518: 641,
|
||||
0x770519: 642,
|
||||
0x77051a: 643,
|
||||
0x77051b: 644,
|
||||
0x77051c: 645,
|
||||
0x77051d: 646,
|
||||
0x77051e: 647,
|
||||
0x77051f: 648,
|
||||
0x770520: 649,
|
||||
0x770521: 650,
|
||||
0x770522: 651,
|
||||
0x770523: 652,
|
||||
0x770524: 653,
|
||||
0x770525: 654,
|
||||
0x770526: 655,
|
||||
0x770527: 656,
|
||||
0x770528: 657,
|
||||
0x770529: 658,
|
||||
0x77052a: 659,
|
||||
0x77052b: 660,
|
||||
0x77052c: 661,
|
||||
0x77052d: 662,
|
||||
0x77052e: 663,
|
||||
0x77052f: 664,
|
||||
0x770530: 665,
|
||||
0x770531: 666,
|
||||
0x770532: 667,
|
||||
0x770533: 668,
|
||||
0x770534: 669,
|
||||
0x770535: 670,
|
||||
0x770536: 674,
|
||||
0x770537: 675,
|
||||
0x770538: 676,
|
||||
0x770539: 677,
|
||||
0x77053a: 678,
|
||||
0x77053b: 679,
|
||||
0x77053c: 680,
|
||||
0x77053d: 681,
|
||||
0x77053e: 682,
|
||||
0x77053f: 683,
|
||||
0x770540: 684,
|
||||
0x770541: 686,
|
||||
0x770542: 687,
|
||||
0x770543: 688,
|
||||
0x770544: 689,
|
||||
0x770545: 690,
|
||||
0x770546: 691,
|
||||
0x770547: 692,
|
||||
0x770548: 694,
|
||||
0x770549: 695,
|
||||
0x77054a: 704,
|
||||
0x77054b: 705,
|
||||
0x77054c: 706,
|
||||
0x77054d: 707,
|
||||
0x77054e: 708,
|
||||
0x77054f: 709,
|
||||
0x770550: 710,
|
||||
0x770551: 711,
|
||||
0x770552: 712,
|
||||
0x770553: 713,
|
||||
0x770554: 714,
|
||||
0x770555: 715,
|
||||
0x770556: 716,
|
||||
0x770557: 717,
|
||||
0x770558: 718,
|
||||
0x770559: 719,
|
||||
0x77055a: 720,
|
||||
0x77055b: 721,
|
||||
0x77055c: 722,
|
||||
0x77055d: 723,
|
||||
0x77055e: 724,
|
||||
0x77055f: 725,
|
||||
0x770560: 726,
|
||||
0x770561: 769,
|
||||
0x770562: 770,
|
||||
0x770563: 771,
|
||||
0x770564: 772,
|
||||
0x770565: 773,
|
||||
0x770566: 774,
|
||||
0x770567: 775,
|
||||
0x770568: 776,
|
||||
0x770569: 777,
|
||||
0x77056a: 778,
|
||||
0x77056b: 779,
|
||||
0x77056c: 780,
|
||||
0x77056d: 781,
|
||||
0x77056e: 782,
|
||||
0x77056f: 783,
|
||||
0x770570: 784,
|
||||
0x770571: 785,
|
||||
0x770572: 786,
|
||||
0x770573: 787,
|
||||
0x770574: 788,
|
||||
0x770575: 789,
|
||||
0x770576: 790,
|
||||
0x770577: 832,
|
||||
0x770578: 833,
|
||||
0x770579: 834,
|
||||
0x77057a: 835,
|
||||
0x77057b: 836,
|
||||
0x77057c: 837,
|
||||
0x77057d: 838,
|
||||
0x77057e: 839,
|
||||
0x77057f: 840,
|
||||
0x770580: 841,
|
||||
0x770581: 842,
|
||||
0x770582: 843,
|
||||
0x770583: 844,
|
||||
0x770584: 845,
|
||||
0x770585: 846,
|
||||
0x770586: 847,
|
||||
0x770587: 848,
|
||||
0x770588: 849,
|
||||
0x770589: 850,
|
||||
0x77058a: 854,
|
||||
0x77058b: 855,
|
||||
0x77058c: 856,
|
||||
0x77058d: 857,
|
||||
0x77058e: 858,
|
||||
0x77058f: 859,
|
||||
0x770590: 860,
|
||||
0x770591: 861,
|
||||
0x770592: 862,
|
||||
0x770593: 863,
|
||||
0x770594: 864,
|
||||
0x770595: 865,
|
||||
0x770596: 866,
|
||||
0x770597: 867,
|
||||
0x770598: 868,
|
||||
0x770599: 869,
|
||||
0x77059a: 870,
|
||||
0x77059b: 871,
|
||||
0x77059c: 872,
|
||||
0x77059d: 873,
|
||||
0x77059e: 874,
|
||||
0x77059f: 875,
|
||||
0x7705a0: 876,
|
||||
0x7705a1: 877,
|
||||
0x7705a2: 878,
|
||||
0x7705a3: 879,
|
||||
0x7705a4: 880,
|
||||
0x7705a5: 881,
|
||||
0x7705a6: 882,
|
||||
0x7705a7: 896,
|
||||
0x7705a8: 897,
|
||||
0x7705a9: 898,
|
||||
0x7705aa: 899,
|
||||
0x7705ab: 900,
|
||||
0x7705ac: 901,
|
||||
0x7705ad: 902,
|
||||
0x7705ae: 903,
|
||||
0x7705af: 904,
|
||||
0x7705b0: 905,
|
||||
0x7705b1: 960,
|
||||
0x7705b2: 961,
|
||||
0x7705b3: 962,
|
||||
0x7705b4: 963,
|
||||
0x7705b5: 964,
|
||||
0x7705b6: 965,
|
||||
0x7705b7: 966,
|
||||
0x7705b8: 967,
|
||||
0x7705b9: 968,
|
||||
0x7705ba: 969,
|
||||
0x7705bb: 970,
|
||||
0x7705bc: 972,
|
||||
0x7705bd: 973,
|
||||
0x7705be: 974,
|
||||
0x7705bf: 975,
|
||||
0x7705c0: 977,
|
||||
0x7705c1: 978,
|
||||
0x7705c2: 979,
|
||||
0x7705c3: 980,
|
||||
0x7705c4: 981,
|
||||
0x7705c5: 982,
|
||||
0x7705c6: 983,
|
||||
0x7705c7: 984,
|
||||
0x7705c8: 1025,
|
||||
0x7705c9: 1026,
|
||||
0x7705ca: 1027,
|
||||
0x7705cb: 1028,
|
||||
0x7705cc: 1029,
|
||||
0x7705cd: 1030,
|
||||
0x7705ce: 1031,
|
||||
0x7705cf: 1032,
|
||||
0x7705d0: 1033,
|
||||
0x7705d1: 1034,
|
||||
0x7705d2: 1037,
|
||||
0x7705d3: 1040,
|
||||
0x7705d4: 1041,
|
||||
0x7705d5: 1042,
|
||||
0x7705d6: 1043,
|
||||
0x7705d7: 1044,
|
||||
0x7705d8: 1045,
|
||||
0x7705d9: 1046,
|
||||
0x7705da: 1049,
|
||||
0x7705db: 1050,
|
||||
0x7705dc: 1051,
|
||||
0x7705dd: 1052,
|
||||
0x7705de: 1053,
|
||||
0x7705df: 1054,
|
||||
0x7705e0: 1055,
|
||||
0x7705e1: 1056,
|
||||
0x7705e2: 1057,
|
||||
0x7705e3: 1058,
|
||||
0x7705e4: 1059,
|
||||
0x7705e5: 1060,
|
||||
0x7705e6: 1061,
|
||||
0x7705e7: 1062,
|
||||
0x7705e8: 1063,
|
||||
0x7705e9: 1064,
|
||||
0x7705ea: 1065,
|
||||
0x7705eb: 1066,
|
||||
0x7705ec: 1067,
|
||||
0x7705ed: 1068,
|
||||
0x7705ee: 1069,
|
||||
0x7705ef: 1070,
|
||||
0x7705f0: 1152,
|
||||
0x7705f1: 1154,
|
||||
0x7705f2: 1155,
|
||||
0x7705f3: 1156,
|
||||
0x7705f4: 1157,
|
||||
0x7705f5: 1158,
|
||||
0x7705f6: 1159,
|
||||
0x7705f7: 1160,
|
||||
0x7705f8: 1161,
|
||||
0x7705f9: 1162,
|
||||
0x7705fa: 1163,
|
||||
0x7705fb: 1164,
|
||||
0x7705fc: 1165,
|
||||
0x7705fd: 1166,
|
||||
0x7705fe: 1167,
|
||||
0x7705ff: 1168,
|
||||
0x770600: 1169,
|
||||
0x770601: 1173,
|
||||
0x770602: 1174,
|
||||
0x770603: 1175,
|
||||
0x770604: 1176,
|
||||
0x770605: 1177,
|
||||
0x770606: 1178,
|
||||
0x770607: 1216,
|
||||
0x770608: 1217,
|
||||
0x770609: 1218,
|
||||
0x77060a: 1219,
|
||||
0x77060b: 1220,
|
||||
0x77060c: 1221,
|
||||
0x77060d: 1222,
|
||||
0x77060e: 1223,
|
||||
0x77060f: 1224,
|
||||
0x770610: 1225,
|
||||
0x770611: 1226,
|
||||
0x770612: 1227,
|
||||
0x770613: 1228,
|
||||
0x770614: 1229,
|
||||
0x770615: 1230,
|
||||
0x770616: 1231,
|
||||
0x770617: 1232,
|
||||
0x770618: 1233,
|
||||
0x770619: 1234,
|
||||
0x77061a: 1235,
|
||||
0x77061b: 1236,
|
||||
0x77061c: 1237,
|
||||
0x77061d: 1238,
|
||||
0x77061e: 1239,
|
||||
0x77061f: 1240,
|
||||
0x770620: 1241,
|
||||
0x770621: 1242,
|
||||
0x770622: 1243,
|
||||
0x770623: 1244,
|
||||
0x770624: 1245,
|
||||
0x770625: 1246,
|
||||
0x770626: 1247,
|
||||
0x770627: 1248,
|
||||
0x770628: 1249,
|
||||
0x770629: 1250,
|
||||
0x77062a: 1251,
|
||||
0x77062b: 1252,
|
||||
0x77062c: 1253,
|
||||
0x77062d: 1254,
|
||||
0x77062e: 1255,
|
||||
0x77062f: 1256,
|
||||
0x770630: 1257,
|
||||
0x770631: 1258,
|
||||
0x770632: 1259,
|
||||
0x770633: 1260,
|
||||
0x770634: 1261,
|
||||
0x770635: 1262,
|
||||
0x770636: 1263,
|
||||
0x770637: 1264,
|
||||
0x770638: 1265,
|
||||
0x770639: 1266,
|
||||
0x77063a: 1267,
|
||||
0x77063b: 1268,
|
||||
0x77063c: 1269,
|
||||
0x77063d: 1280,
|
||||
0x77063e: 1281,
|
||||
0x77063f: 1282,
|
||||
0x770640: 1283,
|
||||
0x770641: 1284,
|
||||
0x770642: 1285,
|
||||
0x770643: 1286,
|
||||
0x770644: 1289,
|
||||
0x770645: 1290,
|
||||
0x770646: 1291,
|
||||
0x770647: 1292,
|
||||
0x770648: 1293,
|
||||
0x770649: 1294,
|
||||
0x77064a: 1295,
|
||||
0x77064b: 1296,
|
||||
0x77064c: 1297,
|
||||
0x77064d: 1298,
|
||||
0x77064e: 1299,
|
||||
0x77064f: 1300,
|
||||
0x770650: 1301,
|
||||
0x770651: 1302,
|
||||
0x770652: 1303,
|
||||
0x770653: 1344,
|
||||
0x770654: 1345,
|
||||
0x770655: 1346,
|
||||
0x770656: 1347,
|
||||
0x770657: 1348,
|
||||
0x770658: 1349,
|
||||
0x770659: 1350,
|
||||
0x77065a: 1351,
|
||||
0x77065b: 1352,
|
||||
0x77065c: 1354,
|
||||
0x77065d: 1355,
|
||||
0x77065e: 1356,
|
||||
0x77065f: 1357,
|
||||
0x770660: 1358,
|
||||
0x770661: 1359,
|
||||
0x770662: 1360,
|
||||
0x770663: 1361,
|
||||
0x770664: 1362,
|
||||
0x770665: 1363,
|
||||
0x770666: 1365,
|
||||
0x770667: 1366,
|
||||
0x770668: 1367,
|
||||
0x770669: 1368,
|
||||
0x77066a: 1369,
|
||||
0x77066b: 1370,
|
||||
0x77066c: 1371,
|
||||
0x77066d: 1372,
|
||||
0x77066e: 1374,
|
||||
0x77066f: 1375,
|
||||
0x770670: 1376,
|
||||
0x770671: 1379,
|
||||
0x770672: 1380,
|
||||
0x770673: 1381,
|
||||
0x770674: 1382,
|
||||
0x770675: 1383,
|
||||
0x770676: 1384,
|
||||
0x770677: 1385,
|
||||
0x770678: 1386,
|
||||
0x770679: 1387,
|
||||
0x77067a: 1388,
|
||||
0x77067b: 1389,
|
||||
0x77067c: 1390,
|
||||
0x77067d: 1391,
|
||||
0x77067e: 1392,
|
||||
0x77067f: 1393,
|
||||
0x770680: 1394,
|
||||
0x770681: 1395,
|
||||
0x770682: 1396,
|
||||
0x770683: 1397,
|
||||
0x770684: 1398,
|
||||
0x770685: 1408,
|
||||
0x770686: 1409,
|
||||
0x770687: 1410,
|
||||
0x770688: 1411,
|
||||
0x770689: 1412,
|
||||
0x77068a: 1414,
|
||||
0x77068b: 1472,
|
||||
0x77068c: 1473,
|
||||
0x77068d: 1474,
|
||||
0x77068e: 1475,
|
||||
0x77068f: 1476,
|
||||
0x770690: 1477,
|
||||
0x770691: 1478,
|
||||
0x770692: 1479,
|
||||
0x770693: 1480,
|
||||
0x770694: 1481,
|
||||
0x770695: 1482,
|
||||
0x770696: 1483,
|
||||
0x770697: 1484,
|
||||
0x770698: 1486,
|
||||
0x770699: 1487,
|
||||
0x77069a: 1488,
|
||||
0x77069b: 1489,
|
||||
0x77069c: 1490,
|
||||
0x77069d: 1491,
|
||||
0x77069e: 1495,
|
||||
0x77069f: 1496,
|
||||
0x7706a0: 1497,
|
||||
0x7706a1: 1498,
|
||||
0x7706a2: 1499,
|
||||
0x7706a3: 1500,
|
||||
0x7706a4: 1501,
|
||||
0x7706a5: 1502,
|
||||
0x7706a6: 1503,
|
||||
0x7706a7: 1504,
|
||||
0x7706a8: 1505,
|
||||
0x7706a9: 1506,
|
||||
0x7706aa: 1507,
|
||||
0x7706ab: 1508,
|
||||
0x7706ac: 1536,
|
||||
0x7706ad: 1537,
|
||||
0x7706ae: 1538,
|
||||
0x7706af: 1539,
|
||||
0x7706b0: 1540,
|
||||
0x7706b1: 1541,
|
||||
0x7706b2: 1600,
|
||||
0x7706b3: 1601,
|
||||
0x7706b4: 1602,
|
||||
0x7706b5: 1603,
|
||||
0x7706b6: 1604,
|
||||
0x7706b7: 1605,
|
||||
0x7706b8: 1606,
|
||||
0x7706b9: 1607,
|
||||
0x7706ba: 1612,
|
||||
0x7706bb: 1613,
|
||||
0x7706bc: 1614,
|
||||
0x7706bd: 1615,
|
||||
0x7706be: 1616,
|
||||
0x7706bf: 1617,
|
||||
0x7706c0: 1618,
|
||||
0x7706c1: 1619,
|
||||
0x7706c2: 1620,
|
||||
0x7706c3: 1621,
|
||||
0x7706c4: 1622,
|
||||
0x7706c5: 1664,
|
||||
0x7706c6: 1665,
|
||||
0x7706c7: 1667,
|
||||
0x7706c8: 1668,
|
||||
0x7706c9: 1670,
|
||||
0x7706ca: 1671,
|
||||
0x7706cb: 1672,
|
||||
0x7706cc: 1673,
|
||||
0x7706cd: 1674,
|
||||
0x7706ce: 1675,
|
||||
0x7706cf: 1676,
|
||||
0x7706d0: 1677,
|
||||
0x7706d1: 1678,
|
||||
0x7706d2: 1679,
|
||||
0x7706d3: 1680,
|
||||
0x7706d4: 1681,
|
||||
0x7706d5: 1682,
|
||||
0x7706d6: 1683,
|
||||
0x7706d7: 1684,
|
||||
0x7706d8: 1685,
|
||||
0x7706d9: 1686,
|
||||
0x7706da: 1730,
|
||||
0x7706db: 1732,
|
||||
0x7706dc: 1734,
|
||||
0x7706dd: 1792,
|
||||
0x7706de: 1793,
|
||||
0x7706df: 1794,
|
||||
0x7706e0: 1795,
|
||||
0x7706e1: 1796,
|
||||
0x7706e2: 1797,
|
||||
0x7706e3: 1798,
|
||||
0x7706e4: 1799,
|
||||
0x7706e5: 1800,
|
||||
0x7706e6: 1801,
|
||||
0x7706e7: 1802,
|
||||
0x7706e8: 1803,
|
||||
0x7706e9: 1804,
|
||||
0x7706ea: 1805,
|
||||
0x7706eb: 1810,
|
||||
0x7706ec: 1811,
|
||||
0x7706ed: 1812,
|
||||
0x7706ee: 1813,
|
||||
0x7706ef: 1814,
|
||||
0x7706f0: 1815,
|
||||
0x7706f1: 1817,
|
||||
0x7706f2: 1818,
|
||||
0x7706f3: 1819,
|
||||
0x7706f4: 1820,
|
||||
0x7706f5: 1821,
|
||||
0x7706f6: 1822,
|
||||
0x7706f7: 1823,
|
||||
0x7706f8: 1824,
|
||||
0x7706f9: 1825,
|
||||
0x7706fa: 1826,
|
||||
0x7706fb: 1827,
|
||||
0x7706fc: 1828,
|
||||
0x7706fd: 1831,
|
||||
0x7706fe: 1832,
|
||||
0x7706ff: 1858,
|
||||
}
|
57
worlds/kdl3/Compression.py
Normal file
57
worlds/kdl3/Compression.py
Normal file
@@ -0,0 +1,57 @@
|
||||
def hal_decompress(comp: bytes) -> bytes:
|
||||
"""
|
||||
HAL decompression based on exhal by devinacker
|
||||
https://github.com/devinacker/exhal
|
||||
"""
|
||||
inpos = 0
|
||||
|
||||
inval = 0
|
||||
output = bytearray()
|
||||
while inval != 0xFF:
|
||||
remaining = 65536 - inpos
|
||||
if remaining < 1:
|
||||
return bytes()
|
||||
inval = comp[inpos]
|
||||
inpos += 1
|
||||
if inval == 0xFF:
|
||||
break
|
||||
if (inval & 0xE0) == 0xE0:
|
||||
command = (inval >> 2) & 0x07
|
||||
length = (((inval & 0x03) << 8) | comp[inpos]) + 1
|
||||
inpos += 1
|
||||
else:
|
||||
command = inval >> 5
|
||||
length = (inval & 0x1F) + 1
|
||||
if (command == 2 and ((len(output) + 2*length) > 65536)) or (len(output) + length) > 65536:
|
||||
return bytes()
|
||||
if command == 0:
|
||||
output.extend(comp[inpos:inpos+length])
|
||||
inpos += length
|
||||
elif command == 1:
|
||||
output.extend([comp[inpos] for _ in range(length)])
|
||||
inpos += 1
|
||||
elif command == 2:
|
||||
output.extend([comp[x] for _ in range(length) for x in (inpos, inpos+1)])
|
||||
inpos += 2
|
||||
elif command == 3:
|
||||
output.extend([comp[inpos] + i for i in range(length)])
|
||||
inpos += 1
|
||||
elif command == 4 or command == 7:
|
||||
offset = (comp[inpos] << 8) | comp[inpos + 1]
|
||||
if (offset + length) > 65536:
|
||||
return bytes()
|
||||
output.extend(output[offset:offset+length])
|
||||
inpos += 2
|
||||
elif command == 5:
|
||||
offset = (comp[inpos] << 8) | comp[inpos + 1]
|
||||
if (offset + length) > 65536:
|
||||
return bytes()
|
||||
output.extend([int('{:08b}'.format(x)[::-1], 2) for x in output[offset:offset+length]])
|
||||
inpos += 2
|
||||
elif command == 6:
|
||||
offset = (comp[inpos] << 8) | comp[inpos + 1]
|
||||
if offset < length - 1:
|
||||
return bytes()
|
||||
output.extend([output[offset - x] for x in range(length)])
|
||||
inpos += 2
|
||||
return bytes(output)
|
282
worlds/kdl3/Gifting.py
Normal file
282
worlds/kdl3/Gifting.py
Normal file
@@ -0,0 +1,282 @@
|
||||
# Small subfile to handle gifting info such as desired traits and giftbox management
|
||||
import typing
|
||||
|
||||
|
||||
async def update_object(ctx, key: str, value: typing.Dict):
|
||||
await ctx.send_msgs([
|
||||
{
|
||||
"cmd": "Set",
|
||||
"key": key,
|
||||
"default": {},
|
||||
"want_reply": False,
|
||||
"operations": [
|
||||
{"operation": "update", "value": value}
|
||||
]
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
async def pop_object(ctx, key: str, value: str):
|
||||
await ctx.send_msgs([
|
||||
{
|
||||
"cmd": "Set",
|
||||
"key": key,
|
||||
"default": {},
|
||||
"want_reply": False,
|
||||
"operations": [
|
||||
{"operation": "pop", "value": value}
|
||||
]
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
async def initialize_giftboxes(ctx, giftbox_key: str, motherbox_key: str, is_open: bool):
|
||||
ctx.set_notify(motherbox_key, giftbox_key)
|
||||
await update_object(ctx, f"Giftboxes;{ctx.team}", {f"{ctx.slot}":
|
||||
{
|
||||
"IsOpen": is_open,
|
||||
**kdl3_gifting_options
|
||||
}})
|
||||
ctx.gifting = is_open
|
||||
|
||||
|
||||
kdl3_gifting_options = {
|
||||
"AcceptsAnyGift": True,
|
||||
"DesiredTraits": [
|
||||
"Consumable", "Food", "Drink", "Candy", "Tomato",
|
||||
"Invincible", "Life", "Heal", "Health", "Trap",
|
||||
"Goo", "Gel", "Slow", "Slowness", "Eject", "Removal"
|
||||
],
|
||||
"MinimumGiftVersion": 2,
|
||||
}
|
||||
|
||||
kdl3_gifts = {
|
||||
1: {
|
||||
"ItemName": "1-Up",
|
||||
"Amount": 1,
|
||||
"ItemValue": 400000,
|
||||
"Traits": [
|
||||
{
|
||||
"Trait": "Consumable",
|
||||
"Quality": 1,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Life",
|
||||
"Quality": 1,
|
||||
"Duration": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
2: {
|
||||
"ItemName": "Maxim Tomato",
|
||||
"Amount": 1,
|
||||
"ItemValue": 500000,
|
||||
"Traits": [
|
||||
{
|
||||
"Trait": "Consumable",
|
||||
"Quality": 5,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Heal",
|
||||
"Quality": 5,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Food",
|
||||
"Quality": 5,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Tomato",
|
||||
"Quality": 5,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Vegetable",
|
||||
"Quality": 5,
|
||||
"Duration": 1,
|
||||
}
|
||||
]
|
||||
},
|
||||
3: {
|
||||
"ItemName": "Energy Drink",
|
||||
"Amount": 1,
|
||||
"ItemValue": 100000,
|
||||
"Traits": [
|
||||
{
|
||||
"Trait": "Consumable",
|
||||
"Quality": 1,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Heal",
|
||||
"Quality": 1,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Drink",
|
||||
"Quality": 1,
|
||||
"Duration": 1,
|
||||
},
|
||||
]
|
||||
},
|
||||
5: {
|
||||
"ItemName": "Small Star Piece",
|
||||
"Amount": 1,
|
||||
"ItemValue": 10000,
|
||||
"Traits": [
|
||||
{
|
||||
"Trait": "Currency",
|
||||
"Quality": 1,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Money",
|
||||
"Quality": 1,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Star",
|
||||
"Quality": 1,
|
||||
"Duration": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
6: {
|
||||
"ItemName": "Medium Star Piece",
|
||||
"Amount": 1,
|
||||
"ItemValue": 30000,
|
||||
"Traits": [
|
||||
{
|
||||
"Trait": "Currency",
|
||||
"Quality": 3,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Money",
|
||||
"Quality": 3,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Star",
|
||||
"Quality": 3,
|
||||
"Duration": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
7: {
|
||||
"ItemName": "Large Star Piece",
|
||||
"Amount": 1,
|
||||
"ItemValue": 50000,
|
||||
"Traits": [
|
||||
{
|
||||
"Trait": "Currency",
|
||||
"Quality": 5,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Money",
|
||||
"Quality": 5,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Star",
|
||||
"Quality": 5,
|
||||
"Duration": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
}
|
||||
|
||||
kdl3_trap_gifts = {
|
||||
0: {
|
||||
"ItemName": "Gooey Bag",
|
||||
"Amount": 1,
|
||||
"ItemValue": 10000,
|
||||
"Traits": [
|
||||
{
|
||||
"Trait": "Trap",
|
||||
"Quality": 1,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Goo",
|
||||
"Quality": 1,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Gel",
|
||||
"Quality": 1,
|
||||
"Duration": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
1: {
|
||||
"ItemName": "Slowness",
|
||||
"Amount": 1,
|
||||
"ItemValue": 10000,
|
||||
"Traits": [
|
||||
{
|
||||
"Trait": "Trap",
|
||||
"Quality": 1,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Slow",
|
||||
"Quality": 1,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Slowness",
|
||||
"Quality": 1,
|
||||
"Duration": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
2: {
|
||||
"ItemName": "Eject Ability",
|
||||
"Amount": 1,
|
||||
"ItemValue": 10000,
|
||||
"Traits": [
|
||||
{
|
||||
"Trait": "Trap",
|
||||
"Quality": 1,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Eject",
|
||||
"Quality": 1,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Removal",
|
||||
"Quality": 1,
|
||||
"Duration": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
3: {
|
||||
"ItemName": "Bad Meal",
|
||||
"Amount": 1,
|
||||
"ItemValue": 10000,
|
||||
"Traits": [
|
||||
{
|
||||
"Trait": "Trap",
|
||||
"Quality": 1,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Damage",
|
||||
"Quality": 1,
|
||||
"Duration": 1,
|
||||
},
|
||||
{
|
||||
"Trait": "Food",
|
||||
"Quality": 1,
|
||||
"Duration": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
}
|
105
worlds/kdl3/Items.py
Normal file
105
worlds/kdl3/Items.py
Normal file
@@ -0,0 +1,105 @@
|
||||
from BaseClasses import Item
|
||||
import typing
|
||||
|
||||
|
||||
class ItemData(typing.NamedTuple):
|
||||
code: typing.Optional[int]
|
||||
progression: bool
|
||||
skip_balancing: bool = False
|
||||
trap: bool = False
|
||||
|
||||
|
||||
class KDL3Item(Item):
|
||||
game = "Kirby's Dream Land 3"
|
||||
|
||||
|
||||
copy_ability_table = {
|
||||
"Burning": ItemData(0x770001, True),
|
||||
"Stone": ItemData(0x770002, True),
|
||||
"Ice": ItemData(0x770003, True),
|
||||
"Needle": ItemData(0x770004, True),
|
||||
"Clean": ItemData(0x770005, True),
|
||||
"Parasol": ItemData(0x770006, True),
|
||||
"Spark": ItemData(0x770007, True),
|
||||
"Cutter": ItemData(0x770008, True)
|
||||
}
|
||||
|
||||
animal_friend_table = {
|
||||
"Rick": ItemData(0x770010, True),
|
||||
"Kine": ItemData(0x770011, True),
|
||||
"Coo": ItemData(0x770012, True),
|
||||
"Nago": ItemData(0x770013, True),
|
||||
"ChuChu": ItemData(0x770014, True),
|
||||
"Pitch": ItemData(0x770015, True)
|
||||
}
|
||||
|
||||
animal_friend_spawn_table = {
|
||||
"Rick Spawn": ItemData(None, True),
|
||||
"Kine Spawn": ItemData(None, True),
|
||||
"Coo Spawn": ItemData(None, True),
|
||||
"Nago Spawn": ItemData(None, True),
|
||||
"ChuChu Spawn": ItemData(None, True),
|
||||
"Pitch Spawn": ItemData(None, True)
|
||||
}
|
||||
|
||||
copy_ability_access_table = {
|
||||
"No Ability": ItemData(None, False),
|
||||
"Burning Ability": ItemData(None, True),
|
||||
"Stone Ability": ItemData(None, True),
|
||||
"Ice Ability": ItemData(None, True),
|
||||
"Needle Ability": ItemData(None, True),
|
||||
"Clean Ability": ItemData(None, True),
|
||||
"Parasol Ability": ItemData(None, True),
|
||||
"Spark Ability": ItemData(None, True),
|
||||
"Cutter Ability": ItemData(None, True),
|
||||
}
|
||||
|
||||
misc_item_table = {
|
||||
"Heart Star": ItemData(0x770020, True, True),
|
||||
"1-Up": ItemData(0x770021, False),
|
||||
"Maxim Tomato": ItemData(0x770022, False),
|
||||
"Invincible Candy": ItemData(0x770023, False),
|
||||
"Little Star": ItemData(0x770024, False),
|
||||
"Medium Star": ItemData(0x770025, False),
|
||||
"Big Star": ItemData(0x770026, False),
|
||||
}
|
||||
|
||||
trap_item_table = {
|
||||
"Gooey Bag": ItemData(0x770040, False, False, True),
|
||||
"Slowness": ItemData(0x770041, False, False, True),
|
||||
"Eject Ability": ItemData(0x770042, False, False, True)
|
||||
}
|
||||
|
||||
filler_item_weights = {
|
||||
"1-Up": 4,
|
||||
"Maxim Tomato": 2,
|
||||
"Invincible Candy": 2
|
||||
}
|
||||
|
||||
star_item_weights = {
|
||||
"Little Star": 4,
|
||||
"Medium Star": 2,
|
||||
"Big Star": 1
|
||||
}
|
||||
|
||||
total_filler_weights = {
|
||||
**filler_item_weights,
|
||||
**star_item_weights
|
||||
}
|
||||
|
||||
|
||||
item_table = {
|
||||
**copy_ability_table,
|
||||
**copy_ability_access_table,
|
||||
**animal_friend_table,
|
||||
**animal_friend_spawn_table,
|
||||
**misc_item_table,
|
||||
**trap_item_table
|
||||
}
|
||||
|
||||
item_names = {
|
||||
"Copy Ability": set(copy_ability_table),
|
||||
"Animal Friend": set(animal_friend_table),
|
||||
}
|
||||
|
||||
lookup_name_to_id: typing.Dict[str, int] = {item_name: data.code for item_name, data in item_table.items() if data.code}
|
940
worlds/kdl3/Locations.py
Normal file
940
worlds/kdl3/Locations.py
Normal file
@@ -0,0 +1,940 @@
|
||||
import typing
|
||||
from BaseClasses import Location, Region
|
||||
from .Names import LocationName
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from .Room import KDL3Room
|
||||
|
||||
|
||||
class KDL3Location(Location):
|
||||
game: str = "Kirby's Dream Land 3"
|
||||
room: typing.Optional["KDL3Room"] = None
|
||||
|
||||
def __init__(self, player: int, name: str, address: typing.Optional[int], parent: typing.Union[Region, None]):
|
||||
super().__init__(player, name, address, parent)
|
||||
if not address:
|
||||
self.show_in_spoiler = False
|
||||
|
||||
|
||||
stage_locations = {
|
||||
0x770001: LocationName.grass_land_1,
|
||||
0x770002: LocationName.grass_land_2,
|
||||
0x770003: LocationName.grass_land_3,
|
||||
0x770004: LocationName.grass_land_4,
|
||||
0x770005: LocationName.grass_land_5,
|
||||
0x770006: LocationName.grass_land_6,
|
||||
0x770007: LocationName.ripple_field_1,
|
||||
0x770008: LocationName.ripple_field_2,
|
||||
0x770009: LocationName.ripple_field_3,
|
||||
0x77000A: LocationName.ripple_field_4,
|
||||
0x77000B: LocationName.ripple_field_5,
|
||||
0x77000C: LocationName.ripple_field_6,
|
||||
0x77000D: LocationName.sand_canyon_1,
|
||||
0x77000E: LocationName.sand_canyon_2,
|
||||
0x77000F: LocationName.sand_canyon_3,
|
||||
0x770010: LocationName.sand_canyon_4,
|
||||
0x770011: LocationName.sand_canyon_5,
|
||||
0x770012: LocationName.sand_canyon_6,
|
||||
0x770013: LocationName.cloudy_park_1,
|
||||
0x770014: LocationName.cloudy_park_2,
|
||||
0x770015: LocationName.cloudy_park_3,
|
||||
0x770016: LocationName.cloudy_park_4,
|
||||
0x770017: LocationName.cloudy_park_5,
|
||||
0x770018: LocationName.cloudy_park_6,
|
||||
0x770019: LocationName.iceberg_1,
|
||||
0x77001A: LocationName.iceberg_2,
|
||||
0x77001B: LocationName.iceberg_3,
|
||||
0x77001C: LocationName.iceberg_4,
|
||||
0x77001D: LocationName.iceberg_5,
|
||||
0x77001E: LocationName.iceberg_6,
|
||||
}
|
||||
|
||||
heart_star_locations = {
|
||||
0x770101: LocationName.grass_land_tulip,
|
||||
0x770102: LocationName.grass_land_muchi,
|
||||
0x770103: LocationName.grass_land_pitcherman,
|
||||
0x770104: LocationName.grass_land_chao,
|
||||
0x770105: LocationName.grass_land_mine,
|
||||
0x770106: LocationName.grass_land_pierre,
|
||||
0x770107: LocationName.ripple_field_kamuribana,
|
||||
0x770108: LocationName.ripple_field_bakasa,
|
||||
0x770109: LocationName.ripple_field_elieel,
|
||||
0x77010A: LocationName.ripple_field_toad,
|
||||
0x77010B: LocationName.ripple_field_mama_pitch,
|
||||
0x77010C: LocationName.ripple_field_hb002,
|
||||
0x77010D: LocationName.sand_canyon_mushrooms,
|
||||
0x77010E: LocationName.sand_canyon_auntie,
|
||||
0x77010F: LocationName.sand_canyon_caramello,
|
||||
0x770110: LocationName.sand_canyon_hikari,
|
||||
0x770111: LocationName.sand_canyon_nyupun,
|
||||
0x770112: LocationName.sand_canyon_rob,
|
||||
0x770113: LocationName.cloudy_park_hibanamodoki,
|
||||
0x770114: LocationName.cloudy_park_piyokeko,
|
||||
0x770115: LocationName.cloudy_park_mrball,
|
||||
0x770116: LocationName.cloudy_park_mikarin,
|
||||
0x770117: LocationName.cloudy_park_pick,
|
||||
0x770118: LocationName.cloudy_park_hb007,
|
||||
0x770119: LocationName.iceberg_kogoesou,
|
||||
0x77011A: LocationName.iceberg_samus,
|
||||
0x77011B: LocationName.iceberg_kawasaki,
|
||||
0x77011C: LocationName.iceberg_name,
|
||||
0x77011D: LocationName.iceberg_shiro,
|
||||
0x77011E: LocationName.iceberg_angel,
|
||||
}
|
||||
|
||||
boss_locations = {
|
||||
0x770200: LocationName.grass_land_whispy,
|
||||
0x770201: LocationName.ripple_field_acro,
|
||||
0x770202: LocationName.sand_canyon_poncon,
|
||||
0x770203: LocationName.cloudy_park_ado,
|
||||
0x770204: LocationName.iceberg_dedede,
|
||||
}
|
||||
|
||||
consumable_locations = {
|
||||
0x770300: LocationName.grass_land_1_u1,
|
||||
0x770301: LocationName.grass_land_1_m1,
|
||||
0x770302: LocationName.grass_land_2_u1,
|
||||
0x770303: LocationName.grass_land_3_u1,
|
||||
0x770304: LocationName.grass_land_3_m1,
|
||||
0x770305: LocationName.grass_land_4_m1,
|
||||
0x770306: LocationName.grass_land_4_u1,
|
||||
0x770307: LocationName.grass_land_4_m2,
|
||||
0x770308: LocationName.grass_land_4_m3,
|
||||
0x770309: LocationName.grass_land_6_u1,
|
||||
0x77030A: LocationName.grass_land_6_u2,
|
||||
0x77030B: LocationName.ripple_field_2_u1,
|
||||
0x77030C: LocationName.ripple_field_2_m1,
|
||||
0x77030D: LocationName.ripple_field_3_m1,
|
||||
0x77030E: LocationName.ripple_field_3_u1,
|
||||
0x77030F: LocationName.ripple_field_4_m2,
|
||||
0x770310: LocationName.ripple_field_4_u1,
|
||||
0x770311: LocationName.ripple_field_4_m1,
|
||||
0x770312: LocationName.ripple_field_5_u1,
|
||||
0x770313: LocationName.ripple_field_5_m2,
|
||||
0x770314: LocationName.ripple_field_5_m1,
|
||||
0x770315: LocationName.sand_canyon_1_u1,
|
||||
0x770316: LocationName.sand_canyon_2_u1,
|
||||
0x770317: LocationName.sand_canyon_2_m1,
|
||||
0x770318: LocationName.sand_canyon_4_m1,
|
||||
0x770319: LocationName.sand_canyon_4_u1,
|
||||
0x77031A: LocationName.sand_canyon_4_m2,
|
||||
0x77031B: LocationName.sand_canyon_5_u1,
|
||||
0x77031C: LocationName.sand_canyon_5_u3,
|
||||
0x77031D: LocationName.sand_canyon_5_m1,
|
||||
0x77031E: LocationName.sand_canyon_5_u4,
|
||||
0x77031F: LocationName.sand_canyon_5_u2,
|
||||
0x770320: LocationName.cloudy_park_1_m1,
|
||||
0x770321: LocationName.cloudy_park_1_u1,
|
||||
0x770322: LocationName.cloudy_park_4_u1,
|
||||
0x770323: LocationName.cloudy_park_4_m1,
|
||||
0x770324: LocationName.cloudy_park_5_m1,
|
||||
0x770325: LocationName.cloudy_park_6_u1,
|
||||
0x770326: LocationName.iceberg_3_m1,
|
||||
0x770327: LocationName.iceberg_5_u1,
|
||||
0x770328: LocationName.iceberg_5_u2,
|
||||
0x770329: LocationName.iceberg_5_u3,
|
||||
0x77032A: LocationName.iceberg_6_m1,
|
||||
0x77032B: LocationName.iceberg_6_u1,
|
||||
}
|
||||
|
||||
level_consumables = {
|
||||
1: [0, 1],
|
||||
2: [2],
|
||||
3: [3, 4],
|
||||
4: [5, 6, 7, 8],
|
||||
6: [9, 10],
|
||||
8: [11, 12],
|
||||
9: [13, 14],
|
||||
10: [15, 16, 17],
|
||||
11: [18, 19, 20],
|
||||
13: [21],
|
||||
14: [22, 23],
|
||||
16: [24, 25, 26],
|
||||
17: [27, 28, 29, 30, 31],
|
||||
19: [32, 33],
|
||||
22: [34, 35],
|
||||
23: [36],
|
||||
24: [37],
|
||||
27: [38],
|
||||
29: [39, 40, 41],
|
||||
30: [42, 43],
|
||||
}
|
||||
|
||||
star_locations = {
|
||||
0x770401: LocationName.grass_land_1_s1,
|
||||
0x770402: LocationName.grass_land_1_s2,
|
||||
0x770403: LocationName.grass_land_1_s3,
|
||||
0x770404: LocationName.grass_land_1_s4,
|
||||
0x770405: LocationName.grass_land_1_s5,
|
||||
0x770406: LocationName.grass_land_1_s6,
|
||||
0x770407: LocationName.grass_land_1_s7,
|
||||
0x770408: LocationName.grass_land_1_s8,
|
||||
0x770409: LocationName.grass_land_1_s9,
|
||||
0x77040a: LocationName.grass_land_1_s10,
|
||||
0x77040b: LocationName.grass_land_1_s11,
|
||||
0x77040c: LocationName.grass_land_1_s12,
|
||||
0x77040d: LocationName.grass_land_1_s13,
|
||||
0x77040e: LocationName.grass_land_1_s14,
|
||||
0x77040f: LocationName.grass_land_1_s15,
|
||||
0x770410: LocationName.grass_land_1_s16,
|
||||
0x770411: LocationName.grass_land_1_s17,
|
||||
0x770412: LocationName.grass_land_1_s18,
|
||||
0x770413: LocationName.grass_land_1_s19,
|
||||
0x770414: LocationName.grass_land_1_s20,
|
||||
0x770415: LocationName.grass_land_1_s21,
|
||||
0x770416: LocationName.grass_land_1_s22,
|
||||
0x770417: LocationName.grass_land_1_s23,
|
||||
0x770418: LocationName.grass_land_2_s1,
|
||||
0x770419: LocationName.grass_land_2_s2,
|
||||
0x77041a: LocationName.grass_land_2_s3,
|
||||
0x77041b: LocationName.grass_land_2_s4,
|
||||
0x77041c: LocationName.grass_land_2_s5,
|
||||
0x77041d: LocationName.grass_land_2_s6,
|
||||
0x77041e: LocationName.grass_land_2_s7,
|
||||
0x77041f: LocationName.grass_land_2_s8,
|
||||
0x770420: LocationName.grass_land_2_s9,
|
||||
0x770421: LocationName.grass_land_2_s10,
|
||||
0x770422: LocationName.grass_land_2_s11,
|
||||
0x770423: LocationName.grass_land_2_s12,
|
||||
0x770424: LocationName.grass_land_2_s13,
|
||||
0x770425: LocationName.grass_land_2_s14,
|
||||
0x770426: LocationName.grass_land_2_s15,
|
||||
0x770427: LocationName.grass_land_2_s16,
|
||||
0x770428: LocationName.grass_land_2_s17,
|
||||
0x770429: LocationName.grass_land_2_s18,
|
||||
0x77042a: LocationName.grass_land_2_s19,
|
||||
0x77042b: LocationName.grass_land_2_s20,
|
||||
0x77042c: LocationName.grass_land_2_s21,
|
||||
0x77042d: LocationName.grass_land_3_s1,
|
||||
0x77042e: LocationName.grass_land_3_s2,
|
||||
0x77042f: LocationName.grass_land_3_s3,
|
||||
0x770430: LocationName.grass_land_3_s4,
|
||||
0x770431: LocationName.grass_land_3_s5,
|
||||
0x770432: LocationName.grass_land_3_s6,
|
||||
0x770433: LocationName.grass_land_3_s7,
|
||||
0x770434: LocationName.grass_land_3_s8,
|
||||
0x770435: LocationName.grass_land_3_s9,
|
||||
0x770436: LocationName.grass_land_3_s10,
|
||||
0x770437: LocationName.grass_land_3_s11,
|
||||
0x770438: LocationName.grass_land_3_s12,
|
||||
0x770439: LocationName.grass_land_3_s13,
|
||||
0x77043a: LocationName.grass_land_3_s14,
|
||||
0x77043b: LocationName.grass_land_3_s15,
|
||||
0x77043c: LocationName.grass_land_3_s16,
|
||||
0x77043d: LocationName.grass_land_3_s17,
|
||||
0x77043e: LocationName.grass_land_3_s18,
|
||||
0x77043f: LocationName.grass_land_3_s19,
|
||||
0x770440: LocationName.grass_land_3_s20,
|
||||
0x770441: LocationName.grass_land_3_s21,
|
||||
0x770442: LocationName.grass_land_3_s22,
|
||||
0x770443: LocationName.grass_land_3_s23,
|
||||
0x770444: LocationName.grass_land_3_s24,
|
||||
0x770445: LocationName.grass_land_3_s25,
|
||||
0x770446: LocationName.grass_land_3_s26,
|
||||
0x770447: LocationName.grass_land_3_s27,
|
||||
0x770448: LocationName.grass_land_3_s28,
|
||||
0x770449: LocationName.grass_land_3_s29,
|
||||
0x77044a: LocationName.grass_land_3_s30,
|
||||
0x77044b: LocationName.grass_land_3_s31,
|
||||
0x77044c: LocationName.grass_land_4_s1,
|
||||
0x77044d: LocationName.grass_land_4_s2,
|
||||
0x77044e: LocationName.grass_land_4_s3,
|
||||
0x77044f: LocationName.grass_land_4_s4,
|
||||
0x770450: LocationName.grass_land_4_s5,
|
||||
0x770451: LocationName.grass_land_4_s6,
|
||||
0x770452: LocationName.grass_land_4_s7,
|
||||
0x770453: LocationName.grass_land_4_s8,
|
||||
0x770454: LocationName.grass_land_4_s9,
|
||||
0x770455: LocationName.grass_land_4_s10,
|
||||
0x770456: LocationName.grass_land_4_s11,
|
||||
0x770457: LocationName.grass_land_4_s12,
|
||||
0x770458: LocationName.grass_land_4_s13,
|
||||
0x770459: LocationName.grass_land_4_s14,
|
||||
0x77045a: LocationName.grass_land_4_s15,
|
||||
0x77045b: LocationName.grass_land_4_s16,
|
||||
0x77045c: LocationName.grass_land_4_s17,
|
||||
0x77045d: LocationName.grass_land_4_s18,
|
||||
0x77045e: LocationName.grass_land_4_s19,
|
||||
0x77045f: LocationName.grass_land_4_s20,
|
||||
0x770460: LocationName.grass_land_4_s21,
|
||||
0x770461: LocationName.grass_land_4_s22,
|
||||
0x770462: LocationName.grass_land_4_s23,
|
||||
0x770463: LocationName.grass_land_4_s24,
|
||||
0x770464: LocationName.grass_land_4_s25,
|
||||
0x770465: LocationName.grass_land_4_s26,
|
||||
0x770466: LocationName.grass_land_4_s27,
|
||||
0x770467: LocationName.grass_land_4_s28,
|
||||
0x770468: LocationName.grass_land_4_s29,
|
||||
0x770469: LocationName.grass_land_4_s30,
|
||||
0x77046a: LocationName.grass_land_4_s31,
|
||||
0x77046b: LocationName.grass_land_4_s32,
|
||||
0x77046c: LocationName.grass_land_4_s33,
|
||||
0x77046d: LocationName.grass_land_4_s34,
|
||||
0x77046e: LocationName.grass_land_4_s35,
|
||||
0x77046f: LocationName.grass_land_4_s36,
|
||||
0x770470: LocationName.grass_land_4_s37,
|
||||
0x770471: LocationName.grass_land_5_s1,
|
||||
0x770472: LocationName.grass_land_5_s2,
|
||||
0x770473: LocationName.grass_land_5_s3,
|
||||
0x770474: LocationName.grass_land_5_s4,
|
||||
0x770475: LocationName.grass_land_5_s5,
|
||||
0x770476: LocationName.grass_land_5_s6,
|
||||
0x770477: LocationName.grass_land_5_s7,
|
||||
0x770478: LocationName.grass_land_5_s8,
|
||||
0x770479: LocationName.grass_land_5_s9,
|
||||
0x77047a: LocationName.grass_land_5_s10,
|
||||
0x77047b: LocationName.grass_land_5_s11,
|
||||
0x77047c: LocationName.grass_land_5_s12,
|
||||
0x77047d: LocationName.grass_land_5_s13,
|
||||
0x77047e: LocationName.grass_land_5_s14,
|
||||
0x77047f: LocationName.grass_land_5_s15,
|
||||
0x770480: LocationName.grass_land_5_s16,
|
||||
0x770481: LocationName.grass_land_5_s17,
|
||||
0x770482: LocationName.grass_land_5_s18,
|
||||
0x770483: LocationName.grass_land_5_s19,
|
||||
0x770484: LocationName.grass_land_5_s20,
|
||||
0x770485: LocationName.grass_land_5_s21,
|
||||
0x770486: LocationName.grass_land_5_s22,
|
||||
0x770487: LocationName.grass_land_5_s23,
|
||||
0x770488: LocationName.grass_land_5_s24,
|
||||
0x770489: LocationName.grass_land_5_s25,
|
||||
0x77048a: LocationName.grass_land_5_s26,
|
||||
0x77048b: LocationName.grass_land_5_s27,
|
||||
0x77048c: LocationName.grass_land_5_s28,
|
||||
0x77048d: LocationName.grass_land_5_s29,
|
||||
0x77048e: LocationName.grass_land_6_s1,
|
||||
0x77048f: LocationName.grass_land_6_s2,
|
||||
0x770490: LocationName.grass_land_6_s3,
|
||||
0x770491: LocationName.grass_land_6_s4,
|
||||
0x770492: LocationName.grass_land_6_s5,
|
||||
0x770493: LocationName.grass_land_6_s6,
|
||||
0x770494: LocationName.grass_land_6_s7,
|
||||
0x770495: LocationName.grass_land_6_s8,
|
||||
0x770496: LocationName.grass_land_6_s9,
|
||||
0x770497: LocationName.grass_land_6_s10,
|
||||
0x770498: LocationName.grass_land_6_s11,
|
||||
0x770499: LocationName.grass_land_6_s12,
|
||||
0x77049a: LocationName.grass_land_6_s13,
|
||||
0x77049b: LocationName.grass_land_6_s14,
|
||||
0x77049c: LocationName.grass_land_6_s15,
|
||||
0x77049d: LocationName.grass_land_6_s16,
|
||||
0x77049e: LocationName.grass_land_6_s17,
|
||||
0x77049f: LocationName.grass_land_6_s18,
|
||||
0x7704a0: LocationName.grass_land_6_s19,
|
||||
0x7704a1: LocationName.grass_land_6_s20,
|
||||
0x7704a2: LocationName.grass_land_6_s21,
|
||||
0x7704a3: LocationName.grass_land_6_s22,
|
||||
0x7704a4: LocationName.grass_land_6_s23,
|
||||
0x7704a5: LocationName.grass_land_6_s24,
|
||||
0x7704a6: LocationName.grass_land_6_s25,
|
||||
0x7704a7: LocationName.grass_land_6_s26,
|
||||
0x7704a8: LocationName.grass_land_6_s27,
|
||||
0x7704a9: LocationName.grass_land_6_s28,
|
||||
0x7704aa: LocationName.grass_land_6_s29,
|
||||
0x7704ab: LocationName.ripple_field_1_s1,
|
||||
0x7704ac: LocationName.ripple_field_1_s2,
|
||||
0x7704ad: LocationName.ripple_field_1_s3,
|
||||
0x7704ae: LocationName.ripple_field_1_s4,
|
||||
0x7704af: LocationName.ripple_field_1_s5,
|
||||
0x7704b0: LocationName.ripple_field_1_s6,
|
||||
0x7704b1: LocationName.ripple_field_1_s7,
|
||||
0x7704b2: LocationName.ripple_field_1_s8,
|
||||
0x7704b3: LocationName.ripple_field_1_s9,
|
||||
0x7704b4: LocationName.ripple_field_1_s10,
|
||||
0x7704b5: LocationName.ripple_field_1_s11,
|
||||
0x7704b6: LocationName.ripple_field_1_s12,
|
||||
0x7704b7: LocationName.ripple_field_1_s13,
|
||||
0x7704b8: LocationName.ripple_field_1_s14,
|
||||
0x7704b9: LocationName.ripple_field_1_s15,
|
||||
0x7704ba: LocationName.ripple_field_1_s16,
|
||||
0x7704bb: LocationName.ripple_field_1_s17,
|
||||
0x7704bc: LocationName.ripple_field_1_s18,
|
||||
0x7704bd: LocationName.ripple_field_1_s19,
|
||||
0x7704be: LocationName.ripple_field_2_s1,
|
||||
0x7704bf: LocationName.ripple_field_2_s2,
|
||||
0x7704c0: LocationName.ripple_field_2_s3,
|
||||
0x7704c1: LocationName.ripple_field_2_s4,
|
||||
0x7704c2: LocationName.ripple_field_2_s5,
|
||||
0x7704c3: LocationName.ripple_field_2_s6,
|
||||
0x7704c4: LocationName.ripple_field_2_s7,
|
||||
0x7704c5: LocationName.ripple_field_2_s8,
|
||||
0x7704c6: LocationName.ripple_field_2_s9,
|
||||
0x7704c7: LocationName.ripple_field_2_s10,
|
||||
0x7704c8: LocationName.ripple_field_2_s11,
|
||||
0x7704c9: LocationName.ripple_field_2_s12,
|
||||
0x7704ca: LocationName.ripple_field_2_s13,
|
||||
0x7704cb: LocationName.ripple_field_2_s14,
|
||||
0x7704cc: LocationName.ripple_field_2_s15,
|
||||
0x7704cd: LocationName.ripple_field_2_s16,
|
||||
0x7704ce: LocationName.ripple_field_2_s17,
|
||||
0x7704cf: LocationName.ripple_field_3_s1,
|
||||
0x7704d0: LocationName.ripple_field_3_s2,
|
||||
0x7704d1: LocationName.ripple_field_3_s3,
|
||||
0x7704d2: LocationName.ripple_field_3_s4,
|
||||
0x7704d3: LocationName.ripple_field_3_s5,
|
||||
0x7704d4: LocationName.ripple_field_3_s6,
|
||||
0x7704d5: LocationName.ripple_field_3_s7,
|
||||
0x7704d6: LocationName.ripple_field_3_s8,
|
||||
0x7704d7: LocationName.ripple_field_3_s9,
|
||||
0x7704d8: LocationName.ripple_field_3_s10,
|
||||
0x7704d9: LocationName.ripple_field_3_s11,
|
||||
0x7704da: LocationName.ripple_field_3_s12,
|
||||
0x7704db: LocationName.ripple_field_3_s13,
|
||||
0x7704dc: LocationName.ripple_field_3_s14,
|
||||
0x7704dd: LocationName.ripple_field_3_s15,
|
||||
0x7704de: LocationName.ripple_field_3_s16,
|
||||
0x7704df: LocationName.ripple_field_3_s17,
|
||||
0x7704e0: LocationName.ripple_field_3_s18,
|
||||
0x7704e1: LocationName.ripple_field_3_s19,
|
||||
0x7704e2: LocationName.ripple_field_3_s20,
|
||||
0x7704e3: LocationName.ripple_field_3_s21,
|
||||
0x7704e4: LocationName.ripple_field_4_s1,
|
||||
0x7704e5: LocationName.ripple_field_4_s2,
|
||||
0x7704e6: LocationName.ripple_field_4_s3,
|
||||
0x7704e7: LocationName.ripple_field_4_s4,
|
||||
0x7704e8: LocationName.ripple_field_4_s5,
|
||||
0x7704e9: LocationName.ripple_field_4_s6,
|
||||
0x7704ea: LocationName.ripple_field_4_s7,
|
||||
0x7704eb: LocationName.ripple_field_4_s8,
|
||||
0x7704ec: LocationName.ripple_field_4_s9,
|
||||
0x7704ed: LocationName.ripple_field_4_s10,
|
||||
0x7704ee: LocationName.ripple_field_4_s11,
|
||||
0x7704ef: LocationName.ripple_field_4_s12,
|
||||
0x7704f0: LocationName.ripple_field_4_s13,
|
||||
0x7704f1: LocationName.ripple_field_4_s14,
|
||||
0x7704f2: LocationName.ripple_field_4_s15,
|
||||
0x7704f3: LocationName.ripple_field_4_s16,
|
||||
0x7704f4: LocationName.ripple_field_4_s17,
|
||||
0x7704f5: LocationName.ripple_field_4_s18,
|
||||
0x7704f6: LocationName.ripple_field_4_s19,
|
||||
0x7704f7: LocationName.ripple_field_4_s20,
|
||||
0x7704f8: LocationName.ripple_field_4_s21,
|
||||
0x7704f9: LocationName.ripple_field_4_s22,
|
||||
0x7704fa: LocationName.ripple_field_4_s23,
|
||||
0x7704fb: LocationName.ripple_field_4_s24,
|
||||
0x7704fc: LocationName.ripple_field_4_s25,
|
||||
0x7704fd: LocationName.ripple_field_4_s26,
|
||||
0x7704fe: LocationName.ripple_field_4_s27,
|
||||
0x7704ff: LocationName.ripple_field_4_s28,
|
||||
0x770500: LocationName.ripple_field_4_s29,
|
||||
0x770501: LocationName.ripple_field_4_s30,
|
||||
0x770502: LocationName.ripple_field_4_s31,
|
||||
0x770503: LocationName.ripple_field_4_s32,
|
||||
0x770504: LocationName.ripple_field_4_s33,
|
||||
0x770505: LocationName.ripple_field_4_s34,
|
||||
0x770506: LocationName.ripple_field_4_s35,
|
||||
0x770507: LocationName.ripple_field_4_s36,
|
||||
0x770508: LocationName.ripple_field_4_s37,
|
||||
0x770509: LocationName.ripple_field_4_s38,
|
||||
0x77050a: LocationName.ripple_field_4_s39,
|
||||
0x77050b: LocationName.ripple_field_4_s40,
|
||||
0x77050c: LocationName.ripple_field_4_s41,
|
||||
0x77050d: LocationName.ripple_field_4_s42,
|
||||
0x77050e: LocationName.ripple_field_4_s43,
|
||||
0x77050f: LocationName.ripple_field_4_s44,
|
||||
0x770510: LocationName.ripple_field_4_s45,
|
||||
0x770511: LocationName.ripple_field_4_s46,
|
||||
0x770512: LocationName.ripple_field_4_s47,
|
||||
0x770513: LocationName.ripple_field_4_s48,
|
||||
0x770514: LocationName.ripple_field_4_s49,
|
||||
0x770515: LocationName.ripple_field_4_s50,
|
||||
0x770516: LocationName.ripple_field_4_s51,
|
||||
0x770517: LocationName.ripple_field_5_s1,
|
||||
0x770518: LocationName.ripple_field_5_s2,
|
||||
0x770519: LocationName.ripple_field_5_s3,
|
||||
0x77051a: LocationName.ripple_field_5_s4,
|
||||
0x77051b: LocationName.ripple_field_5_s5,
|
||||
0x77051c: LocationName.ripple_field_5_s6,
|
||||
0x77051d: LocationName.ripple_field_5_s7,
|
||||
0x77051e: LocationName.ripple_field_5_s8,
|
||||
0x77051f: LocationName.ripple_field_5_s9,
|
||||
0x770520: LocationName.ripple_field_5_s10,
|
||||
0x770521: LocationName.ripple_field_5_s11,
|
||||
0x770522: LocationName.ripple_field_5_s12,
|
||||
0x770523: LocationName.ripple_field_5_s13,
|
||||
0x770524: LocationName.ripple_field_5_s14,
|
||||
0x770525: LocationName.ripple_field_5_s15,
|
||||
0x770526: LocationName.ripple_field_5_s16,
|
||||
0x770527: LocationName.ripple_field_5_s17,
|
||||
0x770528: LocationName.ripple_field_5_s18,
|
||||
0x770529: LocationName.ripple_field_5_s19,
|
||||
0x77052a: LocationName.ripple_field_5_s20,
|
||||
0x77052b: LocationName.ripple_field_5_s21,
|
||||
0x77052c: LocationName.ripple_field_5_s22,
|
||||
0x77052d: LocationName.ripple_field_5_s23,
|
||||
0x77052e: LocationName.ripple_field_5_s24,
|
||||
0x77052f: LocationName.ripple_field_5_s25,
|
||||
0x770530: LocationName.ripple_field_5_s26,
|
||||
0x770531: LocationName.ripple_field_5_s27,
|
||||
0x770532: LocationName.ripple_field_5_s28,
|
||||
0x770533: LocationName.ripple_field_5_s29,
|
||||
0x770534: LocationName.ripple_field_5_s30,
|
||||
0x770535: LocationName.ripple_field_5_s31,
|
||||
0x770536: LocationName.ripple_field_5_s32,
|
||||
0x770537: LocationName.ripple_field_5_s33,
|
||||
0x770538: LocationName.ripple_field_5_s34,
|
||||
0x770539: LocationName.ripple_field_5_s35,
|
||||
0x77053a: LocationName.ripple_field_5_s36,
|
||||
0x77053b: LocationName.ripple_field_5_s37,
|
||||
0x77053c: LocationName.ripple_field_5_s38,
|
||||
0x77053d: LocationName.ripple_field_5_s39,
|
||||
0x77053e: LocationName.ripple_field_5_s40,
|
||||
0x77053f: LocationName.ripple_field_5_s41,
|
||||
0x770540: LocationName.ripple_field_5_s42,
|
||||
0x770541: LocationName.ripple_field_5_s43,
|
||||
0x770542: LocationName.ripple_field_5_s44,
|
||||
0x770543: LocationName.ripple_field_5_s45,
|
||||
0x770544: LocationName.ripple_field_5_s46,
|
||||
0x770545: LocationName.ripple_field_5_s47,
|
||||
0x770546: LocationName.ripple_field_5_s48,
|
||||
0x770547: LocationName.ripple_field_5_s49,
|
||||
0x770548: LocationName.ripple_field_5_s50,
|
||||
0x770549: LocationName.ripple_field_5_s51,
|
||||
0x77054a: LocationName.ripple_field_6_s1,
|
||||
0x77054b: LocationName.ripple_field_6_s2,
|
||||
0x77054c: LocationName.ripple_field_6_s3,
|
||||
0x77054d: LocationName.ripple_field_6_s4,
|
||||
0x77054e: LocationName.ripple_field_6_s5,
|
||||
0x77054f: LocationName.ripple_field_6_s6,
|
||||
0x770550: LocationName.ripple_field_6_s7,
|
||||
0x770551: LocationName.ripple_field_6_s8,
|
||||
0x770552: LocationName.ripple_field_6_s9,
|
||||
0x770553: LocationName.ripple_field_6_s10,
|
||||
0x770554: LocationName.ripple_field_6_s11,
|
||||
0x770555: LocationName.ripple_field_6_s12,
|
||||
0x770556: LocationName.ripple_field_6_s13,
|
||||
0x770557: LocationName.ripple_field_6_s14,
|
||||
0x770558: LocationName.ripple_field_6_s15,
|
||||
0x770559: LocationName.ripple_field_6_s16,
|
||||
0x77055a: LocationName.ripple_field_6_s17,
|
||||
0x77055b: LocationName.ripple_field_6_s18,
|
||||
0x77055c: LocationName.ripple_field_6_s19,
|
||||
0x77055d: LocationName.ripple_field_6_s20,
|
||||
0x77055e: LocationName.ripple_field_6_s21,
|
||||
0x77055f: LocationName.ripple_field_6_s22,
|
||||
0x770560: LocationName.ripple_field_6_s23,
|
||||
0x770561: LocationName.sand_canyon_1_s1,
|
||||
0x770562: LocationName.sand_canyon_1_s2,
|
||||
0x770563: LocationName.sand_canyon_1_s3,
|
||||
0x770564: LocationName.sand_canyon_1_s4,
|
||||
0x770565: LocationName.sand_canyon_1_s5,
|
||||
0x770566: LocationName.sand_canyon_1_s6,
|
||||
0x770567: LocationName.sand_canyon_1_s7,
|
||||
0x770568: LocationName.sand_canyon_1_s8,
|
||||
0x770569: LocationName.sand_canyon_1_s9,
|
||||
0x77056a: LocationName.sand_canyon_1_s10,
|
||||
0x77056b: LocationName.sand_canyon_1_s11,
|
||||
0x77056c: LocationName.sand_canyon_1_s12,
|
||||
0x77056d: LocationName.sand_canyon_1_s13,
|
||||
0x77056e: LocationName.sand_canyon_1_s14,
|
||||
0x77056f: LocationName.sand_canyon_1_s15,
|
||||
0x770570: LocationName.sand_canyon_1_s16,
|
||||
0x770571: LocationName.sand_canyon_1_s17,
|
||||
0x770572: LocationName.sand_canyon_1_s18,
|
||||
0x770573: LocationName.sand_canyon_1_s19,
|
||||
0x770574: LocationName.sand_canyon_1_s20,
|
||||
0x770575: LocationName.sand_canyon_1_s21,
|
||||
0x770576: LocationName.sand_canyon_1_s22,
|
||||
0x770577: LocationName.sand_canyon_2_s1,
|
||||
0x770578: LocationName.sand_canyon_2_s2,
|
||||
0x770579: LocationName.sand_canyon_2_s3,
|
||||
0x77057a: LocationName.sand_canyon_2_s4,
|
||||
0x77057b: LocationName.sand_canyon_2_s5,
|
||||
0x77057c: LocationName.sand_canyon_2_s6,
|
||||
0x77057d: LocationName.sand_canyon_2_s7,
|
||||
0x77057e: LocationName.sand_canyon_2_s8,
|
||||
0x77057f: LocationName.sand_canyon_2_s9,
|
||||
0x770580: LocationName.sand_canyon_2_s10,
|
||||
0x770581: LocationName.sand_canyon_2_s11,
|
||||
0x770582: LocationName.sand_canyon_2_s12,
|
||||
0x770583: LocationName.sand_canyon_2_s13,
|
||||
0x770584: LocationName.sand_canyon_2_s14,
|
||||
0x770585: LocationName.sand_canyon_2_s15,
|
||||
0x770586: LocationName.sand_canyon_2_s16,
|
||||
0x770587: LocationName.sand_canyon_2_s17,
|
||||
0x770588: LocationName.sand_canyon_2_s18,
|
||||
0x770589: LocationName.sand_canyon_2_s19,
|
||||
0x77058a: LocationName.sand_canyon_2_s20,
|
||||
0x77058b: LocationName.sand_canyon_2_s21,
|
||||
0x77058c: LocationName.sand_canyon_2_s22,
|
||||
0x77058d: LocationName.sand_canyon_2_s23,
|
||||
0x77058e: LocationName.sand_canyon_2_s24,
|
||||
0x77058f: LocationName.sand_canyon_2_s25,
|
||||
0x770590: LocationName.sand_canyon_2_s26,
|
||||
0x770591: LocationName.sand_canyon_2_s27,
|
||||
0x770592: LocationName.sand_canyon_2_s28,
|
||||
0x770593: LocationName.sand_canyon_2_s29,
|
||||
0x770594: LocationName.sand_canyon_2_s30,
|
||||
0x770595: LocationName.sand_canyon_2_s31,
|
||||
0x770596: LocationName.sand_canyon_2_s32,
|
||||
0x770597: LocationName.sand_canyon_2_s33,
|
||||
0x770598: LocationName.sand_canyon_2_s34,
|
||||
0x770599: LocationName.sand_canyon_2_s35,
|
||||
0x77059a: LocationName.sand_canyon_2_s36,
|
||||
0x77059b: LocationName.sand_canyon_2_s37,
|
||||
0x77059c: LocationName.sand_canyon_2_s38,
|
||||
0x77059d: LocationName.sand_canyon_2_s39,
|
||||
0x77059e: LocationName.sand_canyon_2_s40,
|
||||
0x77059f: LocationName.sand_canyon_2_s41,
|
||||
0x7705a0: LocationName.sand_canyon_2_s42,
|
||||
0x7705a1: LocationName.sand_canyon_2_s43,
|
||||
0x7705a2: LocationName.sand_canyon_2_s44,
|
||||
0x7705a3: LocationName.sand_canyon_2_s45,
|
||||
0x7705a4: LocationName.sand_canyon_2_s46,
|
||||
0x7705a5: LocationName.sand_canyon_2_s47,
|
||||
0x7705a6: LocationName.sand_canyon_2_s48,
|
||||
0x7705a7: LocationName.sand_canyon_3_s1,
|
||||
0x7705a8: LocationName.sand_canyon_3_s2,
|
||||
0x7705a9: LocationName.sand_canyon_3_s3,
|
||||
0x7705aa: LocationName.sand_canyon_3_s4,
|
||||
0x7705ab: LocationName.sand_canyon_3_s5,
|
||||
0x7705ac: LocationName.sand_canyon_3_s6,
|
||||
0x7705ad: LocationName.sand_canyon_3_s7,
|
||||
0x7705ae: LocationName.sand_canyon_3_s8,
|
||||
0x7705af: LocationName.sand_canyon_3_s9,
|
||||
0x7705b0: LocationName.sand_canyon_3_s10,
|
||||
0x7705b1: LocationName.sand_canyon_4_s1,
|
||||
0x7705b2: LocationName.sand_canyon_4_s2,
|
||||
0x7705b3: LocationName.sand_canyon_4_s3,
|
||||
0x7705b4: LocationName.sand_canyon_4_s4,
|
||||
0x7705b5: LocationName.sand_canyon_4_s5,
|
||||
0x7705b6: LocationName.sand_canyon_4_s6,
|
||||
0x7705b7: LocationName.sand_canyon_4_s7,
|
||||
0x7705b8: LocationName.sand_canyon_4_s8,
|
||||
0x7705b9: LocationName.sand_canyon_4_s9,
|
||||
0x7705ba: LocationName.sand_canyon_4_s10,
|
||||
0x7705bb: LocationName.sand_canyon_4_s11,
|
||||
0x7705bc: LocationName.sand_canyon_4_s12,
|
||||
0x7705bd: LocationName.sand_canyon_4_s13,
|
||||
0x7705be: LocationName.sand_canyon_4_s14,
|
||||
0x7705bf: LocationName.sand_canyon_4_s15,
|
||||
0x7705c0: LocationName.sand_canyon_4_s16,
|
||||
0x7705c1: LocationName.sand_canyon_4_s17,
|
||||
0x7705c2: LocationName.sand_canyon_4_s18,
|
||||
0x7705c3: LocationName.sand_canyon_4_s19,
|
||||
0x7705c4: LocationName.sand_canyon_4_s20,
|
||||
0x7705c5: LocationName.sand_canyon_4_s21,
|
||||
0x7705c6: LocationName.sand_canyon_4_s22,
|
||||
0x7705c7: LocationName.sand_canyon_4_s23,
|
||||
0x7705c8: LocationName.sand_canyon_5_s1,
|
||||
0x7705c9: LocationName.sand_canyon_5_s2,
|
||||
0x7705ca: LocationName.sand_canyon_5_s3,
|
||||
0x7705cb: LocationName.sand_canyon_5_s4,
|
||||
0x7705cc: LocationName.sand_canyon_5_s5,
|
||||
0x7705cd: LocationName.sand_canyon_5_s6,
|
||||
0x7705ce: LocationName.sand_canyon_5_s7,
|
||||
0x7705cf: LocationName.sand_canyon_5_s8,
|
||||
0x7705d0: LocationName.sand_canyon_5_s9,
|
||||
0x7705d1: LocationName.sand_canyon_5_s10,
|
||||
0x7705d2: LocationName.sand_canyon_5_s11,
|
||||
0x7705d3: LocationName.sand_canyon_5_s12,
|
||||
0x7705d4: LocationName.sand_canyon_5_s13,
|
||||
0x7705d5: LocationName.sand_canyon_5_s14,
|
||||
0x7705d6: LocationName.sand_canyon_5_s15,
|
||||
0x7705d7: LocationName.sand_canyon_5_s16,
|
||||
0x7705d8: LocationName.sand_canyon_5_s17,
|
||||
0x7705d9: LocationName.sand_canyon_5_s18,
|
||||
0x7705da: LocationName.sand_canyon_5_s19,
|
||||
0x7705db: LocationName.sand_canyon_5_s20,
|
||||
0x7705dc: LocationName.sand_canyon_5_s21,
|
||||
0x7705dd: LocationName.sand_canyon_5_s22,
|
||||
0x7705de: LocationName.sand_canyon_5_s23,
|
||||
0x7705df: LocationName.sand_canyon_5_s24,
|
||||
0x7705e0: LocationName.sand_canyon_5_s25,
|
||||
0x7705e1: LocationName.sand_canyon_5_s26,
|
||||
0x7705e2: LocationName.sand_canyon_5_s27,
|
||||
0x7705e3: LocationName.sand_canyon_5_s28,
|
||||
0x7705e4: LocationName.sand_canyon_5_s29,
|
||||
0x7705e5: LocationName.sand_canyon_5_s30,
|
||||
0x7705e6: LocationName.sand_canyon_5_s31,
|
||||
0x7705e7: LocationName.sand_canyon_5_s32,
|
||||
0x7705e8: LocationName.sand_canyon_5_s33,
|
||||
0x7705e9: LocationName.sand_canyon_5_s34,
|
||||
0x7705ea: LocationName.sand_canyon_5_s35,
|
||||
0x7705eb: LocationName.sand_canyon_5_s36,
|
||||
0x7705ec: LocationName.sand_canyon_5_s37,
|
||||
0x7705ed: LocationName.sand_canyon_5_s38,
|
||||
0x7705ee: LocationName.sand_canyon_5_s39,
|
||||
0x7705ef: LocationName.sand_canyon_5_s40,
|
||||
0x7705f0: LocationName.cloudy_park_1_s1,
|
||||
0x7705f1: LocationName.cloudy_park_1_s2,
|
||||
0x7705f2: LocationName.cloudy_park_1_s3,
|
||||
0x7705f3: LocationName.cloudy_park_1_s4,
|
||||
0x7705f4: LocationName.cloudy_park_1_s5,
|
||||
0x7705f5: LocationName.cloudy_park_1_s6,
|
||||
0x7705f6: LocationName.cloudy_park_1_s7,
|
||||
0x7705f7: LocationName.cloudy_park_1_s8,
|
||||
0x7705f8: LocationName.cloudy_park_1_s9,
|
||||
0x7705f9: LocationName.cloudy_park_1_s10,
|
||||
0x7705fa: LocationName.cloudy_park_1_s11,
|
||||
0x7705fb: LocationName.cloudy_park_1_s12,
|
||||
0x7705fc: LocationName.cloudy_park_1_s13,
|
||||
0x7705fd: LocationName.cloudy_park_1_s14,
|
||||
0x7705fe: LocationName.cloudy_park_1_s15,
|
||||
0x7705ff: LocationName.cloudy_park_1_s16,
|
||||
0x770600: LocationName.cloudy_park_1_s17,
|
||||
0x770601: LocationName.cloudy_park_1_s18,
|
||||
0x770602: LocationName.cloudy_park_1_s19,
|
||||
0x770603: LocationName.cloudy_park_1_s20,
|
||||
0x770604: LocationName.cloudy_park_1_s21,
|
||||
0x770605: LocationName.cloudy_park_1_s22,
|
||||
0x770606: LocationName.cloudy_park_1_s23,
|
||||
0x770607: LocationName.cloudy_park_2_s1,
|
||||
0x770608: LocationName.cloudy_park_2_s2,
|
||||
0x770609: LocationName.cloudy_park_2_s3,
|
||||
0x77060a: LocationName.cloudy_park_2_s4,
|
||||
0x77060b: LocationName.cloudy_park_2_s5,
|
||||
0x77060c: LocationName.cloudy_park_2_s6,
|
||||
0x77060d: LocationName.cloudy_park_2_s7,
|
||||
0x77060e: LocationName.cloudy_park_2_s8,
|
||||
0x77060f: LocationName.cloudy_park_2_s9,
|
||||
0x770610: LocationName.cloudy_park_2_s10,
|
||||
0x770611: LocationName.cloudy_park_2_s11,
|
||||
0x770612: LocationName.cloudy_park_2_s12,
|
||||
0x770613: LocationName.cloudy_park_2_s13,
|
||||
0x770614: LocationName.cloudy_park_2_s14,
|
||||
0x770615: LocationName.cloudy_park_2_s15,
|
||||
0x770616: LocationName.cloudy_park_2_s16,
|
||||
0x770617: LocationName.cloudy_park_2_s17,
|
||||
0x770618: LocationName.cloudy_park_2_s18,
|
||||
0x770619: LocationName.cloudy_park_2_s19,
|
||||
0x77061a: LocationName.cloudy_park_2_s20,
|
||||
0x77061b: LocationName.cloudy_park_2_s21,
|
||||
0x77061c: LocationName.cloudy_park_2_s22,
|
||||
0x77061d: LocationName.cloudy_park_2_s23,
|
||||
0x77061e: LocationName.cloudy_park_2_s24,
|
||||
0x77061f: LocationName.cloudy_park_2_s25,
|
||||
0x770620: LocationName.cloudy_park_2_s26,
|
||||
0x770621: LocationName.cloudy_park_2_s27,
|
||||
0x770622: LocationName.cloudy_park_2_s28,
|
||||
0x770623: LocationName.cloudy_park_2_s29,
|
||||
0x770624: LocationName.cloudy_park_2_s30,
|
||||
0x770625: LocationName.cloudy_park_2_s31,
|
||||
0x770626: LocationName.cloudy_park_2_s32,
|
||||
0x770627: LocationName.cloudy_park_2_s33,
|
||||
0x770628: LocationName.cloudy_park_2_s34,
|
||||
0x770629: LocationName.cloudy_park_2_s35,
|
||||
0x77062a: LocationName.cloudy_park_2_s36,
|
||||
0x77062b: LocationName.cloudy_park_2_s37,
|
||||
0x77062c: LocationName.cloudy_park_2_s38,
|
||||
0x77062d: LocationName.cloudy_park_2_s39,
|
||||
0x77062e: LocationName.cloudy_park_2_s40,
|
||||
0x77062f: LocationName.cloudy_park_2_s41,
|
||||
0x770630: LocationName.cloudy_park_2_s42,
|
||||
0x770631: LocationName.cloudy_park_2_s43,
|
||||
0x770632: LocationName.cloudy_park_2_s44,
|
||||
0x770633: LocationName.cloudy_park_2_s45,
|
||||
0x770634: LocationName.cloudy_park_2_s46,
|
||||
0x770635: LocationName.cloudy_park_2_s47,
|
||||
0x770636: LocationName.cloudy_park_2_s48,
|
||||
0x770637: LocationName.cloudy_park_2_s49,
|
||||
0x770638: LocationName.cloudy_park_2_s50,
|
||||
0x770639: LocationName.cloudy_park_2_s51,
|
||||
0x77063a: LocationName.cloudy_park_2_s52,
|
||||
0x77063b: LocationName.cloudy_park_2_s53,
|
||||
0x77063c: LocationName.cloudy_park_2_s54,
|
||||
0x77063d: LocationName.cloudy_park_3_s1,
|
||||
0x77063e: LocationName.cloudy_park_3_s2,
|
||||
0x77063f: LocationName.cloudy_park_3_s3,
|
||||
0x770640: LocationName.cloudy_park_3_s4,
|
||||
0x770641: LocationName.cloudy_park_3_s5,
|
||||
0x770642: LocationName.cloudy_park_3_s6,
|
||||
0x770643: LocationName.cloudy_park_3_s7,
|
||||
0x770644: LocationName.cloudy_park_3_s8,
|
||||
0x770645: LocationName.cloudy_park_3_s9,
|
||||
0x770646: LocationName.cloudy_park_3_s10,
|
||||
0x770647: LocationName.cloudy_park_3_s11,
|
||||
0x770648: LocationName.cloudy_park_3_s12,
|
||||
0x770649: LocationName.cloudy_park_3_s13,
|
||||
0x77064a: LocationName.cloudy_park_3_s14,
|
||||
0x77064b: LocationName.cloudy_park_3_s15,
|
||||
0x77064c: LocationName.cloudy_park_3_s16,
|
||||
0x77064d: LocationName.cloudy_park_3_s17,
|
||||
0x77064e: LocationName.cloudy_park_3_s18,
|
||||
0x77064f: LocationName.cloudy_park_3_s19,
|
||||
0x770650: LocationName.cloudy_park_3_s20,
|
||||
0x770651: LocationName.cloudy_park_3_s21,
|
||||
0x770652: LocationName.cloudy_park_3_s22,
|
||||
0x770653: LocationName.cloudy_park_4_s1,
|
||||
0x770654: LocationName.cloudy_park_4_s2,
|
||||
0x770655: LocationName.cloudy_park_4_s3,
|
||||
0x770656: LocationName.cloudy_park_4_s4,
|
||||
0x770657: LocationName.cloudy_park_4_s5,
|
||||
0x770658: LocationName.cloudy_park_4_s6,
|
||||
0x770659: LocationName.cloudy_park_4_s7,
|
||||
0x77065a: LocationName.cloudy_park_4_s8,
|
||||
0x77065b: LocationName.cloudy_park_4_s9,
|
||||
0x77065c: LocationName.cloudy_park_4_s10,
|
||||
0x77065d: LocationName.cloudy_park_4_s11,
|
||||
0x77065e: LocationName.cloudy_park_4_s12,
|
||||
0x77065f: LocationName.cloudy_park_4_s13,
|
||||
0x770660: LocationName.cloudy_park_4_s14,
|
||||
0x770661: LocationName.cloudy_park_4_s15,
|
||||
0x770662: LocationName.cloudy_park_4_s16,
|
||||
0x770663: LocationName.cloudy_park_4_s17,
|
||||
0x770664: LocationName.cloudy_park_4_s18,
|
||||
0x770665: LocationName.cloudy_park_4_s19,
|
||||
0x770666: LocationName.cloudy_park_4_s20,
|
||||
0x770667: LocationName.cloudy_park_4_s21,
|
||||
0x770668: LocationName.cloudy_park_4_s22,
|
||||
0x770669: LocationName.cloudy_park_4_s23,
|
||||
0x77066a: LocationName.cloudy_park_4_s24,
|
||||
0x77066b: LocationName.cloudy_park_4_s25,
|
||||
0x77066c: LocationName.cloudy_park_4_s26,
|
||||
0x77066d: LocationName.cloudy_park_4_s27,
|
||||
0x77066e: LocationName.cloudy_park_4_s28,
|
||||
0x77066f: LocationName.cloudy_park_4_s29,
|
||||
0x770670: LocationName.cloudy_park_4_s30,
|
||||
0x770671: LocationName.cloudy_park_4_s31,
|
||||
0x770672: LocationName.cloudy_park_4_s32,
|
||||
0x770673: LocationName.cloudy_park_4_s33,
|
||||
0x770674: LocationName.cloudy_park_4_s34,
|
||||
0x770675: LocationName.cloudy_park_4_s35,
|
||||
0x770676: LocationName.cloudy_park_4_s36,
|
||||
0x770677: LocationName.cloudy_park_4_s37,
|
||||
0x770678: LocationName.cloudy_park_4_s38,
|
||||
0x770679: LocationName.cloudy_park_4_s39,
|
||||
0x77067a: LocationName.cloudy_park_4_s40,
|
||||
0x77067b: LocationName.cloudy_park_4_s41,
|
||||
0x77067c: LocationName.cloudy_park_4_s42,
|
||||
0x77067d: LocationName.cloudy_park_4_s43,
|
||||
0x77067e: LocationName.cloudy_park_4_s44,
|
||||
0x77067f: LocationName.cloudy_park_4_s45,
|
||||
0x770680: LocationName.cloudy_park_4_s46,
|
||||
0x770681: LocationName.cloudy_park_4_s47,
|
||||
0x770682: LocationName.cloudy_park_4_s48,
|
||||
0x770683: LocationName.cloudy_park_4_s49,
|
||||
0x770684: LocationName.cloudy_park_4_s50,
|
||||
0x770685: LocationName.cloudy_park_5_s1,
|
||||
0x770686: LocationName.cloudy_park_5_s2,
|
||||
0x770687: LocationName.cloudy_park_5_s3,
|
||||
0x770688: LocationName.cloudy_park_5_s4,
|
||||
0x770689: LocationName.cloudy_park_5_s5,
|
||||
0x77068a: LocationName.cloudy_park_5_s6,
|
||||
0x77068b: LocationName.cloudy_park_6_s1,
|
||||
0x77068c: LocationName.cloudy_park_6_s2,
|
||||
0x77068d: LocationName.cloudy_park_6_s3,
|
||||
0x77068e: LocationName.cloudy_park_6_s4,
|
||||
0x77068f: LocationName.cloudy_park_6_s5,
|
||||
0x770690: LocationName.cloudy_park_6_s6,
|
||||
0x770691: LocationName.cloudy_park_6_s7,
|
||||
0x770692: LocationName.cloudy_park_6_s8,
|
||||
0x770693: LocationName.cloudy_park_6_s9,
|
||||
0x770694: LocationName.cloudy_park_6_s10,
|
||||
0x770695: LocationName.cloudy_park_6_s11,
|
||||
0x770696: LocationName.cloudy_park_6_s12,
|
||||
0x770697: LocationName.cloudy_park_6_s13,
|
||||
0x770698: LocationName.cloudy_park_6_s14,
|
||||
0x770699: LocationName.cloudy_park_6_s15,
|
||||
0x77069a: LocationName.cloudy_park_6_s16,
|
||||
0x77069b: LocationName.cloudy_park_6_s17,
|
||||
0x77069c: LocationName.cloudy_park_6_s18,
|
||||
0x77069d: LocationName.cloudy_park_6_s19,
|
||||
0x77069e: LocationName.cloudy_park_6_s20,
|
||||
0x77069f: LocationName.cloudy_park_6_s21,
|
||||
0x7706a0: LocationName.cloudy_park_6_s22,
|
||||
0x7706a1: LocationName.cloudy_park_6_s23,
|
||||
0x7706a2: LocationName.cloudy_park_6_s24,
|
||||
0x7706a3: LocationName.cloudy_park_6_s25,
|
||||
0x7706a4: LocationName.cloudy_park_6_s26,
|
||||
0x7706a5: LocationName.cloudy_park_6_s27,
|
||||
0x7706a6: LocationName.cloudy_park_6_s28,
|
||||
0x7706a7: LocationName.cloudy_park_6_s29,
|
||||
0x7706a8: LocationName.cloudy_park_6_s30,
|
||||
0x7706a9: LocationName.cloudy_park_6_s31,
|
||||
0x7706aa: LocationName.cloudy_park_6_s32,
|
||||
0x7706ab: LocationName.cloudy_park_6_s33,
|
||||
0x7706ac: LocationName.iceberg_1_s1,
|
||||
0x7706ad: LocationName.iceberg_1_s2,
|
||||
0x7706ae: LocationName.iceberg_1_s3,
|
||||
0x7706af: LocationName.iceberg_1_s4,
|
||||
0x7706b0: LocationName.iceberg_1_s5,
|
||||
0x7706b1: LocationName.iceberg_1_s6,
|
||||
0x7706b2: LocationName.iceberg_2_s1,
|
||||
0x7706b3: LocationName.iceberg_2_s2,
|
||||
0x7706b4: LocationName.iceberg_2_s3,
|
||||
0x7706b5: LocationName.iceberg_2_s4,
|
||||
0x7706b6: LocationName.iceberg_2_s5,
|
||||
0x7706b7: LocationName.iceberg_2_s6,
|
||||
0x7706b8: LocationName.iceberg_2_s7,
|
||||
0x7706b9: LocationName.iceberg_2_s8,
|
||||
0x7706ba: LocationName.iceberg_2_s9,
|
||||
0x7706bb: LocationName.iceberg_2_s10,
|
||||
0x7706bc: LocationName.iceberg_2_s11,
|
||||
0x7706bd: LocationName.iceberg_2_s12,
|
||||
0x7706be: LocationName.iceberg_2_s13,
|
||||
0x7706bf: LocationName.iceberg_2_s14,
|
||||
0x7706c0: LocationName.iceberg_2_s15,
|
||||
0x7706c1: LocationName.iceberg_2_s16,
|
||||
0x7706c2: LocationName.iceberg_2_s17,
|
||||
0x7706c3: LocationName.iceberg_2_s18,
|
||||
0x7706c4: LocationName.iceberg_2_s19,
|
||||
0x7706c5: LocationName.iceberg_3_s1,
|
||||
0x7706c6: LocationName.iceberg_3_s2,
|
||||
0x7706c7: LocationName.iceberg_3_s3,
|
||||
0x7706c8: LocationName.iceberg_3_s4,
|
||||
0x7706c9: LocationName.iceberg_3_s5,
|
||||
0x7706ca: LocationName.iceberg_3_s6,
|
||||
0x7706cb: LocationName.iceberg_3_s7,
|
||||
0x7706cc: LocationName.iceberg_3_s8,
|
||||
0x7706cd: LocationName.iceberg_3_s9,
|
||||
0x7706ce: LocationName.iceberg_3_s10,
|
||||
0x7706cf: LocationName.iceberg_3_s11,
|
||||
0x7706d0: LocationName.iceberg_3_s12,
|
||||
0x7706d1: LocationName.iceberg_3_s13,
|
||||
0x7706d2: LocationName.iceberg_3_s14,
|
||||
0x7706d3: LocationName.iceberg_3_s15,
|
||||
0x7706d4: LocationName.iceberg_3_s16,
|
||||
0x7706d5: LocationName.iceberg_3_s17,
|
||||
0x7706d6: LocationName.iceberg_3_s18,
|
||||
0x7706d7: LocationName.iceberg_3_s19,
|
||||
0x7706d8: LocationName.iceberg_3_s20,
|
||||
0x7706d9: LocationName.iceberg_3_s21,
|
||||
0x7706da: LocationName.iceberg_4_s1,
|
||||
0x7706db: LocationName.iceberg_4_s2,
|
||||
0x7706dc: LocationName.iceberg_4_s3,
|
||||
0x7706dd: LocationName.iceberg_5_s1,
|
||||
0x7706de: LocationName.iceberg_5_s2,
|
||||
0x7706df: LocationName.iceberg_5_s3,
|
||||
0x7706e0: LocationName.iceberg_5_s4,
|
||||
0x7706e1: LocationName.iceberg_5_s5,
|
||||
0x7706e2: LocationName.iceberg_5_s6,
|
||||
0x7706e3: LocationName.iceberg_5_s7,
|
||||
0x7706e4: LocationName.iceberg_5_s8,
|
||||
0x7706e5: LocationName.iceberg_5_s9,
|
||||
0x7706e6: LocationName.iceberg_5_s10,
|
||||
0x7706e7: LocationName.iceberg_5_s11,
|
||||
0x7706e8: LocationName.iceberg_5_s12,
|
||||
0x7706e9: LocationName.iceberg_5_s13,
|
||||
0x7706ea: LocationName.iceberg_5_s14,
|
||||
0x7706eb: LocationName.iceberg_5_s15,
|
||||
0x7706ec: LocationName.iceberg_5_s16,
|
||||
0x7706ed: LocationName.iceberg_5_s17,
|
||||
0x7706ee: LocationName.iceberg_5_s18,
|
||||
0x7706ef: LocationName.iceberg_5_s19,
|
||||
0x7706f0: LocationName.iceberg_5_s20,
|
||||
0x7706f1: LocationName.iceberg_5_s21,
|
||||
0x7706f2: LocationName.iceberg_5_s22,
|
||||
0x7706f3: LocationName.iceberg_5_s23,
|
||||
0x7706f4: LocationName.iceberg_5_s24,
|
||||
0x7706f5: LocationName.iceberg_5_s25,
|
||||
0x7706f6: LocationName.iceberg_5_s26,
|
||||
0x7706f7: LocationName.iceberg_5_s27,
|
||||
0x7706f8: LocationName.iceberg_5_s28,
|
||||
0x7706f9: LocationName.iceberg_5_s29,
|
||||
0x7706fa: LocationName.iceberg_5_s30,
|
||||
0x7706fb: LocationName.iceberg_5_s31,
|
||||
0x7706fc: LocationName.iceberg_5_s32,
|
||||
0x7706fd: LocationName.iceberg_5_s33,
|
||||
0x7706fe: LocationName.iceberg_5_s34,
|
||||
0x7706ff: LocationName.iceberg_6_s1,
|
||||
|
||||
}
|
||||
|
||||
location_table = {
|
||||
**stage_locations,
|
||||
**heart_star_locations,
|
||||
**boss_locations,
|
||||
**consumable_locations,
|
||||
**star_locations
|
||||
}
|
199
worlds/kdl3/Names/AnimalFriendSpawns.py
Normal file
199
worlds/kdl3/Names/AnimalFriendSpawns.py
Normal file
@@ -0,0 +1,199 @@
|
||||
grass_land_1_a1 = "Grass Land 1 - Animal 1" # Nago
|
||||
grass_land_1_a2 = "Grass Land 1 - Animal 2" # Rick
|
||||
grass_land_2_a1 = "Grass Land 2 - Animal 1" # ChuChu
|
||||
grass_land_2_a2 = "Grass Land 2 - Animal 2" # Pitch
|
||||
grass_land_3_a1 = "Grass Land 3 - Animal 1" # Kine
|
||||
grass_land_3_a2 = "Grass Land 3 - Animal 2" # Coo
|
||||
grass_land_4_a1 = "Grass Land 4 - Animal 1" # ChuChu
|
||||
grass_land_4_a2 = "Grass Land 4 - Animal 2" # Nago
|
||||
grass_land_5_a1 = "Grass Land 5 - Animal 1" # Coo
|
||||
grass_land_5_a2 = "Grass Land 5 - Animal 2" # Kine
|
||||
grass_land_5_a3 = "Grass Land 5 - Animal 3" # Nago
|
||||
grass_land_5_a4 = "Grass Land 5 - Animal 4" # Rick
|
||||
grass_land_6_a1 = "Grass Land 6 - Animal 1" # Rick
|
||||
grass_land_6_a2 = "Grass Land 6 - Animal 2" # ChuChu
|
||||
grass_land_6_a3 = "Grass Land 6 - Animal 3" # Nago
|
||||
grass_land_6_a4 = "Grass Land 6 - Animal 4" # Coo
|
||||
ripple_field_1_a1 = "Ripple Field 1 - Animal 1" # Pitch
|
||||
ripple_field_1_a2 = "Ripple Field 1 - Animal 2" # Nago
|
||||
ripple_field_2_a1 = "Ripple Field 2 - Animal 1" # Kine
|
||||
ripple_field_2_a2 = "Ripple Field 2 - Animal 2" # ChuChu
|
||||
ripple_field_2_a3 = "Ripple Field 2 - Animal 3" # Rick
|
||||
ripple_field_2_a4 = "Ripple Field 2 - Animal 4" # Coo
|
||||
ripple_field_3_a1 = "Ripple Field 3 - Animal 1" # Kine
|
||||
ripple_field_3_a2 = "Ripple Field 3 - Animal 2" # Rick
|
||||
ripple_field_4_a1 = "Ripple Field 4 - Animal 1" # ChuChu
|
||||
ripple_field_4_a2 = "Ripple Field 4 - Animal 2" # Kine
|
||||
ripple_field_4_a3 = "Ripple Field 4 - Animal 3" # Nago
|
||||
ripple_field_5_a1 = "Ripple Field 5 - Animal 1" # Kine
|
||||
ripple_field_5_a2 = "Ripple Field 5 - Animal 2" # Pitch
|
||||
ripple_field_6_a1 = "Ripple Field 6 - Animal 1" # Nago
|
||||
ripple_field_6_a2 = "Ripple Field 6 - Animal 2" # Pitch
|
||||
ripple_field_6_a3 = "Ripple Field 6 - Animal 3" # Rick
|
||||
ripple_field_6_a4 = "Ripple Field 6 - Animal 4" # Coo
|
||||
sand_canyon_1_a1 = "Sand Canyon 1 - Animal 1" # Rick
|
||||
sand_canyon_1_a2 = "Sand Canyon 1 - Animal 2" # Pitch
|
||||
sand_canyon_2_a1 = "Sand Canyon 2 - Animal 1" # ChuChu
|
||||
sand_canyon_2_a2 = "Sand Canyon 2 - Animal 2" # Coo
|
||||
sand_canyon_3_a1 = "Sand Canyon 3 - Animal 1" # Pitch
|
||||
sand_canyon_3_a2 = "Sand Canyon 3 - Animal 2" # Coo
|
||||
sand_canyon_3_a3 = "Sand Canyon 3 - Animal 3" # ChuChu
|
||||
sand_canyon_4_a1 = "Sand Canyon 4 - Animal 1" # Rick
|
||||
sand_canyon_4_a2 = "Sand Canyon 4 - Animal 2" # Pitch
|
||||
sand_canyon_4_a3 = "Sand Canyon 4 - Animal 3" # Nago
|
||||
sand_canyon_5_a1 = "Sand Canyon 5 - Animal 1" # Rick
|
||||
sand_canyon_5_a2 = "Sand Canyon 5 - Animal 2" # ChuChu
|
||||
sand_canyon_6_a1 = "Sand Canyon 6 - Animal 1" # Coo
|
||||
sand_canyon_6_a2 = "Sand Canyon 6 - Animal 2" # Kine
|
||||
sand_canyon_6_a3 = "Sand Canyon 6 - Animal 3" # Rick
|
||||
sand_canyon_6_a4 = "Sand Canyon 6 - Animal 4" # ChuChu
|
||||
sand_canyon_6_a5 = "Sand Canyon 6 - Animal 5" # Nago
|
||||
sand_canyon_6_a6 = "Sand Canyon 6 - Animal 6" # Pitch
|
||||
cloudy_park_1_a1 = "Cloudy Park 1 - Animal 1" # Rick
|
||||
cloudy_park_1_a2 = "Cloudy Park 1 - Animal 2" # Nago
|
||||
cloudy_park_1_a3 = "Cloudy Park 1 - Animal 3" # Coo
|
||||
cloudy_park_1_a4 = "Cloudy Park 1 - Animal 4" # Kine
|
||||
cloudy_park_1_a5 = "Cloudy Park 1 - Animal 5" # ChuChu
|
||||
cloudy_park_1_a6 = "Cloudy Park 1 - Animal 6" # Pitch
|
||||
cloudy_park_2_a1 = "Cloudy Park 2 - Animal 1" # Nago
|
||||
cloudy_park_2_a2 = "Cloudy Park 2 - Animal 2" # Pitch
|
||||
cloudy_park_2_a3 = "Cloudy Park 2 - Animal 3" # ChuChu
|
||||
cloudy_park_3_a1 = "Cloudy Park 3 - Animal 1" # Kine
|
||||
cloudy_park_3_a2 = "Cloudy Park 3 - Animal 2" # Rick
|
||||
cloudy_park_3_a3 = "Cloudy Park 3 - Animal 3" # ChuChu
|
||||
cloudy_park_4_a1 = "Cloudy Park 4 - Animal 1" # Coo
|
||||
cloudy_park_4_a2 = "Cloudy Park 4 - Animal 2" # ChuChu
|
||||
cloudy_park_5_a1 = "Cloudy Park 5 - Animal 1" # Rick
|
||||
cloudy_park_5_a2 = "Cloudy Park 5 - Animal 2" # Coo
|
||||
cloudy_park_6_a1 = "Cloudy Park 6 - Animal 1" # Nago
|
||||
cloudy_park_6_a2 = "Cloudy Park 6 - Animal 2" # Coo
|
||||
cloudy_park_6_a3 = "Cloudy Park 6 - Animal 3" # Rick
|
||||
iceberg_1_a1 = "Iceberg 1 - Animal 1" # Pitch
|
||||
iceberg_1_a2 = "Iceberg 1 - Animal 2" # Rick
|
||||
iceberg_2_a1 = "Iceberg 2 - Animal 1" # Nago
|
||||
iceberg_2_a2 = "Iceberg 2 - Animal 2" # Pitch
|
||||
iceberg_3_a1 = "Iceberg 3 - Animal 1" # Pitch
|
||||
iceberg_3_a2 = "Iceberg 3 - Animal 2" # Coo
|
||||
iceberg_3_a3 = "Iceberg 3 - Animal 3" # Nago
|
||||
iceberg_3_a4 = "Iceberg 3 - Animal 4" # Rick
|
||||
iceberg_3_a5 = "Iceberg 3 - Animal 5" # Kine
|
||||
iceberg_4_a1 = "Iceberg 4 - Animal 1" # ChuChu
|
||||
iceberg_4_a2 = "Iceberg 4 - Animal 2" # Coo
|
||||
iceberg_4_a3 = "Iceberg 4 - Animal 3" # Pitch
|
||||
iceberg_4_a4 = "Iceberg 4 - Animal 4" # Coo
|
||||
iceberg_4_a5 = "Iceberg 4 - Animal 5" # Rick
|
||||
iceberg_5_a1 = "Iceberg 5 - Animal 1" # Kine
|
||||
iceberg_5_a2 = "Iceberg 5 - Animal 2" # Rick
|
||||
iceberg_5_a3 = "Iceberg 5 - Animal 3" # Pitch
|
||||
iceberg_5_a4 = "Iceberg 5 - Animal 4" # ChuChu
|
||||
iceberg_5_a5 = "Iceberg 5 - Animal 5" # Kine
|
||||
iceberg_5_a6 = "Iceberg 5 - Animal 6" # Coo
|
||||
iceberg_5_a7 = "Iceberg 5 - Animal 7" # Rick
|
||||
iceberg_5_a8 = "Iceberg 5 - Animal 8" # ChuChu
|
||||
iceberg_6_a1 = "Iceberg 6 - Animal 1" # Rick
|
||||
iceberg_6_a2 = "Iceberg 6 - Animal 2" # Coo
|
||||
iceberg_6_a3 = "Iceberg 6 - Animal 3" # Nago
|
||||
iceberg_6_a4 = "Iceberg 6 - Animal 4" # Kine
|
||||
iceberg_6_a5 = "Iceberg 6 - Animal 5" # ChuChu
|
||||
iceberg_6_a6 = "Iceberg 6 - Animal 6" # Nago
|
||||
|
||||
animal_friend_spawns = {
|
||||
grass_land_1_a1: "Nago Spawn",
|
||||
grass_land_1_a2: "Rick Spawn",
|
||||
grass_land_2_a1: "ChuChu Spawn",
|
||||
grass_land_2_a2: "Pitch Spawn",
|
||||
grass_land_3_a1: "Kine Spawn",
|
||||
grass_land_3_a2: "Coo Spawn",
|
||||
grass_land_4_a1: "ChuChu Spawn",
|
||||
grass_land_4_a2: "Nago Spawn",
|
||||
grass_land_5_a1: "Coo Spawn",
|
||||
grass_land_5_a2: "Kine Spawn",
|
||||
grass_land_5_a3: "Nago Spawn",
|
||||
grass_land_5_a4: "Rick Spawn",
|
||||
grass_land_6_a1: "Rick Spawn",
|
||||
grass_land_6_a2: "ChuChu Spawn",
|
||||
grass_land_6_a3: "Nago Spawn",
|
||||
grass_land_6_a4: "Coo Spawn",
|
||||
ripple_field_1_a1: "Pitch Spawn",
|
||||
ripple_field_1_a2: "Nago Spawn",
|
||||
ripple_field_2_a1: "Kine Spawn",
|
||||
ripple_field_2_a2: "ChuChu Spawn",
|
||||
ripple_field_2_a3: "Rick Spawn",
|
||||
ripple_field_2_a4: "Coo Spawn",
|
||||
ripple_field_3_a1: "Kine Spawn",
|
||||
ripple_field_3_a2: "Rick Spawn",
|
||||
ripple_field_4_a1: "ChuChu Spawn",
|
||||
ripple_field_4_a2: "Kine Spawn",
|
||||
ripple_field_4_a3: "Nago Spawn",
|
||||
ripple_field_5_a1: "Kine Spawn",
|
||||
ripple_field_5_a2: "Pitch Spawn",
|
||||
ripple_field_6_a1: "Nago Spawn",
|
||||
ripple_field_6_a2: "Pitch Spawn",
|
||||
ripple_field_6_a3: "Rick Spawn",
|
||||
ripple_field_6_a4: "Coo Spawn",
|
||||
sand_canyon_1_a1: "Rick Spawn",
|
||||
sand_canyon_1_a2: "Pitch Spawn",
|
||||
sand_canyon_2_a1: "ChuChu Spawn",
|
||||
sand_canyon_2_a2: "Coo Spawn",
|
||||
sand_canyon_3_a1: "Pitch Spawn",
|
||||
sand_canyon_3_a2: "Coo Spawn",
|
||||
sand_canyon_3_a3: "ChuChu Spawn",
|
||||
sand_canyon_4_a1: "Rick Spawn",
|
||||
sand_canyon_4_a2: "Pitch Spawn",
|
||||
sand_canyon_4_a3: "Nago Spawn",
|
||||
sand_canyon_5_a1: "Rick Spawn",
|
||||
sand_canyon_5_a2: "ChuChu Spawn",
|
||||
sand_canyon_6_a1: "Coo Spawn",
|
||||
sand_canyon_6_a2: "Kine Spawn",
|
||||
sand_canyon_6_a3: "Rick Spawn",
|
||||
sand_canyon_6_a4: "ChuChu Spawn",
|
||||
sand_canyon_6_a5: "Nago Spawn",
|
||||
sand_canyon_6_a6: "Pitch Spawn",
|
||||
cloudy_park_1_a1: "Rick Spawn",
|
||||
cloudy_park_1_a2: "Nago Spawn",
|
||||
cloudy_park_1_a3: "Coo Spawn",
|
||||
cloudy_park_1_a4: "Kine Spawn",
|
||||
cloudy_park_1_a5: "ChuChu Spawn",
|
||||
cloudy_park_1_a6: "Pitch Spawn",
|
||||
cloudy_park_2_a1: "Nago Spawn",
|
||||
cloudy_park_2_a2: "Pitch Spawn",
|
||||
cloudy_park_2_a3: "ChuChu Spawn",
|
||||
cloudy_park_3_a1: "Kine Spawn",
|
||||
cloudy_park_3_a2: "Rick Spawn",
|
||||
cloudy_park_3_a3: "ChuChu Spawn",
|
||||
cloudy_park_4_a1: "Coo Spawn",
|
||||
cloudy_park_4_a2: "ChuChu Spawn",
|
||||
cloudy_park_5_a1: "Rick Spawn",
|
||||
cloudy_park_5_a2: "Coo Spawn",
|
||||
cloudy_park_6_a1: "Nago Spawn",
|
||||
cloudy_park_6_a2: "Coo Spawn",
|
||||
cloudy_park_6_a3: "Rick Spawn",
|
||||
iceberg_1_a1: "Pitch Spawn",
|
||||
iceberg_1_a2: "Rick Spawn",
|
||||
iceberg_2_a1: "Nago Spawn",
|
||||
iceberg_2_a2: "Pitch Spawn",
|
||||
iceberg_3_a1: "Pitch Spawn",
|
||||
iceberg_3_a2: "Coo Spawn",
|
||||
iceberg_3_a3: "Nago Spawn",
|
||||
iceberg_3_a4: "Rick Spawn",
|
||||
iceberg_3_a5: "Kine Spawn",
|
||||
iceberg_4_a1: "ChuChu Spawn",
|
||||
iceberg_4_a2: "Coo Spawn",
|
||||
iceberg_4_a3: "Pitch Spawn",
|
||||
iceberg_4_a4: "Coo Spawn",
|
||||
iceberg_4_a5: "Rick Spawn",
|
||||
iceberg_5_a1: "Kine Spawn",
|
||||
iceberg_5_a2: "Rick Spawn",
|
||||
iceberg_5_a3: "Pitch Spawn",
|
||||
iceberg_5_a4: "ChuChu Spawn",
|
||||
iceberg_5_a5: "Kine Spawn",
|
||||
iceberg_5_a6: "Coo Spawn",
|
||||
iceberg_5_a7: "Rick Spawn",
|
||||
iceberg_5_a8: "ChuChu Spawn",
|
||||
iceberg_6_a1: "Rick Spawn",
|
||||
iceberg_6_a2: "Coo Spawn",
|
||||
iceberg_6_a3: "Nago Spawn",
|
||||
iceberg_6_a4: "Kine Spawn",
|
||||
iceberg_6_a5: "ChuChu Spawn",
|
||||
iceberg_6_a6: "Nago Spawn",
|
||||
}
|
822
worlds/kdl3/Names/EnemyAbilities.py
Normal file
822
worlds/kdl3/Names/EnemyAbilities.py
Normal file
@@ -0,0 +1,822 @@
|
||||
from typing import List, Tuple, Set
|
||||
|
||||
Grass_Land_1_E1 = "Grass Land 1 - Enemy 1 (Waddle Dee)"
|
||||
Grass_Land_1_E2 = "Grass Land 1 - Enemy 2 (Sir Kibble)"
|
||||
Grass_Land_1_E3 = "Grass Land 1 - Enemy 3 (Cappy)"
|
||||
Grass_Land_1_E4 = "Grass Land 1 - Enemy 4 (Sparky)"
|
||||
Grass_Land_1_E5 = "Grass Land 1 - Enemy 5 (Bronto Burt)"
|
||||
Grass_Land_1_E6 = "Grass Land 1 - Enemy 6 (Sasuke)"
|
||||
Grass_Land_1_E7 = "Grass Land 1 - Enemy 7 (Poppy Bros Jr.)"
|
||||
Grass_Land_2_E1 = "Grass Land 2 - Enemy 1 (Rocky)"
|
||||
Grass_Land_2_E2 = "Grass Land 2 - Enemy 2 (KeKe)"
|
||||
Grass_Land_2_E3 = "Grass Land 2 - Enemy 3 (Bobo)"
|
||||
Grass_Land_2_E4 = "Grass Land 2 - Enemy 4 (Poppy Bros Jr.)"
|
||||
Grass_Land_2_E5 = "Grass Land 2 - Enemy 5 (Waddle Dee)"
|
||||
Grass_Land_2_E6 = "Grass Land 2 - Enemy 6 (Popon Ball)"
|
||||
Grass_Land_2_E7 = "Grass Land 2 - Enemy 7 (Bouncy)"
|
||||
Grass_Land_2_E8 = "Grass Land 2 - Enemy 8 (Tick)"
|
||||
Grass_Land_2_E9 = "Grass Land 2 - Enemy 9 (Bronto Burt)"
|
||||
Grass_Land_2_E10 = "Grass Land 2 - Enemy 10 (Nruff)"
|
||||
Grass_Land_3_E1 = "Grass Land 3 - Enemy 1 (Sparky)"
|
||||
Grass_Land_3_E2 = "Grass Land 3 - Enemy 2 (Rocky)"
|
||||
Grass_Land_3_E3 = "Grass Land 3 - Enemy 3 (Nruff)"
|
||||
Grass_Land_3_E4 = "Grass Land 3 - Enemy 4 (Bouncy)"
|
||||
Grass_Land_4_E1 = "Grass Land 4 - Enemy 1 (Loud)"
|
||||
Grass_Land_4_E2 = "Grass Land 4 - Enemy 2 (Babut)"
|
||||
Grass_Land_4_E3 = "Grass Land 4 - Enemy 3 (Rocky)"
|
||||
Grass_Land_4_E4 = "Grass Land 4 - Enemy 4 (Kapar)"
|
||||
Grass_Land_4_E5 = "Grass Land 4 - Enemy 5 (Glunk)"
|
||||
Grass_Land_4_E6 = "Grass Land 4 - Enemy 6 (Oro)"
|
||||
Grass_Land_4_E7 = "Grass Land 4 - Enemy 7 (Peran)"
|
||||
Grass_Land_5_E1 = "Grass Land 5 - Enemy 1 (Propeller)"
|
||||
Grass_Land_5_E2 = "Grass Land 5 - Enemy 2 (Broom Hatter)"
|
||||
Grass_Land_5_E3 = "Grass Land 5 - Enemy 3 (Bouncy)"
|
||||
Grass_Land_5_E4 = "Grass Land 5 - Enemy 4 (Sir Kibble)"
|
||||
Grass_Land_5_E5 = "Grass Land 5 - Enemy 5 (Waddle Dee)"
|
||||
Grass_Land_5_E6 = "Grass Land 5 - Enemy 6 (Sasuke)"
|
||||
Grass_Land_5_E7 = "Grass Land 5 - Enemy 7 (Nruff)"
|
||||
Grass_Land_5_E8 = "Grass Land 5 - Enemy 8 (Tick)"
|
||||
Grass_Land_6_E1 = "Grass Land 6 - Enemy 1 (Como)"
|
||||
Grass_Land_6_E2 = "Grass Land 6 - Enemy 2 (Togezo)"
|
||||
Grass_Land_6_E3 = "Grass Land 6 - Enemy 3 (Bronto Burt)"
|
||||
Grass_Land_6_E4 = "Grass Land 6 - Enemy 4 (Cappy)"
|
||||
Grass_Land_6_E5 = "Grass Land 6 - Enemy 5 (Bobo)"
|
||||
Grass_Land_6_E6 = "Grass Land 6 - Enemy 6 (Mariel)"
|
||||
Grass_Land_6_E7 = "Grass Land 6 - Enemy 7 (Yaban)"
|
||||
Grass_Land_6_E8 = "Grass Land 6 - Enemy 8 (Broom Hatter)"
|
||||
Grass_Land_6_E9 = "Grass Land 6 - Enemy 9 (Apolo)"
|
||||
Grass_Land_6_E10 = "Grass Land 6 - Enemy 10 (Sasuke)"
|
||||
Grass_Land_6_E11 = "Grass Land 6 - Enemy 11 (Rocky)"
|
||||
Ripple_Field_1_E1 = "Ripple Field 1 - Enemy 1 (Waddle Dee)"
|
||||
Ripple_Field_1_E2 = "Ripple Field 1 - Enemy 2 (Glunk)"
|
||||
Ripple_Field_1_E3 = "Ripple Field 1 - Enemy 3 (Broom Hatter)"
|
||||
Ripple_Field_1_E4 = "Ripple Field 1 - Enemy 4 (Cappy)"
|
||||
Ripple_Field_1_E5 = "Ripple Field 1 - Enemy 5 (Bronto Burt)"
|
||||
Ripple_Field_1_E6 = "Ripple Field 1 - Enemy 6 (Rocky)"
|
||||
Ripple_Field_1_E7 = "Ripple Field 1 - Enemy 7 (Poppy Bros Jr.)"
|
||||
Ripple_Field_1_E8 = "Ripple Field 1 - Enemy 8 (Bobin)"
|
||||
Ripple_Field_2_E1 = "Ripple Field 2 - Enemy 1 (Togezo)"
|
||||
Ripple_Field_2_E2 = "Ripple Field 2 - Enemy 2 (Coconut)"
|
||||
Ripple_Field_2_E3 = "Ripple Field 2 - Enemy 3 (Blipper)"
|
||||
Ripple_Field_2_E4 = "Ripple Field 2 - Enemy 4 (Sasuke)"
|
||||
Ripple_Field_2_E5 = "Ripple Field 2 - Enemy 5 (Kany)"
|
||||
Ripple_Field_2_E6 = "Ripple Field 2 - Enemy 6 (Glunk)"
|
||||
Ripple_Field_3_E1 = "Ripple Field 3 - Enemy 1 (Raft Waddle Dee)"
|
||||
Ripple_Field_3_E2 = "Ripple Field 3 - Enemy 2 (Kapar)"
|
||||
Ripple_Field_3_E3 = "Ripple Field 3 - Enemy 3 (Blipper)"
|
||||
Ripple_Field_3_E4 = "Ripple Field 3 - Enemy 4 (Sparky)"
|
||||
Ripple_Field_3_E5 = "Ripple Field 3 - Enemy 5 (Glunk)"
|
||||
Ripple_Field_3_E6 = "Ripple Field 3 - Enemy 6 (Joe)"
|
||||
Ripple_Field_3_E7 = "Ripple Field 3 - Enemy 7 (Bobo)"
|
||||
Ripple_Field_4_E1 = "Ripple Field 4 - Enemy 1 (Bukiset (Stone))"
|
||||
Ripple_Field_4_E2 = "Ripple Field 4 - Enemy 2 (Bukiset (Needle))"
|
||||
Ripple_Field_4_E3 = "Ripple Field 4 - Enemy 3 (Bukiset (Clean))"
|
||||
Ripple_Field_4_E4 = "Ripple Field 4 - Enemy 4 (Bukiset (Parasol))"
|
||||
Ripple_Field_4_E5 = "Ripple Field 4 - Enemy 5 (Mony)"
|
||||
Ripple_Field_4_E6 = "Ripple Field 4 - Enemy 6 (Bukiset (Burning))"
|
||||
Ripple_Field_4_E7 = "Ripple Field 4 - Enemy 7 (Bobin)"
|
||||
Ripple_Field_4_E8 = "Ripple Field 4 - Enemy 8 (Blipper)"
|
||||
Ripple_Field_4_E9 = "Ripple Field 4 - Enemy 9 (Como)"
|
||||
Ripple_Field_4_E10 = "Ripple Field 4 - Enemy 10 (Oro)"
|
||||
Ripple_Field_4_E11 = "Ripple Field 4 - Enemy 11 (Gansan)"
|
||||
Ripple_Field_4_E12 = "Ripple Field 4 - Enemy 12 (Waddle Dee)"
|
||||
Ripple_Field_4_E13 = "Ripple Field 4 - Enemy 13 (Kapar)"
|
||||
Ripple_Field_4_E14 = "Ripple Field 4 - Enemy 14 (Squishy)"
|
||||
Ripple_Field_4_E15 = "Ripple Field 4 - Enemy 15 (Nidoo)"
|
||||
Ripple_Field_5_E1 = "Ripple Field 5 - Enemy 1 (Glunk)"
|
||||
Ripple_Field_5_E2 = "Ripple Field 5 - Enemy 2 (Joe)"
|
||||
Ripple_Field_5_E3 = "Ripple Field 5 - Enemy 3 (Bobin)"
|
||||
Ripple_Field_5_E4 = "Ripple Field 5 - Enemy 4 (Mony)"
|
||||
Ripple_Field_5_E5 = "Ripple Field 5 - Enemy 5 (Squishy)"
|
||||
Ripple_Field_5_E6 = "Ripple Field 5 - Enemy 6 (Yaban)"
|
||||
Ripple_Field_5_E7 = "Ripple Field 5 - Enemy 7 (Broom Hatter)"
|
||||
Ripple_Field_5_E8 = "Ripple Field 5 - Enemy 8 (Bouncy)"
|
||||
Ripple_Field_5_E9 = "Ripple Field 5 - Enemy 9 (Sparky)"
|
||||
Ripple_Field_5_E10 = "Ripple Field 5 - Enemy 10 (Rocky)"
|
||||
Ripple_Field_5_E11 = "Ripple Field 5 - Enemy 11 (Babut)"
|
||||
Ripple_Field_5_E12 = "Ripple Field 5 - Enemy 12 (Galbo)"
|
||||
Ripple_Field_6_E1 = "Ripple Field 6 - Enemy 1 (Kany)"
|
||||
Ripple_Field_6_E2 = "Ripple Field 6 - Enemy 2 (KeKe)"
|
||||
Ripple_Field_6_E3 = "Ripple Field 6 - Enemy 3 (Kapar)"
|
||||
Ripple_Field_6_E4 = "Ripple Field 6 - Enemy 4 (Rocky)"
|
||||
Ripple_Field_6_E5 = "Ripple Field 6 - Enemy 5 (Poppy Bros Jr.)"
|
||||
Ripple_Field_6_E6 = "Ripple Field 6 - Enemy 6 (Propeller)"
|
||||
Ripple_Field_6_E7 = "Ripple Field 6 - Enemy 7 (Coconut)"
|
||||
Ripple_Field_6_E8 = "Ripple Field 6 - Enemy 8 (Sasuke)"
|
||||
Ripple_Field_6_E9 = "Ripple Field 6 - Enemy 9 (Nruff)"
|
||||
Sand_Canyon_1_E1 = "Sand Canyon 1 - Enemy 1 (Bronto Burt)"
|
||||
Sand_Canyon_1_E2 = "Sand Canyon 1 - Enemy 2 (Galbo)"
|
||||
Sand_Canyon_1_E3 = "Sand Canyon 1 - Enemy 3 (Oro)"
|
||||
Sand_Canyon_1_E4 = "Sand Canyon 1 - Enemy 4 (Sparky)"
|
||||
Sand_Canyon_1_E5 = "Sand Canyon 1 - Enemy 5 (Propeller)"
|
||||
Sand_Canyon_1_E6 = "Sand Canyon 1 - Enemy 6 (Gansan)"
|
||||
Sand_Canyon_1_E7 = "Sand Canyon 1 - Enemy 7 (Babut)"
|
||||
Sand_Canyon_1_E8 = "Sand Canyon 1 - Enemy 8 (Loud)"
|
||||
Sand_Canyon_1_E9 = "Sand Canyon 1 - Enemy 9 (Dogon)"
|
||||
Sand_Canyon_1_E10 = "Sand Canyon 1 - Enemy 10 (Bouncy)"
|
||||
Sand_Canyon_1_E11 = "Sand Canyon 1 - Enemy 11 (Pteran)"
|
||||
Sand_Canyon_1_E12 = "Sand Canyon 1 - Enemy 12 (Polof)"
|
||||
Sand_Canyon_2_E1 = "Sand Canyon 2 - Enemy 1 (KeKe)"
|
||||
Sand_Canyon_2_E2 = "Sand Canyon 2 - Enemy 2 (Doka)"
|
||||
Sand_Canyon_2_E3 = "Sand Canyon 2 - Enemy 3 (Boten)"
|
||||
Sand_Canyon_2_E4 = "Sand Canyon 2 - Enemy 4 (Propeller)"
|
||||
Sand_Canyon_2_E5 = "Sand Canyon 2 - Enemy 5 (Waddle Dee)"
|
||||
Sand_Canyon_2_E6 = "Sand Canyon 2 - Enemy 6 (Sparky)"
|
||||
Sand_Canyon_2_E7 = "Sand Canyon 2 - Enemy 7 (Sasuke)"
|
||||
Sand_Canyon_2_E8 = "Sand Canyon 2 - Enemy 8 (Como)"
|
||||
Sand_Canyon_2_E9 = "Sand Canyon 2 - Enemy 9 (Bukiset (Ice))"
|
||||
Sand_Canyon_2_E10 = "Sand Canyon 2 - Enemy 10 (Bukiset (Needle))"
|
||||
Sand_Canyon_2_E11 = "Sand Canyon 2 - Enemy 11 (Bukiset (Clean))"
|
||||
Sand_Canyon_2_E12 = "Sand Canyon 2 - Enemy 12 (Bukiset (Parasol))"
|
||||
Sand_Canyon_2_E13 = "Sand Canyon 2 - Enemy 13 (Bukiset (Spark))"
|
||||
Sand_Canyon_2_E14 = "Sand Canyon 2 - Enemy 14 (Bukiset (Cutter))"
|
||||
Sand_Canyon_2_E15 = "Sand Canyon 2 - Enemy 15 (Nidoo)"
|
||||
Sand_Canyon_2_E16 = "Sand Canyon 2 - Enemy 16 (Mariel)"
|
||||
Sand_Canyon_2_E17 = "Sand Canyon 2 - Enemy 17 (Yaban)"
|
||||
Sand_Canyon_2_E18 = "Sand Canyon 2 - Enemy 18 (Wapod)"
|
||||
Sand_Canyon_2_E19 = "Sand Canyon 2 - Enemy 19 (Squishy)"
|
||||
Sand_Canyon_2_E20 = "Sand Canyon 2 - Enemy 20 (Pteran)"
|
||||
Sand_Canyon_3_E1 = "Sand Canyon 3 - Enemy 1 (Sir Kibble)"
|
||||
Sand_Canyon_3_E2 = "Sand Canyon 3 - Enemy 2 (Broom Hatter)"
|
||||
Sand_Canyon_3_E3 = "Sand Canyon 3 - Enemy 3 (Rocky)"
|
||||
Sand_Canyon_3_E4 = "Sand Canyon 3 - Enemy 4 (Gabon)"
|
||||
Sand_Canyon_3_E5 = "Sand Canyon 3 - Enemy 5 (Kany)"
|
||||
Sand_Canyon_3_E6 = "Sand Canyon 3 - Enemy 6 (Galbo)"
|
||||
Sand_Canyon_3_E7 = "Sand Canyon 3 - Enemy 7 (Propeller)"
|
||||
Sand_Canyon_3_E8 = "Sand Canyon 3 - Enemy 8 (Sasuke)"
|
||||
Sand_Canyon_3_E9 = "Sand Canyon 3 - Enemy 9 (Wapod)"
|
||||
Sand_Canyon_3_E10 = "Sand Canyon 3 - Enemy 10 (Bobo)"
|
||||
Sand_Canyon_3_E11 = "Sand Canyon 3 - Enemy 11 (Babut)"
|
||||
Sand_Canyon_3_E12 = "Sand Canyon 3 - Enemy 12 (Magoo)"
|
||||
Sand_Canyon_4_E1 = "Sand Canyon 4 - Enemy 1 (Popon Ball)"
|
||||
Sand_Canyon_4_E2 = "Sand Canyon 4 - Enemy 2 (Mariel)"
|
||||
Sand_Canyon_4_E3 = "Sand Canyon 4 - Enemy 3 (Chilly)"
|
||||
Sand_Canyon_4_E4 = "Sand Canyon 4 - Enemy 4 (Tick)"
|
||||
Sand_Canyon_4_E5 = "Sand Canyon 4 - Enemy 5 (Bronto Burt)"
|
||||
Sand_Canyon_4_E6 = "Sand Canyon 4 - Enemy 6 (Babut)"
|
||||
Sand_Canyon_4_E7 = "Sand Canyon 4 - Enemy 7 (Bobin)"
|
||||
Sand_Canyon_4_E8 = "Sand Canyon 4 - Enemy 8 (Joe)"
|
||||
Sand_Canyon_4_E9 = "Sand Canyon 4 - Enemy 9 (Mony)"
|
||||
Sand_Canyon_4_E10 = "Sand Canyon 4 - Enemy 10 (Blipper)"
|
||||
Sand_Canyon_4_E11 = "Sand Canyon 4 - Enemy 11 (Togezo)"
|
||||
Sand_Canyon_4_E12 = "Sand Canyon 4 - Enemy 12 (Rocky)"
|
||||
Sand_Canyon_4_E13 = "Sand Canyon 4 - Enemy 13 (Bobo)"
|
||||
Sand_Canyon_5_E1 = "Sand Canyon 5 - Enemy 1 (Wapod)"
|
||||
Sand_Canyon_5_E2 = "Sand Canyon 5 - Enemy 2 (Dogon)"
|
||||
Sand_Canyon_5_E3 = "Sand Canyon 5 - Enemy 3 (Tick)"
|
||||
Sand_Canyon_5_E4 = "Sand Canyon 5 - Enemy 4 (Rocky)"
|
||||
Sand_Canyon_5_E5 = "Sand Canyon 5 - Enemy 5 (Bobo)"
|
||||
Sand_Canyon_5_E6 = "Sand Canyon 5 - Enemy 6 (Chilly)"
|
||||
Sand_Canyon_5_E7 = "Sand Canyon 5 - Enemy 7 (Sparky)"
|
||||
Sand_Canyon_5_E8 = "Sand Canyon 5 - Enemy 8 (Togezo)"
|
||||
Sand_Canyon_5_E9 = "Sand Canyon 5 - Enemy 9 (Bronto Burt)"
|
||||
Sand_Canyon_5_E10 = "Sand Canyon 5 - Enemy 10 (Sasuke)"
|
||||
Sand_Canyon_5_E11 = "Sand Canyon 5 - Enemy 11 (Oro)"
|
||||
Sand_Canyon_5_E12 = "Sand Canyon 5 - Enemy 12 (Galbo)"
|
||||
Sand_Canyon_5_E13 = "Sand Canyon 5 - Enemy 13 (Nidoo)"
|
||||
Sand_Canyon_5_E14 = "Sand Canyon 5 - Enemy 14 (Propeller)"
|
||||
Sand_Canyon_5_E15 = "Sand Canyon 5 - Enemy 15 (Sir Kibble)"
|
||||
Sand_Canyon_5_E16 = "Sand Canyon 5 - Enemy 16 (KeKe)"
|
||||
Sand_Canyon_5_E17 = "Sand Canyon 5 - Enemy 17 (Kabu)"
|
||||
Sand_Canyon_6_E1 = "Sand Canyon 6 - Enemy 1 (Sparky)"
|
||||
Sand_Canyon_6_E2 = "Sand Canyon 6 - Enemy 2 (Doka)"
|
||||
Sand_Canyon_6_E3 = "Sand Canyon 6 - Enemy 3 (Cappy)"
|
||||
Sand_Canyon_6_E4 = "Sand Canyon 6 - Enemy 4 (Pteran)"
|
||||
Sand_Canyon_6_E5 = "Sand Canyon 6 - Enemy 5 (Bukiset (Parasol))"
|
||||
Sand_Canyon_6_E6 = "Sand Canyon 6 - Enemy 6 (Bukiset (Cutter))"
|
||||
Sand_Canyon_6_E7 = "Sand Canyon 6 - Enemy 7 (Bukiset (Clean))"
|
||||
Sand_Canyon_6_E8 = "Sand Canyon 6 - Enemy 8 (Bukiset (Spark))"
|
||||
Sand_Canyon_6_E9 = "Sand Canyon 6 - Enemy 9 (Bukiset (Ice))"
|
||||
Sand_Canyon_6_E10 = "Sand Canyon 6 - Enemy 10 (Bukiset (Needle))"
|
||||
Sand_Canyon_6_E11 = "Sand Canyon 6 - Enemy 11 (Bukiset (Burning))"
|
||||
Sand_Canyon_6_E12 = "Sand Canyon 6 - Enemy 12 (Bukiset (Stone))"
|
||||
Sand_Canyon_6_E13 = "Sand Canyon 6 - Enemy 13 (Nidoo)"
|
||||
Cloudy_Park_1_E1 = "Cloudy Park 1 - Enemy 1 (Waddle Dee)"
|
||||
Cloudy_Park_1_E2 = "Cloudy Park 1 - Enemy 2 (KeKe)"
|
||||
Cloudy_Park_1_E3 = "Cloudy Park 1 - Enemy 3 (Cappy)"
|
||||
Cloudy_Park_1_E4 = "Cloudy Park 1 - Enemy 4 (Yaban)"
|
||||
Cloudy_Park_1_E5 = "Cloudy Park 1 - Enemy 5 (Togezo)"
|
||||
Cloudy_Park_1_E6 = "Cloudy Park 1 - Enemy 6 (Galbo)"
|
||||
Cloudy_Park_1_E7 = "Cloudy Park 1 - Enemy 7 (Sparky)"
|
||||
Cloudy_Park_1_E8 = "Cloudy Park 1 - Enemy 8 (Como)"
|
||||
Cloudy_Park_1_E9 = "Cloudy Park 1 - Enemy 9 (Bronto Burt)"
|
||||
Cloudy_Park_1_E10 = "Cloudy Park 1 - Enemy 10 (Gabon)"
|
||||
Cloudy_Park_1_E11 = "Cloudy Park 1 - Enemy 11 (Sir Kibble)"
|
||||
Cloudy_Park_1_E12 = "Cloudy Park 1 - Enemy 12 (Mariel)"
|
||||
Cloudy_Park_1_E13 = "Cloudy Park 1 - Enemy 13 (Nruff)"
|
||||
Cloudy_Park_2_E1 = "Cloudy Park 2 - Enemy 1 (Chilly)"
|
||||
Cloudy_Park_2_E2 = "Cloudy Park 2 - Enemy 2 (Sasuke)"
|
||||
Cloudy_Park_2_E3 = "Cloudy Park 2 - Enemy 3 (Waddle Dee)"
|
||||
Cloudy_Park_2_E4 = "Cloudy Park 2 - Enemy 4 (Sparky)"
|
||||
Cloudy_Park_2_E5 = "Cloudy Park 2 - Enemy 5 (Broom Hatter)"
|
||||
Cloudy_Park_2_E6 = "Cloudy Park 2 - Enemy 6 (Sir Kibble)"
|
||||
Cloudy_Park_2_E7 = "Cloudy Park 2 - Enemy 7 (Pteran)"
|
||||
Cloudy_Park_2_E8 = "Cloudy Park 2 - Enemy 8 (Propeller)"
|
||||
Cloudy_Park_2_E9 = "Cloudy Park 2 - Enemy 9 (Dogon)"
|
||||
Cloudy_Park_2_E10 = "Cloudy Park 2 - Enemy 10 (Togezo)"
|
||||
Cloudy_Park_2_E11 = "Cloudy Park 2 - Enemy 11 (Oro)"
|
||||
Cloudy_Park_2_E12 = "Cloudy Park 2 - Enemy 12 (Bronto Burt)"
|
||||
Cloudy_Park_2_E13 = "Cloudy Park 2 - Enemy 13 (Rocky)"
|
||||
Cloudy_Park_2_E14 = "Cloudy Park 2 - Enemy 14 (Galbo)"
|
||||
Cloudy_Park_2_E15 = "Cloudy Park 2 - Enemy 15 (Kapar)"
|
||||
Cloudy_Park_3_E1 = "Cloudy Park 3 - Enemy 1 (Bronto Burt)"
|
||||
Cloudy_Park_3_E2 = "Cloudy Park 3 - Enemy 2 (Mopoo)"
|
||||
Cloudy_Park_3_E3 = "Cloudy Park 3 - Enemy 3 (Poppy Bros Jr.)"
|
||||
Cloudy_Park_3_E4 = "Cloudy Park 3 - Enemy 4 (Como)"
|
||||
Cloudy_Park_3_E5 = "Cloudy Park 3 - Enemy 5 (Glunk)"
|
||||
Cloudy_Park_3_E6 = "Cloudy Park 3 - Enemy 6 (Bobin)"
|
||||
Cloudy_Park_3_E7 = "Cloudy Park 3 - Enemy 7 (Loud)"
|
||||
Cloudy_Park_3_E8 = "Cloudy Park 3 - Enemy 8 (Kapar)"
|
||||
Cloudy_Park_3_E9 = "Cloudy Park 3 - Enemy 9 (Galbo)"
|
||||
Cloudy_Park_3_E10 = "Cloudy Park 3 - Enemy 10 (Batamon)"
|
||||
Cloudy_Park_3_E11 = "Cloudy Park 3 - Enemy 11 (Bouncy)"
|
||||
Cloudy_Park_4_E1 = "Cloudy Park 4 - Enemy 1 (Gabon)"
|
||||
Cloudy_Park_4_E2 = "Cloudy Park 4 - Enemy 2 (Como)"
|
||||
Cloudy_Park_4_E3 = "Cloudy Park 4 - Enemy 3 (Wapod)"
|
||||
Cloudy_Park_4_E4 = "Cloudy Park 4 - Enemy 4 (Cappy)"
|
||||
Cloudy_Park_4_E5 = "Cloudy Park 4 - Enemy 5 (Sparky)"
|
||||
Cloudy_Park_4_E6 = "Cloudy Park 4 - Enemy 6 (Togezo)"
|
||||
Cloudy_Park_4_E7 = "Cloudy Park 4 - Enemy 7 (Bronto Burt)"
|
||||
Cloudy_Park_4_E8 = "Cloudy Park 4 - Enemy 8 (KeKe)"
|
||||
Cloudy_Park_4_E9 = "Cloudy Park 4 - Enemy 9 (Bouncy)"
|
||||
Cloudy_Park_4_E10 = "Cloudy Park 4 - Enemy 10 (Sir Kibble)"
|
||||
Cloudy_Park_4_E11 = "Cloudy Park 4 - Enemy 11 (Mariel)"
|
||||
Cloudy_Park_4_E12 = "Cloudy Park 4 - Enemy 12 (Kabu)"
|
||||
Cloudy_Park_4_E13 = "Cloudy Park 4 - Enemy 13 (Wappa)"
|
||||
Cloudy_Park_5_E1 = "Cloudy Park 5 - Enemy 1 (Yaban)"
|
||||
Cloudy_Park_5_E2 = "Cloudy Park 5 - Enemy 2 (Sir Kibble)"
|
||||
Cloudy_Park_5_E3 = "Cloudy Park 5 - Enemy 3 (Cappy)"
|
||||
Cloudy_Park_5_E4 = "Cloudy Park 5 - Enemy 4 (Wappa)"
|
||||
Cloudy_Park_5_E5 = "Cloudy Park 5 - Enemy 5 (Galbo)"
|
||||
Cloudy_Park_5_E6 = "Cloudy Park 5 - Enemy 6 (Bronto Burt)"
|
||||
Cloudy_Park_5_E7 = "Cloudy Park 5 - Enemy 7 (KeKe)"
|
||||
Cloudy_Park_5_E8 = "Cloudy Park 5 - Enemy 8 (Propeller)"
|
||||
Cloudy_Park_5_E9 = "Cloudy Park 5 - Enemy 9 (Klinko)"
|
||||
Cloudy_Park_5_E10 = "Cloudy Park 5 - Enemy 10 (Wapod)"
|
||||
Cloudy_Park_5_E11 = "Cloudy Park 5 - Enemy 11 (Pteran)"
|
||||
Cloudy_Park_6_E1 = "Cloudy Park 6 - Enemy 1 (Madoo)"
|
||||
Cloudy_Park_6_E2 = "Cloudy Park 6 - Enemy 2 (Tick)"
|
||||
Cloudy_Park_6_E3 = "Cloudy Park 6 - Enemy 3 (Como)"
|
||||
Cloudy_Park_6_E4 = "Cloudy Park 6 - Enemy 4 (Waddle Dee Drawing)"
|
||||
Cloudy_Park_6_E5 = "Cloudy Park 6 - Enemy 5 (Bronto Burt Drawing)"
|
||||
Cloudy_Park_6_E6 = "Cloudy Park 6 - Enemy 6 (Bouncy Drawing)"
|
||||
Cloudy_Park_6_E7 = "Cloudy Park 6 - Enemy 7 (Propeller)"
|
||||
Cloudy_Park_6_E8 = "Cloudy Park 6 - Enemy 8 (Mopoo)"
|
||||
Cloudy_Park_6_E9 = "Cloudy Park 6 - Enemy 9 (Bukiset (Burning))"
|
||||
Cloudy_Park_6_E10 = "Cloudy Park 6 - Enemy 10 (Bukiset (Ice))"
|
||||
Cloudy_Park_6_E11 = "Cloudy Park 6 - Enemy 11 (Bukiset (Needle))"
|
||||
Cloudy_Park_6_E12 = "Cloudy Park 6 - Enemy 12 (Bukiset (Clean))"
|
||||
Cloudy_Park_6_E13 = "Cloudy Park 6 - Enemy 13 (Bukiset (Cutter))"
|
||||
Iceberg_1_E1 = "Iceberg 1 - Enemy 1 (Waddle Dee)"
|
||||
Iceberg_1_E2 = "Iceberg 1 - Enemy 2 (Klinko)"
|
||||
Iceberg_1_E3 = "Iceberg 1 - Enemy 3 (KeKe)"
|
||||
Iceberg_1_E4 = "Iceberg 1 - Enemy 4 (Como)"
|
||||
Iceberg_1_E5 = "Iceberg 1 - Enemy 5 (Galbo)"
|
||||
Iceberg_1_E6 = "Iceberg 1 - Enemy 6 (Rocky)"
|
||||
Iceberg_1_E7 = "Iceberg 1 - Enemy 7 (Kapar)"
|
||||
Iceberg_1_E8 = "Iceberg 1 - Enemy 8 (Mopoo)"
|
||||
Iceberg_1_E9 = "Iceberg 1 - Enemy 9 (Babut)"
|
||||
Iceberg_1_E10 = "Iceberg 1 - Enemy 10 (Wappa)"
|
||||
Iceberg_1_E11 = "Iceberg 1 - Enemy 11 (Bronto Burt)"
|
||||
Iceberg_1_E12 = "Iceberg 1 - Enemy 12 (Chilly)"
|
||||
Iceberg_1_E13 = "Iceberg 1 - Enemy 13 (Poppy Bros Jr.)"
|
||||
Iceberg_2_E1 = "Iceberg 2 - Enemy 1 (Gabon)"
|
||||
Iceberg_2_E2 = "Iceberg 2 - Enemy 2 (Nruff)"
|
||||
Iceberg_2_E3 = "Iceberg 2 - Enemy 3 (Waddle Dee)"
|
||||
Iceberg_2_E4 = "Iceberg 2 - Enemy 4 (Chilly)"
|
||||
Iceberg_2_E5 = "Iceberg 2 - Enemy 5 (Pteran)"
|
||||
Iceberg_2_E6 = "Iceberg 2 - Enemy 6 (Glunk)"
|
||||
Iceberg_2_E7 = "Iceberg 2 - Enemy 7 (Galbo)"
|
||||
Iceberg_2_E8 = "Iceberg 2 - Enemy 8 (Babut)"
|
||||
Iceberg_2_E9 = "Iceberg 2 - Enemy 9 (Magoo)"
|
||||
Iceberg_2_E10 = "Iceberg 2 - Enemy 10 (Propeller)"
|
||||
Iceberg_2_E11 = "Iceberg 2 - Enemy 11 (Nidoo)"
|
||||
Iceberg_2_E12 = "Iceberg 2 - Enemy 12 (Oro)"
|
||||
Iceberg_2_E13 = "Iceberg 2 - Enemy 13 (Klinko)"
|
||||
Iceberg_2_E14 = "Iceberg 2 - Enemy 14 (Bronto Burt)"
|
||||
Iceberg_3_E1 = "Iceberg 3 - Enemy 1 (Corori)"
|
||||
Iceberg_3_E2 = "Iceberg 3 - Enemy 2 (Bouncy)"
|
||||
Iceberg_3_E3 = "Iceberg 3 - Enemy 3 (Chilly)"
|
||||
Iceberg_3_E4 = "Iceberg 3 - Enemy 4 (Pteran)"
|
||||
Iceberg_3_E5 = "Iceberg 3 - Enemy 5 (Raft Waddle Dee)"
|
||||
Iceberg_3_E6 = "Iceberg 3 - Enemy 6 (Kapar)"
|
||||
Iceberg_3_E7 = "Iceberg 3 - Enemy 7 (Blipper)"
|
||||
Iceberg_3_E8 = "Iceberg 3 - Enemy 8 (Wapod)"
|
||||
Iceberg_3_E9 = "Iceberg 3 - Enemy 9 (Glunk)"
|
||||
Iceberg_3_E10 = "Iceberg 3 - Enemy 10 (Icicle)"
|
||||
Iceberg_4_E1 = "Iceberg 4 - Enemy 1 (Bronto Burt)"
|
||||
Iceberg_4_E2 = "Iceberg 4 - Enemy 2 (Galbo)"
|
||||
Iceberg_4_E3 = "Iceberg 4 - Enemy 3 (Klinko)"
|
||||
Iceberg_4_E4 = "Iceberg 4 - Enemy 4 (Chilly)"
|
||||
Iceberg_4_E5 = "Iceberg 4 - Enemy 5 (Babut)"
|
||||
Iceberg_4_E6 = "Iceberg 4 - Enemy 6 (Wappa)"
|
||||
Iceberg_4_E7 = "Iceberg 4 - Enemy 7 (Icicle)"
|
||||
Iceberg_4_E8 = "Iceberg 4 - Enemy 8 (Corori)"
|
||||
Iceberg_4_E9 = "Iceberg 4 - Enemy 9 (Gabon)"
|
||||
Iceberg_4_E10 = "Iceberg 4 - Enemy 10 (Kabu)"
|
||||
Iceberg_4_E11 = "Iceberg 4 - Enemy 11 (Broom Hatter)"
|
||||
Iceberg_4_E12 = "Iceberg 4 - Enemy 12 (Sasuke)"
|
||||
Iceberg_4_E13 = "Iceberg 4 - Enemy 13 (Nruff)"
|
||||
Iceberg_5_E1 = "Iceberg 5 - Enemy 1 (Bukiset (Burning))"
|
||||
Iceberg_5_E2 = "Iceberg 5 - Enemy 2 (Bukiset (Stone))"
|
||||
Iceberg_5_E3 = "Iceberg 5 - Enemy 3 (Bukiset (Ice))"
|
||||
Iceberg_5_E4 = "Iceberg 5 - Enemy 4 (Bukiset (Needle))"
|
||||
Iceberg_5_E5 = "Iceberg 5 - Enemy 5 (Bukiset (Clean))"
|
||||
Iceberg_5_E6 = "Iceberg 5 - Enemy 6 (Bukiset (Parasol))"
|
||||
Iceberg_5_E7 = "Iceberg 5 - Enemy 7 (Bukiset (Spark))"
|
||||
Iceberg_5_E8 = "Iceberg 5 - Enemy 8 (Bukiset (Cutter))"
|
||||
Iceberg_5_E9 = "Iceberg 5 - Enemy 9 (Glunk)"
|
||||
Iceberg_5_E10 = "Iceberg 5 - Enemy 10 (Wapod)"
|
||||
Iceberg_5_E11 = "Iceberg 5 - Enemy 11 (Tick)"
|
||||
Iceberg_5_E12 = "Iceberg 5 - Enemy 12 (Madoo)"
|
||||
Iceberg_5_E13 = "Iceberg 5 - Enemy 13 (Yaban)"
|
||||
Iceberg_5_E14 = "Iceberg 5 - Enemy 14 (Propeller)"
|
||||
Iceberg_5_E15 = "Iceberg 5 - Enemy 15 (Mariel)"
|
||||
Iceberg_5_E16 = "Iceberg 5 - Enemy 16 (Pteran)"
|
||||
Iceberg_5_E17 = "Iceberg 5 - Enemy 17 (Galbo)"
|
||||
Iceberg_5_E18 = "Iceberg 5 - Enemy 18 (KeKe)"
|
||||
Iceberg_5_E19 = "Iceberg 5 - Enemy 19 (Nidoo)"
|
||||
Iceberg_5_E20 = "Iceberg 5 - Enemy 20 (Waddle Dee Drawing)"
|
||||
Iceberg_5_E21 = "Iceberg 5 - Enemy 21 (Bronto Burt Drawing)"
|
||||
Iceberg_5_E22 = "Iceberg 5 - Enemy 22 (Bouncy Drawing)"
|
||||
Iceberg_5_E23 = "Iceberg 5 - Enemy 23 (Joe)"
|
||||
Iceberg_5_E24 = "Iceberg 5 - Enemy 24 (Kapar)"
|
||||
Iceberg_5_E25 = "Iceberg 5 - Enemy 25 (Gansan)"
|
||||
Iceberg_5_E26 = "Iceberg 5 - Enemy 26 (Sasuke)"
|
||||
Iceberg_5_E27 = "Iceberg 5 - Enemy 27 (Togezo)"
|
||||
Iceberg_5_E28 = "Iceberg 5 - Enemy 28 (Sparky)"
|
||||
Iceberg_5_E29 = "Iceberg 5 - Enemy 29 (Bobin)"
|
||||
Iceberg_5_E30 = "Iceberg 5 - Enemy 30 (Chilly)"
|
||||
Iceberg_5_E31 = "Iceberg 5 - Enemy 31 (Peran)"
|
||||
Iceberg_6_E1 = "Iceberg 6 - Enemy 1 (Nruff)"
|
||||
Iceberg_6_E2 = "Iceberg 6 - Enemy 2 (Nidoo)"
|
||||
Iceberg_6_E3 = "Iceberg 6 - Enemy 3 (Sparky)"
|
||||
Iceberg_6_E4 = "Iceberg 6 - Enemy 4 (Sir Kibble)"
|
||||
Grass_Land_4_M1 = "Grass Land 4 - Miniboss 1 (Boboo)"
|
||||
Ripple_Field_4_M1 = "Ripple Field 4 - Miniboss 1 (Captain Stitch)"
|
||||
Sand_Canyon_4_M1 = "Sand Canyon 4 - Miniboss 1 (Haboki)"
|
||||
Cloudy_Park_4_M1 = "Cloudy Park 4 - Miniboss 1 (Jumper Shoot)"
|
||||
Iceberg_4_M1 = "Iceberg 4 - Miniboss 1 (Yuki)"
|
||||
Iceberg_6_M1 = "Iceberg 6 - Miniboss 1 (Blocky)"
|
||||
Iceberg_6_M2 = "Iceberg 6 - Miniboss 2 (Jumper Shoot)"
|
||||
Iceberg_6_M3 = "Iceberg 6 - Miniboss 3 (Yuki)"
|
||||
Iceberg_6_M4 = "Iceberg 6 - Miniboss 4 (Haboki)"
|
||||
Iceberg_6_M5 = "Iceberg 6 - Miniboss 5 (Boboo)"
|
||||
Iceberg_6_M6 = "Iceberg 6 - Miniboss 6 (Captain Stitch)"
|
||||
|
||||
|
||||
enemy_mapping = {
|
||||
Grass_Land_1_E1: "Waddle Dee",
|
||||
Grass_Land_1_E2: "Sir Kibble",
|
||||
Grass_Land_1_E3: "Cappy",
|
||||
Grass_Land_1_E4: "Sparky",
|
||||
Grass_Land_1_E5: "Bronto Burt",
|
||||
Grass_Land_1_E6: "Sasuke",
|
||||
Grass_Land_1_E7: "Poppy Bros Jr.",
|
||||
Grass_Land_2_E1: "Rocky",
|
||||
Grass_Land_2_E2: "KeKe",
|
||||
Grass_Land_2_E3: "Bobo",
|
||||
Grass_Land_2_E4: "Poppy Bros Jr.",
|
||||
Grass_Land_2_E5: "Waddle Dee",
|
||||
Grass_Land_2_E6: "Popon Ball",
|
||||
Grass_Land_2_E7: "Bouncy",
|
||||
Grass_Land_2_E8: "Tick",
|
||||
Grass_Land_2_E9: "Bronto Burt",
|
||||
Grass_Land_2_E10: "Nruff",
|
||||
Grass_Land_3_E1: "Sparky",
|
||||
Grass_Land_3_E2: "Rocky",
|
||||
Grass_Land_3_E3: "Nruff",
|
||||
Grass_Land_3_E4: "Bouncy",
|
||||
Grass_Land_4_E1: "Loud",
|
||||
Grass_Land_4_E2: "Babut",
|
||||
Grass_Land_4_E3: "Rocky",
|
||||
Grass_Land_4_E4: "Kapar",
|
||||
Grass_Land_4_E5: "Glunk",
|
||||
Grass_Land_4_E6: "Oro",
|
||||
Grass_Land_4_E7: "Peran",
|
||||
Grass_Land_5_E1: "Propeller",
|
||||
Grass_Land_5_E2: "Broom Hatter",
|
||||
Grass_Land_5_E3: "Bouncy",
|
||||
Grass_Land_5_E4: "Sir Kibble",
|
||||
Grass_Land_5_E5: "Waddle Dee",
|
||||
Grass_Land_5_E6: "Sasuke",
|
||||
Grass_Land_5_E7: "Nruff",
|
||||
Grass_Land_5_E8: "Tick",
|
||||
Grass_Land_6_E1: "Como",
|
||||
Grass_Land_6_E2: "Togezo",
|
||||
Grass_Land_6_E3: "Bronto Burt",
|
||||
Grass_Land_6_E4: "Cappy",
|
||||
Grass_Land_6_E5: "Bobo",
|
||||
Grass_Land_6_E6: "Mariel",
|
||||
Grass_Land_6_E7: "Yaban",
|
||||
Grass_Land_6_E8: "Broom Hatter",
|
||||
Grass_Land_6_E9: "Apolo",
|
||||
Grass_Land_6_E10: "Sasuke",
|
||||
Grass_Land_6_E11: "Rocky",
|
||||
Ripple_Field_1_E1: "Waddle Dee",
|
||||
Ripple_Field_1_E2: "Glunk",
|
||||
Ripple_Field_1_E3: "Broom Hatter",
|
||||
Ripple_Field_1_E4: "Cappy",
|
||||
Ripple_Field_1_E5: "Bronto Burt",
|
||||
Ripple_Field_1_E6: "Rocky",
|
||||
Ripple_Field_1_E7: "Poppy Bros Jr.",
|
||||
Ripple_Field_1_E8: "Bobin",
|
||||
Ripple_Field_2_E1: "Togezo",
|
||||
Ripple_Field_2_E2: "Coconut",
|
||||
Ripple_Field_2_E3: "Blipper",
|
||||
Ripple_Field_2_E4: "Sasuke",
|
||||
Ripple_Field_2_E5: "Kany",
|
||||
Ripple_Field_2_E6: "Glunk",
|
||||
Ripple_Field_3_E1: "Raft Waddle Dee",
|
||||
Ripple_Field_3_E2: "Kapar",
|
||||
Ripple_Field_3_E3: "Blipper",
|
||||
Ripple_Field_3_E4: "Sparky",
|
||||
Ripple_Field_3_E5: "Glunk",
|
||||
Ripple_Field_3_E6: "Joe",
|
||||
Ripple_Field_3_E7: "Bobo",
|
||||
Ripple_Field_4_E1: "Bukiset (Stone)",
|
||||
Ripple_Field_4_E2: "Bukiset (Needle)",
|
||||
Ripple_Field_4_E3: "Bukiset (Clean)",
|
||||
Ripple_Field_4_E4: "Bukiset (Parasol)",
|
||||
Ripple_Field_4_E5: "Mony",
|
||||
Ripple_Field_4_E6: "Bukiset (Burning)",
|
||||
Ripple_Field_4_E7: "Bobin",
|
||||
Ripple_Field_4_E8: "Blipper",
|
||||
Ripple_Field_4_E9: "Como",
|
||||
Ripple_Field_4_E10: "Oro",
|
||||
Ripple_Field_4_E11: "Gansan",
|
||||
Ripple_Field_4_E12: "Waddle Dee",
|
||||
Ripple_Field_4_E13: "Kapar",
|
||||
Ripple_Field_4_E14: "Squishy",
|
||||
Ripple_Field_4_E15: "Nidoo",
|
||||
Ripple_Field_5_E1: "Glunk",
|
||||
Ripple_Field_5_E2: "Joe",
|
||||
Ripple_Field_5_E3: "Bobin",
|
||||
Ripple_Field_5_E4: "Mony",
|
||||
Ripple_Field_5_E5: "Squishy",
|
||||
Ripple_Field_5_E6: "Yaban",
|
||||
Ripple_Field_5_E7: "Broom Hatter",
|
||||
Ripple_Field_5_E8: "Bouncy",
|
||||
Ripple_Field_5_E9: "Sparky",
|
||||
Ripple_Field_5_E10: "Rocky",
|
||||
Ripple_Field_5_E11: "Babut",
|
||||
Ripple_Field_5_E12: "Galbo",
|
||||
Ripple_Field_6_E1: "Kany",
|
||||
Ripple_Field_6_E2: "KeKe",
|
||||
Ripple_Field_6_E3: "Kapar",
|
||||
Ripple_Field_6_E4: "Rocky",
|
||||
Ripple_Field_6_E5: "Poppy Bros Jr.",
|
||||
Ripple_Field_6_E6: "Propeller",
|
||||
Ripple_Field_6_E7: "Coconut",
|
||||
Ripple_Field_6_E8: "Sasuke",
|
||||
Ripple_Field_6_E9: "Nruff",
|
||||
Sand_Canyon_1_E1: "Bronto Burt",
|
||||
Sand_Canyon_1_E2: "Galbo",
|
||||
Sand_Canyon_1_E3: "Oro",
|
||||
Sand_Canyon_1_E4: "Sparky",
|
||||
Sand_Canyon_1_E5: "Propeller",
|
||||
Sand_Canyon_1_E6: "Gansan",
|
||||
Sand_Canyon_1_E7: "Babut",
|
||||
Sand_Canyon_1_E8: "Loud",
|
||||
Sand_Canyon_1_E9: "Dogon",
|
||||
Sand_Canyon_1_E10: "Bouncy",
|
||||
Sand_Canyon_1_E11: "Pteran",
|
||||
Sand_Canyon_1_E12: "Polof",
|
||||
Sand_Canyon_2_E1: "KeKe",
|
||||
Sand_Canyon_2_E2: "Doka",
|
||||
Sand_Canyon_2_E3: "Boten",
|
||||
Sand_Canyon_2_E4: "Propeller",
|
||||
Sand_Canyon_2_E5: "Waddle Dee",
|
||||
Sand_Canyon_2_E6: "Sparky",
|
||||
Sand_Canyon_2_E7: "Sasuke",
|
||||
Sand_Canyon_2_E8: "Como",
|
||||
Sand_Canyon_2_E9: "Bukiset (Ice)",
|
||||
Sand_Canyon_2_E10: "Bukiset (Needle)",
|
||||
Sand_Canyon_2_E11: "Bukiset (Clean)",
|
||||
Sand_Canyon_2_E12: "Bukiset (Parasol)",
|
||||
Sand_Canyon_2_E13: "Bukiset (Spark)",
|
||||
Sand_Canyon_2_E14: "Bukiset (Cutter)",
|
||||
Sand_Canyon_2_E15: "Nidoo",
|
||||
Sand_Canyon_2_E16: "Mariel",
|
||||
Sand_Canyon_2_E17: "Yaban",
|
||||
Sand_Canyon_2_E18: "Wapod",
|
||||
Sand_Canyon_2_E19: "Squishy",
|
||||
Sand_Canyon_2_E20: "Pteran",
|
||||
Sand_Canyon_3_E1: "Sir Kibble",
|
||||
Sand_Canyon_3_E2: "Broom Hatter",
|
||||
Sand_Canyon_3_E3: "Rocky",
|
||||
Sand_Canyon_3_E4: "Gabon",
|
||||
Sand_Canyon_3_E5: "Kany",
|
||||
Sand_Canyon_3_E6: "Galbo",
|
||||
Sand_Canyon_3_E7: "Propeller",
|
||||
Sand_Canyon_3_E8: "Sasuke",
|
||||
Sand_Canyon_3_E9: "Wapod",
|
||||
Sand_Canyon_3_E10: "Bobo",
|
||||
Sand_Canyon_3_E11: "Babut",
|
||||
Sand_Canyon_3_E12: "Magoo",
|
||||
Sand_Canyon_4_E1: "Popon Ball",
|
||||
Sand_Canyon_4_E2: "Mariel",
|
||||
Sand_Canyon_4_E3: "Chilly",
|
||||
Sand_Canyon_4_E4: "Tick",
|
||||
Sand_Canyon_4_E5: "Bronto Burt",
|
||||
Sand_Canyon_4_E6: "Babut",
|
||||
Sand_Canyon_4_E7: "Bobin",
|
||||
Sand_Canyon_4_E8: "Joe",
|
||||
Sand_Canyon_4_E9: "Mony",
|
||||
Sand_Canyon_4_E10: "Blipper",
|
||||
Sand_Canyon_4_E11: "Togezo",
|
||||
Sand_Canyon_4_E12: "Rocky",
|
||||
Sand_Canyon_4_E13: "Bobo",
|
||||
Sand_Canyon_5_E1: "Wapod",
|
||||
Sand_Canyon_5_E2: "Dogon",
|
||||
Sand_Canyon_5_E3: "Tick",
|
||||
Sand_Canyon_5_E4: "Rocky",
|
||||
Sand_Canyon_5_E5: "Bobo",
|
||||
Sand_Canyon_5_E6: "Chilly",
|
||||
Sand_Canyon_5_E7: "Sparky",
|
||||
Sand_Canyon_5_E8: "Togezo",
|
||||
Sand_Canyon_5_E9: "Bronto Burt",
|
||||
Sand_Canyon_5_E10: "Sasuke",
|
||||
Sand_Canyon_5_E11: "Oro",
|
||||
Sand_Canyon_5_E12: "Galbo",
|
||||
Sand_Canyon_5_E13: "Nidoo",
|
||||
Sand_Canyon_5_E14: "Propeller",
|
||||
Sand_Canyon_5_E15: "Sir Kibble",
|
||||
Sand_Canyon_5_E16: "KeKe",
|
||||
Sand_Canyon_5_E17: "Kabu",
|
||||
Sand_Canyon_6_E1: "Sparky",
|
||||
Sand_Canyon_6_E2: "Doka",
|
||||
Sand_Canyon_6_E3: "Cappy",
|
||||
Sand_Canyon_6_E4: "Pteran",
|
||||
Sand_Canyon_6_E5: "Bukiset (Parasol)",
|
||||
Sand_Canyon_6_E6: "Bukiset (Cutter)",
|
||||
Sand_Canyon_6_E7: "Bukiset (Clean)",
|
||||
Sand_Canyon_6_E8: "Bukiset (Spark)",
|
||||
Sand_Canyon_6_E9: "Bukiset (Ice)",
|
||||
Sand_Canyon_6_E10: "Bukiset (Needle)",
|
||||
Sand_Canyon_6_E11: "Bukiset (Burning)",
|
||||
Sand_Canyon_6_E12: "Bukiset (Stone)",
|
||||
Sand_Canyon_6_E13: "Nidoo",
|
||||
Cloudy_Park_1_E1: "Waddle Dee",
|
||||
Cloudy_Park_1_E2: "KeKe",
|
||||
Cloudy_Park_1_E3: "Cappy",
|
||||
Cloudy_Park_1_E4: "Yaban",
|
||||
Cloudy_Park_1_E5: "Togezo",
|
||||
Cloudy_Park_1_E6: "Galbo",
|
||||
Cloudy_Park_1_E7: "Sparky",
|
||||
Cloudy_Park_1_E8: "Como",
|
||||
Cloudy_Park_1_E9: "Bronto Burt",
|
||||
Cloudy_Park_1_E10: "Gabon",
|
||||
Cloudy_Park_1_E11: "Sir Kibble",
|
||||
Cloudy_Park_1_E12: "Mariel",
|
||||
Cloudy_Park_1_E13: "Nruff",
|
||||
Cloudy_Park_2_E1: "Chilly",
|
||||
Cloudy_Park_2_E2: "Sasuke",
|
||||
Cloudy_Park_2_E3: "Waddle Dee",
|
||||
Cloudy_Park_2_E4: "Sparky",
|
||||
Cloudy_Park_2_E5: "Broom Hatter",
|
||||
Cloudy_Park_2_E6: "Sir Kibble",
|
||||
Cloudy_Park_2_E7: "Pteran",
|
||||
Cloudy_Park_2_E8: "Propeller",
|
||||
Cloudy_Park_2_E9: "Dogon",
|
||||
Cloudy_Park_2_E10: "Togezo",
|
||||
Cloudy_Park_2_E11: "Oro",
|
||||
Cloudy_Park_2_E12: "Bronto Burt",
|
||||
Cloudy_Park_2_E13: "Rocky",
|
||||
Cloudy_Park_2_E14: "Galbo",
|
||||
Cloudy_Park_2_E15: "Kapar",
|
||||
Cloudy_Park_3_E1: "Bronto Burt",
|
||||
Cloudy_Park_3_E2: "Mopoo",
|
||||
Cloudy_Park_3_E3: "Poppy Bros Jr.",
|
||||
Cloudy_Park_3_E4: "Como",
|
||||
Cloudy_Park_3_E5: "Glunk",
|
||||
Cloudy_Park_3_E6: "Bobin",
|
||||
Cloudy_Park_3_E7: "Loud",
|
||||
Cloudy_Park_3_E8: "Kapar",
|
||||
Cloudy_Park_3_E9: "Galbo",
|
||||
Cloudy_Park_3_E10: "Batamon",
|
||||
Cloudy_Park_3_E11: "Bouncy",
|
||||
Cloudy_Park_4_E1: "Gabon",
|
||||
Cloudy_Park_4_E2: "Como",
|
||||
Cloudy_Park_4_E3: "Wapod",
|
||||
Cloudy_Park_4_E4: "Cappy",
|
||||
Cloudy_Park_4_E5: "Sparky",
|
||||
Cloudy_Park_4_E6: "Togezo",
|
||||
Cloudy_Park_4_E7: "Bronto Burt",
|
||||
Cloudy_Park_4_E8: "KeKe",
|
||||
Cloudy_Park_4_E9: "Bouncy",
|
||||
Cloudy_Park_4_E10: "Sir Kibble",
|
||||
Cloudy_Park_4_E11: "Mariel",
|
||||
Cloudy_Park_4_E12: "Kabu",
|
||||
Cloudy_Park_4_E13: "Wappa",
|
||||
Cloudy_Park_5_E1: "Yaban",
|
||||
Cloudy_Park_5_E2: "Sir Kibble",
|
||||
Cloudy_Park_5_E3: "Cappy",
|
||||
Cloudy_Park_5_E4: "Wappa",
|
||||
Cloudy_Park_5_E5: "Galbo",
|
||||
Cloudy_Park_5_E6: "Bronto Burt",
|
||||
Cloudy_Park_5_E7: "KeKe",
|
||||
Cloudy_Park_5_E8: "Propeller",
|
||||
Cloudy_Park_5_E9: "Klinko",
|
||||
Cloudy_Park_5_E10: "Wapod",
|
||||
Cloudy_Park_5_E11: "Pteran",
|
||||
Cloudy_Park_6_E1: "Madoo",
|
||||
Cloudy_Park_6_E2: "Tick",
|
||||
Cloudy_Park_6_E3: "Como",
|
||||
Cloudy_Park_6_E4: "Waddle Dee Drawing",
|
||||
Cloudy_Park_6_E5: "Bronto Burt Drawing",
|
||||
Cloudy_Park_6_E6: "Bouncy Drawing",
|
||||
Cloudy_Park_6_E7: "Propeller",
|
||||
Cloudy_Park_6_E8: "Mopoo",
|
||||
Cloudy_Park_6_E9: "Bukiset (Burning)",
|
||||
Cloudy_Park_6_E10: "Bukiset (Ice)",
|
||||
Cloudy_Park_6_E11: "Bukiset (Needle)",
|
||||
Cloudy_Park_6_E12: "Bukiset (Clean)",
|
||||
Cloudy_Park_6_E13: "Bukiset (Cutter)",
|
||||
Iceberg_1_E1: "Waddle Dee",
|
||||
Iceberg_1_E2: "Klinko",
|
||||
Iceberg_1_E3: "KeKe",
|
||||
Iceberg_1_E4: "Como",
|
||||
Iceberg_1_E5: "Galbo",
|
||||
Iceberg_1_E6: "Rocky",
|
||||
Iceberg_1_E7: "Kapar",
|
||||
Iceberg_1_E8: "Mopoo",
|
||||
Iceberg_1_E9: "Babut",
|
||||
Iceberg_1_E10: "Wappa",
|
||||
Iceberg_1_E11: "Bronto Burt",
|
||||
Iceberg_1_E12: "Chilly",
|
||||
Iceberg_1_E13: "Poppy Bros Jr.",
|
||||
Iceberg_2_E1: "Gabon",
|
||||
Iceberg_2_E2: "Nruff",
|
||||
Iceberg_2_E3: "Waddle Dee",
|
||||
Iceberg_2_E4: "Chilly",
|
||||
Iceberg_2_E5: "Pteran",
|
||||
Iceberg_2_E6: "Glunk",
|
||||
Iceberg_2_E7: "Galbo",
|
||||
Iceberg_2_E8: "Babut",
|
||||
Iceberg_2_E9: "Magoo",
|
||||
Iceberg_2_E10: "Propeller",
|
||||
Iceberg_2_E11: "Nidoo",
|
||||
Iceberg_2_E12: "Oro",
|
||||
Iceberg_2_E13: "Klinko",
|
||||
Iceberg_2_E14: "Bronto Burt",
|
||||
Iceberg_3_E1: "Corori",
|
||||
Iceberg_3_E2: "Bouncy",
|
||||
Iceberg_3_E3: "Chilly",
|
||||
Iceberg_3_E4: "Pteran",
|
||||
Iceberg_3_E5: "Raft Waddle Dee",
|
||||
Iceberg_3_E6: "Kapar",
|
||||
Iceberg_3_E7: "Blipper",
|
||||
Iceberg_3_E8: "Wapod",
|
||||
Iceberg_3_E9: "Glunk",
|
||||
Iceberg_3_E10: "Icicle",
|
||||
Iceberg_4_E1: "Bronto Burt",
|
||||
Iceberg_4_E2: "Galbo",
|
||||
Iceberg_4_E3: "Klinko",
|
||||
Iceberg_4_E4: "Chilly",
|
||||
Iceberg_4_E5: "Babut",
|
||||
Iceberg_4_E6: "Wappa",
|
||||
Iceberg_4_E7: "Icicle",
|
||||
Iceberg_4_E8: "Corori",
|
||||
Iceberg_4_E9: "Gabon",
|
||||
Iceberg_4_E10: "Kabu",
|
||||
Iceberg_4_E11: "Broom Hatter",
|
||||
Iceberg_4_E12: "Sasuke",
|
||||
Iceberg_4_E13: "Nruff",
|
||||
Iceberg_5_E1: "Bukiset (Burning)",
|
||||
Iceberg_5_E2: "Bukiset (Stone)",
|
||||
Iceberg_5_E3: "Bukiset (Ice)",
|
||||
Iceberg_5_E4: "Bukiset (Needle)",
|
||||
Iceberg_5_E5: "Bukiset (Clean)",
|
||||
Iceberg_5_E6: "Bukiset (Parasol)",
|
||||
Iceberg_5_E7: "Bukiset (Spark)",
|
||||
Iceberg_5_E8: "Bukiset (Cutter)",
|
||||
Iceberg_5_E9: "Glunk",
|
||||
Iceberg_5_E10: "Wapod",
|
||||
Iceberg_5_E11: "Tick",
|
||||
Iceberg_5_E12: "Madoo",
|
||||
Iceberg_5_E13: "Yaban",
|
||||
Iceberg_5_E14: "Propeller",
|
||||
Iceberg_5_E15: "Mariel",
|
||||
Iceberg_5_E16: "Pteran",
|
||||
Iceberg_5_E17: "Galbo",
|
||||
Iceberg_5_E18: "KeKe",
|
||||
Iceberg_5_E19: "Nidoo",
|
||||
Iceberg_5_E20: "Waddle Dee Drawing",
|
||||
Iceberg_5_E21: "Bronto Burt Drawing",
|
||||
Iceberg_5_E22: "Bouncy Drawing",
|
||||
Iceberg_5_E23: "Joe",
|
||||
Iceberg_5_E24: "Kapar",
|
||||
Iceberg_5_E25: "Gansan",
|
||||
Iceberg_5_E26: "Sasuke",
|
||||
Iceberg_5_E27: "Togezo",
|
||||
Iceberg_5_E28: "Sparky",
|
||||
Iceberg_5_E29: "Bobin",
|
||||
Iceberg_5_E30: "Chilly",
|
||||
Iceberg_5_E31: "Peran",
|
||||
Iceberg_6_E1: "Nruff",
|
||||
Iceberg_6_E2: "Nidoo",
|
||||
Iceberg_6_E3: "Sparky",
|
||||
Iceberg_6_E4: "Sir Kibble",
|
||||
Grass_Land_4_M1: "Boboo",
|
||||
Ripple_Field_4_M1: "Captain Stitch",
|
||||
Sand_Canyon_4_M1: "Haboki",
|
||||
Cloudy_Park_4_M1: "Jumper Shoot",
|
||||
Iceberg_4_M1: "Yuki",
|
||||
Iceberg_6_M1: "Blocky",
|
||||
Iceberg_6_M2: "Jumper Shoot",
|
||||
Iceberg_6_M3: "Yuki",
|
||||
Iceberg_6_M4: "Haboki",
|
||||
Iceberg_6_M5: "Boboo",
|
||||
Iceberg_6_M6: "Captain Stitch",
|
||||
|
||||
}
|
||||
|
||||
vanilla_enemies = {'Waddle Dee': 'No Ability',
|
||||
'Bronto Burt': 'No Ability',
|
||||
'Rocky': 'Stone Ability',
|
||||
'Bobo': 'Burning Ability',
|
||||
'Chilly': 'Ice Ability',
|
||||
'Poppy Bros Jr.': 'No Ability',
|
||||
'Sparky': 'Spark Ability',
|
||||
'Polof': 'No Ability',
|
||||
'Broom Hatter': 'Clean Ability',
|
||||
'Cappy': 'No Ability',
|
||||
'Bouncy': 'No Ability',
|
||||
'Nruff': 'No Ability',
|
||||
'Glunk': 'No Ability',
|
||||
'Togezo': 'Needle Ability',
|
||||
'Kabu': 'No Ability',
|
||||
'Mony': 'No Ability',
|
||||
'Blipper': 'No Ability',
|
||||
'Squishy': 'No Ability',
|
||||
'Gabon': 'No Ability',
|
||||
'Oro': 'No Ability',
|
||||
'Galbo': 'Burning Ability',
|
||||
'Sir Kibble': 'Cutter Ability',
|
||||
'Nidoo': 'No Ability',
|
||||
'Kany': 'No Ability',
|
||||
'Sasuke': 'Parasol Ability',
|
||||
'Yaban': 'No Ability',
|
||||
'Boten': 'Needle Ability',
|
||||
'Coconut': 'No Ability',
|
||||
'Doka': 'No Ability',
|
||||
'Icicle': 'No Ability',
|
||||
'Pteran': 'No Ability',
|
||||
'Loud': 'No Ability',
|
||||
'Como': 'No Ability',
|
||||
'Klinko': 'Parasol Ability',
|
||||
'Babut': 'No Ability',
|
||||
'Wappa': 'Ice Ability',
|
||||
'Mariel': 'No Ability',
|
||||
'Tick': 'Needle Ability',
|
||||
'Apolo': 'No Ability',
|
||||
'Popon Ball': 'No Ability',
|
||||
'KeKe': 'Clean Ability',
|
||||
'Magoo': 'Burning Ability',
|
||||
'Raft Waddle Dee': 'No Ability',
|
||||
'Madoo': 'No Ability',
|
||||
'Corori': 'No Ability',
|
||||
'Kapar': 'Cutter Ability',
|
||||
'Batamon': 'No Ability',
|
||||
'Peran': 'No Ability',
|
||||
'Bobin': 'Spark Ability',
|
||||
'Mopoo': 'No Ability',
|
||||
'Gansan': 'Stone Ability',
|
||||
'Bukiset (Burning)': 'Burning Ability',
|
||||
'Bukiset (Stone)': 'Stone Ability',
|
||||
'Bukiset (Ice)': 'Ice Ability',
|
||||
'Bukiset (Needle)': 'Needle Ability',
|
||||
'Bukiset (Clean)': 'Clean Ability',
|
||||
'Bukiset (Parasol)': 'Parasol Ability',
|
||||
'Bukiset (Spark)': 'Spark Ability',
|
||||
'Bukiset (Cutter)': 'Cutter Ability',
|
||||
'Waddle Dee Drawing': 'No Ability',
|
||||
'Bronto Burt Drawing': 'No Ability',
|
||||
'Bouncy Drawing': 'No Ability',
|
||||
'Kabu (Dekabu)': 'No Ability',
|
||||
'Wapod': 'No Ability',
|
||||
'Propeller': 'No Ability',
|
||||
'Dogon': 'No Ability',
|
||||
'Joe': 'No Ability',
|
||||
'Captain Stitch': 'Needle Ability',
|
||||
'Yuki': 'Ice Ability',
|
||||
'Blocky': 'Stone Ability',
|
||||
'Jumper Shoot': 'Parasol Ability',
|
||||
'Boboo': 'Burning Ability',
|
||||
'Haboki': 'Clean Ability',
|
||||
}
|
||||
|
||||
enemy_restrictive: List[Tuple[List[str], List[str]]] = [
|
||||
# abilities, enemies, set_all (False to set any)
|
||||
(["Burning Ability", "Stone Ability"], ["Rocky", "Sparky", "Babut", "Squishy", ]), # Ribbon Field 5 - 7
|
||||
# Sand Canyon 6
|
||||
(["Parasol Ability", "Cutter Ability"], ['Bukiset (Parasol)', 'Bukiset (Cutter)']),
|
||||
(["Spark Ability", "Clean Ability"], ['Bukiset (Spark)', 'Bukiset (Clean)']),
|
||||
(["Ice Ability", "Needle Ability"], ['Bukiset (Ice)', 'Bukiset (Needle)']),
|
||||
(["Stone Ability", "Burning Ability"], ['Bukiset (Stone)', 'Bukiset (Burning)']),
|
||||
(["Stone Ability"], ['Bukiset (Burning)', 'Bukiset (Stone)', 'Bukiset (Ice)', 'Bukiset (Needle)',
|
||||
'Bukiset (Clean)', 'Bukiset (Spark)', 'Bukiset (Parasol)', 'Bukiset (Cutter)']),
|
||||
(["Parasol Ability"], ['Bukiset (Burning)', 'Bukiset (Stone)', 'Bukiset (Ice)', 'Bukiset (Needle)',
|
||||
'Bukiset (Clean)', 'Bukiset (Spark)', 'Bukiset (Parasol)', 'Bukiset (Cutter)']),
|
||||
]
|
928
worlds/kdl3/Names/LocationName.py
Normal file
928
worlds/kdl3/Names/LocationName.py
Normal file
@@ -0,0 +1,928 @@
|
||||
# Level 1
|
||||
grass_land_1 = "Grass Land 1 - Complete"
|
||||
grass_land_2 = "Grass Land 2 - Complete"
|
||||
grass_land_3 = "Grass Land 3 - Complete"
|
||||
grass_land_4 = "Grass Land 4 - Complete"
|
||||
grass_land_5 = "Grass Land 5 - Complete"
|
||||
grass_land_6 = "Grass Land 6 - Complete"
|
||||
grass_land_tulip = "Grass Land 1 - Tulip"
|
||||
grass_land_muchi = "Grass Land 2 - Muchimuchi"
|
||||
grass_land_pitcherman = "Grass Land 3 - Pitcherman"
|
||||
grass_land_chao = "Grass Land 4 - Chao & Goku"
|
||||
grass_land_mine = "Grass Land 5 - Mine"
|
||||
grass_land_pierre = "Grass Land 6 - Pierre"
|
||||
grass_land_whispy = "Grass Land - Boss (Whispy Woods) Purified"
|
||||
|
||||
# Level 2
|
||||
ripple_field_1 = "Ripple Field 1 - Complete"
|
||||
ripple_field_2 = "Ripple Field 2 - Complete"
|
||||
ripple_field_3 = "Ripple Field 3 - Complete"
|
||||
ripple_field_4 = "Ripple Field 4 - Complete"
|
||||
ripple_field_5 = "Ripple Field 5 - Complete"
|
||||
ripple_field_6 = "Ripple Field 6 - Complete"
|
||||
ripple_field_kamuribana = "Ripple Field 1 - Kamuribana"
|
||||
ripple_field_bakasa = "Ripple Field 2 - Bakasa"
|
||||
ripple_field_elieel = "Ripple Field 3 - Elieel"
|
||||
ripple_field_toad = "Ripple Field 4 - Toad & Little Toad"
|
||||
ripple_field_mama_pitch = "Ripple Field 5 - Mama Pitch"
|
||||
ripple_field_hb002 = "Ripple Field 6 - HB-002"
|
||||
ripple_field_acro = "Ripple Field - Boss (Acro) Purified"
|
||||
|
||||
# Level 3
|
||||
sand_canyon_1 = "Sand Canyon 1 - Complete"
|
||||
sand_canyon_2 = "Sand Canyon 2 - Complete"
|
||||
sand_canyon_3 = "Sand Canyon 3 - Complete"
|
||||
sand_canyon_4 = "Sand Canyon 4 - Complete"
|
||||
sand_canyon_5 = "Sand Canyon 5 - Complete"
|
||||
sand_canyon_6 = "Sand Canyon 6 - Complete"
|
||||
sand_canyon_mushrooms = "Sand Canyon 1 - Geromuzudake"
|
||||
sand_canyon_auntie = "Sand Canyon 2 - Auntie"
|
||||
sand_canyon_caramello = "Sand Canyon 3 - Caramello"
|
||||
sand_canyon_hikari = "Sand Canyon 4 - Donbe & Hikari"
|
||||
sand_canyon_nyupun = "Sand Canyon 5 - Nyupun"
|
||||
sand_canyon_rob = "Sand Canyon 6 - Professor Hector & R.O.B"
|
||||
sand_canyon_poncon = "Sand Canyon - Boss (Pon & Con) Purified"
|
||||
|
||||
# Level 4
|
||||
cloudy_park_1 = "Cloudy Park 1 - Complete"
|
||||
cloudy_park_2 = "Cloudy Park 2 - Complete"
|
||||
cloudy_park_3 = "Cloudy Park 3 - Complete"
|
||||
cloudy_park_4 = "Cloudy Park 4 - Complete"
|
||||
cloudy_park_5 = "Cloudy Park 5 - Complete"
|
||||
cloudy_park_6 = "Cloudy Park 6 - Complete"
|
||||
cloudy_park_hibanamodoki = "Cloudy Park 1 - Hibanamodoki"
|
||||
cloudy_park_piyokeko = "Cloudy Park 2 - Piyo & Keko"
|
||||
cloudy_park_mrball = "Cloudy Park 3 - Mr. Ball"
|
||||
cloudy_park_mikarin = "Cloudy Park 4 - Mikarin & Kagami Mocchi"
|
||||
cloudy_park_pick = "Cloudy Park 5 - Pick"
|
||||
cloudy_park_hb007 = "Cloudy Park 6 - HB-007"
|
||||
cloudy_park_ado = "Cloudy Park - Boss (Ado) Purified"
|
||||
|
||||
# Level 5
|
||||
iceberg_1 = "Iceberg 1 - Complete"
|
||||
iceberg_2 = "Iceberg 2 - Complete"
|
||||
iceberg_3 = "Iceberg 3 - Complete"
|
||||
iceberg_4 = "Iceberg 4 - Complete"
|
||||
iceberg_5 = "Iceberg 5 - Complete"
|
||||
iceberg_6 = "Iceberg 6 - Complete"
|
||||
iceberg_kogoesou = "Iceberg 1 - Kogoesou"
|
||||
iceberg_samus = "Iceberg 2 - Samus"
|
||||
iceberg_kawasaki = "Iceberg 3 - Chef Kawasaki"
|
||||
iceberg_name = "Iceberg 4 - Name"
|
||||
iceberg_shiro = "Iceberg 5 - Shiro"
|
||||
iceberg_angel = "Iceberg 6 - Angel"
|
||||
iceberg_dedede = "Iceberg - Boss (Dedede) Purified"
|
||||
|
||||
# Level 6
|
||||
hyper_zone = "Hyper Zone - Zero"
|
||||
|
||||
# Extras
|
||||
boss_butch = "Boss Butch"
|
||||
mg5_p = "Minigame 5 - Perfect"
|
||||
jumping_clear = "Jumping - Target Score Reached"
|
||||
|
||||
# 1-Ups
|
||||
grass_land_1_u1 = "Grass Land 1 - 1-Up (Parasol)" # Parasol
|
||||
grass_land_2_u1 = "Grass Land 2 - 1-Up (Needle)" # Needle
|
||||
grass_land_3_u1 = "Grass Land 3 - 1-Up (Climb)" # None
|
||||
grass_land_4_u1 = "Grass Land 4 - 1-Up (Gordo)" # None
|
||||
grass_land_6_u1 = "Grass Land 6 - 1-Up (Tower)" # None
|
||||
grass_land_6_u2 = "Grass Land 6 - 1-Up (Falling)" # None
|
||||
ripple_field_2_u1 = "Ripple Field 2 - 1-Up (Currents)" # Kine
|
||||
ripple_field_3_u1 = "Ripple Field 3 - 1-Up (Cutter/Spark)" # Cutter or Spark
|
||||
ripple_field_4_u1 = "Ripple Field 4 - 1-Up (Stone)" # Stone
|
||||
ripple_field_5_u1 = "Ripple Field 5 - 1-Up (Currents)" # Kine, Burning, Stone
|
||||
sand_canyon_1_u1 = "Sand Canyon 1 - 1-Up (Polof)" # None
|
||||
sand_canyon_2_u1 = "Sand Canyon 2 - 1-Up (Enclave)" # None
|
||||
sand_canyon_4_u1 = "Sand Canyon 4 - 1-Up (Clean)" # Clean
|
||||
sand_canyon_5_u1 = "Sand Canyon 5 - 1-Up (Falling Block)" # None
|
||||
sand_canyon_5_u2 = "Sand Canyon 5 - 1-Up (Ice 1)" # Ice
|
||||
sand_canyon_5_u3 = "Sand Canyon 5 - 1-Up (Ice 2)" # Ice
|
||||
sand_canyon_5_u4 = "Sand Canyon 5 - 1-Up (Ice 3)" # Ice
|
||||
cloudy_park_1_u1 = "Cloudy Park 1 - 1-Up (Shotzo)" # None
|
||||
cloudy_park_4_u1 = "Cloudy Park 4 - 1-Up (Windy)" # Coo
|
||||
cloudy_park_6_u1 = "Cloudy Park 6 - 1-Up (Cutter)" # Cutter
|
||||
iceberg_5_u1 = "Iceberg 5 - 1-Up (Boulder)" # None
|
||||
iceberg_5_u2 = "Iceberg 5 - 1-Up (Floor)" # None
|
||||
iceberg_5_u3 = "Iceberg 5 - 1-Up (Peloo)" # None, just let yourself get eaten by the Peloo
|
||||
iceberg_6_u1 = "Iceberg 6 - 1-Up (Middle)" # None
|
||||
|
||||
# Maxim Tomatoes
|
||||
grass_land_1_m1 = "Grass Land 1 - Maxim Tomato (Spark)" # Spark
|
||||
grass_land_3_m1 = "Grass Land 3 - Maxim Tomato (Climb)" # None
|
||||
grass_land_4_m1 = "Grass Land 4 - Maxim Tomato (Zebon Right)" # None
|
||||
grass_land_4_m2 = "Grass Land 4 - Maxim Tomato (Gordo)" # None
|
||||
grass_land_4_m3 = "Grass Land 4 - Maxim Tomato (Cliff)" # None
|
||||
ripple_field_2_m1 = "Ripple Field 2 - Maxim Tomato (Currents)" # Kine
|
||||
ripple_field_3_m1 = "Ripple Field 3 - Maxim Tomato (Cove)" # None
|
||||
ripple_field_4_m1 = "Ripple Field 4 - Maxim Tomato (Dark)" # None (maybe Spark?)
|
||||
ripple_field_4_m2 = "Ripple Field 4 - Maxim Tomato (Stone)" # Stone
|
||||
ripple_field_5_m1 = "Ripple Field 5 - Maxim Tomato (Exit)" # Kine
|
||||
ripple_field_5_m2 = "Ripple Field 5 - Maxim Tomato (Currents)" # Kine, Burning, Stone
|
||||
sand_canyon_2_m1 = "Sand Canyon 2 - Maxim Tomato (Underwater)" # None
|
||||
sand_canyon_4_m1 = "Sand Canyon 4 - Maxim Tomato (Pacto)" # None
|
||||
sand_canyon_4_m2 = "Sand Canyon 4 - Maxim Tomato (Needle)" # Needle
|
||||
sand_canyon_5_m1 = "Sand Canyon 5 - Maxim Tomato (Pit)" # None
|
||||
cloudy_park_1_m1 = "Cloudy Park 1 - Maxim Tomato (Mariel)" # None
|
||||
cloudy_park_4_m1 = "Cloudy Park 4 - Maxim Tomato (Windy)" # Coo
|
||||
cloudy_park_5_m1 = "Cloudy Park 5 - Maxim Tomato (Pillars)" # None
|
||||
iceberg_3_m1 = "Iceberg 3 - Maxim Tomato (Ceiling)" # None
|
||||
iceberg_6_m1 = "Iceberg 6 - Maxim Tomato (Left)" # None
|
||||
|
||||
# Level Names
|
||||
level_names = {
|
||||
"Grass Land": 1,
|
||||
"Ripple Field": 2,
|
||||
"Sand Canyon": 3,
|
||||
"Cloudy Park": 4,
|
||||
"Iceberg": 5,
|
||||
}
|
||||
|
||||
level_names_inverse = {
|
||||
level_names[level]: level for level in level_names
|
||||
}
|
||||
|
||||
# Boss Names
|
||||
boss_names = {
|
||||
"Whispy Woods": 0x770200,
|
||||
"Acro": 0x770201,
|
||||
"Pon & Con": 0x770202,
|
||||
"Ado": 0x770203,
|
||||
"King Dedede": 0x770204
|
||||
}
|
||||
|
||||
# Goal Mapping
|
||||
goals = {
|
||||
0: hyper_zone,
|
||||
1: boss_butch,
|
||||
2: mg5_p,
|
||||
3: jumping_clear
|
||||
}
|
||||
|
||||
grass_land_1_s1 = "Grass Land 1 - Star 1"
|
||||
grass_land_1_s2 = "Grass Land 1 - Star 2"
|
||||
grass_land_1_s3 = "Grass Land 1 - Star 3"
|
||||
grass_land_1_s4 = "Grass Land 1 - Star 4"
|
||||
grass_land_1_s5 = "Grass Land 1 - Star 5"
|
||||
grass_land_1_s6 = "Grass Land 1 - Star 6"
|
||||
grass_land_1_s7 = "Grass Land 1 - Star 7"
|
||||
grass_land_1_s8 = "Grass Land 1 - Star 8"
|
||||
grass_land_1_s9 = "Grass Land 1 - Star 9"
|
||||
grass_land_1_s10 = "Grass Land 1 - Star 10"
|
||||
grass_land_1_s11 = "Grass Land 1 - Star 11"
|
||||
grass_land_1_s12 = "Grass Land 1 - Star 12"
|
||||
grass_land_1_s13 = "Grass Land 1 - Star 13"
|
||||
grass_land_1_s14 = "Grass Land 1 - Star 14"
|
||||
grass_land_1_s15 = "Grass Land 1 - Star 15"
|
||||
grass_land_1_s16 = "Grass Land 1 - Star 16"
|
||||
grass_land_1_s17 = "Grass Land 1 - Star 17"
|
||||
grass_land_1_s18 = "Grass Land 1 - Star 18"
|
||||
grass_land_1_s19 = "Grass Land 1 - Star 19"
|
||||
grass_land_1_s20 = "Grass Land 1 - Star 20"
|
||||
grass_land_1_s21 = "Grass Land 1 - Star 21"
|
||||
grass_land_1_s22 = "Grass Land 1 - Star 22"
|
||||
grass_land_1_s23 = "Grass Land 1 - Star 23"
|
||||
grass_land_2_s1 = "Grass Land 2 - Star 1"
|
||||
grass_land_2_s2 = "Grass Land 2 - Star 2"
|
||||
grass_land_2_s3 = "Grass Land 2 - Star 3"
|
||||
grass_land_2_s4 = "Grass Land 2 - Star 4"
|
||||
grass_land_2_s5 = "Grass Land 2 - Star 5"
|
||||
grass_land_2_s6 = "Grass Land 2 - Star 6"
|
||||
grass_land_2_s7 = "Grass Land 2 - Star 7"
|
||||
grass_land_2_s8 = "Grass Land 2 - Star 8"
|
||||
grass_land_2_s9 = "Grass Land 2 - Star 9"
|
||||
grass_land_2_s10 = "Grass Land 2 - Star 10"
|
||||
grass_land_2_s11 = "Grass Land 2 - Star 11"
|
||||
grass_land_2_s12 = "Grass Land 2 - Star 12"
|
||||
grass_land_2_s13 = "Grass Land 2 - Star 13"
|
||||
grass_land_2_s14 = "Grass Land 2 - Star 14"
|
||||
grass_land_2_s15 = "Grass Land 2 - Star 15"
|
||||
grass_land_2_s16 = "Grass Land 2 - Star 16"
|
||||
grass_land_2_s17 = "Grass Land 2 - Star 17"
|
||||
grass_land_2_s18 = "Grass Land 2 - Star 18"
|
||||
grass_land_2_s19 = "Grass Land 2 - Star 19"
|
||||
grass_land_2_s20 = "Grass Land 2 - Star 20"
|
||||
grass_land_2_s21 = "Grass Land 2 - Star 21"
|
||||
grass_land_3_s1 = "Grass Land 3 - Star 1"
|
||||
grass_land_3_s2 = "Grass Land 3 - Star 2"
|
||||
grass_land_3_s3 = "Grass Land 3 - Star 3"
|
||||
grass_land_3_s4 = "Grass Land 3 - Star 4"
|
||||
grass_land_3_s5 = "Grass Land 3 - Star 5"
|
||||
grass_land_3_s6 = "Grass Land 3 - Star 6"
|
||||
grass_land_3_s7 = "Grass Land 3 - Star 7"
|
||||
grass_land_3_s8 = "Grass Land 3 - Star 8"
|
||||
grass_land_3_s9 = "Grass Land 3 - Star 9"
|
||||
grass_land_3_s10 = "Grass Land 3 - Star 10"
|
||||
grass_land_3_s11 = "Grass Land 3 - Star 11"
|
||||
grass_land_3_s12 = "Grass Land 3 - Star 12"
|
||||
grass_land_3_s13 = "Grass Land 3 - Star 13"
|
||||
grass_land_3_s14 = "Grass Land 3 - Star 14"
|
||||
grass_land_3_s15 = "Grass Land 3 - Star 15"
|
||||
grass_land_3_s16 = "Grass Land 3 - Star 16"
|
||||
grass_land_3_s17 = "Grass Land 3 - Star 17"
|
||||
grass_land_3_s18 = "Grass Land 3 - Star 18"
|
||||
grass_land_3_s19 = "Grass Land 3 - Star 19"
|
||||
grass_land_3_s20 = "Grass Land 3 - Star 20"
|
||||
grass_land_3_s21 = "Grass Land 3 - Star 21"
|
||||
grass_land_3_s22 = "Grass Land 3 - Star 22"
|
||||
grass_land_3_s23 = "Grass Land 3 - Star 23"
|
||||
grass_land_3_s24 = "Grass Land 3 - Star 24"
|
||||
grass_land_3_s25 = "Grass Land 3 - Star 25"
|
||||
grass_land_3_s26 = "Grass Land 3 - Star 26"
|
||||
grass_land_3_s27 = "Grass Land 3 - Star 27"
|
||||
grass_land_3_s28 = "Grass Land 3 - Star 28"
|
||||
grass_land_3_s29 = "Grass Land 3 - Star 29"
|
||||
grass_land_3_s30 = "Grass Land 3 - Star 30"
|
||||
grass_land_3_s31 = "Grass Land 3 - Star 31"
|
||||
grass_land_4_s1 = "Grass Land 4 - Star 1"
|
||||
grass_land_4_s2 = "Grass Land 4 - Star 2"
|
||||
grass_land_4_s3 = "Grass Land 4 - Star 3"
|
||||
grass_land_4_s4 = "Grass Land 4 - Star 4"
|
||||
grass_land_4_s5 = "Grass Land 4 - Star 5"
|
||||
grass_land_4_s6 = "Grass Land 4 - Star 6"
|
||||
grass_land_4_s7 = "Grass Land 4 - Star 7"
|
||||
grass_land_4_s8 = "Grass Land 4 - Star 8"
|
||||
grass_land_4_s9 = "Grass Land 4 - Star 9"
|
||||
grass_land_4_s10 = "Grass Land 4 - Star 10"
|
||||
grass_land_4_s11 = "Grass Land 4 - Star 11"
|
||||
grass_land_4_s12 = "Grass Land 4 - Star 12"
|
||||
grass_land_4_s13 = "Grass Land 4 - Star 13"
|
||||
grass_land_4_s14 = "Grass Land 4 - Star 14"
|
||||
grass_land_4_s15 = "Grass Land 4 - Star 15"
|
||||
grass_land_4_s16 = "Grass Land 4 - Star 16"
|
||||
grass_land_4_s17 = "Grass Land 4 - Star 17"
|
||||
grass_land_4_s18 = "Grass Land 4 - Star 18"
|
||||
grass_land_4_s19 = "Grass Land 4 - Star 19"
|
||||
grass_land_4_s20 = "Grass Land 4 - Star 20"
|
||||
grass_land_4_s21 = "Grass Land 4 - Star 21"
|
||||
grass_land_4_s22 = "Grass Land 4 - Star 22"
|
||||
grass_land_4_s23 = "Grass Land 4 - Star 23"
|
||||
grass_land_4_s24 = "Grass Land 4 - Star 24"
|
||||
grass_land_4_s25 = "Grass Land 4 - Star 25"
|
||||
grass_land_4_s26 = "Grass Land 4 - Star 26"
|
||||
grass_land_4_s27 = "Grass Land 4 - Star 27"
|
||||
grass_land_4_s28 = "Grass Land 4 - Star 28"
|
||||
grass_land_4_s29 = "Grass Land 4 - Star 29"
|
||||
grass_land_4_s30 = "Grass Land 4 - Star 30"
|
||||
grass_land_4_s31 = "Grass Land 4 - Star 31"
|
||||
grass_land_4_s32 = "Grass Land 4 - Star 32"
|
||||
grass_land_4_s33 = "Grass Land 4 - Star 33"
|
||||
grass_land_4_s34 = "Grass Land 4 - Star 34"
|
||||
grass_land_4_s35 = "Grass Land 4 - Star 35"
|
||||
grass_land_4_s36 = "Grass Land 4 - Star 36"
|
||||
grass_land_4_s37 = "Grass Land 4 - Star 37"
|
||||
grass_land_5_s1 = "Grass Land 5 - Star 1"
|
||||
grass_land_5_s2 = "Grass Land 5 - Star 2"
|
||||
grass_land_5_s3 = "Grass Land 5 - Star 3"
|
||||
grass_land_5_s4 = "Grass Land 5 - Star 4"
|
||||
grass_land_5_s5 = "Grass Land 5 - Star 5"
|
||||
grass_land_5_s6 = "Grass Land 5 - Star 6"
|
||||
grass_land_5_s7 = "Grass Land 5 - Star 7"
|
||||
grass_land_5_s8 = "Grass Land 5 - Star 8"
|
||||
grass_land_5_s9 = "Grass Land 5 - Star 9"
|
||||
grass_land_5_s10 = "Grass Land 5 - Star 10"
|
||||
grass_land_5_s11 = "Grass Land 5 - Star 11"
|
||||
grass_land_5_s12 = "Grass Land 5 - Star 12"
|
||||
grass_land_5_s13 = "Grass Land 5 - Star 13"
|
||||
grass_land_5_s14 = "Grass Land 5 - Star 14"
|
||||
grass_land_5_s15 = "Grass Land 5 - Star 15"
|
||||
grass_land_5_s16 = "Grass Land 5 - Star 16"
|
||||
grass_land_5_s17 = "Grass Land 5 - Star 17"
|
||||
grass_land_5_s18 = "Grass Land 5 - Star 18"
|
||||
grass_land_5_s19 = "Grass Land 5 - Star 19"
|
||||
grass_land_5_s20 = "Grass Land 5 - Star 20"
|
||||
grass_land_5_s21 = "Grass Land 5 - Star 21"
|
||||
grass_land_5_s22 = "Grass Land 5 - Star 22"
|
||||
grass_land_5_s23 = "Grass Land 5 - Star 23"
|
||||
grass_land_5_s24 = "Grass Land 5 - Star 24"
|
||||
grass_land_5_s25 = "Grass Land 5 - Star 25"
|
||||
grass_land_5_s26 = "Grass Land 5 - Star 26"
|
||||
grass_land_5_s27 = "Grass Land 5 - Star 27"
|
||||
grass_land_5_s28 = "Grass Land 5 - Star 28"
|
||||
grass_land_5_s29 = "Grass Land 5 - Star 29"
|
||||
grass_land_6_s1 = "Grass Land 6 - Star 1"
|
||||
grass_land_6_s2 = "Grass Land 6 - Star 2"
|
||||
grass_land_6_s3 = "Grass Land 6 - Star 3"
|
||||
grass_land_6_s4 = "Grass Land 6 - Star 4"
|
||||
grass_land_6_s5 = "Grass Land 6 - Star 5"
|
||||
grass_land_6_s6 = "Grass Land 6 - Star 6"
|
||||
grass_land_6_s7 = "Grass Land 6 - Star 7"
|
||||
grass_land_6_s8 = "Grass Land 6 - Star 8"
|
||||
grass_land_6_s9 = "Grass Land 6 - Star 9"
|
||||
grass_land_6_s10 = "Grass Land 6 - Star 10"
|
||||
grass_land_6_s11 = "Grass Land 6 - Star 11"
|
||||
grass_land_6_s12 = "Grass Land 6 - Star 12"
|
||||
grass_land_6_s13 = "Grass Land 6 - Star 13"
|
||||
grass_land_6_s14 = "Grass Land 6 - Star 14"
|
||||
grass_land_6_s15 = "Grass Land 6 - Star 15"
|
||||
grass_land_6_s16 = "Grass Land 6 - Star 16"
|
||||
grass_land_6_s17 = "Grass Land 6 - Star 17"
|
||||
grass_land_6_s18 = "Grass Land 6 - Star 18"
|
||||
grass_land_6_s19 = "Grass Land 6 - Star 19"
|
||||
grass_land_6_s20 = "Grass Land 6 - Star 20"
|
||||
grass_land_6_s21 = "Grass Land 6 - Star 21"
|
||||
grass_land_6_s22 = "Grass Land 6 - Star 22"
|
||||
grass_land_6_s23 = "Grass Land 6 - Star 23"
|
||||
grass_land_6_s24 = "Grass Land 6 - Star 24"
|
||||
grass_land_6_s25 = "Grass Land 6 - Star 25"
|
||||
grass_land_6_s26 = "Grass Land 6 - Star 26"
|
||||
grass_land_6_s27 = "Grass Land 6 - Star 27"
|
||||
grass_land_6_s28 = "Grass Land 6 - Star 28"
|
||||
grass_land_6_s29 = "Grass Land 6 - Star 29"
|
||||
ripple_field_1_s1 = "Ripple Field 1 - Star 1"
|
||||
ripple_field_1_s2 = "Ripple Field 1 - Star 2"
|
||||
ripple_field_1_s3 = "Ripple Field 1 - Star 3"
|
||||
ripple_field_1_s4 = "Ripple Field 1 - Star 4"
|
||||
ripple_field_1_s5 = "Ripple Field 1 - Star 5"
|
||||
ripple_field_1_s6 = "Ripple Field 1 - Star 6"
|
||||
ripple_field_1_s7 = "Ripple Field 1 - Star 7"
|
||||
ripple_field_1_s8 = "Ripple Field 1 - Star 8"
|
||||
ripple_field_1_s9 = "Ripple Field 1 - Star 9"
|
||||
ripple_field_1_s10 = "Ripple Field 1 - Star 10"
|
||||
ripple_field_1_s11 = "Ripple Field 1 - Star 11"
|
||||
ripple_field_1_s12 = "Ripple Field 1 - Star 12"
|
||||
ripple_field_1_s13 = "Ripple Field 1 - Star 13"
|
||||
ripple_field_1_s14 = "Ripple Field 1 - Star 14"
|
||||
ripple_field_1_s15 = "Ripple Field 1 - Star 15"
|
||||
ripple_field_1_s16 = "Ripple Field 1 - Star 16"
|
||||
ripple_field_1_s17 = "Ripple Field 1 - Star 17"
|
||||
ripple_field_1_s18 = "Ripple Field 1 - Star 18"
|
||||
ripple_field_1_s19 = "Ripple Field 1 - Star 19"
|
||||
ripple_field_2_s1 = "Ripple Field 2 - Star 1"
|
||||
ripple_field_2_s2 = "Ripple Field 2 - Star 2"
|
||||
ripple_field_2_s3 = "Ripple Field 2 - Star 3"
|
||||
ripple_field_2_s4 = "Ripple Field 2 - Star 4"
|
||||
ripple_field_2_s5 = "Ripple Field 2 - Star 5"
|
||||
ripple_field_2_s6 = "Ripple Field 2 - Star 6"
|
||||
ripple_field_2_s7 = "Ripple Field 2 - Star 7"
|
||||
ripple_field_2_s8 = "Ripple Field 2 - Star 8"
|
||||
ripple_field_2_s9 = "Ripple Field 2 - Star 9"
|
||||
ripple_field_2_s10 = "Ripple Field 2 - Star 10"
|
||||
ripple_field_2_s11 = "Ripple Field 2 - Star 11"
|
||||
ripple_field_2_s12 = "Ripple Field 2 - Star 12"
|
||||
ripple_field_2_s13 = "Ripple Field 2 - Star 13"
|
||||
ripple_field_2_s14 = "Ripple Field 2 - Star 14"
|
||||
ripple_field_2_s15 = "Ripple Field 2 - Star 15"
|
||||
ripple_field_2_s16 = "Ripple Field 2 - Star 16"
|
||||
ripple_field_2_s17 = "Ripple Field 2 - Star 17"
|
||||
ripple_field_3_s1 = "Ripple Field 3 - Star 1"
|
||||
ripple_field_3_s2 = "Ripple Field 3 - Star 2"
|
||||
ripple_field_3_s3 = "Ripple Field 3 - Star 3"
|
||||
ripple_field_3_s4 = "Ripple Field 3 - Star 4"
|
||||
ripple_field_3_s5 = "Ripple Field 3 - Star 5"
|
||||
ripple_field_3_s6 = "Ripple Field 3 - Star 6"
|
||||
ripple_field_3_s7 = "Ripple Field 3 - Star 7"
|
||||
ripple_field_3_s8 = "Ripple Field 3 - Star 8"
|
||||
ripple_field_3_s9 = "Ripple Field 3 - Star 9"
|
||||
ripple_field_3_s10 = "Ripple Field 3 - Star 10"
|
||||
ripple_field_3_s11 = "Ripple Field 3 - Star 11"
|
||||
ripple_field_3_s12 = "Ripple Field 3 - Star 12"
|
||||
ripple_field_3_s13 = "Ripple Field 3 - Star 13"
|
||||
ripple_field_3_s14 = "Ripple Field 3 - Star 14"
|
||||
ripple_field_3_s15 = "Ripple Field 3 - Star 15"
|
||||
ripple_field_3_s16 = "Ripple Field 3 - Star 16"
|
||||
ripple_field_3_s17 = "Ripple Field 3 - Star 17"
|
||||
ripple_field_3_s18 = "Ripple Field 3 - Star 18"
|
||||
ripple_field_3_s19 = "Ripple Field 3 - Star 19"
|
||||
ripple_field_3_s20 = "Ripple Field 3 - Star 20"
|
||||
ripple_field_3_s21 = "Ripple Field 3 - Star 21"
|
||||
ripple_field_4_s1 = "Ripple Field 4 - Star 1"
|
||||
ripple_field_4_s2 = "Ripple Field 4 - Star 2"
|
||||
ripple_field_4_s3 = "Ripple Field 4 - Star 3"
|
||||
ripple_field_4_s4 = "Ripple Field 4 - Star 4"
|
||||
ripple_field_4_s5 = "Ripple Field 4 - Star 5"
|
||||
ripple_field_4_s6 = "Ripple Field 4 - Star 6"
|
||||
ripple_field_4_s7 = "Ripple Field 4 - Star 7"
|
||||
ripple_field_4_s8 = "Ripple Field 4 - Star 8"
|
||||
ripple_field_4_s9 = "Ripple Field 4 - Star 9"
|
||||
ripple_field_4_s10 = "Ripple Field 4 - Star 10"
|
||||
ripple_field_4_s11 = "Ripple Field 4 - Star 11"
|
||||
ripple_field_4_s12 = "Ripple Field 4 - Star 12"
|
||||
ripple_field_4_s13 = "Ripple Field 4 - Star 13"
|
||||
ripple_field_4_s14 = "Ripple Field 4 - Star 14"
|
||||
ripple_field_4_s15 = "Ripple Field 4 - Star 15"
|
||||
ripple_field_4_s16 = "Ripple Field 4 - Star 16"
|
||||
ripple_field_4_s17 = "Ripple Field 4 - Star 17"
|
||||
ripple_field_4_s18 = "Ripple Field 4 - Star 18"
|
||||
ripple_field_4_s19 = "Ripple Field 4 - Star 19"
|
||||
ripple_field_4_s20 = "Ripple Field 4 - Star 20"
|
||||
ripple_field_4_s21 = "Ripple Field 4 - Star 21"
|
||||
ripple_field_4_s22 = "Ripple Field 4 - Star 22"
|
||||
ripple_field_4_s23 = "Ripple Field 4 - Star 23"
|
||||
ripple_field_4_s24 = "Ripple Field 4 - Star 24"
|
||||
ripple_field_4_s25 = "Ripple Field 4 - Star 25"
|
||||
ripple_field_4_s26 = "Ripple Field 4 - Star 26"
|
||||
ripple_field_4_s27 = "Ripple Field 4 - Star 27"
|
||||
ripple_field_4_s28 = "Ripple Field 4 - Star 28"
|
||||
ripple_field_4_s29 = "Ripple Field 4 - Star 29"
|
||||
ripple_field_4_s30 = "Ripple Field 4 - Star 30"
|
||||
ripple_field_4_s31 = "Ripple Field 4 - Star 31"
|
||||
ripple_field_4_s32 = "Ripple Field 4 - Star 32"
|
||||
ripple_field_4_s33 = "Ripple Field 4 - Star 33"
|
||||
ripple_field_4_s34 = "Ripple Field 4 - Star 34"
|
||||
ripple_field_4_s35 = "Ripple Field 4 - Star 35"
|
||||
ripple_field_4_s36 = "Ripple Field 4 - Star 36"
|
||||
ripple_field_4_s37 = "Ripple Field 4 - Star 37"
|
||||
ripple_field_4_s38 = "Ripple Field 4 - Star 38"
|
||||
ripple_field_4_s39 = "Ripple Field 4 - Star 39"
|
||||
ripple_field_4_s40 = "Ripple Field 4 - Star 40"
|
||||
ripple_field_4_s41 = "Ripple Field 4 - Star 41"
|
||||
ripple_field_4_s42 = "Ripple Field 4 - Star 42"
|
||||
ripple_field_4_s43 = "Ripple Field 4 - Star 43"
|
||||
ripple_field_4_s44 = "Ripple Field 4 - Star 44"
|
||||
ripple_field_4_s45 = "Ripple Field 4 - Star 45"
|
||||
ripple_field_4_s46 = "Ripple Field 4 - Star 46"
|
||||
ripple_field_4_s47 = "Ripple Field 4 - Star 47"
|
||||
ripple_field_4_s48 = "Ripple Field 4 - Star 48"
|
||||
ripple_field_4_s49 = "Ripple Field 4 - Star 49"
|
||||
ripple_field_4_s50 = "Ripple Field 4 - Star 50"
|
||||
ripple_field_4_s51 = "Ripple Field 4 - Star 51"
|
||||
ripple_field_5_s1 = "Ripple Field 5 - Star 1"
|
||||
ripple_field_5_s2 = "Ripple Field 5 - Star 2"
|
||||
ripple_field_5_s3 = "Ripple Field 5 - Star 3"
|
||||
ripple_field_5_s4 = "Ripple Field 5 - Star 4"
|
||||
ripple_field_5_s5 = "Ripple Field 5 - Star 5"
|
||||
ripple_field_5_s6 = "Ripple Field 5 - Star 6"
|
||||
ripple_field_5_s7 = "Ripple Field 5 - Star 7"
|
||||
ripple_field_5_s8 = "Ripple Field 5 - Star 8"
|
||||
ripple_field_5_s9 = "Ripple Field 5 - Star 9"
|
||||
ripple_field_5_s10 = "Ripple Field 5 - Star 10"
|
||||
ripple_field_5_s11 = "Ripple Field 5 - Star 11"
|
||||
ripple_field_5_s12 = "Ripple Field 5 - Star 12"
|
||||
ripple_field_5_s13 = "Ripple Field 5 - Star 13"
|
||||
ripple_field_5_s14 = "Ripple Field 5 - Star 14"
|
||||
ripple_field_5_s15 = "Ripple Field 5 - Star 15"
|
||||
ripple_field_5_s16 = "Ripple Field 5 - Star 16"
|
||||
ripple_field_5_s17 = "Ripple Field 5 - Star 17"
|
||||
ripple_field_5_s18 = "Ripple Field 5 - Star 18"
|
||||
ripple_field_5_s19 = "Ripple Field 5 - Star 19"
|
||||
ripple_field_5_s20 = "Ripple Field 5 - Star 20"
|
||||
ripple_field_5_s21 = "Ripple Field 5 - Star 21"
|
||||
ripple_field_5_s22 = "Ripple Field 5 - Star 22"
|
||||
ripple_field_5_s23 = "Ripple Field 5 - Star 23"
|
||||
ripple_field_5_s24 = "Ripple Field 5 - Star 24"
|
||||
ripple_field_5_s25 = "Ripple Field 5 - Star 25"
|
||||
ripple_field_5_s26 = "Ripple Field 5 - Star 26"
|
||||
ripple_field_5_s27 = "Ripple Field 5 - Star 27"
|
||||
ripple_field_5_s28 = "Ripple Field 5 - Star 28"
|
||||
ripple_field_5_s29 = "Ripple Field 5 - Star 29"
|
||||
ripple_field_5_s30 = "Ripple Field 5 - Star 30"
|
||||
ripple_field_5_s31 = "Ripple Field 5 - Star 31"
|
||||
ripple_field_5_s32 = "Ripple Field 5 - Star 32"
|
||||
ripple_field_5_s33 = "Ripple Field 5 - Star 33"
|
||||
ripple_field_5_s34 = "Ripple Field 5 - Star 34"
|
||||
ripple_field_5_s35 = "Ripple Field 5 - Star 35"
|
||||
ripple_field_5_s36 = "Ripple Field 5 - Star 36"
|
||||
ripple_field_5_s37 = "Ripple Field 5 - Star 37"
|
||||
ripple_field_5_s38 = "Ripple Field 5 - Star 38"
|
||||
ripple_field_5_s39 = "Ripple Field 5 - Star 39"
|
||||
ripple_field_5_s40 = "Ripple Field 5 - Star 40"
|
||||
ripple_field_5_s41 = "Ripple Field 5 - Star 41"
|
||||
ripple_field_5_s42 = "Ripple Field 5 - Star 42"
|
||||
ripple_field_5_s43 = "Ripple Field 5 - Star 43"
|
||||
ripple_field_5_s44 = "Ripple Field 5 - Star 44"
|
||||
ripple_field_5_s45 = "Ripple Field 5 - Star 45"
|
||||
ripple_field_5_s46 = "Ripple Field 5 - Star 46"
|
||||
ripple_field_5_s47 = "Ripple Field 5 - Star 47"
|
||||
ripple_field_5_s48 = "Ripple Field 5 - Star 48"
|
||||
ripple_field_5_s49 = "Ripple Field 5 - Star 49"
|
||||
ripple_field_5_s50 = "Ripple Field 5 - Star 50"
|
||||
ripple_field_5_s51 = "Ripple Field 5 - Star 51"
|
||||
ripple_field_6_s1 = "Ripple Field 6 - Star 1"
|
||||
ripple_field_6_s2 = "Ripple Field 6 - Star 2"
|
||||
ripple_field_6_s3 = "Ripple Field 6 - Star 3"
|
||||
ripple_field_6_s4 = "Ripple Field 6 - Star 4"
|
||||
ripple_field_6_s5 = "Ripple Field 6 - Star 5"
|
||||
ripple_field_6_s6 = "Ripple Field 6 - Star 6"
|
||||
ripple_field_6_s7 = "Ripple Field 6 - Star 7"
|
||||
ripple_field_6_s8 = "Ripple Field 6 - Star 8"
|
||||
ripple_field_6_s9 = "Ripple Field 6 - Star 9"
|
||||
ripple_field_6_s10 = "Ripple Field 6 - Star 10"
|
||||
ripple_field_6_s11 = "Ripple Field 6 - Star 11"
|
||||
ripple_field_6_s12 = "Ripple Field 6 - Star 12"
|
||||
ripple_field_6_s13 = "Ripple Field 6 - Star 13"
|
||||
ripple_field_6_s14 = "Ripple Field 6 - Star 14"
|
||||
ripple_field_6_s15 = "Ripple Field 6 - Star 15"
|
||||
ripple_field_6_s16 = "Ripple Field 6 - Star 16"
|
||||
ripple_field_6_s17 = "Ripple Field 6 - Star 17"
|
||||
ripple_field_6_s18 = "Ripple Field 6 - Star 18"
|
||||
ripple_field_6_s19 = "Ripple Field 6 - Star 19"
|
||||
ripple_field_6_s20 = "Ripple Field 6 - Star 20"
|
||||
ripple_field_6_s21 = "Ripple Field 6 - Star 21"
|
||||
ripple_field_6_s22 = "Ripple Field 6 - Star 22"
|
||||
ripple_field_6_s23 = "Ripple Field 6 - Star 23"
|
||||
sand_canyon_1_s1 = "Sand Canyon 1 - Star 1"
|
||||
sand_canyon_1_s2 = "Sand Canyon 1 - Star 2"
|
||||
sand_canyon_1_s3 = "Sand Canyon 1 - Star 3"
|
||||
sand_canyon_1_s4 = "Sand Canyon 1 - Star 4"
|
||||
sand_canyon_1_s5 = "Sand Canyon 1 - Star 5"
|
||||
sand_canyon_1_s6 = "Sand Canyon 1 - Star 6"
|
||||
sand_canyon_1_s7 = "Sand Canyon 1 - Star 7"
|
||||
sand_canyon_1_s8 = "Sand Canyon 1 - Star 8"
|
||||
sand_canyon_1_s9 = "Sand Canyon 1 - Star 9"
|
||||
sand_canyon_1_s10 = "Sand Canyon 1 - Star 10"
|
||||
sand_canyon_1_s11 = "Sand Canyon 1 - Star 11"
|
||||
sand_canyon_1_s12 = "Sand Canyon 1 - Star 12"
|
||||
sand_canyon_1_s13 = "Sand Canyon 1 - Star 13"
|
||||
sand_canyon_1_s14 = "Sand Canyon 1 - Star 14"
|
||||
sand_canyon_1_s15 = "Sand Canyon 1 - Star 15"
|
||||
sand_canyon_1_s16 = "Sand Canyon 1 - Star 16"
|
||||
sand_canyon_1_s17 = "Sand Canyon 1 - Star 17"
|
||||
sand_canyon_1_s18 = "Sand Canyon 1 - Star 18"
|
||||
sand_canyon_1_s19 = "Sand Canyon 1 - Star 19"
|
||||
sand_canyon_1_s20 = "Sand Canyon 1 - Star 20"
|
||||
sand_canyon_1_s21 = "Sand Canyon 1 - Star 21"
|
||||
sand_canyon_1_s22 = "Sand Canyon 1 - Star 22"
|
||||
sand_canyon_2_s1 = "Sand Canyon 2 - Star 1"
|
||||
sand_canyon_2_s2 = "Sand Canyon 2 - Star 2"
|
||||
sand_canyon_2_s3 = "Sand Canyon 2 - Star 3"
|
||||
sand_canyon_2_s4 = "Sand Canyon 2 - Star 4"
|
||||
sand_canyon_2_s5 = "Sand Canyon 2 - Star 5"
|
||||
sand_canyon_2_s6 = "Sand Canyon 2 - Star 6"
|
||||
sand_canyon_2_s7 = "Sand Canyon 2 - Star 7"
|
||||
sand_canyon_2_s8 = "Sand Canyon 2 - Star 8"
|
||||
sand_canyon_2_s9 = "Sand Canyon 2 - Star 9"
|
||||
sand_canyon_2_s10 = "Sand Canyon 2 - Star 10"
|
||||
sand_canyon_2_s11 = "Sand Canyon 2 - Star 11"
|
||||
sand_canyon_2_s12 = "Sand Canyon 2 - Star 12"
|
||||
sand_canyon_2_s13 = "Sand Canyon 2 - Star 13"
|
||||
sand_canyon_2_s14 = "Sand Canyon 2 - Star 14"
|
||||
sand_canyon_2_s15 = "Sand Canyon 2 - Star 15"
|
||||
sand_canyon_2_s16 = "Sand Canyon 2 - Star 16"
|
||||
sand_canyon_2_s17 = "Sand Canyon 2 - Star 17"
|
||||
sand_canyon_2_s18 = "Sand Canyon 2 - Star 18"
|
||||
sand_canyon_2_s19 = "Sand Canyon 2 - Star 19"
|
||||
sand_canyon_2_s20 = "Sand Canyon 2 - Star 20"
|
||||
sand_canyon_2_s21 = "Sand Canyon 2 - Star 21"
|
||||
sand_canyon_2_s22 = "Sand Canyon 2 - Star 22"
|
||||
sand_canyon_2_s23 = "Sand Canyon 2 - Star 23"
|
||||
sand_canyon_2_s24 = "Sand Canyon 2 - Star 24"
|
||||
sand_canyon_2_s25 = "Sand Canyon 2 - Star 25"
|
||||
sand_canyon_2_s26 = "Sand Canyon 2 - Star 26"
|
||||
sand_canyon_2_s27 = "Sand Canyon 2 - Star 27"
|
||||
sand_canyon_2_s28 = "Sand Canyon 2 - Star 28"
|
||||
sand_canyon_2_s29 = "Sand Canyon 2 - Star 29"
|
||||
sand_canyon_2_s30 = "Sand Canyon 2 - Star 30"
|
||||
sand_canyon_2_s31 = "Sand Canyon 2 - Star 31"
|
||||
sand_canyon_2_s32 = "Sand Canyon 2 - Star 32"
|
||||
sand_canyon_2_s33 = "Sand Canyon 2 - Star 33"
|
||||
sand_canyon_2_s34 = "Sand Canyon 2 - Star 34"
|
||||
sand_canyon_2_s35 = "Sand Canyon 2 - Star 35"
|
||||
sand_canyon_2_s36 = "Sand Canyon 2 - Star 36"
|
||||
sand_canyon_2_s37 = "Sand Canyon 2 - Star 37"
|
||||
sand_canyon_2_s38 = "Sand Canyon 2 - Star 38"
|
||||
sand_canyon_2_s39 = "Sand Canyon 2 - Star 39"
|
||||
sand_canyon_2_s40 = "Sand Canyon 2 - Star 40"
|
||||
sand_canyon_2_s41 = "Sand Canyon 2 - Star 41"
|
||||
sand_canyon_2_s42 = "Sand Canyon 2 - Star 42"
|
||||
sand_canyon_2_s43 = "Sand Canyon 2 - Star 43"
|
||||
sand_canyon_2_s44 = "Sand Canyon 2 - Star 44"
|
||||
sand_canyon_2_s45 = "Sand Canyon 2 - Star 45"
|
||||
sand_canyon_2_s46 = "Sand Canyon 2 - Star 46"
|
||||
sand_canyon_2_s47 = "Sand Canyon 2 - Star 47"
|
||||
sand_canyon_2_s48 = "Sand Canyon 2 - Star 48"
|
||||
sand_canyon_3_s1 = "Sand Canyon 3 - Star 1"
|
||||
sand_canyon_3_s2 = "Sand Canyon 3 - Star 2"
|
||||
sand_canyon_3_s3 = "Sand Canyon 3 - Star 3"
|
||||
sand_canyon_3_s4 = "Sand Canyon 3 - Star 4"
|
||||
sand_canyon_3_s5 = "Sand Canyon 3 - Star 5"
|
||||
sand_canyon_3_s6 = "Sand Canyon 3 - Star 6"
|
||||
sand_canyon_3_s7 = "Sand Canyon 3 - Star 7"
|
||||
sand_canyon_3_s8 = "Sand Canyon 3 - Star 8"
|
||||
sand_canyon_3_s9 = "Sand Canyon 3 - Star 9"
|
||||
sand_canyon_3_s10 = "Sand Canyon 3 - Star 10"
|
||||
sand_canyon_4_s1 = "Sand Canyon 4 - Star 1"
|
||||
sand_canyon_4_s2 = "Sand Canyon 4 - Star 2"
|
||||
sand_canyon_4_s3 = "Sand Canyon 4 - Star 3"
|
||||
sand_canyon_4_s4 = "Sand Canyon 4 - Star 4"
|
||||
sand_canyon_4_s5 = "Sand Canyon 4 - Star 5"
|
||||
sand_canyon_4_s6 = "Sand Canyon 4 - Star 6"
|
||||
sand_canyon_4_s7 = "Sand Canyon 4 - Star 7"
|
||||
sand_canyon_4_s8 = "Sand Canyon 4 - Star 8"
|
||||
sand_canyon_4_s9 = "Sand Canyon 4 - Star 9"
|
||||
sand_canyon_4_s10 = "Sand Canyon 4 - Star 10"
|
||||
sand_canyon_4_s11 = "Sand Canyon 4 - Star 11"
|
||||
sand_canyon_4_s12 = "Sand Canyon 4 - Star 12"
|
||||
sand_canyon_4_s13 = "Sand Canyon 4 - Star 13"
|
||||
sand_canyon_4_s14 = "Sand Canyon 4 - Star 14"
|
||||
sand_canyon_4_s15 = "Sand Canyon 4 - Star 15"
|
||||
sand_canyon_4_s16 = "Sand Canyon 4 - Star 16"
|
||||
sand_canyon_4_s17 = "Sand Canyon 4 - Star 17"
|
||||
sand_canyon_4_s18 = "Sand Canyon 4 - Star 18"
|
||||
sand_canyon_4_s19 = "Sand Canyon 4 - Star 19"
|
||||
sand_canyon_4_s20 = "Sand Canyon 4 - Star 20"
|
||||
sand_canyon_4_s21 = "Sand Canyon 4 - Star 21"
|
||||
sand_canyon_4_s22 = "Sand Canyon 4 - Star 22"
|
||||
sand_canyon_4_s23 = "Sand Canyon 4 - Star 23"
|
||||
sand_canyon_5_s1 = "Sand Canyon 5 - Star 1"
|
||||
sand_canyon_5_s2 = "Sand Canyon 5 - Star 2"
|
||||
sand_canyon_5_s3 = "Sand Canyon 5 - Star 3"
|
||||
sand_canyon_5_s4 = "Sand Canyon 5 - Star 4"
|
||||
sand_canyon_5_s5 = "Sand Canyon 5 - Star 5"
|
||||
sand_canyon_5_s6 = "Sand Canyon 5 - Star 6"
|
||||
sand_canyon_5_s7 = "Sand Canyon 5 - Star 7"
|
||||
sand_canyon_5_s8 = "Sand Canyon 5 - Star 8"
|
||||
sand_canyon_5_s9 = "Sand Canyon 5 - Star 9"
|
||||
sand_canyon_5_s10 = "Sand Canyon 5 - Star 10"
|
||||
sand_canyon_5_s11 = "Sand Canyon 5 - Star 11"
|
||||
sand_canyon_5_s12 = "Sand Canyon 5 - Star 12"
|
||||
sand_canyon_5_s13 = "Sand Canyon 5 - Star 13"
|
||||
sand_canyon_5_s14 = "Sand Canyon 5 - Star 14"
|
||||
sand_canyon_5_s15 = "Sand Canyon 5 - Star 15"
|
||||
sand_canyon_5_s16 = "Sand Canyon 5 - Star 16"
|
||||
sand_canyon_5_s17 = "Sand Canyon 5 - Star 17"
|
||||
sand_canyon_5_s18 = "Sand Canyon 5 - Star 18"
|
||||
sand_canyon_5_s19 = "Sand Canyon 5 - Star 19"
|
||||
sand_canyon_5_s20 = "Sand Canyon 5 - Star 20"
|
||||
sand_canyon_5_s21 = "Sand Canyon 5 - Star 21"
|
||||
sand_canyon_5_s22 = "Sand Canyon 5 - Star 22"
|
||||
sand_canyon_5_s23 = "Sand Canyon 5 - Star 23"
|
||||
sand_canyon_5_s24 = "Sand Canyon 5 - Star 24"
|
||||
sand_canyon_5_s25 = "Sand Canyon 5 - Star 25"
|
||||
sand_canyon_5_s26 = "Sand Canyon 5 - Star 26"
|
||||
sand_canyon_5_s27 = "Sand Canyon 5 - Star 27"
|
||||
sand_canyon_5_s28 = "Sand Canyon 5 - Star 28"
|
||||
sand_canyon_5_s29 = "Sand Canyon 5 - Star 29"
|
||||
sand_canyon_5_s30 = "Sand Canyon 5 - Star 30"
|
||||
sand_canyon_5_s31 = "Sand Canyon 5 - Star 31"
|
||||
sand_canyon_5_s32 = "Sand Canyon 5 - Star 32"
|
||||
sand_canyon_5_s33 = "Sand Canyon 5 - Star 33"
|
||||
sand_canyon_5_s34 = "Sand Canyon 5 - Star 34"
|
||||
sand_canyon_5_s35 = "Sand Canyon 5 - Star 35"
|
||||
sand_canyon_5_s36 = "Sand Canyon 5 - Star 36"
|
||||
sand_canyon_5_s37 = "Sand Canyon 5 - Star 37"
|
||||
sand_canyon_5_s38 = "Sand Canyon 5 - Star 38"
|
||||
sand_canyon_5_s39 = "Sand Canyon 5 - Star 39"
|
||||
sand_canyon_5_s40 = "Sand Canyon 5 - Star 40"
|
||||
cloudy_park_1_s1 = "Cloudy Park 1 - Star 1"
|
||||
cloudy_park_1_s2 = "Cloudy Park 1 - Star 2"
|
||||
cloudy_park_1_s3 = "Cloudy Park 1 - Star 3"
|
||||
cloudy_park_1_s4 = "Cloudy Park 1 - Star 4"
|
||||
cloudy_park_1_s5 = "Cloudy Park 1 - Star 5"
|
||||
cloudy_park_1_s6 = "Cloudy Park 1 - Star 6"
|
||||
cloudy_park_1_s7 = "Cloudy Park 1 - Star 7"
|
||||
cloudy_park_1_s8 = "Cloudy Park 1 - Star 8"
|
||||
cloudy_park_1_s9 = "Cloudy Park 1 - Star 9"
|
||||
cloudy_park_1_s10 = "Cloudy Park 1 - Star 10"
|
||||
cloudy_park_1_s11 = "Cloudy Park 1 - Star 11"
|
||||
cloudy_park_1_s12 = "Cloudy Park 1 - Star 12"
|
||||
cloudy_park_1_s13 = "Cloudy Park 1 - Star 13"
|
||||
cloudy_park_1_s14 = "Cloudy Park 1 - Star 14"
|
||||
cloudy_park_1_s15 = "Cloudy Park 1 - Star 15"
|
||||
cloudy_park_1_s16 = "Cloudy Park 1 - Star 16"
|
||||
cloudy_park_1_s17 = "Cloudy Park 1 - Star 17"
|
||||
cloudy_park_1_s18 = "Cloudy Park 1 - Star 18"
|
||||
cloudy_park_1_s19 = "Cloudy Park 1 - Star 19"
|
||||
cloudy_park_1_s20 = "Cloudy Park 1 - Star 20"
|
||||
cloudy_park_1_s21 = "Cloudy Park 1 - Star 21"
|
||||
cloudy_park_1_s22 = "Cloudy Park 1 - Star 22"
|
||||
cloudy_park_1_s23 = "Cloudy Park 1 - Star 23"
|
||||
cloudy_park_2_s1 = "Cloudy Park 2 - Star 1"
|
||||
cloudy_park_2_s2 = "Cloudy Park 2 - Star 2"
|
||||
cloudy_park_2_s3 = "Cloudy Park 2 - Star 3"
|
||||
cloudy_park_2_s4 = "Cloudy Park 2 - Star 4"
|
||||
cloudy_park_2_s5 = "Cloudy Park 2 - Star 5"
|
||||
cloudy_park_2_s6 = "Cloudy Park 2 - Star 6"
|
||||
cloudy_park_2_s7 = "Cloudy Park 2 - Star 7"
|
||||
cloudy_park_2_s8 = "Cloudy Park 2 - Star 8"
|
||||
cloudy_park_2_s9 = "Cloudy Park 2 - Star 9"
|
||||
cloudy_park_2_s10 = "Cloudy Park 2 - Star 10"
|
||||
cloudy_park_2_s11 = "Cloudy Park 2 - Star 11"
|
||||
cloudy_park_2_s12 = "Cloudy Park 2 - Star 12"
|
||||
cloudy_park_2_s13 = "Cloudy Park 2 - Star 13"
|
||||
cloudy_park_2_s14 = "Cloudy Park 2 - Star 14"
|
||||
cloudy_park_2_s15 = "Cloudy Park 2 - Star 15"
|
||||
cloudy_park_2_s16 = "Cloudy Park 2 - Star 16"
|
||||
cloudy_park_2_s17 = "Cloudy Park 2 - Star 17"
|
||||
cloudy_park_2_s18 = "Cloudy Park 2 - Star 18"
|
||||
cloudy_park_2_s19 = "Cloudy Park 2 - Star 19"
|
||||
cloudy_park_2_s20 = "Cloudy Park 2 - Star 20"
|
||||
cloudy_park_2_s21 = "Cloudy Park 2 - Star 21"
|
||||
cloudy_park_2_s22 = "Cloudy Park 2 - Star 22"
|
||||
cloudy_park_2_s23 = "Cloudy Park 2 - Star 23"
|
||||
cloudy_park_2_s24 = "Cloudy Park 2 - Star 24"
|
||||
cloudy_park_2_s25 = "Cloudy Park 2 - Star 25"
|
||||
cloudy_park_2_s26 = "Cloudy Park 2 - Star 26"
|
||||
cloudy_park_2_s27 = "Cloudy Park 2 - Star 27"
|
||||
cloudy_park_2_s28 = "Cloudy Park 2 - Star 28"
|
||||
cloudy_park_2_s29 = "Cloudy Park 2 - Star 29"
|
||||
cloudy_park_2_s30 = "Cloudy Park 2 - Star 30"
|
||||
cloudy_park_2_s31 = "Cloudy Park 2 - Star 31"
|
||||
cloudy_park_2_s32 = "Cloudy Park 2 - Star 32"
|
||||
cloudy_park_2_s33 = "Cloudy Park 2 - Star 33"
|
||||
cloudy_park_2_s34 = "Cloudy Park 2 - Star 34"
|
||||
cloudy_park_2_s35 = "Cloudy Park 2 - Star 35"
|
||||
cloudy_park_2_s36 = "Cloudy Park 2 - Star 36"
|
||||
cloudy_park_2_s37 = "Cloudy Park 2 - Star 37"
|
||||
cloudy_park_2_s38 = "Cloudy Park 2 - Star 38"
|
||||
cloudy_park_2_s39 = "Cloudy Park 2 - Star 39"
|
||||
cloudy_park_2_s40 = "Cloudy Park 2 - Star 40"
|
||||
cloudy_park_2_s41 = "Cloudy Park 2 - Star 41"
|
||||
cloudy_park_2_s42 = "Cloudy Park 2 - Star 42"
|
||||
cloudy_park_2_s43 = "Cloudy Park 2 - Star 43"
|
||||
cloudy_park_2_s44 = "Cloudy Park 2 - Star 44"
|
||||
cloudy_park_2_s45 = "Cloudy Park 2 - Star 45"
|
||||
cloudy_park_2_s46 = "Cloudy Park 2 - Star 46"
|
||||
cloudy_park_2_s47 = "Cloudy Park 2 - Star 47"
|
||||
cloudy_park_2_s48 = "Cloudy Park 2 - Star 48"
|
||||
cloudy_park_2_s49 = "Cloudy Park 2 - Star 49"
|
||||
cloudy_park_2_s50 = "Cloudy Park 2 - Star 50"
|
||||
cloudy_park_2_s51 = "Cloudy Park 2 - Star 51"
|
||||
cloudy_park_2_s52 = "Cloudy Park 2 - Star 52"
|
||||
cloudy_park_2_s53 = "Cloudy Park 2 - Star 53"
|
||||
cloudy_park_2_s54 = "Cloudy Park 2 - Star 54"
|
||||
cloudy_park_3_s1 = "Cloudy Park 3 - Star 1"
|
||||
cloudy_park_3_s2 = "Cloudy Park 3 - Star 2"
|
||||
cloudy_park_3_s3 = "Cloudy Park 3 - Star 3"
|
||||
cloudy_park_3_s4 = "Cloudy Park 3 - Star 4"
|
||||
cloudy_park_3_s5 = "Cloudy Park 3 - Star 5"
|
||||
cloudy_park_3_s6 = "Cloudy Park 3 - Star 6"
|
||||
cloudy_park_3_s7 = "Cloudy Park 3 - Star 7"
|
||||
cloudy_park_3_s8 = "Cloudy Park 3 - Star 8"
|
||||
cloudy_park_3_s9 = "Cloudy Park 3 - Star 9"
|
||||
cloudy_park_3_s10 = "Cloudy Park 3 - Star 10"
|
||||
cloudy_park_3_s11 = "Cloudy Park 3 - Star 11"
|
||||
cloudy_park_3_s12 = "Cloudy Park 3 - Star 12"
|
||||
cloudy_park_3_s13 = "Cloudy Park 3 - Star 13"
|
||||
cloudy_park_3_s14 = "Cloudy Park 3 - Star 14"
|
||||
cloudy_park_3_s15 = "Cloudy Park 3 - Star 15"
|
||||
cloudy_park_3_s16 = "Cloudy Park 3 - Star 16"
|
||||
cloudy_park_3_s17 = "Cloudy Park 3 - Star 17"
|
||||
cloudy_park_3_s18 = "Cloudy Park 3 - Star 18"
|
||||
cloudy_park_3_s19 = "Cloudy Park 3 - Star 19"
|
||||
cloudy_park_3_s20 = "Cloudy Park 3 - Star 20"
|
||||
cloudy_park_3_s21 = "Cloudy Park 3 - Star 21"
|
||||
cloudy_park_3_s22 = "Cloudy Park 3 - Star 22"
|
||||
cloudy_park_4_s1 = "Cloudy Park 4 - Star 1"
|
||||
cloudy_park_4_s2 = "Cloudy Park 4 - Star 2"
|
||||
cloudy_park_4_s3 = "Cloudy Park 4 - Star 3"
|
||||
cloudy_park_4_s4 = "Cloudy Park 4 - Star 4"
|
||||
cloudy_park_4_s5 = "Cloudy Park 4 - Star 5"
|
||||
cloudy_park_4_s6 = "Cloudy Park 4 - Star 6"
|
||||
cloudy_park_4_s7 = "Cloudy Park 4 - Star 7"
|
||||
cloudy_park_4_s8 = "Cloudy Park 4 - Star 8"
|
||||
cloudy_park_4_s9 = "Cloudy Park 4 - Star 9"
|
||||
cloudy_park_4_s10 = "Cloudy Park 4 - Star 10"
|
||||
cloudy_park_4_s11 = "Cloudy Park 4 - Star 11"
|
||||
cloudy_park_4_s12 = "Cloudy Park 4 - Star 12"
|
||||
cloudy_park_4_s13 = "Cloudy Park 4 - Star 13"
|
||||
cloudy_park_4_s14 = "Cloudy Park 4 - Star 14"
|
||||
cloudy_park_4_s15 = "Cloudy Park 4 - Star 15"
|
||||
cloudy_park_4_s16 = "Cloudy Park 4 - Star 16"
|
||||
cloudy_park_4_s17 = "Cloudy Park 4 - Star 17"
|
||||
cloudy_park_4_s18 = "Cloudy Park 4 - Star 18"
|
||||
cloudy_park_4_s19 = "Cloudy Park 4 - Star 19"
|
||||
cloudy_park_4_s20 = "Cloudy Park 4 - Star 20"
|
||||
cloudy_park_4_s21 = "Cloudy Park 4 - Star 21"
|
||||
cloudy_park_4_s22 = "Cloudy Park 4 - Star 22"
|
||||
cloudy_park_4_s23 = "Cloudy Park 4 - Star 23"
|
||||
cloudy_park_4_s24 = "Cloudy Park 4 - Star 24"
|
||||
cloudy_park_4_s25 = "Cloudy Park 4 - Star 25"
|
||||
cloudy_park_4_s26 = "Cloudy Park 4 - Star 26"
|
||||
cloudy_park_4_s27 = "Cloudy Park 4 - Star 27"
|
||||
cloudy_park_4_s28 = "Cloudy Park 4 - Star 28"
|
||||
cloudy_park_4_s29 = "Cloudy Park 4 - Star 29"
|
||||
cloudy_park_4_s30 = "Cloudy Park 4 - Star 30"
|
||||
cloudy_park_4_s31 = "Cloudy Park 4 - Star 31"
|
||||
cloudy_park_4_s32 = "Cloudy Park 4 - Star 32"
|
||||
cloudy_park_4_s33 = "Cloudy Park 4 - Star 33"
|
||||
cloudy_park_4_s34 = "Cloudy Park 4 - Star 34"
|
||||
cloudy_park_4_s35 = "Cloudy Park 4 - Star 35"
|
||||
cloudy_park_4_s36 = "Cloudy Park 4 - Star 36"
|
||||
cloudy_park_4_s37 = "Cloudy Park 4 - Star 37"
|
||||
cloudy_park_4_s38 = "Cloudy Park 4 - Star 38"
|
||||
cloudy_park_4_s39 = "Cloudy Park 4 - Star 39"
|
||||
cloudy_park_4_s40 = "Cloudy Park 4 - Star 40"
|
||||
cloudy_park_4_s41 = "Cloudy Park 4 - Star 41"
|
||||
cloudy_park_4_s42 = "Cloudy Park 4 - Star 42"
|
||||
cloudy_park_4_s43 = "Cloudy Park 4 - Star 43"
|
||||
cloudy_park_4_s44 = "Cloudy Park 4 - Star 44"
|
||||
cloudy_park_4_s45 = "Cloudy Park 4 - Star 45"
|
||||
cloudy_park_4_s46 = "Cloudy Park 4 - Star 46"
|
||||
cloudy_park_4_s47 = "Cloudy Park 4 - Star 47"
|
||||
cloudy_park_4_s48 = "Cloudy Park 4 - Star 48"
|
||||
cloudy_park_4_s49 = "Cloudy Park 4 - Star 49"
|
||||
cloudy_park_4_s50 = "Cloudy Park 4 - Star 50"
|
||||
cloudy_park_5_s1 = "Cloudy Park 5 - Star 1"
|
||||
cloudy_park_5_s2 = "Cloudy Park 5 - Star 2"
|
||||
cloudy_park_5_s3 = "Cloudy Park 5 - Star 3"
|
||||
cloudy_park_5_s4 = "Cloudy Park 5 - Star 4"
|
||||
cloudy_park_5_s5 = "Cloudy Park 5 - Star 5"
|
||||
cloudy_park_5_s6 = "Cloudy Park 5 - Star 6"
|
||||
cloudy_park_6_s1 = "Cloudy Park 6 - Star 1"
|
||||
cloudy_park_6_s2 = "Cloudy Park 6 - Star 2"
|
||||
cloudy_park_6_s3 = "Cloudy Park 6 - Star 3"
|
||||
cloudy_park_6_s4 = "Cloudy Park 6 - Star 4"
|
||||
cloudy_park_6_s5 = "Cloudy Park 6 - Star 5"
|
||||
cloudy_park_6_s6 = "Cloudy Park 6 - Star 6"
|
||||
cloudy_park_6_s7 = "Cloudy Park 6 - Star 7"
|
||||
cloudy_park_6_s8 = "Cloudy Park 6 - Star 8"
|
||||
cloudy_park_6_s9 = "Cloudy Park 6 - Star 9"
|
||||
cloudy_park_6_s10 = "Cloudy Park 6 - Star 10"
|
||||
cloudy_park_6_s11 = "Cloudy Park 6 - Star 11"
|
||||
cloudy_park_6_s12 = "Cloudy Park 6 - Star 12"
|
||||
cloudy_park_6_s13 = "Cloudy Park 6 - Star 13"
|
||||
cloudy_park_6_s14 = "Cloudy Park 6 - Star 14"
|
||||
cloudy_park_6_s15 = "Cloudy Park 6 - Star 15"
|
||||
cloudy_park_6_s16 = "Cloudy Park 6 - Star 16"
|
||||
cloudy_park_6_s17 = "Cloudy Park 6 - Star 17"
|
||||
cloudy_park_6_s18 = "Cloudy Park 6 - Star 18"
|
||||
cloudy_park_6_s19 = "Cloudy Park 6 - Star 19"
|
||||
cloudy_park_6_s20 = "Cloudy Park 6 - Star 20"
|
||||
cloudy_park_6_s21 = "Cloudy Park 6 - Star 21"
|
||||
cloudy_park_6_s22 = "Cloudy Park 6 - Star 22"
|
||||
cloudy_park_6_s23 = "Cloudy Park 6 - Star 23"
|
||||
cloudy_park_6_s24 = "Cloudy Park 6 - Star 24"
|
||||
cloudy_park_6_s25 = "Cloudy Park 6 - Star 25"
|
||||
cloudy_park_6_s26 = "Cloudy Park 6 - Star 26"
|
||||
cloudy_park_6_s27 = "Cloudy Park 6 - Star 27"
|
||||
cloudy_park_6_s28 = "Cloudy Park 6 - Star 28"
|
||||
cloudy_park_6_s29 = "Cloudy Park 6 - Star 29"
|
||||
cloudy_park_6_s30 = "Cloudy Park 6 - Star 30"
|
||||
cloudy_park_6_s31 = "Cloudy Park 6 - Star 31"
|
||||
cloudy_park_6_s32 = "Cloudy Park 6 - Star 32"
|
||||
cloudy_park_6_s33 = "Cloudy Park 6 - Star 33"
|
||||
iceberg_1_s1 = "Iceberg 1 - Star 1"
|
||||
iceberg_1_s2 = "Iceberg 1 - Star 2"
|
||||
iceberg_1_s3 = "Iceberg 1 - Star 3"
|
||||
iceberg_1_s4 = "Iceberg 1 - Star 4"
|
||||
iceberg_1_s5 = "Iceberg 1 - Star 5"
|
||||
iceberg_1_s6 = "Iceberg 1 - Star 6"
|
||||
iceberg_2_s1 = "Iceberg 2 - Star 1"
|
||||
iceberg_2_s2 = "Iceberg 2 - Star 2"
|
||||
iceberg_2_s3 = "Iceberg 2 - Star 3"
|
||||
iceberg_2_s4 = "Iceberg 2 - Star 4"
|
||||
iceberg_2_s5 = "Iceberg 2 - Star 5"
|
||||
iceberg_2_s6 = "Iceberg 2 - Star 6"
|
||||
iceberg_2_s7 = "Iceberg 2 - Star 7"
|
||||
iceberg_2_s8 = "Iceberg 2 - Star 8"
|
||||
iceberg_2_s9 = "Iceberg 2 - Star 9"
|
||||
iceberg_2_s10 = "Iceberg 2 - Star 10"
|
||||
iceberg_2_s11 = "Iceberg 2 - Star 11"
|
||||
iceberg_2_s12 = "Iceberg 2 - Star 12"
|
||||
iceberg_2_s13 = "Iceberg 2 - Star 13"
|
||||
iceberg_2_s14 = "Iceberg 2 - Star 14"
|
||||
iceberg_2_s15 = "Iceberg 2 - Star 15"
|
||||
iceberg_2_s16 = "Iceberg 2 - Star 16"
|
||||
iceberg_2_s17 = "Iceberg 2 - Star 17"
|
||||
iceberg_2_s18 = "Iceberg 2 - Star 18"
|
||||
iceberg_2_s19 = "Iceberg 2 - Star 19"
|
||||
iceberg_3_s1 = "Iceberg 3 - Star 1"
|
||||
iceberg_3_s2 = "Iceberg 3 - Star 2"
|
||||
iceberg_3_s3 = "Iceberg 3 - Star 3"
|
||||
iceberg_3_s4 = "Iceberg 3 - Star 4"
|
||||
iceberg_3_s5 = "Iceberg 3 - Star 5"
|
||||
iceberg_3_s6 = "Iceberg 3 - Star 6"
|
||||
iceberg_3_s7 = "Iceberg 3 - Star 7"
|
||||
iceberg_3_s8 = "Iceberg 3 - Star 8"
|
||||
iceberg_3_s9 = "Iceberg 3 - Star 9"
|
||||
iceberg_3_s10 = "Iceberg 3 - Star 10"
|
||||
iceberg_3_s11 = "Iceberg 3 - Star 11"
|
||||
iceberg_3_s12 = "Iceberg 3 - Star 12"
|
||||
iceberg_3_s13 = "Iceberg 3 - Star 13"
|
||||
iceberg_3_s14 = "Iceberg 3 - Star 14"
|
||||
iceberg_3_s15 = "Iceberg 3 - Star 15"
|
||||
iceberg_3_s16 = "Iceberg 3 - Star 16"
|
||||
iceberg_3_s17 = "Iceberg 3 - Star 17"
|
||||
iceberg_3_s18 = "Iceberg 3 - Star 18"
|
||||
iceberg_3_s19 = "Iceberg 3 - Star 19"
|
||||
iceberg_3_s20 = "Iceberg 3 - Star 20"
|
||||
iceberg_3_s21 = "Iceberg 3 - Star 21"
|
||||
iceberg_4_s1 = "Iceberg 4 - Star 1"
|
||||
iceberg_4_s2 = "Iceberg 4 - Star 2"
|
||||
iceberg_4_s3 = "Iceberg 4 - Star 3"
|
||||
iceberg_5_s1 = "Iceberg 5 - Star 1"
|
||||
iceberg_5_s2 = "Iceberg 5 - Star 2"
|
||||
iceberg_5_s3 = "Iceberg 5 - Star 3"
|
||||
iceberg_5_s4 = "Iceberg 5 - Star 4"
|
||||
iceberg_5_s5 = "Iceberg 5 - Star 5"
|
||||
iceberg_5_s6 = "Iceberg 5 - Star 6"
|
||||
iceberg_5_s7 = "Iceberg 5 - Star 7"
|
||||
iceberg_5_s8 = "Iceberg 5 - Star 8"
|
||||
iceberg_5_s9 = "Iceberg 5 - Star 9"
|
||||
iceberg_5_s10 = "Iceberg 5 - Star 10"
|
||||
iceberg_5_s11 = "Iceberg 5 - Star 11"
|
||||
iceberg_5_s12 = "Iceberg 5 - Star 12"
|
||||
iceberg_5_s13 = "Iceberg 5 - Star 13"
|
||||
iceberg_5_s14 = "Iceberg 5 - Star 14"
|
||||
iceberg_5_s15 = "Iceberg 5 - Star 15"
|
||||
iceberg_5_s16 = "Iceberg 5 - Star 16"
|
||||
iceberg_5_s17 = "Iceberg 5 - Star 17"
|
||||
iceberg_5_s18 = "Iceberg 5 - Star 18"
|
||||
iceberg_5_s19 = "Iceberg 5 - Star 19"
|
||||
iceberg_5_s20 = "Iceberg 5 - Star 20"
|
||||
iceberg_5_s21 = "Iceberg 5 - Star 21"
|
||||
iceberg_5_s22 = "Iceberg 5 - Star 22"
|
||||
iceberg_5_s23 = "Iceberg 5 - Star 23"
|
||||
iceberg_5_s24 = "Iceberg 5 - Star 24"
|
||||
iceberg_5_s25 = "Iceberg 5 - Star 25"
|
||||
iceberg_5_s26 = "Iceberg 5 - Star 26"
|
||||
iceberg_5_s27 = "Iceberg 5 - Star 27"
|
||||
iceberg_5_s28 = "Iceberg 5 - Star 28"
|
||||
iceberg_5_s29 = "Iceberg 5 - Star 29"
|
||||
iceberg_5_s30 = "Iceberg 5 - Star 30"
|
||||
iceberg_5_s31 = "Iceberg 5 - Star 31"
|
||||
iceberg_5_s32 = "Iceberg 5 - Star 32"
|
||||
iceberg_5_s33 = "Iceberg 5 - Star 33"
|
||||
iceberg_5_s34 = "Iceberg 5 - Star 34"
|
||||
iceberg_6_s1 = "Iceberg 6 - Star 1"
|
0
worlds/kdl3/Names/__init__.py
Normal file
0
worlds/kdl3/Names/__init__.py
Normal file
432
worlds/kdl3/Options.py
Normal file
432
worlds/kdl3/Options.py
Normal file
@@ -0,0 +1,432 @@
|
||||
import random
|
||||
from dataclasses import dataclass
|
||||
|
||||
from Options import DeathLink, Choice, Toggle, OptionDict, Range, PlandoBosses, DefaultOnToggle, \
|
||||
PerGameCommonOptions
|
||||
from .Names import LocationName
|
||||
|
||||
|
||||
class Goal(Choice):
|
||||
"""
|
||||
Zero: collect the Heart Stars, and defeat Zero in the Hyper Zone.
|
||||
Boss Butch: collect the Heart Stars, and then complete the boss rematches in the Boss Butch mode.
|
||||
MG5: collect the Heart Stars, and then complete a perfect run through the minigame gauntlet within the Super MG5
|
||||
Jumping: collect the Heart Stars, and then reach a designated score within the Jumping sub-game
|
||||
"""
|
||||
display_name = "Goal"
|
||||
option_zero = 0
|
||||
option_boss_butch = 1
|
||||
option_MG5 = 2
|
||||
option_jumping = 3
|
||||
default = 0
|
||||
|
||||
@classmethod
|
||||
def get_option_name(cls, value: int) -> str:
|
||||
if value == 2:
|
||||
return cls.name_lookup[value].upper()
|
||||
return super().get_option_name(value)
|
||||
|
||||
class GoalSpeed(Choice):
|
||||
"""
|
||||
Normal: the goal is unlocked after purifying the five bosses
|
||||
Fast: the goal is unlocked after acquiring the target number of Heart Stars
|
||||
"""
|
||||
display_name = "Goal Speed"
|
||||
option_normal = 0
|
||||
option_fast = 1
|
||||
|
||||
|
||||
class TotalHeartStars(Range):
|
||||
"""
|
||||
Maximum number of heart stars to include in the pool of items.
|
||||
"""
|
||||
display_name = "Max Heart Stars"
|
||||
range_start = 5 # set to 5 so strict bosses does not degrade
|
||||
range_end = 50 # 30 default locations + 30 stage clears + 5 bosses - 14 progression items = 51, so round down
|
||||
default = 30
|
||||
|
||||
|
||||
class HeartStarsRequired(Range):
|
||||
"""
|
||||
Percentage of heart stars required to purify the five bosses and reach Zero.
|
||||
Each boss will require a differing amount of heart stars to purify.
|
||||
"""
|
||||
display_name = "Required Heart Stars"
|
||||
range_start = 1
|
||||
range_end = 100
|
||||
default = 50
|
||||
|
||||
|
||||
class LevelShuffle(Choice):
|
||||
"""
|
||||
None: No stage shuffling.
|
||||
Same World: shuffles stages around their world.
|
||||
Pattern: shuffles stages according to the stage pattern (stage 3 will always be a minigame stage, etc.)
|
||||
Shuffled: shuffles stages across all worlds.
|
||||
"""
|
||||
display_name = "Stage Shuffle"
|
||||
option_none = 0
|
||||
option_same_world = 1
|
||||
option_pattern = 2
|
||||
option_shuffled = 3
|
||||
default = 0
|
||||
|
||||
|
||||
class BossShuffle(PlandoBosses):
|
||||
"""
|
||||
None: Bosses will remain in their vanilla locations
|
||||
Shuffled: Bosses will be shuffled amongst each other
|
||||
Full: Bosses will be randomized
|
||||
Singularity: All (non-Zero) bosses will be replaced with a single boss
|
||||
Supports plando placement.
|
||||
"""
|
||||
bosses = frozenset(LocationName.boss_names.keys())
|
||||
|
||||
locations = frozenset(LocationName.level_names.keys())
|
||||
|
||||
duplicate_bosses = True
|
||||
|
||||
@classmethod
|
||||
def can_place_boss(cls, boss: str, location: str) -> bool:
|
||||
# Kirby has no logic about requiring bosses in specific locations (since we load in their stage)
|
||||
return True
|
||||
|
||||
display_name = "Boss Shuffle"
|
||||
option_none = 0
|
||||
option_shuffled = 1
|
||||
option_full = 2
|
||||
option_singularity = 3
|
||||
|
||||
|
||||
class BossShuffleAllowBB(Choice):
|
||||
"""
|
||||
Allow Boss Butch variants of bosses in Boss Shuffle.
|
||||
Enabled: any boss placed will have a 50% chance of being the Boss Butch variant, including bosses not present
|
||||
Enforced: all bosses will be their Boss Butch variant.
|
||||
Boss Butch boss changes are only visual.
|
||||
"""
|
||||
display_name = "Allow Boss Butch Bosses"
|
||||
option_disabled = 0
|
||||
option_enabled = 1
|
||||
option_enforced = 2
|
||||
default = 0
|
||||
|
||||
|
||||
class AnimalRandomization(Choice):
|
||||
"""
|
||||
Disabled: all animal positions will be vanilla.
|
||||
Shuffled: all animal positions will be shuffled amongst each other.
|
||||
Full: random animals will be placed across the levels. At least one of each animal is guaranteed.
|
||||
"""
|
||||
display_name = "Animal Randomization"
|
||||
option_disabled = 0
|
||||
option_shuffled = 1
|
||||
option_full = 2
|
||||
default = 0
|
||||
|
||||
|
||||
class CopyAbilityRandomization(Choice):
|
||||
"""
|
||||
Disabled: enemies give regular copy abilities and health.
|
||||
Enabled: all enemies will have the copy ability received from them randomized.
|
||||
Enabled Plus Minus: enemies (except minibosses) can additionally give you anywhere from +2 health to -1 health when eaten.
|
||||
"""
|
||||
display_name = "Copy Ability Randomization"
|
||||
option_disabled = 0
|
||||
option_enabled = 1
|
||||
option_enabled_plus_minus = 2
|
||||
|
||||
|
||||
class StrictBosses(DefaultOnToggle):
|
||||
"""
|
||||
If enabled, one will not be able to move onto the next world until the previous world's boss has been purified.
|
||||
"""
|
||||
display_name = "Strict Bosses"
|
||||
|
||||
|
||||
class OpenWorld(DefaultOnToggle):
|
||||
"""
|
||||
If enabled, all 6 stages will be unlocked upon entering a world for the first time. A certain amount of stages
|
||||
will need to be completed in order to unlock the bosses
|
||||
"""
|
||||
display_name = "Open World"
|
||||
|
||||
|
||||
class OpenWorldBossRequirement(Range):
|
||||
"""
|
||||
The amount of stages completed needed to unlock the boss of a world when Open World is turned on.
|
||||
"""
|
||||
display_name = "Open World Boss Requirement"
|
||||
range_start = 1
|
||||
range_end = 6
|
||||
default = 3
|
||||
|
||||
|
||||
class BossRequirementRandom(Toggle):
|
||||
"""
|
||||
If enabled, boss purification will require a random amount of Heart Stars. Depending on options, this may have
|
||||
boss purification unlock in a random order.
|
||||
"""
|
||||
display_name = "Randomize Purification Requirement"
|
||||
|
||||
|
||||
class JumpingTarget(Range):
|
||||
"""
|
||||
The required score needed to complete the Jumping minigame.
|
||||
"""
|
||||
display_name = "Jumping Target Score"
|
||||
range_start = 1
|
||||
range_end = 25
|
||||
default = 10
|
||||
|
||||
|
||||
class GameLanguage(Choice):
|
||||
"""
|
||||
The language that the game should display. This does not have to match the given rom.
|
||||
"""
|
||||
display_name = "Game Language"
|
||||
option_japanese = 0
|
||||
option_english = 1
|
||||
default = 1
|
||||
|
||||
|
||||
class FillerPercentage(Range):
|
||||
"""
|
||||
Percentage of non-required Heart Stars to be converted to filler items (1-Ups, Maxim Tomatoes, Invincibility Candy).
|
||||
"""
|
||||
display_name = "Filler Percentage"
|
||||
range_start = 0
|
||||
range_end = 100
|
||||
default = 50
|
||||
|
||||
|
||||
class TrapPercentage(Range):
|
||||
"""
|
||||
Percentage of filler items to be converted to trap items (Gooey Bags, Slowness, Eject Ability).
|
||||
"""
|
||||
display_name = "Trap Percentage"
|
||||
range_start = 0
|
||||
range_end = 100
|
||||
default = 50
|
||||
|
||||
|
||||
class GooeyTrapPercentage(Range):
|
||||
"""
|
||||
Chance that any given trap is a Gooey Bag (spawns Gooey when you receive it).
|
||||
"""
|
||||
display_name = "Gooey Trap Percentage"
|
||||
range_start = 0
|
||||
range_end = 100
|
||||
default = 50
|
||||
|
||||
|
||||
class SlowTrapPercentage(Range):
|
||||
"""
|
||||
Chance that any given trap is Slowness (halves your max speed for 15 seconds when you receive it).
|
||||
"""
|
||||
display_name = "Slowness Trap Percentage"
|
||||
range_start = 0
|
||||
range_end = 100
|
||||
default = 50
|
||||
|
||||
|
||||
class AbilityTrapPercentage(Range):
|
||||
"""
|
||||
Chance that any given trap is an Eject Ability (ejects your ability when you receive it).
|
||||
"""
|
||||
display_name = "Ability Trap Percentage"
|
||||
range_start = 0
|
||||
range_end = 100
|
||||
default = 50
|
||||
|
||||
|
||||
class ConsumableChecks(Toggle):
|
||||
"""
|
||||
When enabled, adds all 1-Ups and Maxim Tomatoes as possible locations.
|
||||
"""
|
||||
display_name = "Consumable-sanity"
|
||||
|
||||
|
||||
class StarChecks(Toggle):
|
||||
"""
|
||||
When enabled, every star in a given stage will become a check.
|
||||
Will increase the possible filler pool to include 1/3/5 stars.
|
||||
"""
|
||||
display_name = "Starsanity"
|
||||
|
||||
|
||||
class KirbyFlavorPreset(Choice):
|
||||
"""
|
||||
The color of Kirby, from a list of presets.
|
||||
"""
|
||||
display_name = "Kirby Flavor"
|
||||
option_default = 0
|
||||
option_bubblegum = 1
|
||||
option_cherry = 2
|
||||
option_blueberry = 3
|
||||
option_lemon = 4
|
||||
option_kiwi = 5
|
||||
option_grape = 6
|
||||
option_chocolate = 7
|
||||
option_marshmallow = 8
|
||||
option_licorice = 9
|
||||
option_watermelon = 10
|
||||
option_orange = 11
|
||||
option_lime = 12
|
||||
option_lavender = 13
|
||||
option_custom = 14
|
||||
default = 0
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, text: str) -> Choice:
|
||||
text = text.lower()
|
||||
if text == "random":
|
||||
choice_list = list(cls.name_lookup)
|
||||
choice_list.remove(14)
|
||||
return cls(random.choice(choice_list))
|
||||
return super().from_text(text)
|
||||
|
||||
|
||||
class KirbyFlavor(OptionDict):
|
||||
"""
|
||||
A custom color for Kirby. To use a custom color, set the preset to Custom and then define a dict of keys from "1" to
|
||||
"15", with their values being an HTML hex color.
|
||||
"""
|
||||
default = {
|
||||
"1": "B01810",
|
||||
"2": "F0E0E8",
|
||||
"3": "C8A0A8",
|
||||
"4": "A87070",
|
||||
"5": "E02018",
|
||||
"6": "F0A0B8",
|
||||
"7": "D07880",
|
||||
"8": "A85048",
|
||||
"9": "E8D0D0",
|
||||
"10": "E85048",
|
||||
"11": "D0C0C0",
|
||||
"12": "B08888",
|
||||
"13": "E87880",
|
||||
"14": "F8F8F8",
|
||||
"15": "B03830",
|
||||
}
|
||||
|
||||
|
||||
class GooeyFlavorPreset(Choice):
|
||||
"""
|
||||
The color of Gooey, from a list of presets.
|
||||
"""
|
||||
display_name = "Gooey Flavor"
|
||||
option_default = 0
|
||||
option_bubblegum = 1
|
||||
option_cherry = 2
|
||||
option_blueberry = 3
|
||||
option_lemon = 4
|
||||
option_kiwi = 5
|
||||
option_grape = 6
|
||||
option_chocolate = 7
|
||||
option_marshmallow = 8
|
||||
option_licorice = 9
|
||||
option_watermelon = 10
|
||||
option_orange = 11
|
||||
option_lime = 12
|
||||
option_lavender = 13
|
||||
option_custom = 14
|
||||
default = 0
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, text: str) -> Choice:
|
||||
text = text.lower()
|
||||
if text == "random":
|
||||
choice_list = list(cls.name_lookup)
|
||||
choice_list.remove(14)
|
||||
return cls(random.choice(choice_list))
|
||||
return super().from_text(text)
|
||||
|
||||
|
||||
class GooeyFlavor(OptionDict):
|
||||
"""
|
||||
A custom color for Gooey. To use a custom color, set the preset to Custom and then define a dict of keys from "1" to
|
||||
"15", with their values being an HTML hex color.
|
||||
"""
|
||||
default = {
|
||||
"1": "000808",
|
||||
"2": "102838",
|
||||
"3": "183048",
|
||||
"4": "183878",
|
||||
"5": "1838A0",
|
||||
"6": "B01810",
|
||||
"7": "E85048",
|
||||
"8": "D0C0C0",
|
||||
"9": "F8F8F8",
|
||||
}
|
||||
|
||||
|
||||
class MusicShuffle(Choice):
|
||||
"""
|
||||
None: default music will play
|
||||
Shuffled: music will be shuffled amongst each other
|
||||
Full: random music will play in each room
|
||||
Note that certain songs will not be chosen in shuffled or full
|
||||
"""
|
||||
display_name = "Music Randomization"
|
||||
option_none = 0
|
||||
option_shuffled = 1
|
||||
option_full = 2
|
||||
default = 0
|
||||
|
||||
|
||||
class VirtualConsoleChanges(Choice):
|
||||
"""
|
||||
Adds the ability to enable 2 of the Virtual Console changes.
|
||||
Flash Reduction: reduces the flashing during the Zero battle.
|
||||
Color Changes: changes the color of the background within the Zero Boss Butch rematch.
|
||||
"""
|
||||
display_name = "Virtual Console Changes"
|
||||
option_none = 0
|
||||
option_flash_reduction = 1
|
||||
option_color_changes = 2
|
||||
option_both = 3
|
||||
default = 1
|
||||
|
||||
|
||||
class Gifting(Toggle):
|
||||
"""
|
||||
When enabled, the goal game item will be sent to other compatible games as a gift,
|
||||
and you can receive gifts from other players. This can be enabled during gameplay
|
||||
using the client.
|
||||
"""
|
||||
display_name = "Gifting"
|
||||
|
||||
|
||||
@dataclass
|
||||
class KDL3Options(PerGameCommonOptions):
|
||||
death_link: DeathLink
|
||||
game_language: GameLanguage
|
||||
goal: Goal
|
||||
goal_speed: GoalSpeed
|
||||
total_heart_stars: TotalHeartStars
|
||||
heart_stars_required: HeartStarsRequired
|
||||
filler_percentage: FillerPercentage
|
||||
trap_percentage: TrapPercentage
|
||||
gooey_trap_weight: GooeyTrapPercentage
|
||||
slow_trap_weight: SlowTrapPercentage
|
||||
ability_trap_weight: AbilityTrapPercentage
|
||||
jumping_target: JumpingTarget
|
||||
stage_shuffle: LevelShuffle
|
||||
boss_shuffle: BossShuffle
|
||||
allow_bb: BossShuffleAllowBB
|
||||
animal_randomization: AnimalRandomization
|
||||
copy_ability_randomization: CopyAbilityRandomization
|
||||
strict_bosses: StrictBosses
|
||||
open_world: OpenWorld
|
||||
ow_boss_requirement: OpenWorldBossRequirement
|
||||
boss_requirement_random: BossRequirementRandom
|
||||
consumables: ConsumableChecks
|
||||
starsanity: StarChecks
|
||||
gifting: Gifting
|
||||
kirby_flavor_preset: KirbyFlavorPreset
|
||||
kirby_flavor: KirbyFlavor
|
||||
gooey_flavor_preset: GooeyFlavorPreset
|
||||
gooey_flavor: GooeyFlavor
|
||||
music_shuffle: MusicShuffle
|
||||
virtual_console: VirtualConsoleChanges
|
56
worlds/kdl3/Presets.py
Normal file
56
worlds/kdl3/Presets.py
Normal file
@@ -0,0 +1,56 @@
|
||||
from typing import Dict, Any
|
||||
|
||||
all_random = {
|
||||
"progression_balancing": "random",
|
||||
"accessibility": "random",
|
||||
"death_link": "random",
|
||||
"game_language": "random",
|
||||
"goal": "random",
|
||||
"goal_speed": "random",
|
||||
"total_heart_stars": "random",
|
||||
"heart_stars_required": "random",
|
||||
"filler_percentage": "random",
|
||||
"trap_percentage": "random",
|
||||
"gooey_trap_weight": "random",
|
||||
"slow_trap_weight": "random",
|
||||
"ability_trap_weight": "random",
|
||||
"jumping_target": "random",
|
||||
"stage_shuffle": "random",
|
||||
"boss_shuffle": "random",
|
||||
"allow_bb": "random",
|
||||
"animal_randomization": "random",
|
||||
"copy_ability_randomization": "random",
|
||||
"strict_bosses": "random",
|
||||
"open_world": "random",
|
||||
"ow_boss_requirement": "random",
|
||||
"boss_requirement_random": "random",
|
||||
"consumables": "random",
|
||||
"kirby_flavor_preset": "random",
|
||||
"gooey_flavor_preset": "random",
|
||||
"music_shuffle": "random",
|
||||
}
|
||||
|
||||
beginner = {
|
||||
"goal": "zero",
|
||||
"goal_speed": "normal",
|
||||
"total_heart_stars": 50,
|
||||
"heart_stars_required": 30,
|
||||
"filler_percentage": 25,
|
||||
"trap_percentage": 0,
|
||||
"gooey_trap_weight": "random",
|
||||
"slow_trap_weight": "random",
|
||||
"ability_trap_weight": "random",
|
||||
"jumping_target": 5,
|
||||
"stage_shuffle": "pattern",
|
||||
"boss_shuffle": "shuffled",
|
||||
"allow_bb": "random",
|
||||
"strict_bosses": True,
|
||||
"open_world": True,
|
||||
"ow_boss_requirement": 3,
|
||||
}
|
||||
|
||||
|
||||
kdl3_options_presets: Dict[str, Dict[str, Any]] = {
|
||||
"All Random": all_random,
|
||||
"Beginner": beginner,
|
||||
}
|
231
worlds/kdl3/Regions.py
Normal file
231
worlds/kdl3/Regions.py
Normal file
@@ -0,0 +1,231 @@
|
||||
import orjson
|
||||
import os
|
||||
import typing
|
||||
from pkgutil import get_data
|
||||
|
||||
from BaseClasses import Region
|
||||
from worlds.generic.Rules import add_item_rule
|
||||
from .Locations import KDL3Location
|
||||
from .Names import LocationName
|
||||
from .Options import BossShuffle
|
||||
from .Room import KDL3Room
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from . import KDL3World
|
||||
|
||||
default_levels = {
|
||||
1: [0x770001, 0x770002, 0x770003, 0x770004, 0x770005, 0x770006, 0x770200],
|
||||
2: [0x770007, 0x770008, 0x770009, 0x77000A, 0x77000B, 0x77000C, 0x770201],
|
||||
3: [0x77000D, 0x77000E, 0x77000F, 0x770010, 0x770011, 0x770012, 0x770202],
|
||||
4: [0x770013, 0x770014, 0x770015, 0x770016, 0x770017, 0x770018, 0x770203],
|
||||
5: [0x770019, 0x77001A, 0x77001B, 0x77001C, 0x77001D, 0x77001E, 0x770204],
|
||||
}
|
||||
|
||||
first_stage_blacklist = {
|
||||
# We want to confirm that the first stage can be completed without any items
|
||||
0x77000B, # 2-5 needs Kine
|
||||
0x770011, # 3-5 needs Cutter
|
||||
0x77001C, # 5-4 needs Burning
|
||||
}
|
||||
|
||||
|
||||
def generate_valid_level(level, stage, possible_stages, slot_random):
|
||||
new_stage = slot_random.choice(possible_stages)
|
||||
if level == 1 and stage == 0 and new_stage in first_stage_blacklist:
|
||||
return generate_valid_level(level, stage, possible_stages, slot_random)
|
||||
else:
|
||||
return new_stage
|
||||
|
||||
|
||||
def generate_rooms(world: "KDL3World", door_shuffle: bool, level_regions: typing.Dict[int, Region]):
|
||||
level_names = {LocationName.level_names[level]: level for level in LocationName.level_names}
|
||||
room_data = orjson.loads(get_data(__name__, os.path.join("data", "Rooms.json")))
|
||||
rooms: typing.Dict[str, KDL3Room] = dict()
|
||||
for room_entry in room_data:
|
||||
room = KDL3Room(room_entry["name"], world.player, world.multiworld, None, room_entry["level"],
|
||||
room_entry["stage"], room_entry["room"], room_entry["pointer"], room_entry["music"],
|
||||
room_entry["default_exits"], room_entry["animal_pointers"], room_entry["enemies"],
|
||||
room_entry["entity_load"], room_entry["consumables"], room_entry["consumables_pointer"])
|
||||
room.add_locations({location: world.location_name_to_id[location] if location in world.location_name_to_id else
|
||||
None for location in room_entry["locations"]
|
||||
if (not any(x in location for x in ["1-Up", "Maxim"]) or
|
||||
world.options.consumables.value) and ("Star" not in location
|
||||
or world.options.starsanity.value)},
|
||||
KDL3Location)
|
||||
rooms[room.name] = room
|
||||
for location in room.locations:
|
||||
if "Animal" in location.name:
|
||||
add_item_rule(location, lambda item: item.name in {
|
||||
"Rick Spawn", "Kine Spawn", "Coo Spawn", "Nago Spawn", "ChuChu Spawn", "Pitch Spawn"
|
||||
})
|
||||
world.rooms = list(rooms.values())
|
||||
world.multiworld.regions.extend(world.rooms)
|
||||
|
||||
first_rooms: typing.Dict[int, KDL3Room] = dict()
|
||||
if door_shuffle:
|
||||
# first, we need to generate the notable edge cases
|
||||
# 5-6 is the first, being the most restrictive
|
||||
# half of its rooms are required to be vanilla, but can be in different orders
|
||||
# the room before it *must* contain the copy ability required to unlock the room's goal
|
||||
|
||||
raise NotImplementedError()
|
||||
else:
|
||||
for name, room in rooms.items():
|
||||
if room.room == 0:
|
||||
if room.stage == 7:
|
||||
first_rooms[0x770200 + room.level - 1] = room
|
||||
else:
|
||||
first_rooms[0x770000 + ((room.level - 1) * 6) + room.stage] = room
|
||||
exits = dict()
|
||||
for def_exit in room.default_exits:
|
||||
target = f"{level_names[room.level]} {room.stage} - {def_exit['room']}"
|
||||
access_rule = tuple(def_exit["access_rule"])
|
||||
exits[target] = lambda state, rule=access_rule: state.has_all(rule, world.player)
|
||||
room.add_exits(
|
||||
exits.keys(),
|
||||
exits
|
||||
)
|
||||
if world.options.open_world:
|
||||
if any("Complete" in location.name for location in room.locations):
|
||||
room.add_locations({f"{level_names[room.level]} {room.stage} - Stage Completion": None},
|
||||
KDL3Location)
|
||||
|
||||
for level in world.player_levels:
|
||||
for stage in range(6):
|
||||
proper_stage = world.player_levels[level][stage]
|
||||
stage_name = world.multiworld.get_location(world.location_id_to_name[proper_stage],
|
||||
world.player).name.replace(" - Complete", "")
|
||||
stage_regions = [rooms[room] for room in rooms if stage_name in rooms[room].name]
|
||||
for region in stage_regions:
|
||||
region.level = level
|
||||
region.stage = stage
|
||||
if world.options.open_world or stage == 0:
|
||||
level_regions[level].add_exits([first_rooms[proper_stage].name])
|
||||
else:
|
||||
world.multiworld.get_location(world.location_id_to_name[world.player_levels[level][stage-1]],
|
||||
world.player).parent_region.add_exits([first_rooms[proper_stage].name])
|
||||
level_regions[level].add_exits([first_rooms[0x770200 + level - 1].name])
|
||||
|
||||
|
||||
def generate_valid_levels(world: "KDL3World", enforce_world: bool, enforce_pattern: bool) -> dict:
|
||||
levels: typing.Dict[int, typing.List[typing.Optional[int]]] = {
|
||||
1: [None] * 7,
|
||||
2: [None] * 7,
|
||||
3: [None] * 7,
|
||||
4: [None] * 7,
|
||||
5: [None] * 7,
|
||||
}
|
||||
|
||||
possible_stages = [default_levels[level][stage] for level in default_levels for stage in range(6)]
|
||||
if world.multiworld.plando_connections[world.player]:
|
||||
for connection in world.multiworld.plando_connections[world.player]:
|
||||
try:
|
||||
entrance_world, entrance_stage = connection.entrance.rsplit(" ", 1)
|
||||
stage_world, stage_stage = connection.exit.rsplit(" ", 1)
|
||||
new_stage = default_levels[LocationName.level_names[stage_world.strip()]][int(stage_stage) - 1]
|
||||
levels[LocationName.level_names[entrance_world.strip()]][int(entrance_stage) - 1] = new_stage
|
||||
possible_stages.remove(new_stage)
|
||||
|
||||
except Exception:
|
||||
raise Exception(
|
||||
f"Invalid connection: {connection.entrance} =>"
|
||||
f" {connection.exit} for player {world.player} ({world.player_name})")
|
||||
|
||||
for level in range(1, 6):
|
||||
for stage in range(6):
|
||||
# Randomize bosses separately
|
||||
try:
|
||||
if levels[level][stage] is None:
|
||||
stage_candidates = [candidate for candidate in possible_stages
|
||||
if (enforce_world and candidate in default_levels[level])
|
||||
or (enforce_pattern and ((candidate - 1) & 0x00FFFF) % 6 == stage)
|
||||
or (enforce_pattern == enforce_world)
|
||||
]
|
||||
new_stage = generate_valid_level(level, stage, stage_candidates,
|
||||
world.random)
|
||||
possible_stages.remove(new_stage)
|
||||
levels[level][stage] = new_stage
|
||||
except Exception:
|
||||
raise Exception(f"Failed to find valid stage for {level}-{stage}. Remaining Stages:{possible_stages}")
|
||||
|
||||
# now handle bosses
|
||||
boss_shuffle: typing.Union[int, str] = world.options.boss_shuffle.value
|
||||
plando_bosses = []
|
||||
if isinstance(boss_shuffle, str):
|
||||
# boss plando
|
||||
options = boss_shuffle.split(";")
|
||||
boss_shuffle = BossShuffle.options[options.pop()]
|
||||
for option in options:
|
||||
if "-" in option:
|
||||
loc, boss = option.split("-")
|
||||
loc = loc.title()
|
||||
boss = boss.title()
|
||||
levels[LocationName.level_names[loc]][6] = LocationName.boss_names[boss]
|
||||
plando_bosses.append(LocationName.boss_names[boss])
|
||||
else:
|
||||
option = option.title()
|
||||
for level in levels:
|
||||
if levels[level][6] is None:
|
||||
levels[level][6] = LocationName.boss_names[option]
|
||||
plando_bosses.append(LocationName.boss_names[option])
|
||||
|
||||
if boss_shuffle > 0:
|
||||
if boss_shuffle == BossShuffle.option_full:
|
||||
possible_bosses = [default_levels[world.random.randint(1, 5)][6]
|
||||
for _ in range(5 - len(plando_bosses))]
|
||||
elif boss_shuffle == BossShuffle.option_singularity:
|
||||
boss = world.random.randint(1, 5)
|
||||
possible_bosses = [default_levels[boss][6] for _ in range(5 - len(plando_bosses))]
|
||||
else:
|
||||
possible_bosses = [default_levels[level][6] for level in default_levels
|
||||
if default_levels[level][6] not in plando_bosses]
|
||||
for level in levels:
|
||||
if levels[level][6] is None:
|
||||
boss = world.random.choice(possible_bosses)
|
||||
levels[level][6] = boss
|
||||
possible_bosses.remove(boss)
|
||||
else:
|
||||
for level in levels:
|
||||
if levels[level][6] is None:
|
||||
levels[level][6] = default_levels[level][6]
|
||||
|
||||
for level in levels:
|
||||
for stage in range(7):
|
||||
assert levels[level][stage] is not None, "Level tried to be sent with a None stage, incorrect plando?"
|
||||
|
||||
return levels
|
||||
|
||||
|
||||
def create_levels(world: "KDL3World") -> None:
|
||||
menu = Region("Menu", world.player, world.multiworld)
|
||||
level1 = Region("Grass Land", world.player, world.multiworld)
|
||||
level2 = Region("Ripple Field", world.player, world.multiworld)
|
||||
level3 = Region("Sand Canyon", world.player, world.multiworld)
|
||||
level4 = Region("Cloudy Park", world.player, world.multiworld)
|
||||
level5 = Region("Iceberg", world.player, world.multiworld)
|
||||
level6 = Region("Hyper Zone", world.player, world.multiworld)
|
||||
levels = {
|
||||
1: level1,
|
||||
2: level2,
|
||||
3: level3,
|
||||
4: level4,
|
||||
5: level5,
|
||||
}
|
||||
level_shuffle = world.options.stage_shuffle.value
|
||||
if level_shuffle != 0:
|
||||
world.player_levels = generate_valid_levels(
|
||||
world,
|
||||
level_shuffle == 1,
|
||||
level_shuffle == 2)
|
||||
|
||||
generate_rooms(world, False, levels)
|
||||
|
||||
level6.add_locations({LocationName.goals[world.options.goal]: None}, KDL3Location)
|
||||
|
||||
menu.connect(level1, "Start Game")
|
||||
level1.connect(level2, "To Level 2")
|
||||
level2.connect(level3, "To Level 3")
|
||||
level3.connect(level4, "To Level 4")
|
||||
level4.connect(level5, "To Level 5")
|
||||
menu.connect(level6, "To Level 6") # put the connection on menu, since you can reach it before level 5 on fast goal
|
||||
world.multiworld.regions += [menu, level1, level2, level3, level4, level5, level6]
|
577
worlds/kdl3/Rom.py
Normal file
577
worlds/kdl3/Rom.py
Normal file
@@ -0,0 +1,577 @@
|
||||
import typing
|
||||
from pkgutil import get_data
|
||||
|
||||
import Utils
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
import hashlib
|
||||
import os
|
||||
import struct
|
||||
|
||||
import settings
|
||||
from worlds.Files import APDeltaPatch
|
||||
from .Aesthetics import get_palette_bytes, kirby_target_palettes, get_kirby_palette, gooey_target_palettes, \
|
||||
get_gooey_palette
|
||||
from .Compression import hal_decompress
|
||||
import bsdiff4
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from . import KDL3World
|
||||
|
||||
KDL3UHASH = "201e7658f6194458a3869dde36bf8ec2"
|
||||
KDL3JHASH = "b2f2d004ea640c3db66df958fce122b2"
|
||||
|
||||
level_pointers = {
|
||||
0x770001: 0x0084,
|
||||
0x770002: 0x009C,
|
||||
0x770003: 0x00B8,
|
||||
0x770004: 0x00D8,
|
||||
0x770005: 0x0104,
|
||||
0x770006: 0x0124,
|
||||
0x770007: 0x014C,
|
||||
0x770008: 0x0170,
|
||||
0x770009: 0x0190,
|
||||
0x77000A: 0x01B0,
|
||||
0x77000B: 0x01E8,
|
||||
0x77000C: 0x0218,
|
||||
0x77000D: 0x024C,
|
||||
0x77000E: 0x0270,
|
||||
0x77000F: 0x02A0,
|
||||
0x770010: 0x02C4,
|
||||
0x770011: 0x02EC,
|
||||
0x770012: 0x0314,
|
||||
0x770013: 0x03CC,
|
||||
0x770014: 0x0404,
|
||||
0x770015: 0x042C,
|
||||
0x770016: 0x044C,
|
||||
0x770017: 0x0478,
|
||||
0x770018: 0x049C,
|
||||
0x770019: 0x04E4,
|
||||
0x77001A: 0x0504,
|
||||
0x77001B: 0x0530,
|
||||
0x77001C: 0x0554,
|
||||
0x77001D: 0x05A8,
|
||||
0x77001E: 0x0640,
|
||||
0x770200: 0x0148,
|
||||
0x770201: 0x0248,
|
||||
0x770202: 0x03C8,
|
||||
0x770203: 0x04E0,
|
||||
0x770204: 0x06A4,
|
||||
0x770205: 0x06A8,
|
||||
}
|
||||
|
||||
bb_bosses = {
|
||||
0x770200: 0xED85F1,
|
||||
0x770201: 0xF01360,
|
||||
0x770202: 0xEDA3DF,
|
||||
0x770203: 0xEDC2B9,
|
||||
0x770204: 0xED7C3F,
|
||||
0x770205: 0xEC29D2,
|
||||
}
|
||||
|
||||
level_sprites = {
|
||||
0x19B2C6: 1827,
|
||||
0x1A195C: 1584,
|
||||
0x19F6F3: 1679,
|
||||
0x19DC8B: 1717,
|
||||
0x197900: 1872
|
||||
}
|
||||
|
||||
stage_tiles = {
|
||||
0: [
|
||||
0, 1, 2,
|
||||
16, 17, 18,
|
||||
32, 33, 34,
|
||||
48, 49, 50
|
||||
],
|
||||
1: [
|
||||
3, 4, 5,
|
||||
19, 20, 21,
|
||||
35, 36, 37,
|
||||
51, 52, 53
|
||||
],
|
||||
2: [
|
||||
6, 7, 8,
|
||||
22, 23, 24,
|
||||
38, 39, 40,
|
||||
54, 55, 56
|
||||
],
|
||||
3: [
|
||||
9, 10, 11,
|
||||
25, 26, 27,
|
||||
41, 42, 43,
|
||||
57, 58, 59,
|
||||
],
|
||||
4: [
|
||||
12, 13, 64,
|
||||
28, 29, 65,
|
||||
44, 45, 66,
|
||||
60, 61, 67
|
||||
],
|
||||
5: [
|
||||
14, 15, 68,
|
||||
30, 31, 69,
|
||||
46, 47, 70,
|
||||
62, 63, 71
|
||||
]
|
||||
}
|
||||
|
||||
heart_star_address = 0x2D0000
|
||||
heart_star_size = 456
|
||||
consumable_address = 0x2F91DD
|
||||
consumable_size = 698
|
||||
|
||||
stage_palettes = [0x60964, 0x60B64, 0x60D64, 0x60F64, 0x61164]
|
||||
|
||||
music_choices = [
|
||||
2, # Boss 1
|
||||
3, # Boss 2 (Unused)
|
||||
4, # Boss 3 (Miniboss)
|
||||
7, # Dedede
|
||||
9, # Event 2 (used once)
|
||||
10, # Field 1
|
||||
11, # Field 2
|
||||
12, # Field 3
|
||||
13, # Field 4
|
||||
14, # Field 5
|
||||
15, # Field 6
|
||||
16, # Field 7
|
||||
17, # Field 8
|
||||
18, # Field 9
|
||||
19, # Field 10
|
||||
20, # Field 11
|
||||
21, # Field 12 (Gourmet Race)
|
||||
23, # Dark Matter in the Hyper Zone
|
||||
24, # Zero
|
||||
25, # Level 1
|
||||
26, # Level 2
|
||||
27, # Level 4
|
||||
28, # Level 3
|
||||
29, # Heart Star Failed
|
||||
30, # Level 5
|
||||
31, # Minigame
|
||||
38, # Animal Friend 1
|
||||
39, # Animal Friend 2
|
||||
40, # Animal Friend 3
|
||||
]
|
||||
# extra room pointers we don't want to track other than for music
|
||||
room_pointers = [
|
||||
3079990, # Zero
|
||||
2983409, # BB Whispy
|
||||
3150688, # BB Acro
|
||||
2991071, # BB PonCon
|
||||
2998969, # BB Ado
|
||||
2980927, # BB Dedede
|
||||
2894290 # BB Zero
|
||||
]
|
||||
|
||||
enemy_remap = {
|
||||
"Waddle Dee": 0,
|
||||
"Bronto Burt": 2,
|
||||
"Rocky": 3,
|
||||
"Bobo": 5,
|
||||
"Chilly": 6,
|
||||
"Poppy Bros Jr.": 7,
|
||||
"Sparky": 8,
|
||||
"Polof": 9,
|
||||
"Broom Hatter": 11,
|
||||
"Cappy": 12,
|
||||
"Bouncy": 13,
|
||||
"Nruff": 15,
|
||||
"Glunk": 16,
|
||||
"Togezo": 18,
|
||||
"Kabu": 19,
|
||||
"Mony": 20,
|
||||
"Blipper": 21,
|
||||
"Squishy": 22,
|
||||
"Gabon": 24,
|
||||
"Oro": 25,
|
||||
"Galbo": 26,
|
||||
"Sir Kibble": 27,
|
||||
"Nidoo": 28,
|
||||
"Kany": 29,
|
||||
"Sasuke": 30,
|
||||
"Yaban": 32,
|
||||
"Boten": 33,
|
||||
"Coconut": 34,
|
||||
"Doka": 35,
|
||||
"Icicle": 36,
|
||||
"Pteran": 39,
|
||||
"Loud": 40,
|
||||
"Como": 41,
|
||||
"Klinko": 42,
|
||||
"Babut": 43,
|
||||
"Wappa": 44,
|
||||
"Mariel": 45,
|
||||
"Tick": 48,
|
||||
"Apolo": 49,
|
||||
"Popon Ball": 50,
|
||||
"KeKe": 51,
|
||||
"Magoo": 53,
|
||||
"Raft Waddle Dee": 57,
|
||||
"Madoo": 58,
|
||||
"Corori": 60,
|
||||
"Kapar": 67,
|
||||
"Batamon": 68,
|
||||
"Peran": 72,
|
||||
"Bobin": 73,
|
||||
"Mopoo": 74,
|
||||
"Gansan": 75,
|
||||
"Bukiset (Burning)": 76,
|
||||
"Bukiset (Stone)": 77,
|
||||
"Bukiset (Ice)": 78,
|
||||
"Bukiset (Needle)": 79,
|
||||
"Bukiset (Clean)": 80,
|
||||
"Bukiset (Parasol)": 81,
|
||||
"Bukiset (Spark)": 82,
|
||||
"Bukiset (Cutter)": 83,
|
||||
"Waddle Dee Drawing": 84,
|
||||
"Bronto Burt Drawing": 85,
|
||||
"Bouncy Drawing": 86,
|
||||
"Kabu (Dekabu)": 87,
|
||||
"Wapod": 88,
|
||||
"Propeller": 89,
|
||||
"Dogon": 90,
|
||||
"Joe": 91
|
||||
}
|
||||
|
||||
miniboss_remap = {
|
||||
"Captain Stitch": 0,
|
||||
"Yuki": 1,
|
||||
"Blocky": 2,
|
||||
"Jumper Shoot": 3,
|
||||
"Boboo": 4,
|
||||
"Haboki": 5
|
||||
}
|
||||
|
||||
ability_remap = {
|
||||
"No Ability": 0,
|
||||
"Burning Ability": 1,
|
||||
"Stone Ability": 2,
|
||||
"Ice Ability": 3,
|
||||
"Needle Ability": 4,
|
||||
"Clean Ability": 5,
|
||||
"Parasol Ability": 6,
|
||||
"Spark Ability": 7,
|
||||
"Cutter Ability": 8,
|
||||
}
|
||||
|
||||
|
||||
class RomData:
|
||||
def __init__(self, file: str, name: typing.Optional[str] = None):
|
||||
self.file = bytearray()
|
||||
self.read_from_file(file)
|
||||
self.name = name
|
||||
|
||||
def read_byte(self, offset: int):
|
||||
return self.file[offset]
|
||||
|
||||
def read_bytes(self, offset: int, length: int):
|
||||
return self.file[offset:offset + length]
|
||||
|
||||
def write_byte(self, offset: int, value: int):
|
||||
self.file[offset] = value
|
||||
|
||||
def write_bytes(self, offset: int, values: typing.Sequence) -> None:
|
||||
self.file[offset:offset + len(values)] = values
|
||||
|
||||
def write_to_file(self, file: str):
|
||||
with open(file, 'wb') as outfile:
|
||||
outfile.write(self.file)
|
||||
|
||||
def read_from_file(self, file: str):
|
||||
with open(file, 'rb') as stream:
|
||||
self.file = bytearray(stream.read())
|
||||
|
||||
def apply_patch(self, patch: bytes):
|
||||
self.file = bytearray(bsdiff4.patch(bytes(self.file), patch))
|
||||
|
||||
def write_crc(self):
|
||||
crc = (sum(self.file[:0x7FDC] + self.file[0x7FE0:]) + 0x01FE) & 0xFFFF
|
||||
inv = crc ^ 0xFFFF
|
||||
self.write_bytes(0x7FDC, [inv & 0xFF, (inv >> 8) & 0xFF, crc & 0xFF, (crc >> 8) & 0xFF])
|
||||
|
||||
|
||||
def handle_level_sprites(stages, sprites, palettes):
|
||||
palette_by_level = list()
|
||||
for palette in palettes:
|
||||
palette_by_level.extend(palette[10:16])
|
||||
for i in range(5):
|
||||
for j in range(6):
|
||||
palettes[i][10 + j] = palette_by_level[stages[i][j] - 1]
|
||||
palettes[i] = [x for palette in palettes[i] for x in palette]
|
||||
tiles_by_level = list()
|
||||
for spritesheet in sprites:
|
||||
decompressed = hal_decompress(spritesheet)
|
||||
tiles = [decompressed[i:i + 32] for i in range(0, 2304, 32)]
|
||||
tiles_by_level.extend([[tiles[x] for x in stage_tiles[stage]] for stage in stage_tiles])
|
||||
for world in range(5):
|
||||
levels = [stages[world][x] - 1 for x in range(6)]
|
||||
world_tiles: typing.List[typing.Optional[bytes]] = [None for _ in range(72)]
|
||||
for i in range(6):
|
||||
for x in range(12):
|
||||
world_tiles[stage_tiles[i][x]] = tiles_by_level[levels[i]][x]
|
||||
sprites[world] = list()
|
||||
for tile in world_tiles:
|
||||
sprites[world].extend(tile)
|
||||
# insert our fake compression
|
||||
sprites[world][0:0] = [0xe3, 0xff]
|
||||
sprites[world][1026:1026] = [0xe3, 0xff]
|
||||
sprites[world][2052:2052] = [0xe0, 0xff]
|
||||
sprites[world].append(0xff)
|
||||
return sprites, palettes
|
||||
|
||||
|
||||
def write_heart_star_sprites(rom: RomData):
|
||||
compressed = rom.read_bytes(heart_star_address, heart_star_size)
|
||||
decompressed = hal_decompress(compressed)
|
||||
patch = get_data(__name__, os.path.join("data", "APHeartStar.bsdiff4"))
|
||||
patched = bytearray(bsdiff4.patch(decompressed, patch))
|
||||
rom.write_bytes(0x1AF7DF, patched)
|
||||
patched[0:0] = [0xE3, 0xFF]
|
||||
patched.append(0xFF)
|
||||
rom.write_bytes(0x1CD000, patched)
|
||||
rom.write_bytes(0x3F0EBF, [0x00, 0xD0, 0x39])
|
||||
|
||||
|
||||
def write_consumable_sprites(rom: RomData, consumables: bool, stars: bool):
|
||||
compressed = rom.read_bytes(consumable_address, consumable_size)
|
||||
decompressed = hal_decompress(compressed)
|
||||
patched = bytearray(decompressed)
|
||||
if consumables:
|
||||
patch = get_data(__name__, os.path.join("data", "APConsumable.bsdiff4"))
|
||||
patched = bytearray(bsdiff4.patch(bytes(patched), patch))
|
||||
if stars:
|
||||
patch = get_data(__name__, os.path.join("data", "APStars.bsdiff4"))
|
||||
patched = bytearray(bsdiff4.patch(bytes(patched), patch))
|
||||
patched[0:0] = [0xE3, 0xFF]
|
||||
patched.append(0xFF)
|
||||
rom.write_bytes(0x1CD500, patched)
|
||||
rom.write_bytes(0x3F0DAE, [0x00, 0xD5, 0x39])
|
||||
|
||||
|
||||
class KDL3DeltaPatch(APDeltaPatch):
|
||||
hash = [KDL3UHASH, KDL3JHASH]
|
||||
game = "Kirby's Dream Land 3"
|
||||
patch_file_ending = ".apkdl3"
|
||||
|
||||
@classmethod
|
||||
def get_source_data(cls) -> bytes:
|
||||
return get_base_rom_bytes()
|
||||
|
||||
def patch(self, target: str):
|
||||
super().patch(target)
|
||||
rom = RomData(target)
|
||||
target_language = rom.read_byte(0x3C020)
|
||||
rom.write_byte(0x7FD9, target_language)
|
||||
write_heart_star_sprites(rom)
|
||||
if rom.read_bytes(0x3D014, 1)[0] > 0:
|
||||
stages = [struct.unpack("HHHHHHH", rom.read_bytes(0x3D020 + x * 14, 14)) for x in range(5)]
|
||||
palettes = [rom.read_bytes(full_pal, 512) for full_pal in stage_palettes]
|
||||
palettes = [[palette[i:i + 32] for i in range(0, 512, 32)] for palette in palettes]
|
||||
sprites = [rom.read_bytes(offset, level_sprites[offset]) for offset in level_sprites]
|
||||
sprites, palettes = handle_level_sprites(stages, sprites, palettes)
|
||||
for addr, palette in zip(stage_palettes, palettes):
|
||||
rom.write_bytes(addr, palette)
|
||||
for addr, level_sprite in zip([0x1CA000, 0x1CA920, 0x1CB230, 0x1CBB40, 0x1CC450], sprites):
|
||||
rom.write_bytes(addr, level_sprite)
|
||||
rom.write_bytes(0x460A, [0x00, 0xA0, 0x39, 0x20, 0xA9, 0x39, 0x30, 0xB2, 0x39, 0x40, 0xBB, 0x39,
|
||||
0x50, 0xC4, 0x39])
|
||||
write_consumable_sprites(rom, rom.read_byte(0x3D018) > 0, rom.read_byte(0x3D01A) > 0)
|
||||
rom_name = rom.read_bytes(0x3C000, 21)
|
||||
rom.write_bytes(0x7FC0, rom_name)
|
||||
rom.write_crc()
|
||||
rom.write_to_file(target)
|
||||
|
||||
|
||||
def patch_rom(world: "KDL3World", rom: RomData):
|
||||
rom.apply_patch(get_data(__name__, os.path.join("data", "kdl3_basepatch.bsdiff4")))
|
||||
tiles = get_data(__name__, os.path.join("data", "APPauseIcons.dat"))
|
||||
rom.write_bytes(0x3F000, tiles)
|
||||
|
||||
# Write open world patch
|
||||
if world.options.open_world:
|
||||
rom.write_bytes(0x143C7, [0xAD, 0xC1, 0x5A, 0xCD, 0xC1, 0x5A, ])
|
||||
# changes the stage flag function to compare $5AC1 to $5AC1,
|
||||
# always running the "new stage" function
|
||||
# This has further checks present for bosses already, so we just
|
||||
# need to handle regular stages
|
||||
# write check for boss to be unlocked
|
||||
|
||||
if world.options.consumables:
|
||||
# reroute maxim tomatoes to use the 1-UP function, then null out the function
|
||||
rom.write_bytes(0x3002F, [0x37, 0x00])
|
||||
rom.write_bytes(0x30037, [0xA9, 0x26, 0x00, # LDA #$0026
|
||||
0x22, 0x27, 0xD9, 0x00, # JSL $00D927
|
||||
0xA4, 0xD2, # LDY $D2
|
||||
0x6B, # RTL
|
||||
0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, # NOP #10
|
||||
])
|
||||
|
||||
# stars handling is built into the rom, so no changes there
|
||||
|
||||
rooms = world.rooms
|
||||
if world.options.music_shuffle > 0:
|
||||
if world.options.music_shuffle == 1:
|
||||
shuffled_music = music_choices.copy()
|
||||
world.random.shuffle(shuffled_music)
|
||||
music_map = dict(zip(music_choices, shuffled_music))
|
||||
# Avoid putting star twinkle in the pool
|
||||
music_map[5] = world.random.choice(music_choices)
|
||||
# Heart Star music doesn't work on regular stages
|
||||
music_map[8] = world.random.choice(music_choices)
|
||||
for room in rooms:
|
||||
room.music = music_map[room.music]
|
||||
for room in room_pointers:
|
||||
old_music = rom.read_byte(room + 2)
|
||||
rom.write_byte(room + 2, music_map[old_music])
|
||||
for i in range(5):
|
||||
# level themes
|
||||
old_music = rom.read_byte(0x133F2 + i)
|
||||
rom.write_byte(0x133F2 + i, music_map[old_music])
|
||||
# Zero
|
||||
rom.write_byte(0x9AE79, music_map[0x18])
|
||||
# Heart Star success and fail
|
||||
rom.write_byte(0x4A388, music_map[0x08])
|
||||
rom.write_byte(0x4A38D, music_map[0x1D])
|
||||
elif world.options.music_shuffle == 2:
|
||||
for room in rooms:
|
||||
room.music = world.random.choice(music_choices)
|
||||
for room in room_pointers:
|
||||
rom.write_byte(room + 2, world.random.choice(music_choices))
|
||||
for i in range(5):
|
||||
# level themes
|
||||
rom.write_byte(0x133F2 + i, world.random.choice(music_choices))
|
||||
# Zero
|
||||
rom.write_byte(0x9AE79, world.random.choice(music_choices))
|
||||
# Heart Star success and fail
|
||||
rom.write_byte(0x4A388, world.random.choice(music_choices))
|
||||
rom.write_byte(0x4A38D, world.random.choice(music_choices))
|
||||
|
||||
for room in rooms:
|
||||
room.patch(rom)
|
||||
|
||||
if world.options.virtual_console in [1, 3]:
|
||||
# Flash Reduction
|
||||
rom.write_byte(0x9AE68, 0x10)
|
||||
rom.write_bytes(0x9AE8E, [0x08, 0x00, 0x22, 0x5D, 0xF7, 0x00, 0xA2, 0x08, ])
|
||||
rom.write_byte(0x9AEA1, 0x08)
|
||||
rom.write_byte(0x9AEC9, 0x01)
|
||||
rom.write_bytes(0x9AED2, [0xA9, 0x1F])
|
||||
rom.write_byte(0x9AEE1, 0x08)
|
||||
|
||||
if world.options.virtual_console in [2, 3]:
|
||||
# Hyper Zone BB colors
|
||||
rom.write_bytes(0x2C5E16, [0xEE, 0x1B, 0x18, 0x5B, 0xD3, 0x4A, 0xF4, 0x3B, ])
|
||||
rom.write_bytes(0x2C8217, [0xFF, 0x1E, ])
|
||||
|
||||
# boss requirements
|
||||
rom.write_bytes(0x3D000, struct.pack("HHHHH", world.boss_requirements[0], world.boss_requirements[1],
|
||||
world.boss_requirements[2], world.boss_requirements[3],
|
||||
world.boss_requirements[4]))
|
||||
rom.write_bytes(0x3D00A, struct.pack("H", world.required_heart_stars if world.options.goal_speed == 1 else 0xFFFF))
|
||||
rom.write_byte(0x3D00C, world.options.goal_speed.value)
|
||||
rom.write_byte(0x3D00E, world.options.open_world.value)
|
||||
rom.write_byte(0x3D010, world.options.death_link.value)
|
||||
rom.write_byte(0x3D012, world.options.goal.value)
|
||||
rom.write_byte(0x3D014, world.options.stage_shuffle.value)
|
||||
rom.write_byte(0x3D016, world.options.ow_boss_requirement.value)
|
||||
rom.write_byte(0x3D018, world.options.consumables.value)
|
||||
rom.write_byte(0x3D01A, world.options.starsanity.value)
|
||||
rom.write_byte(0x3D01C, world.options.gifting.value if world.multiworld.players > 1 else 0)
|
||||
rom.write_byte(0x3D01E, world.options.strict_bosses.value)
|
||||
# don't write gifting for solo game, since there's no one to send anything to
|
||||
|
||||
for level in world.player_levels:
|
||||
for i in range(len(world.player_levels[level])):
|
||||
rom.write_bytes(0x3F002E + ((level - 1) * 14) + (i * 2),
|
||||
struct.pack("H", level_pointers[world.player_levels[level][i]]))
|
||||
rom.write_bytes(0x3D020 + (level - 1) * 14 + (i * 2),
|
||||
struct.pack("H", world.player_levels[level][i] & 0x00FFFF))
|
||||
if (i == 0) or (i > 0 and i % 6 != 0):
|
||||
rom.write_bytes(0x3D080 + (level - 1) * 12 + (i * 2),
|
||||
struct.pack("H", (world.player_levels[level][i] & 0x00FFFF) % 6))
|
||||
|
||||
for i in range(6):
|
||||
if world.boss_butch_bosses[i]:
|
||||
rom.write_bytes(0x3F0000 + (level_pointers[0x770200 + i]), struct.pack("I", bb_bosses[0x770200 + i]))
|
||||
|
||||
# copy ability shuffle
|
||||
if world.options.copy_ability_randomization.value > 0:
|
||||
for enemy in world.copy_abilities:
|
||||
if enemy in miniboss_remap:
|
||||
rom.write_bytes(0xB417E + (miniboss_remap[enemy] << 1),
|
||||
struct.pack("H", ability_remap[world.copy_abilities[enemy]]))
|
||||
else:
|
||||
rom.write_bytes(0xB3CAC + (enemy_remap[enemy] << 1),
|
||||
struct.pack("H", ability_remap[world.copy_abilities[enemy]]))
|
||||
# following only needs done on non-door rando
|
||||
# incredibly lucky this follows the same order (including 5E == star block)
|
||||
rom.write_byte(0x2F77EA, 0x5E + (ability_remap[world.copy_abilities["Sparky"]] << 1))
|
||||
rom.write_byte(0x2F7811, 0x5E + (ability_remap[world.copy_abilities["Sparky"]] << 1))
|
||||
rom.write_byte(0x2F9BC4, 0x5E + (ability_remap[world.copy_abilities["Blocky"]] << 1))
|
||||
rom.write_byte(0x2F9BEB, 0x5E + (ability_remap[world.copy_abilities["Blocky"]] << 1))
|
||||
rom.write_byte(0x2FAC06, 0x5E + (ability_remap[world.copy_abilities["Jumper Shoot"]] << 1))
|
||||
rom.write_byte(0x2FAC2D, 0x5E + (ability_remap[world.copy_abilities["Jumper Shoot"]] << 1))
|
||||
rom.write_byte(0x2F9E7B, 0x5E + (ability_remap[world.copy_abilities["Yuki"]] << 1))
|
||||
rom.write_byte(0x2F9EA2, 0x5E + (ability_remap[world.copy_abilities["Yuki"]] << 1))
|
||||
rom.write_byte(0x2FA951, 0x5E + (ability_remap[world.copy_abilities["Sir Kibble"]] << 1))
|
||||
rom.write_byte(0x2FA978, 0x5E + (ability_remap[world.copy_abilities["Sir Kibble"]] << 1))
|
||||
rom.write_byte(0x2FA132, 0x5E + (ability_remap[world.copy_abilities["Haboki"]] << 1))
|
||||
rom.write_byte(0x2FA159, 0x5E + (ability_remap[world.copy_abilities["Haboki"]] << 1))
|
||||
rom.write_byte(0x2FA3E8, 0x5E + (ability_remap[world.copy_abilities["Boboo"]] << 1))
|
||||
rom.write_byte(0x2FA40F, 0x5E + (ability_remap[world.copy_abilities["Boboo"]] << 1))
|
||||
rom.write_byte(0x2F90E2, 0x5E + (ability_remap[world.copy_abilities["Captain Stitch"]] << 1))
|
||||
rom.write_byte(0x2F9109, 0x5E + (ability_remap[world.copy_abilities["Captain Stitch"]] << 1))
|
||||
|
||||
if world.options.copy_ability_randomization == 2:
|
||||
for enemy in enemy_remap:
|
||||
# we just won't include it for minibosses
|
||||
rom.write_bytes(0xB3E40 + (enemy_remap[enemy] << 1), struct.pack("h", world.random.randint(-1, 2)))
|
||||
|
||||
# write jumping goal
|
||||
rom.write_bytes(0x94F8, struct.pack("H", world.options.jumping_target))
|
||||
rom.write_bytes(0x944E, struct.pack("H", world.options.jumping_target))
|
||||
|
||||
from Utils import __version__
|
||||
rom.name = bytearray(
|
||||
f'KDL3{__version__.replace(".", "")[0:3]}_{world.player}_{world.multiworld.seed:11}\0', 'utf8')[:21]
|
||||
rom.name.extend([0] * (21 - len(rom.name)))
|
||||
rom.write_bytes(0x3C000, rom.name)
|
||||
rom.write_byte(0x3C020, world.options.game_language.value)
|
||||
|
||||
# handle palette
|
||||
if world.options.kirby_flavor_preset.value != 0:
|
||||
for addr in kirby_target_palettes:
|
||||
target = kirby_target_palettes[addr]
|
||||
palette = get_kirby_palette(world)
|
||||
rom.write_bytes(addr, get_palette_bytes(palette, target[0], target[1], target[2]))
|
||||
|
||||
if world.options.gooey_flavor_preset.value != 0:
|
||||
for addr in gooey_target_palettes:
|
||||
target = gooey_target_palettes[addr]
|
||||
palette = get_gooey_palette(world)
|
||||
rom.write_bytes(addr, get_palette_bytes(palette, target[0], target[1], target[2]))
|
||||
|
||||
|
||||
def get_base_rom_bytes() -> bytes:
|
||||
rom_file: str = get_base_rom_path()
|
||||
base_rom_bytes: Optional[bytes] = getattr(get_base_rom_bytes, "base_rom_bytes", None)
|
||||
if not base_rom_bytes:
|
||||
base_rom_bytes = bytes(Utils.read_snes_rom(open(rom_file, "rb")))
|
||||
|
||||
basemd5 = hashlib.md5()
|
||||
basemd5.update(base_rom_bytes)
|
||||
if basemd5.hexdigest() not in {KDL3UHASH, KDL3JHASH}:
|
||||
raise Exception("Supplied Base Rom does not match known MD5 for US or JP release. "
|
||||
"Get the correct game and version, then dump it")
|
||||
get_base_rom_bytes.base_rom_bytes = base_rom_bytes
|
||||
return base_rom_bytes
|
||||
|
||||
|
||||
def get_base_rom_path(file_name: str = "") -> str:
|
||||
options: settings.Settings = settings.get_settings()
|
||||
if not file_name:
|
||||
file_name = options["kdl3_options"]["rom_file"]
|
||||
if not os.path.exists(file_name):
|
||||
file_name = Utils.user_path(file_name)
|
||||
return file_name
|
95
worlds/kdl3/Room.py
Normal file
95
worlds/kdl3/Room.py
Normal file
@@ -0,0 +1,95 @@
|
||||
import struct
|
||||
import typing
|
||||
from BaseClasses import Region, ItemClassification
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from .Rom import RomData
|
||||
|
||||
animal_map = {
|
||||
"Rick Spawn": 0,
|
||||
"Kine Spawn": 1,
|
||||
"Coo Spawn": 2,
|
||||
"Nago Spawn": 3,
|
||||
"ChuChu Spawn": 4,
|
||||
"Pitch Spawn": 5
|
||||
}
|
||||
|
||||
|
||||
class KDL3Room(Region):
|
||||
pointer: int = 0
|
||||
level: int = 0
|
||||
stage: int = 0
|
||||
room: int = 0
|
||||
music: int = 0
|
||||
default_exits: typing.List[typing.Dict[str, typing.Union[int, typing.List[str]]]]
|
||||
animal_pointers: typing.List[int]
|
||||
enemies: typing.List[str]
|
||||
entity_load: typing.List[typing.List[int]]
|
||||
consumables: typing.List[typing.Dict[str, typing.Union[int, str]]]
|
||||
|
||||
def __init__(self, name, player, multiworld, hint, level, stage, room, pointer, music, default_exits,
|
||||
animal_pointers, enemies, entity_load, consumables, consumable_pointer):
|
||||
super().__init__(name, player, multiworld, hint)
|
||||
self.level = level
|
||||
self.stage = stage
|
||||
self.room = room
|
||||
self.pointer = pointer
|
||||
self.music = music
|
||||
self.default_exits = default_exits
|
||||
self.animal_pointers = animal_pointers
|
||||
self.enemies = enemies
|
||||
self.entity_load = entity_load
|
||||
self.consumables = consumables
|
||||
self.consumable_pointer = consumable_pointer
|
||||
|
||||
def patch(self, rom: "RomData"):
|
||||
rom.write_byte(self.pointer + 2, self.music)
|
||||
animals = [x.item.name for x in self.locations if "Animal" in x.name]
|
||||
if len(animals) > 0:
|
||||
for current_animal, address in zip(animals, self.animal_pointers):
|
||||
rom.write_byte(self.pointer + address + 7, animal_map[current_animal])
|
||||
if self.multiworld.worlds[self.player].options.consumables:
|
||||
load_len = len(self.entity_load)
|
||||
for consumable in self.consumables:
|
||||
location = next(x for x in self.locations if x.name == consumable["name"])
|
||||
assert location.item
|
||||
is_progression = location.item.classification & ItemClassification.progression
|
||||
if load_len == 8:
|
||||
# edge case, there is exactly 1 room with 8 entities and only 1 consumable among them
|
||||
if not (any(x in self.entity_load for x in [[0, 22], [1, 22]])
|
||||
and any(x in self.entity_load for x in [[2, 22], [3, 22]])):
|
||||
replacement_target = self.entity_load.index(
|
||||
next(x for x in self.entity_load if x in [[0, 22], [1, 22], [2, 22], [3, 22]]))
|
||||
if is_progression:
|
||||
vtype = 0
|
||||
else:
|
||||
vtype = 2
|
||||
rom.write_byte(self.pointer + 88 + (replacement_target * 2), vtype)
|
||||
self.entity_load[replacement_target] = [vtype, 22]
|
||||
else:
|
||||
if is_progression:
|
||||
# we need to see if 1-ups are in our load list
|
||||
if any(x not in self.entity_load for x in [[0, 22], [1, 22]]):
|
||||
self.entity_load.append([0, 22])
|
||||
else:
|
||||
if any(x not in self.entity_load for x in [[2, 22], [3, 22]]):
|
||||
# edge case: if (1, 22) is in, we need to load (3, 22) instead
|
||||
if [1, 22] in self.entity_load:
|
||||
self.entity_load.append([3, 22])
|
||||
else:
|
||||
self.entity_load.append([2, 22])
|
||||
if load_len < len(self.entity_load):
|
||||
rom.write_bytes(self.pointer + 88 + (load_len * 2), bytes(self.entity_load[load_len]))
|
||||
rom.write_bytes(self.pointer + 104 + (load_len * 2),
|
||||
bytes(struct.pack("H", self.consumable_pointer)))
|
||||
if is_progression:
|
||||
if [1, 22] in self.entity_load:
|
||||
vtype = 1
|
||||
else:
|
||||
vtype = 0
|
||||
else:
|
||||
if [3, 22] in self.entity_load:
|
||||
vtype = 3
|
||||
else:
|
||||
vtype = 2
|
||||
rom.write_byte(self.pointer + consumable["pointer"] + 7, vtype)
|
332
worlds/kdl3/Rules.py
Normal file
332
worlds/kdl3/Rules.py
Normal file
@@ -0,0 +1,332 @@
|
||||
from worlds.generic.Rules import set_rule, add_rule
|
||||
from .Names import LocationName, EnemyAbilities
|
||||
from .Locations import location_table
|
||||
from .Options import GoalSpeed
|
||||
import typing
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from . import KDL3World
|
||||
from BaseClasses import CollectionState
|
||||
|
||||
|
||||
def can_reach_boss(state: "CollectionState", player: int, level: int, open_world: int,
|
||||
ow_boss_req: int, player_levels: typing.Dict[int, typing.Dict[int, int]]):
|
||||
if open_world:
|
||||
return state.has(f"{LocationName.level_names_inverse[level]} - Stage Completion", player, ow_boss_req)
|
||||
else:
|
||||
return state.can_reach(location_table[player_levels[level][5]], "Location", player)
|
||||
|
||||
|
||||
def can_reach_rick(state: "CollectionState", player: int) -> bool:
|
||||
return state.has("Rick", player) and state.has("Rick Spawn", player)
|
||||
|
||||
|
||||
def can_reach_kine(state: "CollectionState", player: int) -> bool:
|
||||
return state.has("Kine", player) and state.has("Kine Spawn", player)
|
||||
|
||||
|
||||
def can_reach_coo(state: "CollectionState", player: int) -> bool:
|
||||
return state.has("Coo", player) and state.has("Coo Spawn", player)
|
||||
|
||||
|
||||
def can_reach_nago(state: "CollectionState", player: int) -> bool:
|
||||
return state.has("Nago", player) and state.has("Nago Spawn", player)
|
||||
|
||||
|
||||
def can_reach_chuchu(state: "CollectionState", player: int) -> bool:
|
||||
return state.has("ChuChu", player) and state.has("ChuChu Spawn", player)
|
||||
|
||||
|
||||
def can_reach_pitch(state: "CollectionState", player: int) -> bool:
|
||||
return state.has("Pitch", player) and state.has("Pitch Spawn", player)
|
||||
|
||||
|
||||
def can_reach_burning(state: "CollectionState", player: int) -> bool:
|
||||
return state.has("Burning", player) and state.has("Burning Ability", player)
|
||||
|
||||
|
||||
def can_reach_stone(state: "CollectionState", player: int) -> bool:
|
||||
return state.has("Stone", player) and state.has("Stone Ability", player)
|
||||
|
||||
|
||||
def can_reach_ice(state: "CollectionState", player: int) -> bool:
|
||||
return state.has("Ice", player) and state.has("Ice Ability", player)
|
||||
|
||||
|
||||
def can_reach_needle(state: "CollectionState", player: int) -> bool:
|
||||
return state.has("Needle", player) and state.has("Needle Ability", player)
|
||||
|
||||
|
||||
def can_reach_clean(state: "CollectionState", player: int) -> bool:
|
||||
return state.has("Clean", player) and state.has("Clean Ability", player)
|
||||
|
||||
|
||||
def can_reach_parasol(state: "CollectionState", player: int) -> bool:
|
||||
return state.has("Parasol", player) and state.has("Parasol Ability", player)
|
||||
|
||||
|
||||
def can_reach_spark(state: "CollectionState", player: int) -> bool:
|
||||
return state.has("Spark", player) and state.has("Spark Ability", player)
|
||||
|
||||
|
||||
def can_reach_cutter(state: "CollectionState", player: int) -> bool:
|
||||
return state.has("Cutter", player) and state.has("Cutter Ability", player)
|
||||
|
||||
|
||||
ability_map: typing.Dict[str, typing.Callable[["CollectionState", int], bool]] = {
|
||||
"No Ability": lambda state, player: True,
|
||||
"Burning Ability": can_reach_burning,
|
||||
"Stone Ability": can_reach_stone,
|
||||
"Ice Ability": can_reach_ice,
|
||||
"Needle Ability": can_reach_needle,
|
||||
"Clean Ability": can_reach_clean,
|
||||
"Parasol Ability": can_reach_parasol,
|
||||
"Spark Ability": can_reach_spark,
|
||||
"Cutter Ability": can_reach_cutter,
|
||||
}
|
||||
|
||||
|
||||
def can_assemble_rob(state: "CollectionState", player: int, copy_abilities: typing.Dict[str, str]):
|
||||
# check animal requirements
|
||||
if not (can_reach_coo(state, player) and can_reach_kine(state, player)):
|
||||
return False
|
||||
for abilities, bukisets in EnemyAbilities.enemy_restrictive[1:5]:
|
||||
iterator = iter(x for x in bukisets if copy_abilities[x] in abilities)
|
||||
target_bukiset = next(iterator, None)
|
||||
can_reach = False
|
||||
while target_bukiset is not None:
|
||||
can_reach = can_reach | ability_map[copy_abilities[target_bukiset]](state, player)
|
||||
target_bukiset = next(iterator, None)
|
||||
if not can_reach:
|
||||
return False
|
||||
# now the known needed abilities
|
||||
return can_reach_parasol(state, player) and can_reach_stone(state, player)
|
||||
|
||||
|
||||
def can_fix_angel_wings(state: "CollectionState", player: int, copy_abilities: typing.Dict[str, str]):
|
||||
can_reach = True
|
||||
for enemy in {"Sparky", "Blocky", "Jumper Shoot", "Yuki", "Sir Kibble", "Haboki", "Boboo", "Captain Stitch"}:
|
||||
can_reach = can_reach & ability_map[copy_abilities[enemy]](state, player)
|
||||
return can_reach
|
||||
|
||||
|
||||
def set_rules(world: "KDL3World") -> None:
|
||||
# Level 1
|
||||
set_rule(world.multiworld.get_location(LocationName.grass_land_muchi, world.player),
|
||||
lambda state: can_reach_chuchu(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.grass_land_chao, world.player),
|
||||
lambda state: can_reach_stone(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.grass_land_mine, world.player),
|
||||
lambda state: can_reach_kine(state, world.player))
|
||||
|
||||
# Level 2
|
||||
set_rule(world.multiworld.get_location(LocationName.ripple_field_5, world.player),
|
||||
lambda state: can_reach_kine(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.ripple_field_kamuribana, world.player),
|
||||
lambda state: can_reach_pitch(state, world.player) and can_reach_clean(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.ripple_field_bakasa, world.player),
|
||||
lambda state: can_reach_kine(state, world.player) and can_reach_parasol(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.ripple_field_toad, world.player),
|
||||
lambda state: can_reach_needle(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.ripple_field_mama_pitch, world.player),
|
||||
lambda state: (can_reach_pitch(state, world.player) and
|
||||
can_reach_kine(state, world.player) and
|
||||
can_reach_burning(state, world.player) and
|
||||
can_reach_stone(state, world.player)))
|
||||
|
||||
# Level 3
|
||||
set_rule(world.multiworld.get_location(LocationName.sand_canyon_5, world.player),
|
||||
lambda state: can_reach_cutter(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.sand_canyon_auntie, world.player),
|
||||
lambda state: can_reach_clean(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.sand_canyon_nyupun, world.player),
|
||||
lambda state: can_reach_chuchu(state, world.player) and can_reach_cutter(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.sand_canyon_rob, world.player),
|
||||
lambda state: can_assemble_rob(state, world.player, world.copy_abilities)
|
||||
)
|
||||
|
||||
# Level 4
|
||||
set_rule(world.multiworld.get_location(LocationName.cloudy_park_hibanamodoki, world.player),
|
||||
lambda state: can_reach_coo(state, world.player) and can_reach_clean(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.cloudy_park_piyokeko, world.player),
|
||||
lambda state: can_reach_needle(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.cloudy_park_mikarin, world.player),
|
||||
lambda state: can_reach_coo(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.cloudy_park_pick, world.player),
|
||||
lambda state: can_reach_rick(state, world.player))
|
||||
|
||||
# Level 5
|
||||
set_rule(world.multiworld.get_location(LocationName.iceberg_4, world.player),
|
||||
lambda state: can_reach_burning(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.iceberg_kogoesou, world.player),
|
||||
lambda state: can_reach_burning(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.iceberg_samus, world.player),
|
||||
lambda state: can_reach_ice(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.iceberg_name, world.player),
|
||||
lambda state: (can_reach_coo(state, world.player) and
|
||||
can_reach_burning(state, world.player) and
|
||||
can_reach_chuchu(state, world.player)))
|
||||
# ChuChu is guaranteed here, but we use this for consistency
|
||||
set_rule(world.multiworld.get_location(LocationName.iceberg_shiro, world.player),
|
||||
lambda state: can_reach_nago(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.iceberg_angel, world.player),
|
||||
lambda state: can_fix_angel_wings(state, world.player, world.copy_abilities))
|
||||
|
||||
# Consumables
|
||||
if world.options.consumables:
|
||||
set_rule(world.multiworld.get_location(LocationName.grass_land_1_u1, world.player),
|
||||
lambda state: can_reach_parasol(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.grass_land_1_m1, world.player),
|
||||
lambda state: can_reach_spark(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.grass_land_2_u1, world.player),
|
||||
lambda state: can_reach_needle(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.ripple_field_2_u1, world.player),
|
||||
lambda state: can_reach_kine(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.ripple_field_2_m1, world.player),
|
||||
lambda state: can_reach_kine(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.ripple_field_3_u1, world.player),
|
||||
lambda state: can_reach_cutter(state, world.player) or can_reach_spark(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.ripple_field_4_u1, world.player),
|
||||
lambda state: can_reach_stone(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.ripple_field_4_m2, world.player),
|
||||
lambda state: can_reach_stone(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.ripple_field_5_m1, world.player),
|
||||
lambda state: can_reach_kine(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.ripple_field_5_u1, world.player),
|
||||
lambda state: (can_reach_kine(state, world.player) and
|
||||
can_reach_burning(state, world.player) and
|
||||
can_reach_stone(state, world.player)))
|
||||
set_rule(world.multiworld.get_location(LocationName.ripple_field_5_m2, world.player),
|
||||
lambda state: (can_reach_kine(state, world.player) and
|
||||
can_reach_burning(state, world.player) and
|
||||
can_reach_stone(state, world.player)))
|
||||
set_rule(world.multiworld.get_location(LocationName.sand_canyon_4_u1, world.player),
|
||||
lambda state: can_reach_clean(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.sand_canyon_4_m2, world.player),
|
||||
lambda state: can_reach_needle(state, world.player))
|
||||
set_rule(world.multiworld.get_location(LocationName.sand_canyon_5_u2, world.player),
|
||||
lambda state: can_reach_ice(state, world.player) and
|
||||
(can_reach_rick(state, world.player) or can_reach_coo(state, world.player)))
|
||||
set_rule(world.multiworld.get_location(LocationName.sand_canyon_5_u3, world.player),
|
||||
lambda state: can_reach_ice(state, world.player) and
|
||||
(can_reach_rick(state, world.player) or can_reach_coo(state, world.player)))
|
||||
set_rule(world.multiworld.get_location(LocationName.sand_canyon_5_u4, world.player),
|
||||
lambda state: can_reach_ice(state, world.player) and
|
||||
(can_reach_rick(state, world.player) or can_reach_coo(state, world.player)))
|
||||
set_rule(world.multiworld.get_location(LocationName.cloudy_park_6_u1, world.player),
|
||||
lambda state: can_reach_cutter(state, world.player))
|
||||
|
||||
if world.options.starsanity:
|
||||
# ranges are our friend
|
||||
for i in range(7, 11):
|
||||
set_rule(world.multiworld.get_location(f"Grass Land 1 - Star {i}", world.player),
|
||||
lambda state: can_reach_cutter(state, world.player))
|
||||
for i in range(11, 14):
|
||||
set_rule(world.multiworld.get_location(f"Grass Land 1 - Star {i}", world.player),
|
||||
lambda state: can_reach_parasol(state, world.player))
|
||||
for i in [1, 3, 4, 9, 10]:
|
||||
set_rule(world.multiworld.get_location(f"Grass Land 2 - Star {i}", world.player),
|
||||
lambda state: can_reach_stone(state, world.player))
|
||||
set_rule(world.multiworld.get_location("Grass Land 2 - Star 2", world.player),
|
||||
lambda state: can_reach_burning(state, world.player))
|
||||
set_rule(world.multiworld.get_location("Ripple Field 2 - Star 17", world.player),
|
||||
lambda state: can_reach_kine(state, world.player))
|
||||
for i in range(41, 43):
|
||||
# any star past this point also needs kine, but so does the exit
|
||||
set_rule(world.multiworld.get_location(f"Ripple Field 5 - Star {i}", world.player),
|
||||
lambda state: can_reach_kine(state, world.player))
|
||||
for i in range(46, 49):
|
||||
# also requires kine, but only for access from the prior room
|
||||
set_rule(world.multiworld.get_location(f"Ripple Field 5 - Star {i}", world.player),
|
||||
lambda state: can_reach_burning(state, world.player) and can_reach_stone(state, world.player))
|
||||
for i in range(12, 18):
|
||||
set_rule(world.multiworld.get_location(f"Sand Canyon 5 - Star {i}", world.player),
|
||||
lambda state: can_reach_ice(state, world.player) and
|
||||
(can_reach_rick(state, world.player) or can_reach_coo(state, world.player)))
|
||||
for i in range(21, 23):
|
||||
set_rule(world.multiworld.get_location(f"Sand Canyon 5 - Star {i}", world.player),
|
||||
lambda state: can_reach_chuchu(state, world.player))
|
||||
for r in [range(19, 21), range(23, 31)]:
|
||||
for i in r:
|
||||
set_rule(world.multiworld.get_location(f"Sand Canyon 5 - Star {i}", world.player),
|
||||
lambda state: can_reach_clean(state, world.player))
|
||||
for i in range(31, 41):
|
||||
set_rule(world.multiworld.get_location(f"Sand Canyon 5 - Star {i}", world.player),
|
||||
lambda state: can_reach_burning(state, world.player))
|
||||
for r in [range(1, 31), range(44, 51)]:
|
||||
for i in r:
|
||||
set_rule(world.multiworld.get_location(f"Cloudy Park 4 - Star {i}", world.player),
|
||||
lambda state: can_reach_clean(state, world.player))
|
||||
for i in [18, *list(range(20, 25))]:
|
||||
set_rule(world.multiworld.get_location(f"Cloudy Park 6 - Star {i}", world.player),
|
||||
lambda state: can_reach_ice(state, world.player))
|
||||
for i in [19, *list(range(25, 30))]:
|
||||
set_rule(world.multiworld.get_location(f"Cloudy Park 6 - Star {i}", world.player),
|
||||
lambda state: can_reach_ice(state, world.player))
|
||||
# copy ability access edge cases
|
||||
# Kirby cannot eat enemies fully submerged in water. Vast majority of cases, the enemy can be brought to the surface
|
||||
# and eaten by inhaling while falling on top of them
|
||||
set_rule(world.multiworld.get_location(EnemyAbilities.Ripple_Field_2_E3, world.player),
|
||||
lambda state: can_reach_kine(state, world.player))
|
||||
set_rule(world.multiworld.get_location(EnemyAbilities.Ripple_Field_3_E6, world.player),
|
||||
lambda state: can_reach_kine(state, world.player))
|
||||
# Ripple Field 4 E5, E7, and E8 are doable, but too strict to leave in logic
|
||||
set_rule(world.multiworld.get_location(EnemyAbilities.Ripple_Field_4_E5, world.player),
|
||||
lambda state: can_reach_kine(state, world.player))
|
||||
set_rule(world.multiworld.get_location(EnemyAbilities.Ripple_Field_4_E7, world.player),
|
||||
lambda state: can_reach_kine(state, world.player))
|
||||
set_rule(world.multiworld.get_location(EnemyAbilities.Ripple_Field_4_E8, world.player),
|
||||
lambda state: can_reach_kine(state, world.player))
|
||||
set_rule(world.multiworld.get_location(EnemyAbilities.Ripple_Field_5_E1, world.player),
|
||||
lambda state: can_reach_kine(state, world.player))
|
||||
set_rule(world.multiworld.get_location(EnemyAbilities.Ripple_Field_5_E2, world.player),
|
||||
lambda state: can_reach_kine(state, world.player))
|
||||
set_rule(world.multiworld.get_location(EnemyAbilities.Ripple_Field_5_E3, world.player),
|
||||
lambda state: can_reach_kine(state, world.player))
|
||||
set_rule(world.multiworld.get_location(EnemyAbilities.Ripple_Field_5_E4, world.player),
|
||||
lambda state: can_reach_kine(state, world.player))
|
||||
set_rule(world.multiworld.get_location(EnemyAbilities.Sand_Canyon_4_E7, world.player),
|
||||
lambda state: can_reach_kine(state, world.player))
|
||||
set_rule(world.multiworld.get_location(EnemyAbilities.Sand_Canyon_4_E8, world.player),
|
||||
lambda state: can_reach_kine(state, world.player))
|
||||
set_rule(world.multiworld.get_location(EnemyAbilities.Sand_Canyon_4_E9, world.player),
|
||||
lambda state: can_reach_kine(state, world.player))
|
||||
set_rule(world.multiworld.get_location(EnemyAbilities.Sand_Canyon_4_E10, world.player),
|
||||
lambda state: can_reach_kine(state, world.player))
|
||||
|
||||
for boss_flag, purification, i in zip(["Level 1 Boss - Purified", "Level 2 Boss - Purified",
|
||||
"Level 3 Boss - Purified", "Level 4 Boss - Purified",
|
||||
"Level 5 Boss - Purified"],
|
||||
[LocationName.grass_land_whispy, LocationName.ripple_field_acro,
|
||||
LocationName.sand_canyon_poncon, LocationName.cloudy_park_ado,
|
||||
LocationName.iceberg_dedede],
|
||||
range(1, 6)):
|
||||
set_rule(world.multiworld.get_location(boss_flag, world.player),
|
||||
lambda state, i=i: (state.has("Heart Star", world.player, world.boss_requirements[i - 1])
|
||||
and can_reach_boss(state, world.player, i,
|
||||
world.options.open_world.value,
|
||||
world.options.ow_boss_requirement.value,
|
||||
world.player_levels)))
|
||||
set_rule(world.multiworld.get_location(purification, world.player),
|
||||
lambda state, i=i: (state.has("Heart Star", world.player, world.boss_requirements[i - 1])
|
||||
and can_reach_boss(state, world.player, i,
|
||||
world.options.open_world.value,
|
||||
world.options.ow_boss_requirement.value,
|
||||
world.player_levels)))
|
||||
|
||||
set_rule(world.multiworld.get_entrance("To Level 6", world.player),
|
||||
lambda state: state.has("Heart Star", world.player, world.required_heart_stars))
|
||||
|
||||
for level in range(2, 6):
|
||||
set_rule(world.multiworld.get_entrance(f"To Level {level}", world.player),
|
||||
lambda state, i=level: state.has(f"Level {i - 1} Boss Defeated", world.player))
|
||||
|
||||
if world.options.strict_bosses:
|
||||
for level in range(2, 6):
|
||||
add_rule(world.multiworld.get_entrance(f"To Level {level}", world.player),
|
||||
lambda state, i=level: state.has(f"Level {i - 1} Boss Purified", world.player))
|
||||
|
||||
if world.options.goal_speed == GoalSpeed.option_normal:
|
||||
add_rule(world.multiworld.get_entrance("To Level 6", world.player),
|
||||
lambda state: state.has_all(["Level 1 Boss Purified", "Level 2 Boss Purified", "Level 3 Boss Purified",
|
||||
"Level 4 Boss Purified", "Level 5 Boss Purified"], world.player))
|
350
worlds/kdl3/__init__.py
Normal file
350
worlds/kdl3/__init__.py
Normal file
@@ -0,0 +1,350 @@
|
||||
import logging
|
||||
import typing
|
||||
|
||||
from BaseClasses import Tutorial, ItemClassification, MultiWorld
|
||||
from Fill import fill_restrictive
|
||||
from Options import PerGameCommonOptions
|
||||
from worlds.AutoWorld import World, WebWorld
|
||||
from .Items import item_table, item_names, copy_ability_table, animal_friend_table, filler_item_weights, KDL3Item, \
|
||||
trap_item_table, copy_ability_access_table, star_item_weights, total_filler_weights
|
||||
from .Locations import location_table, KDL3Location, level_consumables, consumable_locations, star_locations
|
||||
from .Names.AnimalFriendSpawns import animal_friend_spawns
|
||||
from .Names.EnemyAbilities import vanilla_enemies, enemy_mapping, enemy_restrictive
|
||||
from .Regions import create_levels, default_levels
|
||||
from .Options import KDL3Options
|
||||
from .Presets import kdl3_options_presets
|
||||
from .Names import LocationName
|
||||
from .Room import KDL3Room
|
||||
from .Rules import set_rules
|
||||
from .Rom import KDL3DeltaPatch, get_base_rom_path, RomData, patch_rom, KDL3JHASH, KDL3UHASH
|
||||
from .Client import KDL3SNIClient
|
||||
|
||||
from typing import Dict, TextIO, Optional, List
|
||||
import os
|
||||
import math
|
||||
import threading
|
||||
import base64
|
||||
import settings
|
||||
|
||||
logger = logging.getLogger("Kirby's Dream Land 3")
|
||||
|
||||
|
||||
class KDL3Settings(settings.Group):
|
||||
class RomFile(settings.SNESRomPath):
|
||||
"""File name of the KDL3 JP or EN rom"""
|
||||
description = "Kirby's Dream Land 3 ROM File"
|
||||
copy_to = "Kirby's Dream Land 3.sfc"
|
||||
md5s = [KDL3JHASH, KDL3UHASH]
|
||||
|
||||
rom_file: RomFile = RomFile(RomFile.copy_to)
|
||||
|
||||
|
||||
class KDL3WebWorld(WebWorld):
|
||||
theme = "partyTime"
|
||||
tutorials = [
|
||||
|
||||
Tutorial(
|
||||
"Multiworld Setup Guide",
|
||||
"A guide to setting up the Kirby's Dream Land 3 randomizer connected to an Archipelago Multiworld.",
|
||||
"English",
|
||||
"setup_en.md",
|
||||
"setup/en",
|
||||
["Silvris"]
|
||||
)
|
||||
]
|
||||
options_presets = kdl3_options_presets
|
||||
|
||||
|
||||
class KDL3World(World):
|
||||
"""
|
||||
Join Kirby and his Animal Friends on an adventure to collect Heart Stars and drive Dark Matter away from Dream Land!
|
||||
"""
|
||||
|
||||
game = "Kirby's Dream Land 3"
|
||||
options_dataclass: typing.ClassVar[typing.Type[PerGameCommonOptions]] = KDL3Options
|
||||
options: KDL3Options
|
||||
item_name_to_id = {item: item_table[item].code for item in item_table}
|
||||
location_name_to_id = {location_table[location]: location for location in location_table}
|
||||
item_name_groups = item_names
|
||||
web = KDL3WebWorld()
|
||||
settings: typing.ClassVar[KDL3Settings]
|
||||
|
||||
def __init__(self, multiworld: MultiWorld, player: int):
|
||||
self.rom_name = None
|
||||
self.rom_name_available_event = threading.Event()
|
||||
super().__init__(multiworld, player)
|
||||
self.copy_abilities: Dict[str, str] = vanilla_enemies.copy()
|
||||
self.required_heart_stars: int = 0 # we fill this during create_items
|
||||
self.boss_requirements: Dict[int, int] = dict()
|
||||
self.player_levels = default_levels.copy()
|
||||
self.stage_shuffle_enabled = False
|
||||
self.boss_butch_bosses: List[Optional[bool]] = list()
|
||||
self.rooms: Optional[List[KDL3Room]] = None
|
||||
|
||||
@classmethod
|
||||
def stage_assert_generate(cls, multiworld: MultiWorld) -> None:
|
||||
rom_file: str = get_base_rom_path()
|
||||
if not os.path.exists(rom_file):
|
||||
raise FileNotFoundError(f"Could not find base ROM for {cls.game}: {rom_file}")
|
||||
|
||||
create_regions = create_levels
|
||||
|
||||
def create_item(self, name: str, force_non_progression=False) -> KDL3Item:
|
||||
item = item_table[name]
|
||||
classification = ItemClassification.filler
|
||||
if item.progression and not force_non_progression:
|
||||
classification = ItemClassification.progression_skip_balancing \
|
||||
if item.skip_balancing else ItemClassification.progression
|
||||
elif item.trap:
|
||||
classification = ItemClassification.trap
|
||||
return KDL3Item(name, classification, item.code, self.player)
|
||||
|
||||
def get_filler_item_name(self, include_stars=True) -> str:
|
||||
if include_stars:
|
||||
return self.random.choices(list(total_filler_weights.keys()),
|
||||
weights=list(total_filler_weights.values()))[0]
|
||||
return self.random.choices(list(filler_item_weights.keys()),
|
||||
weights=list(filler_item_weights.values()))[0]
|
||||
|
||||
def get_trap_item_name(self) -> str:
|
||||
return self.random.choices(["Gooey Bag", "Slowness", "Eject Ability"],
|
||||
weights=[self.options.gooey_trap_weight.value,
|
||||
self.options.slow_trap_weight.value,
|
||||
self.options.ability_trap_weight.value])[0]
|
||||
|
||||
def get_restrictive_copy_ability_placement(self, copy_ability: str, enemies_to_set: typing.List[str],
|
||||
level: int, stage: int):
|
||||
valid_rooms = [room for room in self.rooms if (room.level < level)
|
||||
or (room.level == level and room.stage < stage)] # leave out the stage in question to avoid edge
|
||||
valid_enemies = set()
|
||||
for room in valid_rooms:
|
||||
valid_enemies.update(room.enemies)
|
||||
placed_enemies = [enemy for enemy in valid_enemies if enemy not in enemies_to_set]
|
||||
if any(self.copy_abilities[enemy] == copy_ability for enemy in placed_enemies):
|
||||
return None # a valid enemy got placed by a more restrictive placement
|
||||
return self.random.choice(sorted([enemy for enemy in valid_enemies if enemy not in placed_enemies]))
|
||||
|
||||
def pre_fill(self) -> None:
|
||||
if self.options.copy_ability_randomization:
|
||||
# randomize copy abilities
|
||||
valid_abilities = list(copy_ability_access_table.keys())
|
||||
enemies_to_set = list(self.copy_abilities.keys())
|
||||
# now for the edge cases
|
||||
for abilities, enemies in enemy_restrictive:
|
||||
available_enemies = list()
|
||||
for enemy in enemies:
|
||||
if enemy not in enemies_to_set:
|
||||
if self.copy_abilities[enemy] in abilities:
|
||||
break
|
||||
else:
|
||||
available_enemies.append(enemy)
|
||||
else:
|
||||
chosen_enemy = self.random.choice(available_enemies)
|
||||
chosen_ability = self.random.choice(abilities)
|
||||
self.copy_abilities[chosen_enemy] = chosen_ability
|
||||
enemies_to_set.remove(chosen_enemy)
|
||||
# two less restrictive ones, we need to ensure Cutter and Burning appear before their required stages
|
||||
sand_canyon_5 = self.get_region("Sand Canyon 5 - 9")
|
||||
# this is primarily for typing, but if this ever hits it's fine to crash
|
||||
assert isinstance(sand_canyon_5, KDL3Room)
|
||||
cutter_enemy = self.get_restrictive_copy_ability_placement("Cutter Ability", enemies_to_set,
|
||||
sand_canyon_5.level, sand_canyon_5.stage)
|
||||
if cutter_enemy:
|
||||
self.copy_abilities[cutter_enemy] = "Cutter Ability"
|
||||
enemies_to_set.remove(cutter_enemy)
|
||||
iceberg_4 = self.get_region("Iceberg 4 - 7")
|
||||
# this is primarily for typing, but if this ever hits it's fine to crash
|
||||
assert isinstance(iceberg_4, KDL3Room)
|
||||
burning_enemy = self.get_restrictive_copy_ability_placement("Burning Ability", enemies_to_set,
|
||||
iceberg_4.level, iceberg_4.stage)
|
||||
if burning_enemy:
|
||||
self.copy_abilities[burning_enemy] = "Burning Ability"
|
||||
enemies_to_set.remove(burning_enemy)
|
||||
# place remaining
|
||||
for enemy in enemies_to_set:
|
||||
self.copy_abilities[enemy] = self.random.choice(valid_abilities)
|
||||
for enemy in enemy_mapping:
|
||||
self.multiworld.get_location(enemy, self.player) \
|
||||
.place_locked_item(self.create_item(self.copy_abilities[enemy_mapping[enemy]]))
|
||||
# fill animals
|
||||
if self.options.animal_randomization != 0:
|
||||
spawns = [animal for animal in animal_friend_spawns.keys() if
|
||||
animal not in ["Ripple Field 5 - Animal 2", "Sand Canyon 6 - Animal 1", "Iceberg 4 - Animal 1"]]
|
||||
self.multiworld.get_location("Iceberg 4 - Animal 1", self.player) \
|
||||
.place_locked_item(self.create_item("ChuChu Spawn"))
|
||||
# Not having ChuChu here makes the room impossible (since only she has vertical burning)
|
||||
self.multiworld.get_location("Ripple Field 5 - Animal 2", self.player) \
|
||||
.place_locked_item(self.create_item("Pitch Spawn"))
|
||||
guaranteed_animal = self.random.choice(["Kine Spawn", "Coo Spawn"])
|
||||
self.multiworld.get_location("Sand Canyon 6 - Animal 1", self.player) \
|
||||
.place_locked_item(self.create_item(guaranteed_animal))
|
||||
# Ripple Field 5 - Animal 2 needs to be Pitch to ensure accessibility on non-door rando
|
||||
if self.options.animal_randomization == 1:
|
||||
animal_pool = [animal_friend_spawns[spawn] for spawn in animal_friend_spawns
|
||||
if spawn not in ["Ripple Field 5 - Animal 2", "Sand Canyon 6 - Animal 1",
|
||||
"Iceberg 4 - Animal 1"]]
|
||||
else:
|
||||
animal_base = ["Rick Spawn", "Kine Spawn", "Coo Spawn", "Nago Spawn", "ChuChu Spawn", "Pitch Spawn"]
|
||||
animal_pool = [self.random.choice(animal_base)
|
||||
for _ in range(len(animal_friend_spawns) - 9)]
|
||||
# have to guarantee one of each animal
|
||||
animal_pool.extend(animal_base)
|
||||
if guaranteed_animal == "Kine Spawn":
|
||||
animal_pool.append("Coo Spawn")
|
||||
else:
|
||||
animal_pool.append("Kine Spawn")
|
||||
locations = [self.multiworld.get_location(spawn, self.player) for spawn in spawns]
|
||||
items = [self.create_item(animal) for animal in animal_pool]
|
||||
allstate = self.multiworld.get_all_state(False)
|
||||
fill_restrictive(self.multiworld, allstate, locations, items, True, True)
|
||||
else:
|
||||
animal_friends = animal_friend_spawns.copy()
|
||||
for animal in animal_friends:
|
||||
self.multiworld.get_location(animal, self.player) \
|
||||
.place_locked_item(self.create_item(animal_friends[animal]))
|
||||
|
||||
def create_items(self) -> None:
|
||||
itempool = []
|
||||
itempool.extend([self.create_item(name) for name in copy_ability_table])
|
||||
itempool.extend([self.create_item(name) for name in animal_friend_table])
|
||||
required_percentage = self.options.heart_stars_required / 100.0
|
||||
remaining_items = len(location_table) - len(itempool)
|
||||
if not self.options.consumables:
|
||||
remaining_items -= len(consumable_locations)
|
||||
remaining_items -= len(star_locations)
|
||||
if self.options.starsanity:
|
||||
# star fill, keep consumable pool locked to consumable and fill 767 stars specifically
|
||||
star_items = list(star_item_weights.keys())
|
||||
star_weights = list(star_item_weights.values())
|
||||
itempool.extend([self.create_item(item) for item in self.random.choices(star_items, weights=star_weights,
|
||||
k=767)])
|
||||
total_heart_stars = self.options.total_heart_stars
|
||||
# ensure at least 1 heart star required per world
|
||||
required_heart_stars = max(int(total_heart_stars * required_percentage), 5)
|
||||
filler_items = total_heart_stars - required_heart_stars
|
||||
filler_amount = math.floor(filler_items * (self.options.filler_percentage / 100.0))
|
||||
trap_amount = math.floor(filler_amount * (self.options.trap_percentage / 100.0))
|
||||
filler_amount -= trap_amount
|
||||
non_required_heart_stars = filler_items - filler_amount - trap_amount
|
||||
self.required_heart_stars = required_heart_stars
|
||||
# handle boss requirements here
|
||||
requirements = [required_heart_stars]
|
||||
quotient = required_heart_stars // 5 # since we set the last manually, we can afford imperfect rounding
|
||||
if self.options.boss_requirement_random:
|
||||
for i in range(1, 5):
|
||||
if self.options.strict_bosses:
|
||||
max_stars = quotient * i
|
||||
else:
|
||||
max_stars = required_heart_stars
|
||||
requirements.insert(i, self.random.randint(
|
||||
min(1, max_stars), max_stars))
|
||||
if self.options.strict_bosses:
|
||||
requirements.sort()
|
||||
else:
|
||||
self.random.shuffle(requirements)
|
||||
else:
|
||||
for i in range(1, 5):
|
||||
requirements.insert(i - 1, quotient * i)
|
||||
self.boss_requirements = requirements
|
||||
itempool.extend([self.create_item("Heart Star") for _ in range(required_heart_stars)])
|
||||
itempool.extend([self.create_item(self.get_filler_item_name(False))
|
||||
for _ in range(filler_amount + (remaining_items - total_heart_stars))])
|
||||
itempool.extend([self.create_item(self.get_trap_item_name())
|
||||
for _ in range(trap_amount)])
|
||||
itempool.extend([self.create_item("Heart Star", True) for _ in range(non_required_heart_stars)])
|
||||
self.multiworld.itempool += itempool
|
||||
if self.options.open_world:
|
||||
for level in self.player_levels:
|
||||
for stage in range(0, 6):
|
||||
self.multiworld.get_location(location_table[self.player_levels[level][stage]]
|
||||
.replace("Complete", "Stage Completion"), self.player) \
|
||||
.place_locked_item(KDL3Item(
|
||||
f"{LocationName.level_names_inverse[level]} - Stage Completion",
|
||||
ItemClassification.progression, None, self.player))
|
||||
|
||||
set_rules = set_rules
|
||||
|
||||
def generate_basic(self) -> None:
|
||||
self.stage_shuffle_enabled = self.options.stage_shuffle > 0
|
||||
goal = self.options.goal
|
||||
goal_location = self.multiworld.get_location(LocationName.goals[goal], self.player)
|
||||
goal_location.place_locked_item(KDL3Item("Love-Love Rod", ItemClassification.progression, None, self.player))
|
||||
for level in range(1, 6):
|
||||
self.multiworld.get_location(f"Level {level} Boss - Defeated", self.player) \
|
||||
.place_locked_item(
|
||||
KDL3Item(f"Level {level} Boss Defeated", ItemClassification.progression, None, self.player))
|
||||
self.multiworld.get_location(f"Level {level} Boss - Purified", self.player) \
|
||||
.place_locked_item(
|
||||
KDL3Item(f"Level {level} Boss Purified", ItemClassification.progression, None, self.player))
|
||||
self.multiworld.completion_condition[self.player] = lambda state: state.has("Love-Love Rod", self.player)
|
||||
# this can technically be done at any point before generate_output
|
||||
if self.options.allow_bb:
|
||||
if self.options.allow_bb == self.options.allow_bb.option_enforced:
|
||||
self.boss_butch_bosses = [True for _ in range(6)]
|
||||
else:
|
||||
self.boss_butch_bosses = [self.random.choice([True, False]) for _ in range(6)]
|
||||
|
||||
def generate_output(self, output_directory: str):
|
||||
rom_path = ""
|
||||
try:
|
||||
rom = RomData(get_base_rom_path())
|
||||
patch_rom(self, rom)
|
||||
|
||||
rom_path = os.path.join(output_directory, f"{self.multiworld.get_out_file_name_base(self.player)}.sfc")
|
||||
rom.write_to_file(rom_path)
|
||||
self.rom_name = rom.name
|
||||
|
||||
patch = KDL3DeltaPatch(os.path.splitext(rom_path)[0] + KDL3DeltaPatch.patch_file_ending, player=self.player,
|
||||
player_name=self.multiworld.player_name[self.player], patched_path=rom_path)
|
||||
patch.write()
|
||||
except Exception:
|
||||
raise
|
||||
finally:
|
||||
self.rom_name_available_event.set() # make sure threading continues and errors are collected
|
||||
if os.path.exists(rom_path):
|
||||
os.unlink(rom_path)
|
||||
|
||||
def modify_multidata(self, multidata: dict):
|
||||
# wait for self.rom_name to be available.
|
||||
self.rom_name_available_event.wait()
|
||||
rom_name = getattr(self, "rom_name", None)
|
||||
# we skip in case of error, so that the original error in the output thread is the one that gets raised
|
||||
if rom_name:
|
||||
new_name = base64.b64encode(bytes(self.rom_name)).decode()
|
||||
multidata["connect_names"][new_name] = multidata["connect_names"][self.multiworld.player_name[self.player]]
|
||||
|
||||
def write_spoiler(self, spoiler_handle: TextIO) -> None:
|
||||
if self.stage_shuffle_enabled:
|
||||
spoiler_handle.write(f"\nLevel Layout ({self.multiworld.get_player_name(self.player)}):\n")
|
||||
for level in LocationName.level_names:
|
||||
for stage, i in zip(self.player_levels[LocationName.level_names[level]], range(1, 7)):
|
||||
spoiler_handle.write(f"{level} {i}: {location_table[stage].replace(' - Complete', '')}\n")
|
||||
if self.options.animal_randomization:
|
||||
spoiler_handle.write(f"\nAnimal Friends ({self.multiworld.get_player_name(self.player)}):\n")
|
||||
for level in self.player_levels:
|
||||
for stage in range(6):
|
||||
rooms = [room for room in self.rooms if room.level == level and room.stage == stage]
|
||||
animals = []
|
||||
for room in rooms:
|
||||
animals.extend([location.item.name.replace(" Spawn", "")
|
||||
for location in room.locations if "Animal" in location.name])
|
||||
spoiler_handle.write(f"{location_table[self.player_levels[level][stage]].replace(' - Complete','')}"
|
||||
f": {', '.join(animals)}\n")
|
||||
if self.options.copy_ability_randomization:
|
||||
spoiler_handle.write(f"\nCopy Abilities ({self.multiworld.get_player_name(self.player)}):\n")
|
||||
for enemy in self.copy_abilities:
|
||||
spoiler_handle.write(f"{enemy}: {self.copy_abilities[enemy].replace('No Ability', 'None').replace(' Ability', '')}\n")
|
||||
|
||||
def extend_hint_information(self, hint_data: Dict[int, Dict[int, str]]):
|
||||
if self.stage_shuffle_enabled:
|
||||
regions = {LocationName.level_names[level]: level for level in LocationName.level_names}
|
||||
level_hint_data = {}
|
||||
for level in regions:
|
||||
for stage in range(7):
|
||||
stage_name = self.multiworld.get_location(self.location_id_to_name[self.player_levels[level][stage]],
|
||||
self.player).name.replace(" - Complete", "")
|
||||
stage_regions = [room for room in self.rooms if stage_name in room.name]
|
||||
for region in stage_regions:
|
||||
for location in [location for location in region.locations if location.address]:
|
||||
level_hint_data[location.address] = f"{regions[level]} {stage + 1 if stage < 6 else 'Boss'}"
|
||||
hint_data[self.player] = level_hint_data
|
BIN
worlds/kdl3/data/APConsumable.bsdiff4
Normal file
BIN
worlds/kdl3/data/APConsumable.bsdiff4
Normal file
Binary file not shown.
BIN
worlds/kdl3/data/APHeartStar.bsdiff4
Normal file
BIN
worlds/kdl3/data/APHeartStar.bsdiff4
Normal file
Binary file not shown.
BIN
worlds/kdl3/data/APPauseIcons.dat
Normal file
BIN
worlds/kdl3/data/APPauseIcons.dat
Normal file
Binary file not shown.
BIN
worlds/kdl3/data/APStars.bsdiff4
Normal file
BIN
worlds/kdl3/data/APStars.bsdiff4
Normal file
Binary file not shown.
1
worlds/kdl3/data/Rooms.json
Normal file
1
worlds/kdl3/data/Rooms.json
Normal file
File diff suppressed because one or more lines are too long
BIN
worlds/kdl3/data/kdl3_basepatch.bsdiff4
Normal file
BIN
worlds/kdl3/data/kdl3_basepatch.bsdiff4
Normal file
Binary file not shown.
38
worlds/kdl3/docs/en_Kirby's Dream Land 3.md
Normal file
38
worlds/kdl3/docs/en_Kirby's Dream Land 3.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# Kirby's Dream Land 3
|
||||
|
||||
## Where is the settings page?
|
||||
|
||||
The [player settings page for this game](../player-settings) contains all the options you need to configure and export a
|
||||
config file.
|
||||
|
||||
## What does randomization do to this game?
|
||||
Kirby will be unable to absorb Copy Abilities and meet up with his animal friends until they are sent to him. Items such
|
||||
as Heart Stars, 1-Ups, and Invincibility Candy will be shuffled into the pool for Kirby to receive.
|
||||
|
||||
## What is considered a location check in Kirby's Dream Land 3?
|
||||
- Completing a stage for the first time
|
||||
- Completing the given task of a stage and receiving a Heart Star
|
||||
- Purifying a boss after acquiring a certain number of Heart Stars
|
||||
(indicated by their portrait flashing in the level select)
|
||||
- If enabled, 1-Ups and Maxim Tomatoes
|
||||
|
||||
## When the player receives an item, what happens?
|
||||
A sound effect will play, and Kirby will immediately receive the effects of that item, such as being able to receive Copy Abilities from enemies that
|
||||
give said Copy Ability. Animal Friends will require leaving the room you are currently in before they will appear.
|
||||
|
||||
## What is the goal of Kirby's Dream Land 3?
|
||||
Under the Zero goal, players must collect enough Heart Stars to purify the five bosses and gain access to the Hyper Zone,
|
||||
where Zero can be found and defeated.
|
||||
|
||||
Under the Boss Butch goal, players must collect enough Heart Stars to purify the five bosses
|
||||
and then complete the Boss Butch game mode accessible from the main menu.
|
||||
|
||||
Under the MG5 goal, players must collect enough Heart Stars to purify the five bosses
|
||||
and then perfect the Super MG5 game mode accessible from the main menu.
|
||||
|
||||
Under the Jumping goal, players must collect enough Heart Stars to purify the five bosses
|
||||
and then reach a target score in the Jumping game mode accessible from the main menu.
|
||||
|
||||
## Why is EmuHawk resizing itself while I'm playing?
|
||||
Kirby's Dream Land 3 changes the SNES's display resolution from 1x to 2x many times during gameplay (particularly in rooms with foreground effects).
|
||||
To counter-act this resizing, set SNES -> Options -> "Always use double-size frame buffer".
|
148
worlds/kdl3/docs/setup_en.md
Normal file
148
worlds/kdl3/docs/setup_en.md
Normal file
@@ -0,0 +1,148 @@
|
||||
# Kirby's Dream Land 3 Randomizer Setup Guide
|
||||
|
||||
## Required Software
|
||||
|
||||
- [Archipelago](https://github.com/ArchipelagoMW/Archipelago/releases).
|
||||
- Hardware or software capable of loading and playing SNES ROM files
|
||||
- An emulator capable of connecting to SNI with ROM access. Any one of the following will work:
|
||||
- snes9x-emunwa from: [snes9x-emunwa Releases Page](https://github.com/Skarsnik/snes9x-emunwa/releases)
|
||||
- snes9x-rr from: [snes9x-rr Releases Page](https://github.com/gocha/snes9x-rr/releases)
|
||||
- BizHawk from: [BizHawk Website](http://tasvideos.org/BizHawk.html)
|
||||
- bsnes-plus-nwa from: [bsnes-plus GitHub](https://github.com/black-sliver/bsnes-plus)
|
||||
- **RetroArch is currently incompatible with Kirby's Dream Land 3**
|
||||
- Or SD2SNES, FXPak Pro ([FXPak Pro Store Page](https://krikzz.com/store/home/54-fxpak-pro.html)), or other
|
||||
compatible hardware.
|
||||
- Your KDL3 ROM file, probably named either `Kirby's Dream Land 3 (USA).sfc` or `Hoshi no Kirby 3 (J).sfc`
|
||||
|
||||
## Installation Procedures
|
||||
|
||||
1. Download and install Archipelago from the link above, making sure to install the most recent version.
|
||||
**The installer file is located in the assets section at the bottom of the version information**.
|
||||
- During generation/patching, you will be asked to locate your base ROM file. This is your Kirby's Dream Land 3 ROM file.
|
||||
|
||||
2. If you are using an emulator, you should assign your SNI-compatible emulator as your default program for launching ROM
|
||||
files.
|
||||
1. Extract your emulator's folder to your Desktop, or somewhere you will remember.
|
||||
2. Right-click on a ROM file and select **Open with...**
|
||||
3. Check the box next to **Always use this app to open .sfc files**
|
||||
4. Scroll to the bottom of the list and click the grey text **Look for another App on this PC**
|
||||
5. Browse for your emulator's `.exe` file and click **Open**. This file should be located inside the folder you
|
||||
extracted in step one.
|
||||
|
||||
## Create a Config (.yaml) File
|
||||
|
||||
### What is a config file and why do I need one?
|
||||
|
||||
Your config file contains a set of configuration options which provide the generator with information about how it
|
||||
should generate your game. Each player of a multiworld will provide their own config file. This setup allows each player
|
||||
to enjoy an experience customized for their taste, and different players in the same multiworld can all have different
|
||||
options.
|
||||
|
||||
See the guide on setting up a basic YAML at the Archipelago setup
|
||||
guide: [Basic Multiworld Setup Guide](/tutorial/Archipelago/setup/en)
|
||||
|
||||
### Where do I get a config file?
|
||||
|
||||
The [Player Settings](/games/Kirby's%20Dream%20Land%203/player-settings) page on the website allows you to configure
|
||||
your personal settings and export a config file from them.
|
||||
|
||||
### Verifying your config file
|
||||
|
||||
If you would like to validate your config file to make sure it works, you may do so on the
|
||||
[YAML Validator](/mysterycheck) page.
|
||||
|
||||
## Generating a Single-Player Game
|
||||
|
||||
1. Navigate to the [Player Settings](/games/Kirby's%20Dream%20Land%203/player-settings) page, configure your options,
|
||||
and click the "Generate Game" button.
|
||||
2. You will be presented with a "Seed Info" page.
|
||||
3. Click the "Create New Room" link.
|
||||
4. You will be presented with a server page, from which you can download your patch file.
|
||||
5. Double-click on your patch file, and SNIClient will launch automatically, create your ROM from the patch file, and
|
||||
open your emulator for you.
|
||||
|
||||
## Joining a MultiWorld Game
|
||||
|
||||
### Obtain your patch file and create your ROM
|
||||
|
||||
When you join a multiworld game, you will be asked to provide your config file to whoever is hosting. Once that is done,
|
||||
the host will provide you with either a link to download your patch file, or with a zip file containing everyone's patch
|
||||
files. Your patch file should have a `.apkdl3` extension.
|
||||
|
||||
Put your patch file on your desktop or somewhere convenient, and double click it. This should automatically launch the
|
||||
client, and will also create your ROM in the same place as your patch file.
|
||||
|
||||
### Connect to the client
|
||||
|
||||
#### With an emulator
|
||||
|
||||
When the client launched automatically, SNI should have also automatically launched in the background. If this is its
|
||||
first time launching, you may be prompted to allow it to communicate through the Windows Firewall.
|
||||
|
||||
##### snes9x-rr
|
||||
|
||||
1. Load your ROM file if it hasn't already been loaded.
|
||||
2. Click on the File menu and hover on **Lua Scripting**
|
||||
3. Click on **New Lua Script Window...**
|
||||
4. In the new window, click **Browse...**
|
||||
5. Select the connector lua file included with your client
|
||||
- Look in the Archipelago folder for `/SNI/lua/Connector.lua`
|
||||
6. If you see an error while loading the script that states `socket.dll missing` or similar, navigate to the folder of
|
||||
the lua you are using in your file explorer and copy the `socket.dll` to the base folder of your snes9x install.
|
||||
|
||||
##### BizHawk
|
||||
|
||||
1. Ensure you have the BSNES core loaded. You may do this by clicking on the Tools menu in BizHawk and following these
|
||||
menu options:
|
||||
`Config --> Cores --> SNES --> BSNES`
|
||||
Once you have changed the loaded core, you must restart BizHawk.
|
||||
2. Load your ROM file if it hasn't already been loaded.
|
||||
3. Click on the Tools menu and click on **Lua Console**
|
||||
4. Click Script -> Open Script...
|
||||
5. Select the `Connector.lua` file you downloaded above
|
||||
- Look in the Archipelago folder for `/SNI/lua/Connector.lua`
|
||||
|
||||
##### bsnes-plus-nwa and snes9x-nwa
|
||||
|
||||
These should automatically connect to SNI. If this is the first time launching, you may be prompted to allow it to
|
||||
communicate through the Windows Firewall.
|
||||
|
||||
#### With hardware
|
||||
|
||||
This guide assumes you have downloaded the correct firmware for your device. If you have not done so already, please do
|
||||
this now. SD2SNES and FXPak Pro users may download the appropriate firmware
|
||||
[here](https://github.com/RedGuyyyy/sd2snes/releases). Other hardware may find helpful information
|
||||
[on this page](http://usb2snes.com/#supported-platforms).
|
||||
|
||||
1. Close your emulator, which may have auto-launched.
|
||||
2. Power on your device and load the ROM.
|
||||
|
||||
### Connect to the Archipelago Server
|
||||
|
||||
The patch file which launched your client should have automatically connected you to the AP Server. There are a few
|
||||
reasons this may not happen however, including if the game is hosted on the website but was generated elsewhere. If the
|
||||
client window shows "Server Status: Not Connected", simply ask the host for the address of the server, and copy/paste it
|
||||
into the "Server" input field then press enter.
|
||||
|
||||
The client will attempt to reconnect to the new server address, and should momentarily show "Server Status: Connected".
|
||||
|
||||
### Play the game
|
||||
|
||||
When the client shows both SNES Device and Server as connected, you're ready to begin playing. Congratulations on
|
||||
successfully joining a multiworld game! You can execute various commands in your client. For more information regarding
|
||||
these commands you can use `/help` for local client commands and `!help` for server commands.
|
||||
|
||||
## Hosting a MultiWorld game
|
||||
|
||||
The recommended way to host a game is to use our [hosting service](/generate). The process is relatively simple:
|
||||
|
||||
1. Collect config files from your players.
|
||||
2. Create a zip file containing your players' config files.
|
||||
3. Upload that zip file to the website linked above.
|
||||
4. Wait a moment while the seed is generated.
|
||||
5. When the seed is generated, you will be redirected to a "Seed Info" page.
|
||||
6. Click "Create New Room". This will take you to the server page. Provide the link to this page to your players, so
|
||||
they may download their patch files from there.
|
||||
7. Note that a link to a MultiWorld Tracker is at the top of the room page. The tracker shows the progress of all
|
||||
players in the game. Any observers may also be given the link to this page.
|
||||
8. Once all players have joined, you may begin playing.
|
1237
worlds/kdl3/src/kdl3_basepatch.asm
Normal file
1237
worlds/kdl3/src/kdl3_basepatch.asm
Normal file
File diff suppressed because it is too large
Load Diff
37
worlds/kdl3/test/__init__.py
Normal file
37
worlds/kdl3/test/__init__.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import typing
|
||||
from argparse import Namespace
|
||||
|
||||
from BaseClasses import MultiWorld, PlandoOptions, CollectionState
|
||||
from test.TestBase import WorldTestBase
|
||||
from test.general import gen_steps
|
||||
from worlds import AutoWorld
|
||||
from worlds.AutoWorld import call_all
|
||||
|
||||
|
||||
class KDL3TestBase(WorldTestBase):
|
||||
game = "Kirby's Dream Land 3"
|
||||
|
||||
def world_setup(self, seed: typing.Optional[int] = None) -> None:
|
||||
if type(self) is WorldTestBase or \
|
||||
(hasattr(WorldTestBase, self._testMethodName)
|
||||
and not self.run_default_tests and
|
||||
getattr(self, self._testMethodName).__code__ is
|
||||
getattr(WorldTestBase, self._testMethodName, None).__code__):
|
||||
return # setUp gets called for tests defined in the base class. We skip world_setup here.
|
||||
if not hasattr(self, "game"):
|
||||
raise NotImplementedError("didn't define game name")
|
||||
self.multiworld = MultiWorld(1)
|
||||
self.multiworld.game[1] = self.game
|
||||
self.multiworld.player_name = {1: "Tester"}
|
||||
self.multiworld.set_seed(seed)
|
||||
self.multiworld.state = CollectionState(self.multiworld)
|
||||
args = Namespace()
|
||||
for name, option in AutoWorld.AutoWorldRegister.world_types[self.game].options_dataclass.type_hints.items():
|
||||
setattr(args, name, {
|
||||
1: option.from_any(self.options.get(name, getattr(option, "default")))
|
||||
})
|
||||
self.multiworld.set_options(args)
|
||||
self.multiworld.plando_options = PlandoOptions.connections
|
||||
self.multiworld.plando_connections = self.options["plando_connections"] if "plando_connections" in self.options.keys() else []
|
||||
for step in gen_steps:
|
||||
call_all(self.multiworld, step)
|
64
worlds/kdl3/test/test_goal.py
Normal file
64
worlds/kdl3/test/test_goal.py
Normal file
@@ -0,0 +1,64 @@
|
||||
from . import KDL3TestBase
|
||||
|
||||
|
||||
class TestFastGoal(KDL3TestBase):
|
||||
options = {
|
||||
"open_world": False,
|
||||
"goal_speed": "fast",
|
||||
"total_heart_stars": 30,
|
||||
"heart_stars_required": 50,
|
||||
"filler_percentage": 0,
|
||||
}
|
||||
|
||||
def test_goal(self):
|
||||
self.assertBeatable(False)
|
||||
heart_stars = self.get_items_by_name("Heart Star")
|
||||
self.collect(heart_stars[0:14])
|
||||
self.assertEqual(self.count("Heart Star"), 14, str(self.multiworld.seed))
|
||||
self.assertBeatable(False)
|
||||
self.collect(heart_stars[14:15])
|
||||
self.assertEqual(self.count("Heart Star"), 15, str(self.multiworld.seed))
|
||||
self.assertBeatable(True)
|
||||
self.remove([self.get_item_by_name("Love-Love Rod")])
|
||||
self.collect_by_name("Kine") # Ensure a little more progress, but leave out cutter and burning
|
||||
self.collect(heart_stars[15:])
|
||||
self.assertBeatable(True)
|
||||
|
||||
|
||||
class TestNormalGoal(KDL3TestBase):
|
||||
# TODO: open world tests
|
||||
options = {
|
||||
"open_world": False,
|
||||
"goal_speed": "normal",
|
||||
"total_heart_stars": 30,
|
||||
"heart_stars_required": 50,
|
||||
"filler_percentage": 0,
|
||||
}
|
||||
|
||||
def test_goal(self):
|
||||
self.assertBeatable(False)
|
||||
heart_stars = self.get_items_by_name("Heart Star")
|
||||
self.collect(heart_stars[0:14])
|
||||
self.assertEqual(self.count("Heart Star"), 14, str(self.multiworld.seed))
|
||||
self.assertBeatable(False)
|
||||
self.collect(heart_stars[14:15])
|
||||
self.assertEqual(self.count("Heart Star"), 15, str(self.multiworld.seed))
|
||||
self.assertBeatable(False)
|
||||
self.collect_by_name(["Burning", "Cutter", "Kine"])
|
||||
self.assertBeatable(True)
|
||||
self.remove([self.get_item_by_name("Love-Love Rod")])
|
||||
self.collect(heart_stars)
|
||||
self.assertEqual(self.count("Heart Star"), 30, str(self.multiworld.seed))
|
||||
self.assertBeatable(True)
|
||||
|
||||
def test_kine(self):
|
||||
self.collect_by_name(["Cutter", "Burning", "Heart Star"])
|
||||
self.assertBeatable(False)
|
||||
|
||||
def test_cutter(self):
|
||||
self.collect_by_name(["Kine", "Burning", "Heart Star"])
|
||||
self.assertBeatable(False)
|
||||
|
||||
def test_burning(self):
|
||||
self.collect_by_name(["Cutter", "Kine", "Heart Star"])
|
||||
self.assertBeatable(False)
|
68
worlds/kdl3/test/test_locations.py
Normal file
68
worlds/kdl3/test/test_locations.py
Normal file
@@ -0,0 +1,68 @@
|
||||
from . import KDL3TestBase
|
||||
from worlds.generic import PlandoConnection
|
||||
from ..Names import LocationName
|
||||
import typing
|
||||
|
||||
|
||||
class TestLocations(KDL3TestBase):
|
||||
options = {
|
||||
"open_world": True,
|
||||
"ow_boss_requirement": 1,
|
||||
"strict_bosses": False
|
||||
# these ensure we can always reach all stages physically
|
||||
}
|
||||
|
||||
def test_simple_heart_stars(self):
|
||||
self.run_location_test(LocationName.grass_land_muchi, ["ChuChu"])
|
||||
self.run_location_test(LocationName.grass_land_chao, ["Stone"])
|
||||
self.run_location_test(LocationName.grass_land_mine, ["Kine"])
|
||||
self.run_location_test(LocationName.ripple_field_kamuribana, ["Pitch", "Clean"])
|
||||
self.run_location_test(LocationName.ripple_field_bakasa, ["Kine", "Parasol"])
|
||||
self.run_location_test(LocationName.ripple_field_toad, ["Needle"])
|
||||
self.run_location_test(LocationName.ripple_field_mama_pitch, ["Pitch", "Kine", "Burning", "Stone"])
|
||||
self.run_location_test(LocationName.sand_canyon_auntie, ["Clean"])
|
||||
self.run_location_test(LocationName.sand_canyon_nyupun, ["ChuChu", "Cutter"])
|
||||
self.run_location_test(LocationName.sand_canyon_rob, ["Stone", "Kine", "Coo", "Parasol", "Spark", "Ice"])
|
||||
self.run_location_test(LocationName.sand_canyon_rob, ["Stone", "Kine", "Coo", "Parasol", "Clean", "Ice"]),
|
||||
self.run_location_test(LocationName.sand_canyon_rob, ["Stone", "Kine", "Coo", "Parasol", "Spark", "Needle"]),
|
||||
self.run_location_test(LocationName.sand_canyon_rob, ["Stone", "Kine", "Coo", "Parasol", "Clean", "Needle"]),
|
||||
self.run_location_test(LocationName.cloudy_park_hibanamodoki, ["Coo", "Clean"])
|
||||
self.run_location_test(LocationName.cloudy_park_piyokeko, ["Needle"])
|
||||
self.run_location_test(LocationName.cloudy_park_mikarin, ["Coo"])
|
||||
self.run_location_test(LocationName.cloudy_park_pick, ["Rick"])
|
||||
self.run_location_test(LocationName.iceberg_kogoesou, ["Burning"])
|
||||
self.run_location_test(LocationName.iceberg_samus, ["Ice"])
|
||||
self.run_location_test(LocationName.iceberg_name, ["Burning", "Coo", "ChuChu"])
|
||||
self.run_location_test(LocationName.iceberg_angel, ["Cutter", "Burning", "Spark", "Parasol", "Needle", "Clean", "Stone", "Ice"])
|
||||
|
||||
def run_location_test(self, location: str, itempool: typing.List[str]):
|
||||
items = itempool.copy()
|
||||
while len(itempool) > 0:
|
||||
self.assertFalse(self.can_reach_location(location), str(self.multiworld.seed))
|
||||
self.collect_by_name(itempool.pop())
|
||||
self.assertTrue(self.can_reach_location(location), str(self.multiworld.seed))
|
||||
self.remove(self.get_items_by_name(items))
|
||||
|
||||
|
||||
class TestShiro(KDL3TestBase):
|
||||
options = {
|
||||
"open_world": False,
|
||||
"plando_connections": [
|
||||
[],
|
||||
[
|
||||
PlandoConnection("Grass Land 1", "Iceberg 5", "both"),
|
||||
PlandoConnection("Grass Land 2", "Ripple Field 5", "both"),
|
||||
PlandoConnection("Grass Land 3", "Grass Land 1", "both")
|
||||
]],
|
||||
"stage_shuffle": "shuffled",
|
||||
"plando_options": "connections"
|
||||
}
|
||||
|
||||
def test_shiro(self):
|
||||
self.assertFalse(self.can_reach_location("Iceberg 5 - Shiro"), str(self.multiworld.seed))
|
||||
self.collect_by_name("Nago")
|
||||
self.assertFalse(self.can_reach_location("Iceberg 5 - Shiro"), str(self.multiworld.seed))
|
||||
# despite Shiro only requiring Nago for logic, it cannot be in logic because our two accessible stages
|
||||
# do not actually give the player access to Nago, thus we need Kine to pass 2-5
|
||||
self.collect_by_name("Kine")
|
||||
self.assertTrue(self.can_reach_location("Iceberg 5 - Shiro"), str(self.multiworld.seed))
|
245
worlds/kdl3/test/test_shuffles.py
Normal file
245
worlds/kdl3/test/test_shuffles.py
Normal file
@@ -0,0 +1,245 @@
|
||||
from typing import List, Tuple
|
||||
from . import KDL3TestBase
|
||||
from ..Room import KDL3Room
|
||||
|
||||
|
||||
class TestCopyAbilityShuffle(KDL3TestBase):
|
||||
options = {
|
||||
"open_world": False,
|
||||
"goal_speed": "normal",
|
||||
"total_heart_stars": 30,
|
||||
"heart_stars_required": 50,
|
||||
"filler_percentage": 0,
|
||||
"copy_ability_randomization": "enabled",
|
||||
}
|
||||
|
||||
def test_goal(self):
|
||||
self.assertBeatable(False)
|
||||
heart_stars = self.get_items_by_name("Heart Star")
|
||||
self.collect(heart_stars[0:14])
|
||||
self.assertEqual(self.count("Heart Star"), 14, str(self.multiworld.seed))
|
||||
self.assertBeatable(False)
|
||||
self.collect(heart_stars[14:15])
|
||||
self.assertEqual(self.count("Heart Star"), 15, str(self.multiworld.seed))
|
||||
self.assertBeatable(False)
|
||||
self.collect_by_name(["Burning", "Cutter", "Kine"])
|
||||
self.assertBeatable(True)
|
||||
self.remove([self.get_item_by_name("Love-Love Rod")])
|
||||
self.collect(heart_stars)
|
||||
self.assertEqual(self.count("Heart Star"), 30, str(self.multiworld.seed))
|
||||
self.assertBeatable(True)
|
||||
|
||||
def test_kine(self):
|
||||
self.collect_by_name(["Cutter", "Burning", "Heart Star"])
|
||||
self.assertBeatable(False)
|
||||
|
||||
def test_cutter(self):
|
||||
self.collect_by_name(["Kine", "Burning", "Heart Star"])
|
||||
self.assertBeatable(False)
|
||||
|
||||
def test_burning(self):
|
||||
self.collect_by_name(["Cutter", "Kine", "Heart Star"])
|
||||
self.assertBeatable(False)
|
||||
|
||||
def test_cutter_and_burning_reachable(self):
|
||||
rooms = self.multiworld.worlds[1].rooms
|
||||
copy_abilities = self.multiworld.worlds[1].copy_abilities
|
||||
sand_canyon_5 = self.multiworld.get_region("Sand Canyon 5 - 9", 1)
|
||||
assert isinstance(sand_canyon_5, KDL3Room)
|
||||
valid_rooms = [room for room in rooms if (room.level < sand_canyon_5.level)
|
||||
or (room.level == sand_canyon_5.level and room.stage < sand_canyon_5.stage)]
|
||||
for room in valid_rooms:
|
||||
if any(copy_abilities[enemy] == "Cutter Ability" for enemy in room.enemies):
|
||||
break
|
||||
else:
|
||||
self.fail("Could not reach Cutter Ability before Sand Canyon 5!")
|
||||
iceberg_4 = self.multiworld.get_region("Iceberg 4 - 7", 1)
|
||||
assert isinstance(iceberg_4, KDL3Room)
|
||||
valid_rooms = [room for room in rooms if (room.level < iceberg_4.level)
|
||||
or (room.level == iceberg_4.level and room.stage < iceberg_4.stage)]
|
||||
for room in valid_rooms:
|
||||
if any(copy_abilities[enemy] == "Burning Ability" for enemy in room.enemies):
|
||||
break
|
||||
else:
|
||||
self.fail("Could not reach Burning Ability before Iceberg 4!")
|
||||
|
||||
def test_valid_abilities_for_ROB(self):
|
||||
# there exists a subset of 4-7 abilities that will allow us access to ROB heart star on default settings
|
||||
self.collect_by_name(["Heart Star", "Kine", "Coo"]) # we will guaranteed need Coo, Kine, and Heart Stars to reach
|
||||
# first we need to identify our bukiset requirements
|
||||
groups = [
|
||||
({"Parasol Ability", "Cutter Ability"}, {'Bukiset (Parasol)', 'Bukiset (Cutter)'}),
|
||||
({"Spark Ability", "Clean Ability"}, {'Bukiset (Spark)', 'Bukiset (Clean)'}),
|
||||
({"Ice Ability", "Needle Ability"}, {'Bukiset (Ice)', 'Bukiset (Needle)'}),
|
||||
({"Stone Ability", "Burning Ability"}, {'Bukiset (Stone)', 'Bukiset (Burning)'}),
|
||||
]
|
||||
copy_abilities = self.multiworld.worlds[1].copy_abilities
|
||||
required_abilities: List[Tuple[str]] = []
|
||||
for abilities, bukisets in groups:
|
||||
potential_abilities: List[str] = list()
|
||||
for bukiset in bukisets:
|
||||
if copy_abilities[bukiset] in abilities:
|
||||
potential_abilities.append(copy_abilities[bukiset])
|
||||
required_abilities.append(tuple(potential_abilities))
|
||||
collected_abilities = list()
|
||||
for group in required_abilities:
|
||||
self.assertFalse(len(group) == 0, str(self.multiworld.seed))
|
||||
collected_abilities.append(group[0])
|
||||
self.collect_by_name([ability.replace(" Ability", "") for ability in collected_abilities])
|
||||
if "Parasol Ability" not in collected_abilities or "Stone Ability" not in collected_abilities:
|
||||
# required for non-Bukiset related portions
|
||||
self.collect_by_name(["Parasol", "Stone"])
|
||||
|
||||
if "Cutter Ability" not in collected_abilities:
|
||||
# we can't actually reach 3-6 without Cutter
|
||||
self.assertFalse(self.can_reach_location("Sand Canyon 6 - Professor Hector & R.O.B"), str(self.multiworld.seed))
|
||||
self.collect_by_name(["Cutter"])
|
||||
|
||||
self.assertTrue(self.can_reach_location("Sand Canyon 6 - Professor Hector & R.O.B"),
|
||||
''.join(str(self.multiworld.seed)).join(collected_abilities))
|
||||
|
||||
|
||||
class TestAnimalShuffle(KDL3TestBase):
|
||||
options = {
|
||||
"open_world": False,
|
||||
"goal_speed": "normal",
|
||||
"total_heart_stars": 30,
|
||||
"heart_stars_required": 50,
|
||||
"filler_percentage": 0,
|
||||
"animal_randomization": "full",
|
||||
}
|
||||
|
||||
def test_goal(self):
|
||||
self.assertBeatable(False)
|
||||
heart_stars = self.get_items_by_name("Heart Star")
|
||||
self.collect(heart_stars[0:14])
|
||||
self.assertEqual(self.count("Heart Star"), 14, str(self.multiworld.seed))
|
||||
self.assertBeatable(False)
|
||||
self.collect(heart_stars[14:15])
|
||||
self.assertEqual(self.count("Heart Star"), 15, str(self.multiworld.seed))
|
||||
self.assertBeatable(False)
|
||||
self.collect_by_name(["Burning", "Cutter", "Kine"])
|
||||
self.assertBeatable(True)
|
||||
self.remove([self.get_item_by_name("Love-Love Rod")])
|
||||
self.collect(heart_stars)
|
||||
self.assertEqual(self.count("Heart Star"), 30, str(self.multiworld.seed))
|
||||
self.assertBeatable(True)
|
||||
|
||||
def test_kine(self):
|
||||
self.collect_by_name(["Cutter", "Burning", "Heart Star"])
|
||||
self.assertBeatable(False)
|
||||
|
||||
def test_cutter(self):
|
||||
self.collect_by_name(["Kine", "Burning", "Heart Star"])
|
||||
self.assertBeatable(False)
|
||||
|
||||
def test_burning(self):
|
||||
self.collect_by_name(["Cutter", "Kine", "Heart Star"])
|
||||
self.assertBeatable(False)
|
||||
|
||||
def test_locked_animals(self):
|
||||
self.assertTrue(self.multiworld.get_location("Ripple Field 5 - Animal 2", 1).item.name == "Pitch Spawn")
|
||||
self.assertTrue(self.multiworld.get_location("Iceberg 4 - Animal 1", 1).item.name == "ChuChu Spawn")
|
||||
self.assertTrue(self.multiworld.get_location("Sand Canyon 6 - Animal 1", 1).item.name in {"Kine Spawn", "Coo Spawn"})
|
||||
|
||||
|
||||
class TestAllShuffle(KDL3TestBase):
|
||||
options = {
|
||||
"open_world": False,
|
||||
"goal_speed": "normal",
|
||||
"total_heart_stars": 30,
|
||||
"heart_stars_required": 50,
|
||||
"filler_percentage": 0,
|
||||
"animal_randomization": "full",
|
||||
"copy_ability_randomization": "enabled",
|
||||
}
|
||||
|
||||
def test_goal(self):
|
||||
self.assertBeatable(False)
|
||||
heart_stars = self.get_items_by_name("Heart Star")
|
||||
self.collect(heart_stars[0:14])
|
||||
self.assertEqual(self.count("Heart Star"), 14, str(self.multiworld.seed))
|
||||
self.assertBeatable(False)
|
||||
self.collect(heart_stars[14:15])
|
||||
self.assertEqual(self.count("Heart Star"), 15, str(self.multiworld.seed))
|
||||
self.assertBeatable(False)
|
||||
self.collect_by_name(["Burning", "Cutter", "Kine"])
|
||||
self.assertBeatable(True)
|
||||
self.remove([self.get_item_by_name("Love-Love Rod")])
|
||||
self.collect(heart_stars)
|
||||
self.assertEqual(self.count("Heart Star"), 30, str(self.multiworld.seed))
|
||||
self.assertBeatable(True)
|
||||
|
||||
def test_kine(self):
|
||||
self.collect_by_name(["Cutter", "Burning", "Heart Star"])
|
||||
self.assertBeatable(False)
|
||||
|
||||
def test_cutter(self):
|
||||
self.collect_by_name(["Kine", "Burning", "Heart Star"])
|
||||
self.assertBeatable(False)
|
||||
|
||||
def test_burning(self):
|
||||
self.collect_by_name(["Cutter", "Kine", "Heart Star"])
|
||||
self.assertBeatable(False)
|
||||
|
||||
def test_locked_animals(self):
|
||||
self.assertTrue(self.multiworld.get_location("Ripple Field 5 - Animal 2", 1).item.name == "Pitch Spawn")
|
||||
self.assertTrue(self.multiworld.get_location("Iceberg 4 - Animal 1", 1).item.name == "ChuChu Spawn")
|
||||
self.assertTrue(self.multiworld.get_location("Sand Canyon 6 - Animal 1", 1).item.name in {"Kine Spawn", "Coo Spawn"})
|
||||
|
||||
def test_cutter_and_burning_reachable(self):
|
||||
rooms = self.multiworld.worlds[1].rooms
|
||||
copy_abilities = self.multiworld.worlds[1].copy_abilities
|
||||
sand_canyon_5 = self.multiworld.get_region("Sand Canyon 5 - 9", 1)
|
||||
assert isinstance(sand_canyon_5, KDL3Room)
|
||||
valid_rooms = [room for room in rooms if (room.level < sand_canyon_5.level)
|
||||
or (room.level == sand_canyon_5.level and room.stage < sand_canyon_5.stage)]
|
||||
for room in valid_rooms:
|
||||
if any(copy_abilities[enemy] == "Cutter Ability" for enemy in room.enemies):
|
||||
break
|
||||
else:
|
||||
self.fail("Could not reach Cutter Ability before Sand Canyon 5!")
|
||||
iceberg_4 = self.multiworld.get_region("Iceberg 4 - 7", 1)
|
||||
assert isinstance(iceberg_4, KDL3Room)
|
||||
valid_rooms = [room for room in rooms if (room.level < iceberg_4.level)
|
||||
or (room.level == iceberg_4.level and room.stage < iceberg_4.stage)]
|
||||
for room in valid_rooms:
|
||||
if any(copy_abilities[enemy] == "Burning Ability" for enemy in room.enemies):
|
||||
break
|
||||
else:
|
||||
self.fail("Could not reach Burning Ability before Iceberg 4!")
|
||||
|
||||
def test_valid_abilities_for_ROB(self):
|
||||
# there exists a subset of 4-7 abilities that will allow us access to ROB heart star on default settings
|
||||
self.collect_by_name(["Heart Star", "Kine", "Coo"]) # we will guaranteed need Coo, Kine, and Heart Stars to reach
|
||||
# first we need to identify our bukiset requirements
|
||||
groups = [
|
||||
({"Parasol Ability", "Cutter Ability"}, {'Bukiset (Parasol)', 'Bukiset (Cutter)'}),
|
||||
({"Spark Ability", "Clean Ability"}, {'Bukiset (Spark)', 'Bukiset (Clean)'}),
|
||||
({"Ice Ability", "Needle Ability"}, {'Bukiset (Ice)', 'Bukiset (Needle)'}),
|
||||
({"Stone Ability", "Burning Ability"}, {'Bukiset (Stone)', 'Bukiset (Burning)'}),
|
||||
]
|
||||
copy_abilities = self.multiworld.worlds[1].copy_abilities
|
||||
required_abilities: List[Tuple[str]] = []
|
||||
for abilities, bukisets in groups:
|
||||
potential_abilities: List[str] = list()
|
||||
for bukiset in bukisets:
|
||||
if copy_abilities[bukiset] in abilities:
|
||||
potential_abilities.append(copy_abilities[bukiset])
|
||||
required_abilities.append(tuple(potential_abilities))
|
||||
collected_abilities = list()
|
||||
for group in required_abilities:
|
||||
self.assertFalse(len(group) == 0, str(self.multiworld.seed))
|
||||
collected_abilities.append(group[0])
|
||||
self.collect_by_name([ability.replace(" Ability", "") for ability in collected_abilities])
|
||||
if "Parasol Ability" not in collected_abilities or "Stone Ability" not in collected_abilities:
|
||||
# required for non-Bukiset related portions
|
||||
self.collect_by_name(["Parasol", "Stone"])
|
||||
|
||||
if "Cutter Ability" not in collected_abilities:
|
||||
# we can't actually reach 3-6 without Cutter
|
||||
self.assertFalse(self.can_reach_location("Sand Canyon 6 - Professor Hector & R.O.B"), str(self.multiworld.seed))
|
||||
self.collect_by_name(["Cutter"])
|
||||
|
||||
self.assertTrue(self.can_reach_location("Sand Canyon 6 - Professor Hector & R.O.B"),
|
||||
''.join(str(self.multiworld.seed)).join(collected_abilities))
|
Reference in New Issue
Block a user