From e76df684b58501597439bd6d73c4710da4fae2c5 Mon Sep 17 00:00:00 2001 From: massimilianodelliubaldini <8584296+massimilianodelliubaldini@users.noreply.github.com> Date: Tue, 21 May 2024 22:12:01 -0400 Subject: [PATCH] Jak and Daxter - Gondola, Pontoons, Rules, Regions, and Client Update * Jak 1: Overhaul of regions, rules, and special locations. Updated game info page. * Jak 1: Preparations for Alpha. Reintroducing automatic startup in client. Updating docs, readme, codeowners. --- README.md | 1 + docs/CODEOWNERS | 3 + worlds/jakanddaxter/Client.py | 82 ++++++++------- worlds/jakanddaxter/Items.py | 22 +++-- worlds/jakanddaxter/Regions.py | 55 ++++------- worlds/jakanddaxter/Rules.py | 66 +++++-------- worlds/jakanddaxter/__init__.py | 4 +- .../en_Jak and Daxter The Precursor Legacy.md | 99 ++++++++++++------- worlds/jakanddaxter/locs/SpecialLocations.py | 2 + 9 files changed, 170 insertions(+), 164 deletions(-) diff --git a/README.md b/README.md index 4633c99c66..f5965bd9be 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ Currently, the following games are supported: * Super Mario World * Pokémon Red and Blue * Hylics 2 +* Jak and Daxter: The Precursor Legacy * Overcooked! 2 * Zillion * Lufia II Ancient Cave diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index c34046d5dc..9e26ce0487 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -82,6 +82,9 @@ # Hylics 2 /worlds/hylics2/ @TRPG0 +# Jak and Daxter: The Precursor Legacy +/worlds/jakanddaxter/ @massimilianodelliubaldini + # Kirby's Dream Land 3 /worlds/kdl3/ @Silvris diff --git a/worlds/jakanddaxter/Client.py b/worlds/jakanddaxter/Client.py index 51a38bb3f5..c5c36b610e 100644 --- a/worlds/jakanddaxter/Client.py +++ b/worlds/jakanddaxter/Client.py @@ -4,6 +4,8 @@ import subprocess import typing import asyncio import colorama +import pymem +from pymem.exception import ProcessNotFound, ProcessError import Utils from NetUtils import ClientStatus @@ -137,45 +139,52 @@ class JakAndDaxterContext(CommonContext): async def run_game(ctx: JakAndDaxterContext): - exec_directory = "" - try: - exec_directory = Utils.get_settings()["jakanddaxter_options"]["root_directory"] - files_in_path = os.listdir(exec_directory) - if ".git" in files_in_path: - # Indicates the user is running from source, append expected subdirectory appropriately. - exec_directory = os.path.join(exec_directory, "out", "build", "Release", "bin") - else: - # Indicates the user is running from the official launcher, a mod launcher, or otherwise. - # We'll need to handle version numbers in the path somehow... - exec_directory = os.path.join(exec_directory, "versions", "official") - latest_version = list(reversed(os.listdir(exec_directory)))[0] - exec_directory = os.path.join(exec_directory, str(latest_version)) - except FileNotFoundError: - logger.error(f"Unable to locate directory {exec_directory}, " - f"unable to locate game executable.") - return - except KeyError as e: - logger.error(f"Hosts.yaml does not contain {e.args[0]}, " - f"unable to locate game executable.") - return - gk = os.path.join(exec_directory, "gk.exe") - goalc = os.path.join(exec_directory, "goalc.exe") + # If you're running the game through the mod launcher, these may already be running. + # If they are not running, try to start them. + gk_running = False + try: + pymem.Pymem("gk.exe") # The GOAL Kernel + gk_running = True + except ProcessNotFound: + logger.info("Game not running, attempting to start.") + + goalc_running = False + try: + pymem.Pymem("goalc.exe") # The GOAL Compiler and REPL + goalc_running = True + except ProcessNotFound: + logger.info("Compiler not running, attempting to start.") # Don't mind all the arguments, they are exactly what you get when you run "task boot-game" or "task repl". - await asyncio.create_subprocess_exec( - gk, - "-v", "--game jak1", "--", "-boot", "-fakeiso", "-debug", - stderr=subprocess.PIPE, - stdout=subprocess.PIPE, - stdin=subprocess.DEVNULL) + # TODO - Support other OS's. cmd for some reason does not work with goalc. + if not gk_running: + try: + gk_path = Utils.get_settings()["jakanddaxter_options"]["root_directory"] + gk_path = os.path.normpath(gk_path) + gk_path = os.path.join(gk_path, "gk.exe") + except AttributeError as e: + logger.error(f"Hosts.yaml does not contain {e.args[0]}, unable to locate game executables.") + return - # You MUST launch goalc as a console application, so powershell/cmd/bash/etc is the program - # and goalc is just an argument. It HAS to be this way. - # TODO - Support other OS's. - await asyncio.create_subprocess_exec( - "powershell.exe", - goalc, "--user-auto", "--game jak1") + if gk_path: + gk_process = subprocess.Popen( + ["powershell.exe", gk_path, "--game jak1", "--", "-v", "-boot", "-fakeiso", "-debug"], + creationflags=subprocess.CREATE_NEW_CONSOLE) # These need to be new consoles for stability. + + if not goalc_running: + try: + goalc_path = Utils.get_settings()["jakanddaxter_options"]["root_directory"] + goalc_path = os.path.normpath(goalc_path) + goalc_path = os.path.join(goalc_path, "goalc.exe") + except AttributeError as e: + logger.error(f"Hosts.yaml does not contain {e.args[0]}, unable to locate game executables.") + return + + if goalc_path: + goalc_process = subprocess.Popen( + ["powershell.exe", goalc_path, "--game jak1"], + creationflags=subprocess.CREATE_NEW_CONSOLE) # These need to be new consoles for stability. # Auto connect the repl and memr agents. Sleep 5 because goalc takes just a little bit of time to load, # and it's not something we can await. @@ -189,7 +198,6 @@ async def main(): Utils.init_logging("JakAndDaxterClient", exception_logger="Client") ctx = JakAndDaxterContext(None, None) - ctx.server_task = asyncio.create_task(server_loop(ctx), name="server loop") ctx.repl_task = create_task_log_exception(ctx.run_repl_loop()) ctx.memr_task = create_task_log_exception(ctx.run_memr_loop()) @@ -199,7 +207,7 @@ async def main(): ctx.run_cli() # Find and run the game (gk) and compiler/repl (goalc). - # await run_game(ctx) + await run_game(ctx) await ctx.exit_event.wait() await ctx.shutdown() diff --git a/worlds/jakanddaxter/Items.py b/worlds/jakanddaxter/Items.py index 2fa0654726..56743b7cef 100644 --- a/worlds/jakanddaxter/Items.py +++ b/worlds/jakanddaxter/Items.py @@ -42,16 +42,18 @@ scout_item_table = { # These are special items representing unique unlocks in the world. Notice that their Item ID equals their # respective Location ID. Like scout flies, this is necessary for game<->archipelago communication. special_item_table = { - 5: "Fisherman's Boat", - 4: "Jungle Elevator", - 2: "Blue Eco Switch", - 17: "Flut Flut", - 60: "Yellow Eco Switch", - 63: "Snowy Fort Gate", - 71: "Freed The Blue Sage", - 72: "Freed The Red Sage", - 73: "Freed The Yellow Sage", - 70: "Freed The Green Sage", + 5: "Fisherman's Boat", # Unlocks 14 checks in Misty Island + 4: "Jungle Elevator", # Unlocks 2 checks in Forbidden Jungle + 2: "Blue Eco Switch", # Unlocks 1 check in Jungle and 1 in Beach + 17: "Flut Flut", # Unlocks 2 checks in Swamp and 2 in Snowy + 33: "Warrior's Pontoons", # Unlocks 14 checks in Swamp and everything post-Rock Village + 105: "Snowy Mountain Gondola", # Unlocks 15 checks in Snowy Mountain + 60: "Yellow Eco Switch", # Unlocks 1 check in Pass and 1 in Snowy + 63: "Snowy Fort Gate", # Unlocks 3 checks in Snowy Mountain + 71: "Freed The Blue Sage", # 1 of 3 unlocks for the final staircase and 2 checks in Citadel + 72: "Freed The Red Sage", # 1 of 3 unlocks for the final staircase and 2 checks in Citadel + 73: "Freed The Yellow Sage", # 1 of 3 unlocks for the final staircase and 2 checks in Citadel + 70: "Freed The Green Sage", # Unlocks the final elevator } # All Items diff --git a/worlds/jakanddaxter/Regions.py b/worlds/jakanddaxter/Regions.py index 16bab791ff..44490c9bc4 100644 --- a/worlds/jakanddaxter/Regions.py +++ b/worlds/jakanddaxter/Regions.py @@ -47,11 +47,8 @@ class Jak1SubLevel(int, Enum): FORBIDDEN_JUNGLE_SWITCH_ROOM = auto() FORBIDDEN_JUNGLE_PLANT_ROOM = auto() SENTINEL_BEACH_CANNON_TOWER = auto() - PRECURSOR_BASIN_BLUE_RINGS = auto() - LOST_PRECURSOR_CITY_SUNKEN_ROOM = auto() - LOST_PRECURSOR_CITY_HELIX_ROOM = auto() + ROCK_VILLAGE_PONTOON_BRIDGE = auto() BOGGY_SWAMP_FLUT_FLUT = auto() - MOUNTAIN_PASS_RACE = auto() MOUNTAIN_PASS_SHORTCUT = auto() SNOWY_MOUNTAIN_FLUT_FLUT = auto() SNOWY_MOUNTAIN_LURKER_FORT = auto() @@ -76,15 +73,15 @@ level_table: typing.Dict[Jak1Level, Jak1LevelInfo] = { Jak1Level.FIRE_CANYON: Jak1LevelInfo("Fire Canyon", 50), Jak1Level.ROCK_VILLAGE: - Jak1LevelInfo("Rock Village", 50), + Jak1LevelInfo("Rock Village", 43), Jak1Level.PRECURSOR_BASIN: Jak1LevelInfo("Precursor Basin", 200), Jak1Level.LOST_PRECURSOR_CITY: - Jak1LevelInfo("Lost Precursor City", 133), + Jak1LevelInfo("Lost Precursor City", 200), Jak1Level.BOGGY_SWAMP: Jak1LevelInfo("Boggy Swamp", 177), Jak1Level.MOUNTAIN_PASS: - Jak1LevelInfo("Mountain Pass", 0), + Jak1LevelInfo("Mountain Pass", 50), Jak1Level.VOLCANIC_CRATER: Jak1LevelInfo("Volcanic Crater", 50), Jak1Level.SPIDER_CAVE: @@ -104,16 +101,10 @@ sub_level_table: typing.Dict[Jak1SubLevel, Jak1LevelInfo] = { Jak1LevelInfo("Forbidden Jungle Plant Room", 27), Jak1SubLevel.SENTINEL_BEACH_CANNON_TOWER: Jak1LevelInfo("Sentinel Beach Cannon Tower", 22), - Jak1SubLevel.PRECURSOR_BASIN_BLUE_RINGS: - Jak1LevelInfo("Precursor Basin Blue Rings", 0), # Another virtual location, no orbs. - Jak1SubLevel.LOST_PRECURSOR_CITY_SUNKEN_ROOM: - Jak1LevelInfo("Lost Precursor City Sunken Room", 37), - Jak1SubLevel.LOST_PRECURSOR_CITY_HELIX_ROOM: - Jak1LevelInfo("Lost Precursor City Helix Room", 30), + Jak1SubLevel.ROCK_VILLAGE_PONTOON_BRIDGE: + Jak1LevelInfo("Rock Village Pontoon Bridge", 7), Jak1SubLevel.BOGGY_SWAMP_FLUT_FLUT: Jak1LevelInfo("Boggy Swamp Flut Flut", 23), - Jak1SubLevel.MOUNTAIN_PASS_RACE: - Jak1LevelInfo("Mountain Pass Race", 50), Jak1SubLevel.MOUNTAIN_PASS_SHORTCUT: Jak1LevelInfo("Mountain Pass Shortcut", 0), Jak1SubLevel.SNOWY_MOUNTAIN_FLUT_FLUT: @@ -177,26 +168,20 @@ def create_regions(multiworld: MultiWorld, options: JakAndDaxterOptions, player: region_rv = create_region(player, multiworld, Jak1Level.ROCK_VILLAGE) create_cell_locations(region_rv, Cells.locRV_cellTable) - create_fly_locations(region_rv, Scouts.locRV_scoutTable) + create_fly_locations(region_rv, {k: Scouts.locRV_scoutTable[k] + for k in {76, 131148, 196684, 262220, 65612, 327756}}) + create_special_locations(region_rv, {k: Specials.loc_specialTable[k] for k in {33}}) + + sub_region_rvpb = create_subregion(region_rv, Jak1SubLevel.ROCK_VILLAGE_PONTOON_BRIDGE) + create_fly_locations(sub_region_rvpb, {k: Scouts.locRV_scoutTable[k] for k in {393292}}) region_pb = create_region(player, multiworld, Jak1Level.PRECURSOR_BASIN) - create_cell_locations(region_pb, {k: Cells.locPB_cellTable[k] for k in {54, 53, 52, 56, 55, 58}}) + create_cell_locations(region_pb, Cells.locPB_cellTable) create_fly_locations(region_pb, Scouts.locPB_scoutTable) - sub_region_pbbr = create_subregion(region_pb, Jak1SubLevel.PRECURSOR_BASIN_BLUE_RINGS) - create_cell_locations(sub_region_pbbr, {k: Cells.locPB_cellTable[k] for k in {59}}) - region_lpc = create_region(player, multiworld, Jak1Level.LOST_PRECURSOR_CITY) - create_cell_locations(region_lpc, {k: Cells.locLPC_cellTable[k] for k in {45, 48, 44, 51}}) - create_fly_locations(region_lpc, {k: Scouts.locLPC_scoutTable[k] - for k in {262193, 131121, 393265, 196657, 49, 65585}}) - - sub_region_lpcsr = create_subregion(region_lpc, Jak1SubLevel.LOST_PRECURSOR_CITY_SUNKEN_ROOM) - create_cell_locations(sub_region_lpcsr, {k: Cells.locLPC_cellTable[k] for k in {47}}) - create_fly_locations(region_lpc, {k: Scouts.locLPC_scoutTable[k] for k in {327729}}) - - sub_region_lpchr = create_subregion(region_lpc, Jak1SubLevel.LOST_PRECURSOR_CITY_HELIX_ROOM) - create_cell_locations(sub_region_lpchr, {k: Cells.locLPC_cellTable[k] for k in {46, 50}}) + create_cell_locations(region_lpc, Cells.locLPC_cellTable) + create_fly_locations(region_lpc, Scouts.locLPC_scoutTable) region_bs = create_region(player, multiworld, Jak1Level.BOGGY_SWAMP) create_cell_locations(region_bs, {k: Cells.locBS_cellTable[k] for k in {36, 38, 39, 40, 41, 42}}) @@ -207,18 +192,16 @@ def create_regions(multiworld: MultiWorld, options: JakAndDaxterOptions, player: create_fly_locations(sub_region_bsff, {k: Scouts.locBS_scoutTable[k] for k in {327723, 131115}}) region_mp = create_region(player, multiworld, Jak1Level.MOUNTAIN_PASS) - create_cell_locations(region_mp, {k: Cells.locMP_cellTable[k] for k in {86}}) + create_cell_locations(region_mp, {k: Cells.locMP_cellTable[k] for k in {86, 87}}) + create_fly_locations(region_mp, Scouts.locMP_scoutTable) - sub_region_mpr = create_subregion(region_mp, Jak1SubLevel.MOUNTAIN_PASS_RACE) - create_cell_locations(sub_region_mpr, {k: Cells.locMP_cellTable[k] for k in {87}}) - create_fly_locations(sub_region_mpr, Scouts.locMP_scoutTable) - - sub_region_mps = create_subregion(sub_region_mpr, Jak1SubLevel.MOUNTAIN_PASS_SHORTCUT) + sub_region_mps = create_subregion(region_mp, Jak1SubLevel.MOUNTAIN_PASS_SHORTCUT) create_cell_locations(sub_region_mps, {k: Cells.locMP_cellTable[k] for k in {110}}) region_vc = create_region(player, multiworld, Jak1Level.VOLCANIC_CRATER) create_cell_locations(region_vc, Cells.locVC_cellTable) create_fly_locations(region_vc, Scouts.locVC_scoutTable) + create_special_locations(region_vc, {k: Specials.loc_specialTable[k] for k in {105}}) region_sc = create_region(player, multiworld, Jak1Level.SPIDER_CAVE) create_cell_locations(region_sc, Cells.locSC_cellTable) diff --git a/worlds/jakanddaxter/Rules.py b/worlds/jakanddaxter/Rules.py index f0c4a7e694..8ce4d5c255 100644 --- a/worlds/jakanddaxter/Rules.py +++ b/worlds/jakanddaxter/Rules.py @@ -25,8 +25,11 @@ def set_rules(multiworld: MultiWorld, options: JakAndDaxterOptions, player: int) fj_fisherman = item_table[Specials.to_ap_id(5)] sb_flut_flut = item_table[Specials.to_ap_id(17)] + rv_pontoon_bridge = item_table[Specials.to_ap_id(33)] + sm_yellow_switch = item_table[Specials.to_ap_id(60)] sm_fort_gate = item_table[Specials.to_ap_id(63)] + sm_gondola = item_table[Specials.to_ap_id(105)] gmc_blue_sage = item_table[Specials.to_ap_id(71)] gmc_red_sage = item_table[Specials.to_ap_id(72)] @@ -96,39 +99,20 @@ def set_rules(multiworld: MultiWorld, options: JakAndDaxterOptions, player: int) Jak1Level.ROCK_VILLAGE, Jak1Level.PRECURSOR_BASIN) - # This is another virtual location that shares it's "borders" with its parent location. - # You can do blue rings as soon as you finish purple rings. - connect_region_to_sub(multiworld, player, - Jak1Level.PRECURSOR_BASIN, - Jak1SubLevel.PRECURSOR_BASIN_BLUE_RINGS) - connect_regions(multiworld, player, Jak1Level.ROCK_VILLAGE, Jak1Level.LOST_PRECURSOR_CITY) + # This pontoon bridge locks out Boggy Swamp and Mountain Pass, + # effectively making it required to complete the game. connect_region_to_sub(multiworld, player, - Jak1Level.LOST_PRECURSOR_CITY, - Jak1SubLevel.LOST_PRECURSOR_CITY_SUNKEN_ROOM) + Jak1Level.ROCK_VILLAGE, + Jak1SubLevel.ROCK_VILLAGE_PONTOON_BRIDGE, + lambda state: state.has(rv_pontoon_bridge, player)) - connect_subregions(multiworld, player, - Jak1SubLevel.LOST_PRECURSOR_CITY_SUNKEN_ROOM, - Jak1SubLevel.LOST_PRECURSOR_CITY_HELIX_ROOM) - - # LPC is such a mess logistically... once you complete the climb up the helix room, - # you are back to the room before the first slide, which is still the "main area" of LPC. connect_sub_to_region(multiworld, player, - Jak1SubLevel.LOST_PRECURSOR_CITY_HELIX_ROOM, - Jak1Level.LOST_PRECURSOR_CITY) - - # Once you raise the sunken room to the surface, you can access Rock Village directly. - # You just need to complete the Location check to do this, you don't need to receive the power cell Item. - connect_sub_to_region(multiworld, player, - Jak1SubLevel.LOST_PRECURSOR_CITY_SUNKEN_ROOM, - Jak1Level.ROCK_VILLAGE) - - connect_regions(multiworld, player, - Jak1Level.ROCK_VILLAGE, - Jak1Level.BOGGY_SWAMP) + Jak1SubLevel.ROCK_VILLAGE_PONTOON_BRIDGE, + Jak1Level.BOGGY_SWAMP) # Flut Flut only has one landing pad here, so leaving this subregion is as easy # as dismounting Flut Flut right where you found her. @@ -137,36 +121,30 @@ def set_rules(multiworld: MultiWorld, options: JakAndDaxterOptions, player: int) Jak1SubLevel.BOGGY_SWAMP_FLUT_FLUT, lambda state: state.has(sb_flut_flut, player)) - # Klaww is considered the "main area" of MP, and the "race" is a subregion. - # It's not really intended to get back up the ledge overlooking Klaww's lava pit. - connect_regions(multiworld, player, - Jak1Level.ROCK_VILLAGE, - Jak1Level.MOUNTAIN_PASS, - lambda state: state.has(power_cell, player, 45)) + connect_sub_to_region(multiworld, player, + Jak1SubLevel.ROCK_VILLAGE_PONTOON_BRIDGE, + Jak1Level.MOUNTAIN_PASS, + lambda state: state.has(power_cell, player, 45)) connect_region_to_sub(multiworld, player, Jak1Level.MOUNTAIN_PASS, - Jak1SubLevel.MOUNTAIN_PASS_RACE) + Jak1SubLevel.MOUNTAIN_PASS_SHORTCUT, + lambda state: state.has(sm_yellow_switch, player)) - connect_subregions(multiworld, player, - Jak1SubLevel.MOUNTAIN_PASS_RACE, - Jak1SubLevel.MOUNTAIN_PASS_SHORTCUT, - lambda state: state.has(sm_yellow_switch, player)) - - connect_sub_to_region(multiworld, player, - Jak1SubLevel.MOUNTAIN_PASS_RACE, - Jak1Level.VOLCANIC_CRATER) + connect_regions(multiworld, player, + Jak1Level.MOUNTAIN_PASS, + Jak1Level.VOLCANIC_CRATER) set_trade_requirements(multiworld, player, Jak1Level.VOLCANIC_CRATER, vc_traders, 1530) connect_regions(multiworld, player, Jak1Level.VOLCANIC_CRATER, Jak1Level.SPIDER_CAVE) - # TODO - Yeah, this is a weird one. You technically need either 71 power cells OR - # any 2 power cells after arriving at Volcanic Crater. Not sure how to model this... + # Custom-added unlock for snowy mountain's gondola. connect_regions(multiworld, player, Jak1Level.VOLCANIC_CRATER, - Jak1Level.SNOWY_MOUNTAIN) + Jak1Level.SNOWY_MOUNTAIN, + lambda state: state.has(sm_gondola, player)) connect_region_to_sub(multiworld, player, Jak1Level.SNOWY_MOUNTAIN, diff --git a/worlds/jakanddaxter/__init__.py b/worlds/jakanddaxter/__init__.py index 8bdfffc5ba..82e588214e 100644 --- a/worlds/jakanddaxter/__init__.py +++ b/worlds/jakanddaxter/__init__.py @@ -16,10 +16,10 @@ from worlds.LauncherComponents import components, Component, launch_subprocess, class JakAndDaxterSettings(settings.Group): class RootDirectory(settings.UserFolderPath): - """Path to folder containing the ArchipelaGOAL mod.""" + """Path to folder containing the ArchipelaGOAL mod executables (gk.exe and goalc.exe).""" description = "ArchipelaGOAL Root Directory" - root_directory: RootDirectory = RootDirectory("D:/Files/Repositories/ArchipelaGOAL") + root_directory: RootDirectory = RootDirectory("D:/Files/Repositories/ArchipelaGOAL/out/build/Release/bin") class JakAndDaxterWebWorld(WebWorld): diff --git a/worlds/jakanddaxter/docs/en_Jak and Daxter The Precursor Legacy.md b/worlds/jakanddaxter/docs/en_Jak and Daxter The Precursor Legacy.md index a96d2797f2..54e0a1a563 100644 --- a/worlds/jakanddaxter/docs/en_Jak and Daxter The Precursor Legacy.md +++ b/worlds/jakanddaxter/docs/en_Jak and Daxter The Precursor Legacy.md @@ -5,52 +5,82 @@ The [Player Options Page](../player-options) for this game contains all the options you need to configure and export a config file. -At this time, Scout Flies are always randomized, and Precursor Orbs -are never randomized. +At this time, there are several caveats and restrictions: +- Power Cells and Scout Flies are **always** randomized. +- Precursor Orbs are **never** randomized. +- **All** of the traders in the game become in-logic checks **if and only if** you have enough Orbs (1530) to pay them all at once. + - This is to prevent hard locks, where an item required for progression is locked behind a trade you can't afford. ## What does randomization do to this game? -All 101 Power Cells and 112 Scout Flies are now Location Checks -and may contain Items for different games, as well as different Items from within Jak and Daxter. +All 101 Power Cells and 112 Scout Flies are now Location Checks and may contain Items for different games, +as well as different Items from within Jak and Daxter. Additionally, several special checks and corresponding items +have been added that are required to complete the game. + +## What are the special checks and how do I check them? +| Check Name | How To Check | +|------------------------|------------------------------------------------------------------------------| +| Fisherman's Boat | Complete the fishing minigame in Forbidden Jungle | +| Jungle Elevator | Collect the power cell at the top of the temple in Forbidden Jungle | +| Blue Eco Switch | Collect the power cell on the blue vent switch in Forbidden Jungle | +| Flut Flut | Push the egg off the cliff in Sentinel Beach and talk to the bird lady | +| Warrior's Pontoons | Talk to the Warrior in Rock Village once (you do NOT have to trade with him) | +| Snowy Mountain Gondola | Approach the gondola in Volcanic Crater | +| Yellow Eco Switch | Collect the power cell on the yellow vent switch in Snowy Mountain | +| Snowy Fort Gate | Ride the Flut Flut in Snowy Mountain and press the fort gate switch | +| Freed The Blue Sage | Free the Blue Sage in Gol and Maia's Citadel | +| Freed The Red Sage | Free the Red Sage in Gol and Maia's Citadel | +| Freed The Yellow Sage | Free the Yellow Sage in Gol and Maia's Citadel | +| Freed The Green Sage | Free the Green Sage in Gol and Maia's Citadel | + +## What are the special items and what do they unlock? +| Item Name | What It Unlocks | +|--------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------| +| Fisherman's Boat | Misty Island | +| Jungle Elevator | The blue vent switch inside the temple in Forbidden Jungle | +| Blue Eco Switch | The plant boss inside the temple in Forbidden Jungle
The cannon tower in Sentinel Beach | +| Flut Flut | The upper platforms in Boggy Swamp
The fort gate switch in Snowy Mountain | +| Warrior's Pontoons | Boggy Swamp and Mountain Pass | +| Snowy Mountain Gondola | Snowy Mountain | +| Yellow Eco Switch | The frozen box in Snowy Mountain
The shortcut in Mountain Pass | +| Snowy Fort Gate | The fort in Snowy Mountain | +| Freed The Blue Sage
Freed The Red Sage
Freed The Yellow Sage | The final staircase in Gol and Maia's Citadel | +| Freed The Green Sage | The final elevator in Gol and Maia's Citadel | ## What is the goal of the game once randomized? To complete the game, you must defeat the Gol and Maia and stop them from opening the Dark Eco silo. In order to reach them, you will need at least 72 Power Cells to cross the Lava Tube. In addition, -you will need the four specific Power Cells obtained by freeing the Red, Blue, Yellow, and Green Sages. +you will need the four special items that free the Red, Blue, Yellow, and Green Sages. -## How do I progress through the game? -You can progress by performing tasks and completing the challenges that would normally give you Power Cells and -Scout Flies in the game. If you are playing with others, those players may find Power Cells and Scout Flies -in their games, and those Items will be automatically sent to your game. +## What happens when I pick up or receive a power cell? +When you pick up a power cell, Jak and Daxter will perform their victory animation. Your power cell count will +NOT change. The pause menu will say "Task Completed" below the picked-up Power Cell. If your power cell was related +to one of the special checks listed above, you will automatically check that location as well - a 2 for 1 deal! +Finally, your text client will inform you what you found and who it belongs to. -If you have completed all possible tasks available to you but still cannot progress, you may have to wait for -another player to find enough of your game's Items to allow you to progress. If that does not apply, -double-check your spoiler log to make sure you have all the items you should have. If you don't, -you may have encountered a bug. Please see the options for bug reporting below. +When you receive a power cell, your power cell count will tick up by 1. Gameplay will otherwise continue as normal. +Finally, your text client will inform you where you received the power cell from. -## What happens when I pick up an item? -Jak and Daxter will perform their victory animation, if applicable. You will not receive that item, and -the Item count for that item will not change. The pause menu will say "Task Completed" below the -picked-up Power Cell, but the icon will remain "dormant." You will see a message in your text client saying -what you found and who it belongs to. +## What happens when I pick up or receive a scout fly? +When you pick up a scout fly, your scout fly count will NOT change. The pause menu will show you the number of +scout flies you picked up per-region, and this number will have ticked up by 1 for the region that scout fly belongs to. +Finally, your text client will inform you what you found and who it belongs to. -## What happens when I receive an item? -Jak and Daxter won't perform their victory animation, and gameplay will continue as normal. Your text client will -inform you where you received the Item from, and which one it is. Your Item count for that type of Item will also -tick up. The pause menu will not say "Task Completed" below the selected Power Cell, but the icon will be "activated." +When you receive a scout fly, your total scout fly count will tick up by 1. The pause menu will show you the number of +scout flies you received per-region, and this number will have ticked up by 1 for the region that scout fly belongs to. +Finally, your text client will inform you where you received the scout fly from, and which one it is. -## I can't reach a certain area within an accessible region, how do I get there? -Some areas are locked behind possession of specific Power Cells. For example, you cannot access Misty Island -until you have the "Catch 200 Pounds of Fish" Power Cell. Keep in mind, your access to Misty Island is determined -_through possession of this specific Power Cell only,_ **not** _by you completing the Fishing minigame._ +## How do I check the "Free 7 Scout Flies" power cell? +You will automatically check this power cell when you _receive_ your 7th scout fly, NOT when you _pick up_ your 7th +scout fly. So in short: + +- When you _pick up_ your 7th fly, the normal rules apply. +- When you _receive_ your 7th fly, 2 things will happen in quick succession. + - First, you will receive that scout fly, as normal. + - Second, you will immediately complete the "Free 7 Scout Flies" check, which will send out another item. ## I got soft-locked and can't leave, how do I get out of here? -As stated before, some areas are locked behind possession of specific Power Cells. But you may already be past -a point-of-no-return preventing you from backtracking. One example is the Forbidden Jungle temple, where -the elevator is locked at the bottom, and if you haven't unlocked the Blue Eco Switch, you cannot access -the Plant Boss's room and escape. - -In this scenario, you will need to open your menu and find the "Warp To Home" option at the bottom of the list. +Open the game's menu, navigate to Options, and find the "Warp To Home" option at the bottom of the list. Selecting this option will instantly teleport you to Geyser Rock. From there, you can teleport back to the nearest sage's hut to continue your journey. @@ -60,8 +90,7 @@ Depending on the nature of the bug, there are a couple of different options. * If you found a logical error in the randomizer, please create a new Issue [here.](https://github.com/ArchipelaGOAL/Archipelago/issues) * Use this page if: - * You are hard-locked from progressing. For example, you are stuck on Geyser Rock because one of the four - Geyser Rock Power Cells is not on Geyser Rock. + * An item required for progression is unreachable. * The randomizer did not respect one of the Options you chose. * You see a mistake, typo, etc. on this webpage. * You see an error or stack trace appear on the text client. @@ -70,7 +99,7 @@ Depending on the nature of the bug, there are a couple of different options. * If you encountered an error in OpenGOAL, please create a new Issue [here.](https://github.com/ArchipelaGOAL/ArchipelaGOAL/issues) * Use this page if: - * You encounter a crash, freeze, reset, etc. + * You encounter a crash, freeze, reset, etc in the game. * You fail to send Items you find in the game to the Archipelago server. * You fail to receive Items the server sends to you. * Your game disconnects from the server and cannot reconnect. diff --git a/worlds/jakanddaxter/locs/SpecialLocations.py b/worlds/jakanddaxter/locs/SpecialLocations.py index 4ce5b63812..e9ebecbfd9 100644 --- a/worlds/jakanddaxter/locs/SpecialLocations.py +++ b/worlds/jakanddaxter/locs/SpecialLocations.py @@ -38,6 +38,8 @@ loc_specialTable = { 4: "Jungle Elevator", 2: "Blue Eco Switch", 17: "Flut Flut", + 33: "Warrior's Pontoons", + 105: "Snowy Mountain Gondola", 60: "Yellow Eco Switch", 63: "Snowy Fort Gate", 71: "Freed The Blue Sage",