From db8d74e2ec6930b69af37c5f66c86378044d30eb Mon Sep 17 00:00:00 2001 From: massimilianodelliubaldini <8584296+massimilianodelliubaldini@users.noreply.github.com> Date: Thu, 18 Apr 2024 14:11:44 -0400 Subject: [PATCH] Jak 1: Refactor ID scheme to better fit game's scheme. Add more subregions and rules, but still missing one-way Entrances. --- worlds/jakanddaxter/GameID.py | 10 +- worlds/jakanddaxter/Items.py | 27 +-- worlds/jakanddaxter/Locations.py | 103 +++++--- worlds/jakanddaxter/Regions.py | 235 +++++++++---------- worlds/jakanddaxter/Rules.py | 100 ++++++-- worlds/jakanddaxter/__init__.py | 40 ++-- worlds/jakanddaxter/locs/CellLocations.py | 193 +++++++-------- worlds/jakanddaxter/locs/OrbLocations.py | 5 +- worlds/jakanddaxter/locs/ScoutLocations.py | 17 +- worlds/jakanddaxter/locs/SpecialLocations.py | 15 -- 10 files changed, 405 insertions(+), 340 deletions(-) delete mode 100644 worlds/jakanddaxter/locs/SpecialLocations.py diff --git a/worlds/jakanddaxter/GameID.py b/worlds/jakanddaxter/GameID.py index 12d0079483..e4ebb030f8 100644 --- a/worlds/jakanddaxter/GameID.py +++ b/worlds/jakanddaxter/GameID.py @@ -1,5 +1,13 @@ # All Jak And Daxter IDs must be offset by this number. -game_id = 74680000 +game_id = 746800000 # The name of the game. game_name = "Jak and Daxter: The Precursor Legacy" + +# What follows are offsets for each Location/Item type, +# necessary for Archipelago to avoid collision between +# ID numbers shared across items. See respective +# Locations files for explanations. +cell_offset = 0 +fly_offset = 1048576 # 2^20 +orb_offset = 2097152 # 2^21 diff --git a/worlds/jakanddaxter/Items.py b/worlds/jakanddaxter/Items.py index ee94ca55e0..4c9f16af0e 100644 --- a/worlds/jakanddaxter/Items.py +++ b/worlds/jakanddaxter/Items.py @@ -1,32 +1,7 @@ from BaseClasses import Item -from .GameID import game_id, game_name +from .GameID import game_name class JakAndDaxterItem(Item): game: str = game_name - -# Items Found Multiple Times -generic_item_table = { - 0: "Power Cell", - 101: "Scout Fly", - 213: "Precursor Orb" -} - -# Items Only Found Once -special_item_table = { - 2213: "Fisherman's Boat", - # 2214: "Sculptor's Muse", # Unused? - 2215: "Flut Flut", - 2216: "Blue Eco Switch", - 2217: "Gladiator's Pontoons", - 2218: "Yellow Eco Switch", - 2219: "Lurker Fort Gate", - 2220: "Free The Yellow Sage", - 2221: "Free The Red Sage", - 2222: "Free The Blue Sage", - 2223: "Free The Green Sage" -} - -# All Items -item_table = {**generic_item_table, **special_item_table} diff --git a/worlds/jakanddaxter/Locations.py b/worlds/jakanddaxter/Locations.py index 9d03297e4a..84dd27f6ed 100644 --- a/worlds/jakanddaxter/Locations.py +++ b/worlds/jakanddaxter/Locations.py @@ -1,6 +1,6 @@ from BaseClasses import Location -from .GameID import game_id, game_name -from .locs import CellLocations, SpecialLocations, ScoutLocations +from .GameID import game_id, game_name, cell_offset, fly_offset +from .locs import CellLocations, ScoutLocations class JakAndDaxterLocation(Location): @@ -8,38 +8,71 @@ class JakAndDaxterLocation(Location): # All Locations +# Because all items in Jak And Daxter are unique and do not regenerate, we can use this same table as our item table. +# Each Item ID == its corresponding Location ID. And then we only have to do this ugly math once. location_table = { - **CellLocations.locGR_cellTable, - **CellLocations.locSV_cellTable, - **CellLocations.locFJ_cellTable, - **CellLocations.locSB_cellTable, - **CellLocations.locMI_cellTable, - **CellLocations.locFC_cellTable, - **CellLocations.locRV_cellTable, - **CellLocations.locPB_cellTable, - **CellLocations.locLPC_cellTable, - **CellLocations.locBS_cellTable, - **CellLocations.locMP_cellTable, - **CellLocations.locVC_cellTable, - **CellLocations.locSC_cellTable, - **CellLocations.locSM_cellTable, - **CellLocations.locLT_cellTable, - **CellLocations.locGMC_cellTable, - **SpecialLocations.loc_specialTable, - **ScoutLocations.locGR_scoutTable, - **ScoutLocations.locSV_scoutTable, - **ScoutLocations.locFJ_scoutTable, - **ScoutLocations.locSB_scoutTable, - **ScoutLocations.locMI_scoutTable, - **ScoutLocations.locFC_scoutTable, - **ScoutLocations.locRV_scoutTable, - **ScoutLocations.locPB_scoutTable, - **ScoutLocations.locLPC_scoutTable, - **ScoutLocations.locBS_scoutTable, - **ScoutLocations.locMP_scoutTable, - **ScoutLocations.locVC_scoutTable, - **ScoutLocations.locSC_scoutTable, - **ScoutLocations.locSM_scoutTable, - **ScoutLocations.locLT_scoutTable, - **ScoutLocations.locGMC_scoutTable + **{game_id + cell_offset + k: CellLocations.locGR_cellTable[k] + for k in CellLocations.locGR_cellTable}, + **{game_id + cell_offset + k: CellLocations.locSV_cellTable[k] + for k in CellLocations.locSV_cellTable}, + **{game_id + cell_offset + k: CellLocations.locFJ_cellTable[k] + for k in CellLocations.locFJ_cellTable}, + **{game_id + cell_offset + k: CellLocations.locSB_cellTable[k] + for k in CellLocations.locSB_cellTable}, + **{game_id + cell_offset + k: CellLocations.locMI_cellTable[k] + for k in CellLocations.locMI_cellTable}, + **{game_id + cell_offset + k: CellLocations.locFC_cellTable[k] + for k in CellLocations.locFC_cellTable}, + **{game_id + cell_offset + k: CellLocations.locRV_cellTable[k] + for k in CellLocations.locRV_cellTable}, + **{game_id + cell_offset + k: CellLocations.locPB_cellTable[k] + for k in CellLocations.locPB_cellTable}, + **{game_id + cell_offset + k: CellLocations.locLPC_cellTable[k] + for k in CellLocations.locLPC_cellTable}, + **{game_id + cell_offset + k: CellLocations.locBS_cellTable[k] + for k in CellLocations.locBS_cellTable}, + **{game_id + cell_offset + k: CellLocations.locMP_cellTable[k] + for k in CellLocations.locMP_cellTable}, + **{game_id + cell_offset + k: CellLocations.locVC_cellTable[k] + for k in CellLocations.locVC_cellTable}, + **{game_id + cell_offset + k: CellLocations.locSC_cellTable[k] + for k in CellLocations.locSC_cellTable}, + **{game_id + cell_offset + k: CellLocations.locSM_cellTable[k] + for k in CellLocations.locSM_cellTable}, + **{game_id + cell_offset + k: CellLocations.locLT_cellTable[k] + for k in CellLocations.locLT_cellTable}, + **{game_id + cell_offset + k: CellLocations.locGMC_cellTable[k] + for k in CellLocations.locGMC_cellTable}, + **{game_id + fly_offset + k: ScoutLocations.locGR_scoutTable[k] + for k in ScoutLocations.locGR_scoutTable}, + **{game_id + fly_offset + k: ScoutLocations.locSV_scoutTable[k] + for k in ScoutLocations.locSV_scoutTable}, + **{game_id + fly_offset + k: ScoutLocations.locFJ_scoutTable[k] + for k in ScoutLocations.locFJ_scoutTable}, + **{game_id + fly_offset + k: ScoutLocations.locSB_scoutTable[k] + for k in ScoutLocations.locSB_scoutTable}, + **{game_id + fly_offset + k: ScoutLocations.locMI_scoutTable[k] + for k in ScoutLocations.locMI_scoutTable}, + **{game_id + fly_offset + k: ScoutLocations.locFC_scoutTable[k] + for k in ScoutLocations.locFC_scoutTable}, + **{game_id + fly_offset + k: ScoutLocations.locRV_scoutTable[k] + for k in ScoutLocations.locRV_scoutTable}, + **{game_id + fly_offset + k: ScoutLocations.locPB_scoutTable[k] + for k in ScoutLocations.locPB_scoutTable}, + **{game_id + fly_offset + k: ScoutLocations.locLPC_scoutTable[k] + for k in ScoutLocations.locLPC_scoutTable}, + **{game_id + fly_offset + k: ScoutLocations.locBS_scoutTable[k] + for k in ScoutLocations.locBS_scoutTable}, + **{game_id + fly_offset + k: ScoutLocations.locMP_scoutTable[k] + for k in ScoutLocations.locMP_scoutTable}, + **{game_id + fly_offset + k: ScoutLocations.locVC_scoutTable[k] + for k in ScoutLocations.locVC_scoutTable}, + **{game_id + fly_offset + k: ScoutLocations.locSC_scoutTable[k] + for k in ScoutLocations.locSC_scoutTable}, + **{game_id + fly_offset + k: ScoutLocations.locSM_scoutTable[k] + for k in ScoutLocations.locSM_scoutTable}, + **{game_id + fly_offset + k: ScoutLocations.locLT_scoutTable[k] + for k in ScoutLocations.locLT_scoutTable}, + **{game_id + fly_offset + k: ScoutLocations.locGMC_scoutTable[k] + for k in ScoutLocations.locGMC_scoutTable} } diff --git a/worlds/jakanddaxter/Regions.py b/worlds/jakanddaxter/Regions.py index 59cd9e5ff7..787ad59214 100644 --- a/worlds/jakanddaxter/Regions.py +++ b/worlds/jakanddaxter/Regions.py @@ -1,41 +1,45 @@ import typing -from enum import Enum +from enum import Enum, auto from BaseClasses import MultiWorld, Region -from .GameID import game_id, game_name +from .GameID import game_id, game_name, cell_offset, fly_offset from .Options import JakAndDaxterOptions from .Locations import JakAndDaxterLocation, location_table -from .locs import CellLocations, SpecialLocations, ScoutLocations +from .locs import CellLocations, ScoutLocations class JakAndDaxterLevel(int, Enum): - GEYSER_ROCK = 0 - SANDOVER_VILLAGE = 1 - FORBIDDEN_JUNGLE = 2 - SENTINEL_BEACH = 3 - MISTY_ISLAND = 4 - FIRE_CANYON = 5 - ROCK_VILLAGE = 6 - PRECURSOR_BASIN = 7 - LOST_PRECURSOR_CITY = 8 - BOGGY_SWAMP = 9 - MOUNTAIN_PASS = 10 - VOLCANIC_CRATER = 11 - SPIDER_CAVE = 12 - SNOWY_MOUNTAIN = 13 - LAVA_TUBE = 14 - GOL_AND_MAIAS_CITADEL = 15 + GEYSER_ROCK = auto() + SANDOVER_VILLAGE = auto() + FORBIDDEN_JUNGLE = auto() + SENTINEL_BEACH = auto() + MISTY_ISLAND = auto() + FIRE_CANYON = auto() + ROCK_VILLAGE = auto() + PRECURSOR_BASIN = auto() + LOST_PRECURSOR_CITY = auto() + BOGGY_SWAMP = auto() + MOUNTAIN_PASS = auto() + VOLCANIC_CRATER = auto() + SPIDER_CAVE = auto() + SNOWY_MOUNTAIN = auto() + LAVA_TUBE = auto() + GOL_AND_MAIAS_CITADEL = auto() class JakAndDaxterSubLevel(int, Enum): - MAIN_AREA = 0 - FORBIDDEN_JUNGLE_PLANT_ROOM = 1 - SENTINEL_BEACH_CANNON_TOWER = 2 - BOGGY_SWAMP_FLUT_FLUT = 3 - MOUNTAIN_PASS_SHORTCUT = 4 - SNOWY_MOUNTAIN_FLUT_FLUT = 5 - SNOWY_MOUNTAIN_LURKER_FORT = 6 - GOL_AND_MAIAS_CITADEL_ROTATING_TOWER = 7 - GOL_AND_MAIAS_CITADEL_FINAL_BOSS = 8 + MAIN_AREA = auto() + FORBIDDEN_JUNGLE_SWITCH_ROOM = auto() + FORBIDDEN_JUNGLE_PLANT_ROOM = auto() + SENTINEL_BEACH_CANNON_TOWER = auto() + PRECURSOR_BASIN_BLUE_RINGS = auto() + BOGGY_SWAMP_FLUT_FLUT = auto() + MOUNTAIN_PASS_RACE = auto() + MOUNTAIN_PASS_SHORTCUT = auto() + SNOWY_MOUNTAIN_FLUT_FLUT = auto() + SNOWY_MOUNTAIN_LURKER_FORT = auto() + SNOWY_MOUNTAIN_FROZEN_BOX = auto() + GOL_AND_MAIAS_CITADEL_ROTATING_TOWER = auto() + GOL_AND_MAIAS_CITADEL_FINAL_BOSS = auto() level_table: typing.Dict[JakAndDaxterLevel, str] = { @@ -59,12 +63,16 @@ level_table: typing.Dict[JakAndDaxterLevel, str] = { subLevel_table: typing.Dict[JakAndDaxterSubLevel, str] = { JakAndDaxterSubLevel.MAIN_AREA: "Main Area", + JakAndDaxterSubLevel.FORBIDDEN_JUNGLE_SWITCH_ROOM: "Forbidden Jungle Switch Room", JakAndDaxterSubLevel.FORBIDDEN_JUNGLE_PLANT_ROOM: "Forbidden Jungle Plant Room", JakAndDaxterSubLevel.SENTINEL_BEACH_CANNON_TOWER: "Sentinel Beach Cannon Tower", + JakAndDaxterSubLevel.PRECURSOR_BASIN_BLUE_RINGS: "Precursor Basin Blue Rings", JakAndDaxterSubLevel.BOGGY_SWAMP_FLUT_FLUT: "Boggy Swamp Flut Flut", + JakAndDaxterSubLevel.MOUNTAIN_PASS_RACE: "Mountain Pass Race", JakAndDaxterSubLevel.MOUNTAIN_PASS_SHORTCUT: "Mountain Pass Shortcut", JakAndDaxterSubLevel.SNOWY_MOUNTAIN_FLUT_FLUT: "Snowy Mountain Flut Flut", JakAndDaxterSubLevel.SNOWY_MOUNTAIN_LURKER_FORT: "Snowy Mountain Lurker Fort", + JakAndDaxterSubLevel.SNOWY_MOUNTAIN_FROZEN_BOX: "Snowy Mountain Frozen Box", JakAndDaxterSubLevel.GOL_AND_MAIAS_CITADEL_ROTATING_TOWER: "Gol and Maia's Citadel Rotating Tower", JakAndDaxterSubLevel.GOL_AND_MAIAS_CITADEL_FINAL_BOSS: "Gol and Maia's Citadel Final Boss" } @@ -74,162 +82,137 @@ class JakAndDaxterRegion(Region): game: str = game_name +# Use the original ID's for each item to tell the Region which Locations are available in it. +# You do NOT need to add the item offsets, that will be handled by create_*_locations. def create_regions(multiworld: MultiWorld, options: JakAndDaxterOptions, player: int): create_region(player, multiworld, "Menu") region_gr = create_region(player, multiworld, level_table[JakAndDaxterLevel.GEYSER_ROCK]) - create_locations(region_gr, { - **CellLocations.locGR_cellTable, - **ScoutLocations.locGR_scoutTable - }) + create_cell_locations(region_gr, CellLocations.locGR_cellTable) + create_fly_locations(region_gr, ScoutLocations.locGR_scoutTable) region_sv = create_region(player, multiworld, level_table[JakAndDaxterLevel.SANDOVER_VILLAGE]) - create_locations(region_sv, { - **CellLocations.locSV_cellTable, - **ScoutLocations.locSV_scoutTable - }) + create_cell_locations(region_sv, CellLocations.locSV_cellTable) + create_fly_locations(region_sv, ScoutLocations.locSV_scoutTable) region_fj = create_region(player, multiworld, level_table[JakAndDaxterLevel.FORBIDDEN_JUNGLE]) - create_locations(region_fj, { - **{k: CellLocations.locFJ_cellTable[k] for k in {10, 11, 12, 14, 15, 16, 17}}, - **{k: SpecialLocations.loc_specialTable[k] for k in {2213, 2216}}, - **ScoutLocations.locFJ_scoutTable - }) + create_cell_locations(region_fj, {k: CellLocations.locFJ_cellTable[k] for k in {3, 4, 5, 8, 9, 7}}) + create_fly_locations(region_fj, ScoutLocations.locFJ_scoutTable) - sub_region_fjpr = create_subregion(region_fj, subLevel_table[JakAndDaxterSubLevel.FORBIDDEN_JUNGLE_PLANT_ROOM]) - create_locations(sub_region_fjpr, {k: CellLocations.locFJ_cellTable[k] for k in {13}}) + sub_region_fjsr = create_subregion(region_fj, subLevel_table[JakAndDaxterSubLevel.FORBIDDEN_JUNGLE_SWITCH_ROOM]) + create_cell_locations(sub_region_fjsr, {k: CellLocations.locFJ_cellTable[k] for k in {2}}) + + sub_region_fjpr = create_subregion(sub_region_fjsr, subLevel_table[JakAndDaxterSubLevel + .FORBIDDEN_JUNGLE_PLANT_ROOM]) + create_cell_locations(sub_region_fjpr, {k: CellLocations.locFJ_cellTable[k] for k in {6}}) region_sb = create_region(player, multiworld, level_table[JakAndDaxterLevel.SENTINEL_BEACH]) - create_locations(region_sb, { - **{k: CellLocations.locSB_cellTable[k] for k in {18, 19, 20, 21, 23, 24, 25}}, - **{k: SpecialLocations.loc_specialTable[k] for k in {2215}}, - **ScoutLocations.locSB_scoutTable - }) + create_cell_locations(region_sb, {k: CellLocations.locSB_cellTable[k] for k in {15, 17, 16, 18, 21, 22, 20}}) + create_fly_locations(region_sb, ScoutLocations.locSB_scoutTable) sub_region_sbct = create_subregion(region_sb, subLevel_table[JakAndDaxterSubLevel.SENTINEL_BEACH_CANNON_TOWER]) - create_locations(sub_region_sbct, {k: CellLocations.locSB_cellTable[k] for k in {22}}) + create_cell_locations(sub_region_sbct, {k: CellLocations.locSB_cellTable[k] for k in {19}}) region_mi = create_region(player, multiworld, level_table[JakAndDaxterLevel.MISTY_ISLAND]) - create_locations(region_mi, { - **CellLocations.locMI_cellTable, - **ScoutLocations.locMI_scoutTable - }) + create_cell_locations(region_mi, CellLocations.locMI_cellTable) + create_fly_locations(region_mi, ScoutLocations.locMI_scoutTable) region_fc = create_region(player, multiworld, level_table[JakAndDaxterLevel.FIRE_CANYON]) - create_locations(region_fc, { - **CellLocations.locFC_cellTable, - **ScoutLocations.locFC_scoutTable - }) + create_cell_locations(region_fc, CellLocations.locFC_cellTable) + create_fly_locations(region_fc, ScoutLocations.locFC_scoutTable) region_rv = create_region(player, multiworld, level_table[JakAndDaxterLevel.ROCK_VILLAGE]) - create_locations(region_rv, { - **CellLocations.locRV_cellTable, - **{k: SpecialLocations.loc_specialTable[k] for k in {2217}}, - **ScoutLocations.locRV_scoutTable - }) + create_cell_locations(region_rv, CellLocations.locRV_cellTable) + create_fly_locations(region_rv, ScoutLocations.locRV_scoutTable) region_pb = create_region(player, multiworld, level_table[JakAndDaxterLevel.PRECURSOR_BASIN]) - create_locations(region_pb, { - **CellLocations.locPB_cellTable, - **ScoutLocations.locPB_scoutTable - }) + create_cell_locations(region_pb, {k: CellLocations.locPB_cellTable[k] for k in {54, 53, 52, 56, 55, 58, 57}}) + create_fly_locations(region_pb, ScoutLocations.locPB_scoutTable) + + sub_region_pbbr = create_subregion(region_pb, subLevel_table[JakAndDaxterSubLevel.PRECURSOR_BASIN_BLUE_RINGS]) + create_cell_locations(sub_region_pbbr, {k: CellLocations.locPB_cellTable[k] for k in {59}}) region_lpc = create_region(player, multiworld, level_table[JakAndDaxterLevel.LOST_PRECURSOR_CITY]) - create_locations(region_lpc, { - **CellLocations.locLPC_cellTable, - **ScoutLocations.locLPC_scoutTable - }) + create_cell_locations(region_lpc, CellLocations.locLPC_cellTable) + create_fly_locations(region_lpc, ScoutLocations.locLPC_scoutTable) region_bs = create_region(player, multiworld, level_table[JakAndDaxterLevel.BOGGY_SWAMP]) - create_locations(region_bs, { - **{k: CellLocations.locBS_cellTable[k] for k in {59, 60, 61, 62, 63, 64}}, - **{k: ScoutLocations.locBS_scoutTable[k] for k in {164, 165, 166, 167, 170}} - }) + create_cell_locations(region_bs, {k: CellLocations.locBS_cellTable[k] for k in {36, 38, 39, 40, 41, 42}}) + create_fly_locations(region_bs, {k: ScoutLocations.locBS_scoutTable[k] for k in {164, 165, 166, 167, 170}}) sub_region_bsff = create_subregion(region_bs, subLevel_table[JakAndDaxterSubLevel.BOGGY_SWAMP_FLUT_FLUT]) - create_locations(sub_region_bsff, { - **{k: CellLocations.locBS_cellTable[k] for k in {58, 65}}, - **{k: ScoutLocations.locBS_scoutTable[k] for k in {168, 169}} - }) + create_cell_locations(sub_region_bsff, {k: CellLocations.locBS_cellTable[k] for k in {43, 37}}) + create_fly_locations(sub_region_bsff, {k: ScoutLocations.locBS_scoutTable[k] for k in {168, 169}}) region_mp = create_region(player, multiworld, level_table[JakAndDaxterLevel.MOUNTAIN_PASS]) - create_locations(region_mp, { - **{k: CellLocations.locMP_cellTable[k] for k in {66, 67, 69}}, - **ScoutLocations.locMP_scoutTable - }) + create_cell_locations(region_mp, {k: CellLocations.locMP_cellTable[k] for k in {86}}) - sub_region_mps = create_subregion(region_mp, subLevel_table[JakAndDaxterSubLevel.MOUNTAIN_PASS_SHORTCUT]) - create_locations(sub_region_mps, {k: CellLocations.locMP_cellTable[k] for k in {68}}) + sub_region_mpr = create_subregion(region_mp, subLevel_table[JakAndDaxterSubLevel.MOUNTAIN_PASS_RACE]) + create_cell_locations(sub_region_mpr, {k: CellLocations.locMP_cellTable[k] for k in {87, 88}}) + create_fly_locations(sub_region_mpr, ScoutLocations.locMP_scoutTable) + + sub_region_mps = create_subregion(sub_region_mpr, subLevel_table[JakAndDaxterSubLevel.MOUNTAIN_PASS_SHORTCUT]) + create_cell_locations(sub_region_mps, {k: CellLocations.locMP_cellTable[k] for k in {110}}) region_vc = create_region(player, multiworld, level_table[JakAndDaxterLevel.VOLCANIC_CRATER]) - create_locations(region_vc, { - **CellLocations.locVC_cellTable, - **ScoutLocations.locVC_scoutTable - }) + create_cell_locations(region_vc, CellLocations.locVC_cellTable) + create_fly_locations(region_vc, ScoutLocations.locVC_scoutTable) region_sc = create_region(player, multiworld, level_table[JakAndDaxterLevel.SPIDER_CAVE]) - create_locations(region_sc, { - **CellLocations.locSC_cellTable, - **ScoutLocations.locSC_scoutTable - }) + create_cell_locations(region_sc, CellLocations.locSC_cellTable) + create_fly_locations(region_sc, ScoutLocations.locSC_scoutTable) region_sm = create_region(player, multiworld, level_table[JakAndDaxterLevel.SNOWY_MOUNTAIN]) - create_locations(region_sm, { - **{k: CellLocations.locSM_cellTable[k] for k in {86, 87, 88, 89, 92}}, - **{k: SpecialLocations.loc_specialTable[k] for k in {2218}}, - **{k: ScoutLocations.locSM_scoutTable[k] for k in {192, 193, 194, 195, 196}} - }) + create_cell_locations(region_sm, {k: CellLocations.locSM_cellTable[k] for k in {60, 61, 66, 64}}) + create_fly_locations(region_sm, {k: ScoutLocations.locSM_scoutTable[k] for k in {192, 193, 194, 195, 196}}) + + sub_region_smfb = create_subregion(region_sm, subLevel_table[JakAndDaxterSubLevel.SNOWY_MOUNTAIN_FROZEN_BOX]) + create_cell_locations(sub_region_smfb, {k: CellLocations.locSM_cellTable[k] for k in {67}}) sub_region_smff = create_subregion(region_sm, subLevel_table[JakAndDaxterSubLevel.SNOWY_MOUNTAIN_FLUT_FLUT]) - create_locations(sub_region_smff, { - **{k: CellLocations.locSM_cellTable[k] for k in {90}}, - **{k: SpecialLocations.loc_specialTable[k] for k in {2219}} - }) + create_cell_locations(sub_region_smff, {k: CellLocations.locSM_cellTable[k] for k in {63}}) sub_region_smlf = create_subregion(region_sm, subLevel_table[JakAndDaxterSubLevel.SNOWY_MOUNTAIN_LURKER_FORT]) - create_locations(sub_region_smlf, { - **{k: CellLocations.locSM_cellTable[k] for k in {91, 93}}, - **{k: ScoutLocations.locSM_scoutTable[k] for k in {197, 198}} - }) + create_cell_locations(sub_region_smlf, {k: CellLocations.locSM_cellTable[k] for k in {62, 65}}) + create_fly_locations(sub_region_smlf, {k: ScoutLocations.locSM_scoutTable[k] for k in {197, 198}}) region_lt = create_region(player, multiworld, level_table[JakAndDaxterLevel.LAVA_TUBE]) - create_locations(region_lt, { - **CellLocations.locLT_cellTable, - **ScoutLocations.locLT_scoutTable - }) + create_cell_locations(region_lt, CellLocations.locLT_cellTable) + create_fly_locations(region_lt, ScoutLocations.locLT_scoutTable) region_gmc = create_region(player, multiworld, level_table[JakAndDaxterLevel.GOL_AND_MAIAS_CITADEL]) - create_locations(region_gmc, { - **{k: CellLocations.locGMC_cellTable[k] for k in {96, 97, 98}}, - **{k: ScoutLocations.locGMC_scoutTable[k] for k in {206, 207, 208, 209, 210, 211}}, - **{k: SpecialLocations.loc_specialTable[k] for k in {2220, 2221, 2222}} - }) + create_cell_locations(region_gmc, {k: CellLocations.locGMC_cellTable[k] for k in {71, 72, 73}}) + create_fly_locations(region_gmc, {k: ScoutLocations.locGMC_scoutTable[k] for k in {206, 207, 208, 209, 210, 211}}) - sub_region_gmcrt = create_subregion(region_gmc, - subLevel_table[JakAndDaxterSubLevel.GOL_AND_MAIAS_CITADEL_ROTATING_TOWER]) - create_locations(sub_region_gmcrt, { - **{k: CellLocations.locGMC_cellTable[k] for k in {99, 100}}, - **{k: ScoutLocations.locGMC_scoutTable[k] for k in {212}}, - **{k: SpecialLocations.loc_specialTable[k] for k in {2223}} - }) + sub_region_gmcrt = create_subregion(region_gmc, subLevel_table[JakAndDaxterSubLevel + .GOL_AND_MAIAS_CITADEL_ROTATING_TOWER]) + create_cell_locations(sub_region_gmcrt, {k: CellLocations.locGMC_cellTable[k] for k in {70, 91}}) + create_fly_locations(sub_region_gmcrt, {k: ScoutLocations.locGMC_scoutTable[k] for k in {212}}) create_subregion(sub_region_gmcrt, subLevel_table[JakAndDaxterSubLevel.GOL_AND_MAIAS_CITADEL_FINAL_BOSS]) def create_region(player: int, multiworld: MultiWorld, name: str) -> JakAndDaxterRegion: region = JakAndDaxterRegion(name, player, multiworld) - multiworld.regions.append(region) return region def create_subregion(parent: Region, name: str) -> JakAndDaxterRegion: region = JakAndDaxterRegion(name, parent.player, parent.multiworld) - parent.multiworld.regions.append(region) return region -def create_locations(region: Region, locations: typing.Dict[int, str]): - region.locations += [JakAndDaxterLocation(region.player, location_table[loc], game_id + loc, region) - for loc in locations] +def create_cell_locations(region: Region, locations: typing.Dict[int, str]): + region.locations += [JakAndDaxterLocation(region.player, + location_table[game_id + cell_offset + loc], + game_id + cell_offset + loc, + region) for loc in locations] + + +def create_fly_locations(region: Region, locations: typing.Dict[int, str]): + region.locations += [JakAndDaxterLocation(region.player, + location_table[game_id + fly_offset + loc], + game_id + fly_offset + loc, + region) for loc in locations] diff --git a/worlds/jakanddaxter/Rules.py b/worlds/jakanddaxter/Rules.py index 4165ea8d4a..deeef7c92d 100644 --- a/worlds/jakanddaxter/Rules.py +++ b/worlds/jakanddaxter/Rules.py @@ -1,18 +1,38 @@ from BaseClasses import MultiWorld +from .GameID import game_id, cell_offset, fly_offset from .Options import JakAndDaxterOptions from .Regions import JakAndDaxterLevel, JakAndDaxterSubLevel, level_table, subLevel_table -from .Items import item_table +from .Locations import location_table as item_table +from .locs.CellLocations import locGR_cellTable def set_rules(multiworld: MultiWorld, options: JakAndDaxterOptions, player: int): - region_menu = multiworld.get_region("Menu", player) - region_gr = multiworld.get_region(level_table[JakAndDaxterLevel.GEYSER_ROCK], player) - region_menu.connect(region_gr) + # Setting up some useful variables here because the offset numbers can get confusing + # for access rules. Feel free to add more variables here to keep the code more readable. + gr_cells = {game_id + cell_offset + k for k in locGR_cellTable} + fj_temple_top = game_id + cell_offset + 4 + fj_blue_switch = game_id + cell_offset + 2 + fj_fisherman = game_id + cell_offset + 5 + pb_purple_rings = game_id + cell_offset + 58 + sb_flut_flut = game_id + cell_offset + 17 + fc_end = game_id + cell_offset + 69 + mp_klaww = game_id + cell_offset + 86 + mp_end = game_id + cell_offset + 87 + sm_yellow_switch = game_id + cell_offset + 60 + sm_fort_gate = game_id + cell_offset + 63 + lt_end = game_id + cell_offset + 89 + gmc_blue_sage = game_id + cell_offset + 71 + gmc_red_sage = game_id + cell_offset + 72 + gmc_yellow_sage = game_id + cell_offset + 73 + gmc_green_sage = game_id + cell_offset + 70 + + # Start connecting regions and set their access rules. + connect_start(multiworld, player, JakAndDaxterLevel.GEYSER_ROCK) connect_regions(multiworld, player, JakAndDaxterLevel.GEYSER_ROCK, JakAndDaxterLevel.SANDOVER_VILLAGE, - lambda state: state.has(item_table[0], player, 4)) + lambda state: state.has_all({item_table[k] for k in gr_cells}, player)) connect_regions(multiworld, player, JakAndDaxterLevel.SANDOVER_VILLAGE, @@ -20,8 +40,13 @@ def set_rules(multiworld: MultiWorld, options: JakAndDaxterOptions, player: int) connect_region_to_sub(multiworld, player, JakAndDaxterLevel.FORBIDDEN_JUNGLE, - JakAndDaxterSubLevel.FORBIDDEN_JUNGLE_PLANT_ROOM, - lambda state: state.has(item_table[2216], player)) + JakAndDaxterSubLevel.FORBIDDEN_JUNGLE_SWITCH_ROOM, + lambda state: state.has(item_table[fj_temple_top], player)) + + connect_subregions(multiworld, player, + JakAndDaxterSubLevel.FORBIDDEN_JUNGLE_SWITCH_ROOM, + JakAndDaxterSubLevel.FORBIDDEN_JUNGLE_PLANT_ROOM, + lambda state: state.has(item_table[fj_blue_switch], player)) connect_regions(multiworld, player, JakAndDaxterLevel.SANDOVER_VILLAGE, @@ -30,53 +55,64 @@ def set_rules(multiworld: MultiWorld, options: JakAndDaxterOptions, player: int) connect_region_to_sub(multiworld, player, JakAndDaxterLevel.SENTINEL_BEACH, JakAndDaxterSubLevel.SENTINEL_BEACH_CANNON_TOWER, - lambda state: state.has(item_table[2216], player)) + lambda state: state.has(item_table[fj_blue_switch], player)) connect_regions(multiworld, player, JakAndDaxterLevel.SANDOVER_VILLAGE, JakAndDaxterLevel.MISTY_ISLAND, - lambda state: state.has(item_table[2213], player)) + lambda state: state.has(item_table[fj_fisherman], player)) connect_regions(multiworld, player, JakAndDaxterLevel.SANDOVER_VILLAGE, JakAndDaxterLevel.FIRE_CANYON, - lambda state: state.has(item_table[0], player, 20)) + lambda state: state.count_group("Power Cell", player) >= 20) connect_regions(multiworld, player, JakAndDaxterLevel.FIRE_CANYON, - JakAndDaxterLevel.ROCK_VILLAGE) + JakAndDaxterLevel.ROCK_VILLAGE, + lambda state: state.has(item_table[fc_end], player)) connect_regions(multiworld, player, JakAndDaxterLevel.ROCK_VILLAGE, JakAndDaxterLevel.PRECURSOR_BASIN) + connect_region_to_sub(multiworld, player, + JakAndDaxterLevel.PRECURSOR_BASIN, + JakAndDaxterSubLevel.PRECURSOR_BASIN_BLUE_RINGS, + lambda state: state.has(item_table[pb_purple_rings], player)) + connect_regions(multiworld, player, JakAndDaxterLevel.ROCK_VILLAGE, JakAndDaxterLevel.LOST_PRECURSOR_CITY) connect_regions(multiworld, player, JakAndDaxterLevel.ROCK_VILLAGE, - JakAndDaxterLevel.BOGGY_SWAMP, - lambda state: state.has(item_table[2217], player)) + JakAndDaxterLevel.BOGGY_SWAMP) connect_region_to_sub(multiworld, player, JakAndDaxterLevel.BOGGY_SWAMP, JakAndDaxterSubLevel.BOGGY_SWAMP_FLUT_FLUT, - lambda state: state.has(item_table[2215], player)) + lambda state: state.has(item_table[sb_flut_flut], player)) connect_regions(multiworld, player, JakAndDaxterLevel.ROCK_VILLAGE, JakAndDaxterLevel.MOUNTAIN_PASS, - lambda state: state.has(item_table[2217], player) and state.has(item_table[0], player, 45)) + lambda state: state.count_group("Power Cell", player) >= 45) connect_region_to_sub(multiworld, player, JakAndDaxterLevel.MOUNTAIN_PASS, - JakAndDaxterSubLevel.MOUNTAIN_PASS_SHORTCUT, - lambda state: state.has(item_table[2218], player)) + JakAndDaxterSubLevel.MOUNTAIN_PASS_RACE, + lambda state: state.has(item_table[mp_klaww], player)) + + connect_subregions(multiworld, player, + JakAndDaxterSubLevel.MOUNTAIN_PASS_RACE, + JakAndDaxterSubLevel.MOUNTAIN_PASS_SHORTCUT, + lambda state: state.has(item_table[sm_yellow_switch], player)) connect_regions(multiworld, player, JakAndDaxterLevel.MOUNTAIN_PASS, - JakAndDaxterLevel.VOLCANIC_CRATER) + JakAndDaxterLevel.VOLCANIC_CRATER, + lambda state: state.has(item_table[mp_end], player)) connect_regions(multiworld, player, JakAndDaxterLevel.VOLCANIC_CRATER, @@ -86,36 +122,42 @@ def set_rules(multiworld: MultiWorld, options: JakAndDaxterOptions, player: int) JakAndDaxterLevel.VOLCANIC_CRATER, JakAndDaxterLevel.SNOWY_MOUNTAIN) + connect_region_to_sub(multiworld, player, + JakAndDaxterLevel.SNOWY_MOUNTAIN, + JakAndDaxterSubLevel.SNOWY_MOUNTAIN_FROZEN_BOX, + lambda state: state.has(item_table[sm_yellow_switch], player)) + connect_region_to_sub(multiworld, player, JakAndDaxterLevel.SNOWY_MOUNTAIN, JakAndDaxterSubLevel.SNOWY_MOUNTAIN_FLUT_FLUT, - lambda state: state.has(item_table[2215], player)) + lambda state: state.has(item_table[sb_flut_flut], player)) connect_region_to_sub(multiworld, player, JakAndDaxterLevel.SNOWY_MOUNTAIN, JakAndDaxterSubLevel.SNOWY_MOUNTAIN_LURKER_FORT, - lambda state: state.has(item_table[2219], player)) + lambda state: state.has(item_table[sm_fort_gate], player)) connect_regions(multiworld, player, JakAndDaxterLevel.VOLCANIC_CRATER, JakAndDaxterLevel.LAVA_TUBE, - lambda state: state.has(item_table[0], player, 72)) + lambda state: state.count_group("Power Cell", player) >= 72) connect_regions(multiworld, player, JakAndDaxterLevel.LAVA_TUBE, - JakAndDaxterLevel.GOL_AND_MAIAS_CITADEL) + JakAndDaxterLevel.GOL_AND_MAIAS_CITADEL, + lambda state: state.has(item_table[lt_end], player)) connect_region_to_sub(multiworld, player, JakAndDaxterLevel.GOL_AND_MAIAS_CITADEL, JakAndDaxterSubLevel.GOL_AND_MAIAS_CITADEL_ROTATING_TOWER, - lambda state: state.has(item_table[2220], player) - and state.has(item_table[2221], player) - and state.has(item_table[2222], player)) + lambda state: state.has(item_table[gmc_blue_sage], player) + and state.has(item_table[gmc_red_sage], player) + and state.has(item_table[gmc_yellow_sage], player)) connect_subregions(multiworld, player, JakAndDaxterSubLevel.GOL_AND_MAIAS_CITADEL_ROTATING_TOWER, JakAndDaxterSubLevel.GOL_AND_MAIAS_CITADEL_FINAL_BOSS, - lambda state: state.has(item_table[2223], player)) + lambda state: state.has(item_table[gmc_green_sage], player)) multiworld.completion_condition[player] = lambda state: state.can_reach( multiworld.get_region(subLevel_table[JakAndDaxterSubLevel.GOL_AND_MAIAS_CITADEL_FINAL_BOSS], player), @@ -123,6 +165,12 @@ def set_rules(multiworld: MultiWorld, options: JakAndDaxterOptions, player: int) player) +def connect_start(multiworld: MultiWorld, player: int, target: JakAndDaxterLevel): + menu_region = multiworld.get_region("Menu", player) + start_region = multiworld.get_region(level_table[target], player) + menu_region.connect(start_region) + + def connect_regions(multiworld: MultiWorld, player: int, source: JakAndDaxterLevel, target: JakAndDaxterLevel, rule=None): source_region = multiworld.get_region(level_table[source], player) diff --git a/worlds/jakanddaxter/__init__.py b/worlds/jakanddaxter/__init__.py index d2a8db9982..3a99126b0d 100644 --- a/worlds/jakanddaxter/__init__.py +++ b/worlds/jakanddaxter/__init__.py @@ -1,11 +1,11 @@ from BaseClasses import Item, ItemClassification -from .Locations import JakAndDaxterLocation, location_table +from .Locations import JakAndDaxterLocation, location_table as item_table from .Options import JakAndDaxterOptions from .Regions import JakAndDaxterLevel, JakAndDaxterSubLevel, JakAndDaxterRegion, level_table, subLevel_table, \ create_regions from .Rules import set_rules -from .Items import JakAndDaxterItem, item_table, generic_item_table, special_item_table -from .GameID import game_id, game_name +from .Items import JakAndDaxterItem +from .GameID import game_id, game_name, cell_offset, fly_offset, orb_offset from ..AutoWorld import World @@ -14,34 +14,42 @@ class JakAndDaxterWorld(World): data_version = 1 required_client_version = (0, 4, 5) - # Stored as {ID: Name} pairs, these must now be swapped to {Name: ID} pairs. - item_name_to_id = {item_table[k]: game_id + k for k in item_table} - location_name_to_id = {location_table[k]: game_id + k for k in location_table} - options_dataclass = JakAndDaxterOptions options: JakAndDaxterOptions + # Stored as {ID: Name} pairs, these must now be swapped to {Name: ID} pairs. + item_name_to_id = {item_table[k]: k for k in item_table} + location_name_to_id = {item_table[k]: k for k in item_table} + item_name_groups = { + "Power Cell": {item_table[k]: k + for k in item_table if k in range(game_id + cell_offset, game_id + fly_offset)}, + "Scout Fly": {item_table[k]: k + for k in item_table if k in range(game_id + fly_offset, game_id + orb_offset)}, + "Precursor Orb": {} # TODO + } + def create_regions(self): create_regions(self.multiworld, self.options, self.player) def set_rules(self): set_rules(self.multiworld, self.options, self.player) + def create_items(self): + self.multiworld.itempool += [self.create_item(item_table[k]) for k in item_table] + def create_item(self, name: str) -> Item: item_id = self.item_name_to_id[name] - if "Power Cell" in name: + if item_id in range(game_id + cell_offset, game_id + fly_offset): + # Power Cell classification = ItemClassification.progression_skip_balancing - elif "Scout Fly" in name: + elif item_id in range(game_id + fly_offset, game_id + orb_offset): + # Scout Fly classification = ItemClassification.progression_skip_balancing - elif "Precursor Orb" in name: + elif item_id > game_id + orb_offset: + # Precursor Orb classification = ItemClassification.filler # TODO else: - classification = ItemClassification.progression + classification = ItemClassification.filler item = JakAndDaxterItem(name, classification, item_id, self.player) return item - - def create_items(self): - self.multiworld.itempool += [self.create_item("Power Cell") for _ in range(0, 101)] - self.multiworld.itempool += [self.create_item("Scout Fly") for _ in range(101, 213)] - self.multiworld.itempool += [self.create_item(item_table[k]) for k in special_item_table] diff --git a/worlds/jakanddaxter/locs/CellLocations.py b/worlds/jakanddaxter/locs/CellLocations.py index 4f674bff61..a16f40ce94 100644 --- a/worlds/jakanddaxter/locs/CellLocations.py +++ b/worlds/jakanddaxter/locs/CellLocations.py @@ -1,128 +1,135 @@ -# Power Cells start at ID 0 and end at ID 100. +# Power Cells are given ID's between 0 and 116 by the game. + +# The game tracks all game-tasks as integers. +# 101 of these ID's correspond directly to power cells, but they are not +# necessarily ordered, nor are they the first 101 in the task list. +# The remaining ones are cutscenes and other events. + +# The ID's you see below correspond directly to that cell's game-task ID. # Geyser Rock locGR_cellTable = { - 0: "GR: Find The Cell On The Path", - 1: "GR: Open The Precursor Door", - 2: "GR: Climb Up The Cliff", - 3: "GR: Free 7 Scout Flies" + 92: "GR: Find The Cell On The Path", + 93: "GR: Open The Precursor Door", + 94: "GR: Climb Up The Cliff", + 95: "GR: Free 7 Scout Flies" } # Sandover Village locSV_cellTable = { - 4: "SV: Bring 90 Orbs To The Mayor", - 5: "SV: Bring 90 Orbs to Your Uncle", - 6: "SV: Herd The Yakows Into The Pen", - 7: "SV: Bring 120 Orbs To The Oracle (1)", - 8: "SV: Bring 120 Orbs To The Oracle (2)", - 9: "SV: Free 7 Scout Flies" + 11: "SV: Bring 90 Orbs To The Mayor", + 12: "SV: Bring 90 Orbs to Your Uncle", + 10: "SV: Herd The Yakows Into The Pen", + 13: "SV: Bring 120 Orbs To The Oracle (1)", + 14: "SV: Bring 120 Orbs To The Oracle (2)", + 75: "SV: Free 7 Scout Flies" } # Forbidden Jungle locFJ_cellTable = { - 10: "FJ: Connect The Eco Beams", - 11: "FJ: Get To The Top Of The Temple", - 12: "FJ: Find The Blue Vent Switch", - 13: "FJ: Defeat The Dark Eco Plant", - 14: "FJ: Catch 200 Pounds Of Fish", - 15: "FJ: Follow The Canyon To The Sea", - 16: "FJ: Open The Locked Temple Door", - 17: "FJ: Free 7 Scout Flies" + 3: "FJ: Connect The Eco Beams", + 4: "FJ: Get To The Top Of The Temple", + 2: "FJ: Find The Blue Vent Switch", + 6: "FJ: Defeat The Dark Eco Plant", + 5: "FJ: Catch 200 Pounds Of Fish", + 8: "FJ: Follow The Canyon To The Sea", + 9: "FJ: Open The Locked Temple Door", + 7: "FJ: Free 7 Scout Flies" } # Sentinel Beach locSB_cellTable = { - 18: "SB: Unblock The Eco Harvesters", - 19: "SB: Push The Flut Flut Egg Off The Cliff", - 20: "SB: Get The Power Cell From The Pelican", - 21: "SB: Chase The Seagulls", - 22: "SB: Launch Up To The Cannon Tower", - 23: "SB: Explore The Beach", - 24: "SB: Climb The Sentinel", - 25: "SB: Free 7 Scout Flies" + 15: "SB: Unblock The Eco Harvesters", + 17: "SB: Push The Flut Flut Egg Off The Cliff", + 16: "SB: Get The Power Cell From The Pelican", + 18: "SB: Chase The Seagulls", + 19: "SB: Launch Up To The Cannon Tower", + 21: "SB: Explore The Beach", + 22: "SB: Climb The Sentinel", + 20: "SB: Free 7 Scout Flies" } # Misty Island locMI_cellTable = { - 26: "MI: Catch The Sculptor's Muse", - 27: "MI: Climb The Lurker Ship", - 28: "MI: Stop The Cannon", - 29: "MI: Return To The Dark Eco Pool", - 30: "MI: Destroy the Balloon Lurkers", - 31: "MI: Use Zoomer To Reach Power Cell", - 32: "MI: Use Blue Eco To Reach Power Cell", - 33: "MI: Free 7 Scout Flies" + 23: "MI: Catch The Sculptor's Muse", + 24: "MI: Climb The Lurker Ship", + 26: "MI: Stop The Cannon", + 25: "MI: Return To The Dark Eco Pool", + 27: "MI: Destroy the Balloon Lurkers", + 29: "MI: Use Zoomer To Reach Power Cell", + 30: "MI: Use Blue Eco To Reach Power Cell", + 28: "MI: Free 7 Scout Flies" } # Fire Canyon locFC_cellTable = { - 34: "FC: Reach The End Of Fire Canyon", - 35: "FC: Free 7 Scout Flies" + 69: "FC: Reach The End Of Fire Canyon", + 68: "FC: Free 7 Scout Flies" } # Rock Village locRV_cellTable = { - 36: "RV: Bring 90 Orbs To The Gambler", - 37: "RV: Bring 90 Orbs To The Geologist", - 38: "RV: Bring 90 Orbs To The Warrior", - 39: "RV: Bring 120 Orbs To The Oracle (1)", - 40: "RV: Bring 120 Orbs To The Oracle (2)", - 41: "RV: Free 7 Scout Flies" + 31: "RV: Bring 90 Orbs To The Gambler", + 32: "RV: Bring 90 Orbs To The Geologist", + 33: "RV: Bring 90 Orbs To The Warrior", + 34: "RV: Bring 120 Orbs To The Oracle (1)", + 35: "RV: Bring 120 Orbs To The Oracle (2)", + 76: "RV: Free 7 Scout Flies" } # Precursor Basin locPB_cellTable = { - 42: "PB: Herd The Moles Into Their Hole", - 43: "PB: Catch The Flying Lurkers", - 44: "PB: Beat Record Time On The Gorge", - 45: "PB: Get The Power Cell Over The Lake", - 46: "PB: Cure Dark Eco Infected Plants", - 47: "PB: Navigate The Purple Precursor Rings", - 48: "PB: Navigate The Blue Precursor Rings", - 49: "PB: Free 7 Scout Flies" + 54: "PB: Herd The Moles Into Their Hole", + 53: "PB: Catch The Flying Lurkers", + 52: "PB: Beat Record Time On The Gorge", + 56: "PB: Get The Power Cell Over The Lake", + 55: "PB: Cure Dark Eco Infected Plants", + 58: "PB: Navigate The Purple Precursor Rings", + 59: "PB: Navigate The Blue Precursor Rings", + 57: "PB: Free 7 Scout Flies" } # Lost Precursor City locLPC_cellTable = { - 50: "LPC: Raise The Chamber", - 51: "LPC: Follow The Colored Pipes", - 52: "LPC: Reach The Bottom Of The City", - 53: "LPC: Quickly Cross The Dangerous Pool", - 54: "LPC: Match The Platform Colors", - 55: "LPC: Climb The Slide Tube", - 56: "LPC: Reach The Center Of The Complex", - 57: "LPC: Free 7 Scout Flies" + 47: "LPC: Raise The Chamber", + 45: "LPC: Follow The Colored Pipes", + 46: "LPC: Reach The Bottom Of The City", + 48: "LPC: Quickly Cross The Dangerous Pool", + 44: "LPC: Match The Platform Colors", + 50: "LPC: Climb The Slide Tube", + 51: "LPC: Reach The Center Of The Complex", + 49: "LPC: Free 7 Scout Flies" } # Boggy Swamp locBS_cellTable = { - 58: "BS: Ride The Flut Flut", - 59: "BS: Protect Farthy's Snacks", - 60: "BS: Defeat The Lurker Ambush", - 61: "BS: Break The Tethers To The Zeppelin (1)", - 62: "BS: Break The Tethers To The Zeppelin (2)", - 63: "BS: Break The Tethers To The Zeppelin (3)", - 64: "BS: Break The Tethers To The Zeppelin (4)", - 65: "BS: Free 7 Scout Flies" + 37: "BS: Ride The Flut Flut", + 36: "BS: Protect Farthy's Snacks", + 38: "BS: Defeat The Lurker Ambush", + 39: "BS: Break The Tethers To The Zeppelin (1)", + 40: "BS: Break The Tethers To The Zeppelin (2)", + 41: "BS: Break The Tethers To The Zeppelin (3)", + 42: "BS: Break The Tethers To The Zeppelin (4)", + 43: "BS: Free 7 Scout Flies" } # Mountain Pass locMP_cellTable = { - 66: "MP: Defeat Klaww", - 67: "MP: Reach The End Of The Mountain Pass", - 68: "MP: Find The Hidden Power Cell", - 69: "MP: Free 7 Scout Flies" + 86: "MP: Defeat Klaww", + 87: "MP: Reach The End Of The Mountain Pass", + 110: "MP: Find The Hidden Power Cell", + 88: "MP: Free 7 Scout Flies" } # Volcanic Crater locVC_cellTable = { - 70: "VC: Bring 90 Orbs To The Miners (1)", - 71: "VC: Bring 90 Orbs To The Miners (2)", - 72: "VC: Bring 90 Orbs To The Miners (3)", - 73: "VC: Bring 90 Orbs To The Miners (4)", - 74: "VC: Bring 120 Orbs To The Oracle (1)", - 75: "VC: Bring 120 Orbs To The Oracle (2)", - 76: "VC: Find The Hidden Power Cell", + 96: "VC: Bring 90 Orbs To The Miners (1)", + 97: "VC: Bring 90 Orbs To The Miners (2)", + 98: "VC: Bring 90 Orbs To The Miners (3)", + 99: "VC: Bring 90 Orbs To The Miners (4)", + 100: "VC: Bring 120 Orbs To The Oracle (1)", + 101: "VC: Bring 120 Orbs To The Oracle (2)", + 74: "VC: Find The Hidden Power Cell", 77: "VC: Free 7 Scout Flies" } @@ -140,27 +147,27 @@ locSC_cellTable = { # Snowy Mountain locSM_cellTable = { - 86: "SM: Find The Yellow Vent Switch", - 87: "SM: Stop The 3 Lurker Glacier Troops", - 88: "SM: Deactivate The Precursor Blockers", - 89: "SM: Open The Frozen Crate", - 90: "SM: Open The Lurker Fort Gate", - 91: "SM: Get Through The Lurker Fort", - 92: "SM: Survive The Lurker Infested Cave", - 93: "SM: Free 7 Scout Flies" + 60: "SM: Find The Yellow Vent Switch", + 61: "SM: Stop The 3 Lurker Glacier Troops", + 66: "SM: Deactivate The Precursor Blockers", + 67: "SM: Open The Frozen Crate", + 63: "SM: Open The Lurker Fort Gate", + 62: "SM: Get Through The Lurker Fort", + 64: "SM: Survive The Lurker Infested Cave", + 65: "SM: Free 7 Scout Flies" } # Lava Tube locLT_cellTable = { - 94: "LT: Cross The Lava Tube", - 95: "LT: Free 7 Scout Flies" + 89: "LT: Cross The Lava Tube", + 90: "LT: Free 7 Scout Flies" } # Gol and Maias Citadel locGMC_cellTable = { - 96: "GMC: Free The Blue Sage", - 97: "GMC: Free The Red Sage", - 98: "GMC: Free The Yellow Sage", - 99: "GMC: Free The Green Sage", - 100: "GMC: Free 7 Scout Flies" + 71: "GMC: Free The Blue Sage", + 72: "GMC: Free The Red Sage", + 73: "GMC: Free The Yellow Sage", + 70: "GMC: Free The Green Sage", + 91: "GMC: Free 7 Scout Flies" } diff --git a/worlds/jakanddaxter/locs/OrbLocations.py b/worlds/jakanddaxter/locs/OrbLocations.py index 83037790d4..2da5972e17 100644 --- a/worlds/jakanddaxter/locs/OrbLocations.py +++ b/worlds/jakanddaxter/locs/OrbLocations.py @@ -1,4 +1,7 @@ -# Precursor Orbs start at ID 213 and end at ID 2212. +# Precursor Orbs start at ??? and end at ??? + +# Given that Scout Flies are being offset by 2^20 to avoid collisions with power cells, +# I'm tentatively setting the Orb offset to 2^21, or 2,097,152. # Geyser Rock locGR_orbTable = { diff --git a/worlds/jakanddaxter/locs/ScoutLocations.py b/worlds/jakanddaxter/locs/ScoutLocations.py index a05b39bb8c..1f86416d28 100644 --- a/worlds/jakanddaxter/locs/ScoutLocations.py +++ b/worlds/jakanddaxter/locs/ScoutLocations.py @@ -1,4 +1,19 @@ -# Scout Flies start at ID 101 and end at ID 212. +# Scout Flies are given ID's between 0 and 393311 by the game, explanation below. + +# Each fly is given a unique 32-bit number broken into two 16-bit numbers. +# The lower 16 bits are the game-task ID of the power cell the fly corresponds to. +# The higher 16 bits are the index of the fly itself, from 000 (0) to 110 (6). + +# Ex: The final scout fly on Geyser Rock +# 0000000000000110 0000000001011111 +# ( Index: 6 ) ( Cell: 95 ) + +# Because flies are indexed from 0, each 0th fly's full ID == the power cell's ID. +# So we need to offset all of their ID's in order for Archipelago to separate them +# from their power cells. We use 1,048,576 (2^20) for this purpose, because scout flies +# don't use more than 19 bits to describe themselves. + +# TODO - The ID's you see below correspond directly to that fly's 32-bit ID in the game. # Geyser Rock locGR_scoutTable = { diff --git a/worlds/jakanddaxter/locs/SpecialLocations.py b/worlds/jakanddaxter/locs/SpecialLocations.py deleted file mode 100644 index c93c86f02b..0000000000 --- a/worlds/jakanddaxter/locs/SpecialLocations.py +++ /dev/null @@ -1,15 +0,0 @@ -# Special Locations start at ID 2213 and end at ID 22xx. - -loc_specialTable = { - 2213: "Fisherman's Boat", - # 2214: "Sculptor's Muse", # Unused? - 2215: "Flut Flut", - 2216: "Blue Eco Switch", - 2217: "Gladiator's Pontoons", - 2218: "Yellow Eco Switch", - 2219: "Lurker Fort Gate", - 2220: "Free The Yellow Sage", - 2221: "Free The Red Sage", - 2222: "Free The Blue Sage", - 2223: "Free The Green Sage" -}