mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-08-12 18:52:58 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7c4fcb4c6 | ||
|
|
bcd3f9a74c | ||
|
|
6262235161 | ||
|
|
030cb4b578 | ||
|
|
36bab6f52a | ||
|
|
e0cfef3407 | ||
|
|
bb2a775c05 | ||
|
|
427b147818 | ||
|
|
3f3c343fb3 | ||
|
|
debe4cf035 | ||
|
|
68f25f4642 | ||
|
|
3c4af8f432 |
@@ -24,7 +24,6 @@ Currently, the following games are supported:
|
||||
* The Witness
|
||||
* Sonic Adventure 2: Battle
|
||||
* Starcraft 2
|
||||
* Donkey Kong Country 3
|
||||
* Dark Souls 3
|
||||
* Super Mario World
|
||||
* Pokémon Red and Blue
|
||||
|
||||
+2
-1
@@ -110,13 +110,14 @@ if __name__ == "__main__":
|
||||
logging.exception(e)
|
||||
logging.warning("Could not update LttP sprites.")
|
||||
app = get_app()
|
||||
from worlds import AutoWorldRegister
|
||||
from worlds import AutoWorldRegister, network_data_package
|
||||
# Update to only valid WebHost worlds
|
||||
invalid_worlds = {name for name, world in AutoWorldRegister.world_types.items()
|
||||
if not hasattr(world.web, "tutorials")}
|
||||
if invalid_worlds:
|
||||
logging.error(f"Following worlds not loaded as they are invalid for WebHost: {invalid_worlds}")
|
||||
AutoWorldRegister.world_types = {k: v for k, v in AutoWorldRegister.world_types.items() if k not in invalid_worlds}
|
||||
network_data_package["games"] = {k: v for k, v in network_data_package["games"].items() if k not in invalid_worlds}
|
||||
create_options_files()
|
||||
copy_tutorials_files_to_static()
|
||||
if app.config["SELFLAUNCH"]:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{% block footer %}
|
||||
<footer id="island-footer">
|
||||
<div id="copyright-notice">Copyright 2025 Archipelago</div>
|
||||
<div id="copyright-notice">Copyright 2026 Archipelago</div>
|
||||
<div id="links">
|
||||
<a href="/sitemap">Site Map</a>
|
||||
-
|
||||
|
||||
@@ -56,9 +56,6 @@
|
||||
# Dark Souls III
|
||||
/worlds/dark_souls_3/ @Marechal-L @nex3
|
||||
|
||||
# Donkey Kong Country 3
|
||||
/worlds/dkc3/ @PoryGone
|
||||
|
||||
# DLCQuest
|
||||
/worlds/dlcquest/ @axe-y @agilbert1412
|
||||
|
||||
|
||||
@@ -69,12 +69,6 @@ flowchart LR
|
||||
end
|
||||
SNI <-- Various, depending on SNES device --> SMZ
|
||||
|
||||
%% Donkey Kong Country 3
|
||||
subgraph Donkey Kong Country 3
|
||||
DK3[SNES]
|
||||
end
|
||||
SNI <-- Various, depending on SNES device --> DK3
|
||||
|
||||
%% Super Mario World
|
||||
subgraph Super Mario World
|
||||
SMW[SNES]
|
||||
|
||||
@@ -108,7 +108,6 @@ Example:
|
||||
```json
|
||||
{
|
||||
...
|
||||
"Donkey Kong Country 3":"f90acedcd958213f483a6a4c238e2a3faf92165e",
|
||||
"Factorio":"a699194a9589db3ebc0d821915864b422c782f44",
|
||||
...
|
||||
}
|
||||
|
||||
@@ -98,11 +98,6 @@ Root: HKCR; Subkey: "{#MyAppName}smpatch"; ValueData: "Arc
|
||||
Root: HKCR; Subkey: "{#MyAppName}smpatch\DefaultIcon"; ValueData: "{app}\ArchipelagoSNIClient.exe,0"; ValueType: string; ValueName: "";
|
||||
Root: HKCR; Subkey: "{#MyAppName}smpatch\shell\open\command"; ValueData: """{app}\ArchipelagoSNIClient.exe"" ""%1"""; ValueType: string; ValueName: "";
|
||||
|
||||
Root: HKCR; Subkey: ".apdkc3"; ValueData: "{#MyAppName}dkc3patch"; Flags: uninsdeletevalue; ValueType: string; ValueName: "";
|
||||
Root: HKCR; Subkey: "{#MyAppName}dkc3patch"; ValueData: "Archipelago Donkey Kong Country 3 Patch"; Flags: uninsdeletekey; ValueType: string; ValueName: "";
|
||||
Root: HKCR; Subkey: "{#MyAppName}dkc3patch\DefaultIcon"; ValueData: "{app}\ArchipelagoSNIClient.exe,0"; ValueType: string; ValueName: "";
|
||||
Root: HKCR; Subkey: "{#MyAppName}dkc3patch\shell\open\command"; ValueData: """{app}\ArchipelagoSNIClient.exe"" ""%1"""; ValueType: string; ValueName: "";
|
||||
|
||||
Root: HKCR; Subkey: ".apsmw"; ValueData: "{#MyAppName}smwpatch"; Flags: uninsdeletevalue; ValueType: string; ValueName: "";
|
||||
Root: HKCR; Subkey: "{#MyAppName}smwpatch"; ValueData: "Archipelago Super Mario World Patch"; Flags: uninsdeletekey; ValueType: string; ValueName: "";
|
||||
Root: HKCR; Subkey: "{#MyAppName}smwpatch\DefaultIcon"; ValueData: "{app}\ArchipelagoSNIClient.exe,0"; ValueType: string; ValueName: "";
|
||||
|
||||
@@ -269,8 +269,9 @@ if not is_frozen():
|
||||
from Launcher import open_folder
|
||||
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser("Build script for APWorlds")
|
||||
parser.add_argument("worlds", type=str, default=(), nargs="*", help="Names of APWorlds to build.")
|
||||
parser = argparse.ArgumentParser(prog="Build APWorlds", description="Build script for APWorlds")
|
||||
parser.add_argument("worlds", type=str, default=(), nargs="*", help="names of APWorlds to build")
|
||||
parser.add_argument("--skip_open_folder", action="store_true", help="don't open the output build folder")
|
||||
args = parser.parse_args(launch_args)
|
||||
|
||||
if args.worlds:
|
||||
@@ -320,7 +321,9 @@ if not is_frozen():
|
||||
zf.write(pathlib.Path(world_directory, file), pathlib.Path(file_name, file))
|
||||
|
||||
zf.writestr(apworld.manifest_path, json.dumps(manifest))
|
||||
open_folder(apworlds_folder)
|
||||
|
||||
if not args.skip_open_folder:
|
||||
open_folder(apworlds_folder)
|
||||
|
||||
components.append(Component("Build APWorlds", func=_build_apworlds, cli=True,
|
||||
description="Build APWorlds from loose-file world folders."))
|
||||
|
||||
@@ -3,10 +3,10 @@ from Options import PerGameCommonOptions
|
||||
from .Locations import location_table, AdventureLocation, dragon_room_to_region
|
||||
|
||||
|
||||
def connect(world: MultiWorld, player: int, source: str, target: str, rule: callable = lambda state: True,
|
||||
def connect(multiworld: MultiWorld, player: int, source: str, target: str, rule: callable = lambda state: True,
|
||||
one_way=False, name=None):
|
||||
source_region = world.get_region(source, player)
|
||||
target_region = world.get_region(target, player)
|
||||
source_region = multiworld.get_region(source, player)
|
||||
target_region = multiworld.get_region(target, player)
|
||||
|
||||
if name is None:
|
||||
name = source + " to " + target
|
||||
@@ -22,7 +22,7 @@ def connect(world: MultiWorld, player: int, source: str, target: str, rule: call
|
||||
source_region.exits.append(connection)
|
||||
connection.connect(target_region)
|
||||
if not one_way:
|
||||
connect(world, player, target, source, rule, True)
|
||||
connect(multiworld, player, target, source, rule, True)
|
||||
|
||||
|
||||
def create_regions(options: PerGameCommonOptions, multiworld: MultiWorld, player: int, dragon_rooms: []) -> None:
|
||||
|
||||
+25
-25
@@ -3,47 +3,47 @@ from worlds.generic.Rules import add_rule, set_rule, forbid_item
|
||||
|
||||
|
||||
def set_rules(self) -> None:
|
||||
world = self.multiworld
|
||||
multiworld = self.multiworld
|
||||
use_bat_logic = self.options.bat_logic.value == BatLogic.option_use_logic
|
||||
|
||||
set_rule(world.get_entrance("YellowCastlePort", self.player),
|
||||
set_rule(multiworld.get_entrance("YellowCastlePort", self.player),
|
||||
lambda state: state.has("Yellow Key", self.player))
|
||||
set_rule(world.get_entrance("BlackCastlePort", self.player),
|
||||
set_rule(multiworld.get_entrance("BlackCastlePort", self.player),
|
||||
lambda state: state.has("Black Key", self.player))
|
||||
set_rule(world.get_entrance("WhiteCastlePort", self.player),
|
||||
set_rule(multiworld.get_entrance("WhiteCastlePort", self.player),
|
||||
lambda state: state.has("White Key", self.player))
|
||||
|
||||
# a future thing would be to make the bat an actual item, or at least allow it to
|
||||
# be placed in a castle, which would require some additions to the rules when
|
||||
# use_bat_logic is true
|
||||
if not use_bat_logic:
|
||||
set_rule(world.get_entrance("WhiteCastleSecretPassage", self.player),
|
||||
set_rule(multiworld.get_entrance("WhiteCastleSecretPassage", self.player),
|
||||
lambda state: state.has("Bridge", self.player))
|
||||
set_rule(world.get_entrance("WhiteCastlePeekPassage", self.player),
|
||||
set_rule(multiworld.get_entrance("WhiteCastlePeekPassage", self.player),
|
||||
lambda state: state.has("Bridge", self.player) or
|
||||
state.has("Magnet", self.player))
|
||||
set_rule(world.get_entrance("BlackCastleVaultEntrance", self.player),
|
||||
set_rule(multiworld.get_entrance("BlackCastleVaultEntrance", self.player),
|
||||
lambda state: state.has("Bridge", self.player) or
|
||||
state.has("Magnet", self.player))
|
||||
|
||||
dragon_slay_check = self.options.dragon_slay_check.value
|
||||
if dragon_slay_check:
|
||||
if self.difficulty_switch_b == DifficultySwitchB.option_hard_with_unlock_item:
|
||||
set_rule(world.get_location("Slay Yorgle", self.player),
|
||||
set_rule(multiworld.get_location("Slay Yorgle", self.player),
|
||||
lambda state: state.has("Sword", self.player) and
|
||||
state.has("Right Difficulty Switch", self.player))
|
||||
set_rule(world.get_location("Slay Grundle", self.player),
|
||||
set_rule(multiworld.get_location("Slay Grundle", self.player),
|
||||
lambda state: state.has("Sword", self.player) and
|
||||
state.has("Right Difficulty Switch", self.player))
|
||||
set_rule(world.get_location("Slay Rhindle", self.player),
|
||||
set_rule(multiworld.get_location("Slay Rhindle", self.player),
|
||||
lambda state: state.has("Sword", self.player) and
|
||||
state.has("Right Difficulty Switch", self.player))
|
||||
else:
|
||||
set_rule(world.get_location("Slay Yorgle", self.player),
|
||||
set_rule(multiworld.get_location("Slay Yorgle", self.player),
|
||||
lambda state: state.has("Sword", self.player))
|
||||
set_rule(world.get_location("Slay Grundle", self.player),
|
||||
set_rule(multiworld.get_location("Slay Grundle", self.player),
|
||||
lambda state: state.has("Sword", self.player))
|
||||
set_rule(world.get_location("Slay Rhindle", self.player),
|
||||
set_rule(multiworld.get_location("Slay Rhindle", self.player),
|
||||
lambda state: state.has("Sword", self.player))
|
||||
|
||||
# really this requires getting the dot item, and having another item or enemy
|
||||
@@ -51,37 +51,37 @@ def set_rules(self) -> None:
|
||||
# to actually make randomized, since it is invisible. May add some options
|
||||
# for how that works in the distant future, but for now, just say you need
|
||||
# the bridge and black key to get to it, as that simplifies things a lot
|
||||
set_rule(world.get_entrance("CreditsWall", self.player),
|
||||
set_rule(multiworld.get_entrance("CreditsWall", self.player),
|
||||
lambda state: state.has("Bridge", self.player) and
|
||||
state.has("Black Key", self.player))
|
||||
|
||||
if not use_bat_logic:
|
||||
set_rule(world.get_entrance("CreditsToFarSide", self.player),
|
||||
set_rule(multiworld.get_entrance("CreditsToFarSide", self.player),
|
||||
lambda state: state.has("Magnet", self.player))
|
||||
|
||||
# bridge literally does not fit in this space, I think. I'll just exclude it
|
||||
forbid_item(world.get_location("Dungeon Vault", self.player), "Bridge", self.player)
|
||||
forbid_item(multiworld.get_location("Dungeon Vault", self.player), "Bridge", self.player)
|
||||
# don't put magnet in locations that can pull in-logic items out of reach unless the bat is in play
|
||||
if not use_bat_logic:
|
||||
forbid_item(world.get_location("Dungeon Vault", self.player), "Magnet", self.player)
|
||||
forbid_item(world.get_location("Red Maze Vault Entrance", self.player), "Magnet", self.player)
|
||||
forbid_item(world.get_location("Credits Right Side", self.player), "Magnet", self.player)
|
||||
forbid_item(multiworld.get_location("Dungeon Vault", self.player), "Magnet", self.player)
|
||||
forbid_item(multiworld.get_location("Red Maze Vault Entrance", self.player), "Magnet", self.player)
|
||||
forbid_item(multiworld.get_location("Credits Right Side", self.player), "Magnet", self.player)
|
||||
|
||||
# and obviously we don't want to start with the game already won
|
||||
forbid_item(world.get_location("Inside Yellow Castle", self.player), "Chalice", self.player)
|
||||
overworld = world.get_region("Overworld", self.player)
|
||||
forbid_item(multiworld.get_location("Inside Yellow Castle", self.player), "Chalice", self.player)
|
||||
overworld = multiworld.get_region("Overworld", self.player)
|
||||
|
||||
for loc in overworld.locations:
|
||||
forbid_item(loc, "Chalice", self.player)
|
||||
|
||||
add_rule(world.get_location("Chalice Home", self.player),
|
||||
add_rule(multiworld.get_location("Chalice Home", self.player),
|
||||
lambda state: state.has("Chalice", self.player) and state.has("Yellow Key", self.player))
|
||||
|
||||
# world.random.choice(overworld.locations).progress_type = LocationProgressType.PRIORITY
|
||||
# multiworld.random.choice(overworld.locations).progress_type = LocationProgressType.PRIORITY
|
||||
|
||||
# all_locations = world.get_locations(self.player).copy()
|
||||
# all_locations = multiworld.get_locations(self.player).copy()
|
||||
# while priority_count < get_num_items():
|
||||
# loc = world.random.choice(all_locations)
|
||||
# loc = multiworld.random.choice(all_locations)
|
||||
# if loc.progress_type == LocationProgressType.DEFAULT:
|
||||
# loc.progress_type = LocationProgressType.PRIORITY
|
||||
# priority_count += 1
|
||||
|
||||
@@ -105,8 +105,8 @@ class AdventureWorld(World):
|
||||
location_name_to_id: ClassVar[Dict[str, int]] = {name: data.location_id for name, data in location_table.items()}
|
||||
required_client_version: Tuple[int, int, int] = (0, 3, 9)
|
||||
|
||||
def __init__(self, world: MultiWorld, player: int):
|
||||
super().__init__(world, player)
|
||||
def __init__(self, multiworld: MultiWorld, player: int):
|
||||
super().__init__(multiworld, player)
|
||||
self.rom_name: Optional[bytearray] = bytearray("", "utf8" )
|
||||
self.dragon_rooms: [int] = [0x14, 0x19, 0x4]
|
||||
self.dragon_slay_check: Optional[int] = 0
|
||||
|
||||
@@ -30,7 +30,10 @@
|
||||
C to fire available Confetti Cannons
|
||||
Number Keys + Backspace for Math Trap\n
|
||||
|
||||
Rebinding controls might be added in the future :)"""
|
||||
[b]Click to move also works![/b]
|
||||
|
||||
Click/tap Confetti Cannon to fire it
|
||||
Submit Math Trap solution in the command line at the bottom"""
|
||||
|
||||
<VolumeSliderView>:
|
||||
orientation: "horizontal"
|
||||
|
||||
@@ -4,8 +4,9 @@ from argparse import Namespace
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from CommonClient import CommonContext, gui_enabled, logger, server_loop
|
||||
from CommonClient import ClientCommandProcessor, CommonContext, logger, server_loop
|
||||
from NetUtils import ClientStatus
|
||||
from Utils import gui_enabled
|
||||
|
||||
from ..game.events import ConfettiFired, LocationClearedEvent, MathProblemSolved, MathProblemStarted, VictoryEvent
|
||||
from ..game.game import Game
|
||||
@@ -41,6 +42,16 @@ class ConnectionStatus(Enum):
|
||||
GAME_RUNNING = 3
|
||||
|
||||
|
||||
class APQuestClientCommandProcessor(ClientCommandProcessor):
|
||||
ctx: "APQuestContext"
|
||||
|
||||
def default(self, raw: str) -> None:
|
||||
if self.ctx.external_math_trap_input(raw):
|
||||
return
|
||||
|
||||
super().default(raw)
|
||||
|
||||
|
||||
class APQuestContext(CommonContext):
|
||||
game = "APQuest"
|
||||
items_handling = 0b111 # full remote
|
||||
@@ -65,6 +76,7 @@ class APQuestContext(CommonContext):
|
||||
delay_intro_song: bool
|
||||
|
||||
ui: APQuestManager
|
||||
command_processor = APQuestClientCommandProcessor
|
||||
|
||||
def __init__(
|
||||
self, server_address: str | None = None, password: str | None = None, delay_intro_song: bool = False
|
||||
@@ -172,7 +184,6 @@ class APQuestContext(CommonContext):
|
||||
assert self.ap_quest_game is not None
|
||||
self.ap_quest_game.gameboard.fill_remote_location_content(remote_item_graphic_overrides)
|
||||
self.render()
|
||||
self.ui.game_view.bind_keyboard()
|
||||
|
||||
self.connection_status = ConnectionStatus.GAME_RUNNING
|
||||
self.ui.game_started()
|
||||
@@ -244,6 +255,59 @@ class APQuestContext(CommonContext):
|
||||
self.ap_quest_game.input(input_key)
|
||||
self.render()
|
||||
|
||||
def queue_auto_move(self, target_x: int, target_y: int) -> None:
|
||||
if self.ap_quest_game is None:
|
||||
return
|
||||
if not self.ap_quest_game.gameboard.ready:
|
||||
return
|
||||
if not self.ui.game_view.focused > 1: # Must already be in focus
|
||||
return
|
||||
self.ap_quest_game.queue_auto_move(target_x, target_y)
|
||||
self.ui.start_auto_move()
|
||||
|
||||
def do_auto_move_and_rerender(self) -> None:
|
||||
if self.ap_quest_game is None:
|
||||
return
|
||||
if not self.ap_quest_game.gameboard.ready:
|
||||
return
|
||||
changed = self.ap_quest_game.do_auto_move()
|
||||
if changed:
|
||||
self.render()
|
||||
|
||||
def confetti_and_rerender(self) -> None:
|
||||
# Used by tap mode
|
||||
if self.ap_quest_game is None:
|
||||
return
|
||||
if not self.ap_quest_game.gameboard.ready:
|
||||
return
|
||||
|
||||
if self.ap_quest_game.attempt_fire_confetti_cannon():
|
||||
self.render()
|
||||
|
||||
def external_math_trap_input(self, raw: str) -> bool:
|
||||
if self.ap_quest_game is None:
|
||||
return False
|
||||
if not self.ap_quest_game.gameboard.ready:
|
||||
return False
|
||||
if not self.ap_quest_game.active_math_problem:
|
||||
return False
|
||||
|
||||
raw = raw.strip()
|
||||
|
||||
if not raw:
|
||||
return False
|
||||
if not raw.isnumeric():
|
||||
return False
|
||||
|
||||
self.ap_quest_game.math_problem_replace([int(digit) for digit in raw])
|
||||
|
||||
if not self.ap_quest_game.active_math_problem:
|
||||
self.ui.game_view.force_focus()
|
||||
|
||||
self.render()
|
||||
|
||||
return True
|
||||
|
||||
def make_gui(self) -> "type[kvui.GameManager]":
|
||||
self.load_kv()
|
||||
return APQuestManager
|
||||
|
||||
@@ -4,29 +4,26 @@ from math import sqrt
|
||||
from random import choice, random
|
||||
from typing import Any
|
||||
|
||||
from kivy.core.window import Keyboard, Window
|
||||
from kivy.core.window import Window
|
||||
from kivy.graphics import Color, Triangle
|
||||
from kivy.graphics.instructions import Canvas
|
||||
from kivy.input import MotionEvent
|
||||
from kivy.uix.behaviors import ButtonBehavior
|
||||
from kivy.uix.boxlayout import BoxLayout
|
||||
from kivy.uix.gridlayout import GridLayout
|
||||
from kivy.uix.image import Image
|
||||
from kivy.uix.widget import Widget
|
||||
from kivymd.uix.recycleview import MDRecycleView
|
||||
|
||||
from CommonClient import logger
|
||||
|
||||
from ..game.inputs import Input
|
||||
|
||||
|
||||
INPUT_MAP = {
|
||||
"up": Input.UP,
|
||||
INPUT_MAP_STR = {
|
||||
"w": Input.UP,
|
||||
"down": Input.DOWN,
|
||||
"s": Input.DOWN,
|
||||
"right": Input.RIGHT,
|
||||
"d": Input.RIGHT,
|
||||
"left": Input.LEFT,
|
||||
"a": Input.LEFT,
|
||||
"spacebar": Input.ACTION,
|
||||
" ": Input.ACTION,
|
||||
"c": Input.CONFETTI,
|
||||
"0": Input.ZERO,
|
||||
"1": Input.ONE,
|
||||
@@ -38,38 +35,52 @@ INPUT_MAP = {
|
||||
"7": Input.SEVEN,
|
||||
"8": Input.EIGHT,
|
||||
"9": Input.NINE,
|
||||
"backspace": Input.BACKSPACE,
|
||||
}
|
||||
|
||||
INPUT_MAP_SPECIAL_INT = {
|
||||
# Arrow Keys and Backspace
|
||||
273: Input.UP,
|
||||
274: Input.DOWN,
|
||||
275: Input.RIGHT,
|
||||
276: Input.LEFT,
|
||||
8: Input.BACKSPACE,
|
||||
}
|
||||
|
||||
|
||||
class APQuestGameView(MDRecycleView):
|
||||
_keyboard: Keyboard | None = None
|
||||
focused: int = 1
|
||||
input_function: Callable[[Input], None]
|
||||
|
||||
def __init__(self, input_function: Callable[[Input], None], **kwargs: Any) -> None:
|
||||
super().__init__(**kwargs)
|
||||
self.input_function = input_function
|
||||
self.bind_keyboard()
|
||||
Window.bind(on_key_down=self._on_keyboard_down)
|
||||
Window.bind(on_touch_down=self.check_focus)
|
||||
self.opacity = 0.5
|
||||
|
||||
def on_touch_down(self, touch: MotionEvent) -> None:
|
||||
self.bind_keyboard()
|
||||
|
||||
def bind_keyboard(self) -> None:
|
||||
if self._keyboard is not None:
|
||||
def check_focus(self, _, touch, *args, **kwargs) -> None:
|
||||
if self.parent.collide_point(*touch.pos):
|
||||
self.focused += 1
|
||||
self.opacity = 1
|
||||
return
|
||||
self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
|
||||
self._keyboard.bind(on_key_down=self._on_keyboard_down)
|
||||
|
||||
def _keyboard_closed(self) -> None:
|
||||
if self._keyboard is None:
|
||||
return
|
||||
self._keyboard.unbind(on_key_down=self._on_keyboard_down)
|
||||
self._keyboard = None
|
||||
self.focused = 0
|
||||
self.opacity = 0.5
|
||||
|
||||
def _on_keyboard_down(self, _: Any, keycode: tuple[int, str], _1: Any, _2: Any) -> bool:
|
||||
if keycode[1] in INPUT_MAP:
|
||||
self.input_function(INPUT_MAP[keycode[1]])
|
||||
return True
|
||||
def force_focus(self) -> None:
|
||||
Window.release_keyboard()
|
||||
self.focused = 1
|
||||
self.opacity = 1
|
||||
|
||||
def _on_keyboard_down(self, _: Any, keycode_int: int, _2: Any, keycode: str, _4: Any) -> bool:
|
||||
if not self.focused:
|
||||
return False
|
||||
|
||||
if keycode in INPUT_MAP_STR:
|
||||
self.input_function(INPUT_MAP_STR[keycode])
|
||||
elif keycode_int in INPUT_MAP_SPECIAL_INT:
|
||||
self.input_function(INPUT_MAP_SPECIAL_INT[keycode_int])
|
||||
return False
|
||||
|
||||
|
||||
class APQuestGrid(GridLayout):
|
||||
@@ -203,13 +214,23 @@ class Confetti:
|
||||
return True
|
||||
|
||||
|
||||
class ConfettiView(MDRecycleView):
|
||||
class ConfettiView(Widget):
|
||||
confetti: list[Confetti]
|
||||
|
||||
def __init__(self, **kwargs: Any) -> None:
|
||||
super().__init__(**kwargs)
|
||||
self.confetti = []
|
||||
|
||||
# Don't eat tap events for the game grid under the confetti view
|
||||
def on_touch_down(self, touch) -> bool:
|
||||
return False
|
||||
|
||||
def on_touch_move(self, touch) -> bool:
|
||||
return False
|
||||
|
||||
def on_touch_up(self, touch) -> bool:
|
||||
return False
|
||||
|
||||
def check_resize(self, _: int, _1: int) -> None:
|
||||
parent_width, parent_height = self.parent.size
|
||||
|
||||
@@ -254,3 +275,32 @@ class VolumeSliderView(BoxLayout):
|
||||
|
||||
class APQuestControlsView(BoxLayout):
|
||||
pass
|
||||
|
||||
|
||||
class TapImage(ButtonBehavior, Image):
|
||||
callback: Callable[[], None]
|
||||
|
||||
def __init__(self, callback: Callable[[], None], **kwargs) -> None:
|
||||
self.callback = callback
|
||||
super().__init__(**kwargs)
|
||||
|
||||
def on_release(self) -> bool:
|
||||
self.callback()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class TapIfConfettiCannonImage(ButtonBehavior, Image):
|
||||
callback: Callable[[], None]
|
||||
|
||||
is_confetti_cannon: bool = False
|
||||
|
||||
def __init__(self, callback: Callable[[], None], **kwargs: dict[str, Any]) -> None:
|
||||
self.callback = callback
|
||||
super().__init__(**kwargs)
|
||||
|
||||
def on_release(self) -> bool:
|
||||
if self.is_confetti_cannon:
|
||||
self.callback()
|
||||
|
||||
return True
|
||||
|
||||
@@ -6,6 +6,7 @@ from kvui import GameManager, MDNavigationItemBase
|
||||
# isort: on
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from kivy._clock import ClockEvent
|
||||
from kivy.clock import Clock
|
||||
from kivy.uix.gridlayout import GridLayout
|
||||
from kivy.uix.image import Image
|
||||
@@ -13,7 +14,16 @@ from kivy.uix.layout import Layout
|
||||
from kivymd.uix.recycleview import MDRecycleView
|
||||
|
||||
from ..game.game import Game
|
||||
from .custom_views import APQuestControlsView, APQuestGameView, APQuestGrid, ConfettiView, VolumeSliderView
|
||||
from ..game.graphics import Graphic
|
||||
from .custom_views import (
|
||||
APQuestControlsView,
|
||||
APQuestGameView,
|
||||
APQuestGrid,
|
||||
ConfettiView,
|
||||
TapIfConfettiCannonImage,
|
||||
TapImage,
|
||||
VolumeSliderView,
|
||||
)
|
||||
from .graphics import PlayerSprite, get_texture
|
||||
from .sounds import SoundManager
|
||||
|
||||
@@ -28,15 +38,17 @@ class APQuestManager(GameManager):
|
||||
lower_game_grid: GridLayout
|
||||
upper_game_grid: GridLayout
|
||||
|
||||
game_view: MDRecycleView
|
||||
game_view: MDRecycleView | None = None
|
||||
game_view_tab: MDNavigationItemBase
|
||||
|
||||
sound_manager: SoundManager
|
||||
|
||||
bottom_image_grid: list[list[Image]]
|
||||
top_image_grid: list[list[Image]]
|
||||
top_image_grid: list[list[TapImage]]
|
||||
confetti_view: ConfettiView
|
||||
|
||||
move_event: ClockEvent | None
|
||||
|
||||
bottom_grid_is_grass: bool
|
||||
|
||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||
@@ -45,6 +57,7 @@ class APQuestManager(GameManager):
|
||||
self.sound_manager.allow_intro_to_play = not self.ctx.delay_intro_song
|
||||
self.top_image_grid = []
|
||||
self.bottom_image_grid = []
|
||||
self.move_event = None
|
||||
self.bottom_grid_is_grass = False
|
||||
|
||||
def allow_intro_song(self) -> None:
|
||||
@@ -71,10 +84,12 @@ class APQuestManager(GameManager):
|
||||
|
||||
def game_started(self) -> None:
|
||||
self.switch_to_game_tab()
|
||||
if self.game_view is not None:
|
||||
self.game_view.force_focus()
|
||||
self.sound_manager.game_started = True
|
||||
|
||||
def render(self, game: Game, player_sprite: PlayerSprite) -> None:
|
||||
self.setup_game_grid_if_not_setup(game.gameboard.size)
|
||||
self.setup_game_grid_if_not_setup(game)
|
||||
|
||||
# This calls game.render(), which needs to happen to update the state of math traps
|
||||
self.render_gameboard(game, player_sprite)
|
||||
@@ -104,6 +119,8 @@ class APQuestManager(GameManager):
|
||||
for item_graphic, image_row in zip(rendered_item_column, self.top_image_grid, strict=False):
|
||||
image = image_row[-1]
|
||||
|
||||
image.is_confetti_cannon = item_graphic == Graphic.CONFETTI_CANNON
|
||||
|
||||
texture = get_texture(item_graphic)
|
||||
if texture is None:
|
||||
image.opacity = 0
|
||||
@@ -136,23 +153,25 @@ class APQuestManager(GameManager):
|
||||
|
||||
self.bottom_grid_is_grass = grass
|
||||
|
||||
def setup_game_grid_if_not_setup(self, size: tuple[int, int]) -> None:
|
||||
def setup_game_grid_if_not_setup(self, game: Game) -> None:
|
||||
if self.upper_game_grid.children:
|
||||
return
|
||||
|
||||
self.top_image_grid = []
|
||||
self.bottom_image_grid = []
|
||||
|
||||
for _row in range(size[1]):
|
||||
size = game.gameboard.size
|
||||
|
||||
for row in range(size[1]):
|
||||
self.top_image_grid.append([])
|
||||
self.bottom_image_grid.append([])
|
||||
|
||||
for _column in range(size[0]):
|
||||
for column in range(size[0]):
|
||||
bottom_image = Image(fit_mode="fill", color=(0.3, 0.3, 0.3))
|
||||
self.lower_game_grid.add_widget(bottom_image)
|
||||
self.bottom_image_grid[-1].append(bottom_image)
|
||||
|
||||
top_image = Image(fit_mode="fill")
|
||||
top_image = TapImage(lambda y=row, x=column: self.ctx.queue_auto_move(x, y), fit_mode="fill")
|
||||
self.upper_game_grid.add_widget(top_image)
|
||||
self.top_image_grid[-1].append(top_image)
|
||||
|
||||
@@ -160,11 +179,19 @@ class APQuestManager(GameManager):
|
||||
image = Image(fit_mode="fill", color=(0.3, 0.3, 0.3))
|
||||
self.lower_game_grid.add_widget(image)
|
||||
|
||||
image2 = Image(fit_mode="fill", opacity=0)
|
||||
image2 = TapIfConfettiCannonImage(lambda: self.ctx.confetti_and_rerender(), fit_mode="fill", opacity=0)
|
||||
self.upper_game_grid.add_widget(image2)
|
||||
|
||||
self.top_image_grid[-1].append(image2)
|
||||
|
||||
def start_auto_move(self) -> None:
|
||||
if self.move_event is not None:
|
||||
self.move_event.cancel()
|
||||
|
||||
self.ctx.do_auto_move_and_rerender()
|
||||
|
||||
self.move_event = Clock.schedule_interval(lambda _: self.ctx.do_auto_move_and_rerender(), 0.10)
|
||||
|
||||
def build(self) -> Layout:
|
||||
container = super().build()
|
||||
|
||||
|
||||
@@ -6,6 +6,11 @@
|
||||
- Die [APQuest-apworld](https://github.com/NewSoupVi/Archipelago/releases),
|
||||
falls diese nicht mit deiner Version von Archipelago gebündelt ist.
|
||||
|
||||
## Optionale Software
|
||||
|
||||
- [APQuest AP Tracker](https://github.com/palex00/ap-quest-tracker/releases/latest), zur Verwendung mit
|
||||
[PopTracker](https://github.com/black-sliver/PopTracker/releases)
|
||||
|
||||
## Wie man spielt
|
||||
|
||||
Zuerst brauchst du einen Raum, mit dem du dich verbinden kannst.
|
||||
@@ -41,3 +46,15 @@ Du solltest jetzt verbunden sein und kannst APQuest spielen.
|
||||
Der APQuest Client kann zwischen verschiedenen Slots wechseln, ohne neugestartet werden zu müssen,
|
||||
|
||||
Klicke einfach den "Disconnect"-Knopf. Dann verbinde dich mit dem anderen Raum / Slot.
|
||||
|
||||
|
||||
## Automatisches Tracken
|
||||
|
||||
AP Quest verfügt über einen voll funktionsfähigen, automatischen Tracker mit Karten der Spielwelt.
|
||||
|
||||
1. Lade [APQuest AP Tracker](https://github.com/palex00/ap-quest-tracker/releases/latest) und
|
||||
[PopTracker](https://github.com/black-sliver/PopTracker/releases) herunter.
|
||||
2. Lege das Tracker-Pack im Ordner „packs/“ deiner PopTracker-Installation ab.
|
||||
3. Öffne PopTracker und lade das APQuest-Pack.
|
||||
4. Für das automatische Tracking klick oben auf das „AP“-Symbol.
|
||||
5. Gib die Serveradresse von Archipelago (die, mit der du deinen Client verbunden hast), den Slot-Namen und das Passwort ein.
|
||||
|
||||
@@ -6,6 +6,11 @@
|
||||
- [The APQuest apworld](https://github.com/NewSoupVi/Archipelago/releases),
|
||||
if not bundled with your version of Archipelago
|
||||
|
||||
## Optional Software
|
||||
|
||||
- [APQuest AP Tracker](https://github.com/palex00/ap-quest-tracker/releases/latest), for use with
|
||||
[PopTracker](https://github.com/black-sliver/PopTracker/releases)
|
||||
|
||||
## How to play
|
||||
|
||||
First, you need a room to connect to. For this, you or someone you know has to generate a game.
|
||||
@@ -40,3 +45,14 @@ You should now be connected and able to play APQuest.
|
||||
The APQuest Client can seamlessly switch rooms without restarting.
|
||||
|
||||
Simply click the "Disconnect" button, then connect to a different slot/room.
|
||||
|
||||
## Auto-Tracking
|
||||
|
||||
AP Quest has a fully functional map tracker that supports auto-tracking.
|
||||
|
||||
1. Download [APQuest AP Tracker](https://github.com/palex00/ap-quest-tracker/releases/latest) and
|
||||
[PopTracker](https://github.com/black-sliver/PopTracker/releases).
|
||||
2. Put the tracker pack into packs/ in your PopTracker install.
|
||||
3. Open PopTracker, and load the APQuest pack.
|
||||
4. For autotracking, click on the "AP" symbol at the top.
|
||||
5. Enter the Archipelago server address (the one you connected your client to), slot name, and password.
|
||||
|
||||
@@ -17,8 +17,10 @@ class Entity:
|
||||
|
||||
|
||||
class InteractableMixin:
|
||||
auto_move_attempt_passing_through = False
|
||||
|
||||
@abstractmethod
|
||||
def interact(self, player: Player) -> None:
|
||||
def interact(self, player: Player) -> bool:
|
||||
pass
|
||||
|
||||
|
||||
@@ -89,15 +91,16 @@ class Chest(Entity, InteractableMixin, LocationMixin):
|
||||
self.is_open = True
|
||||
self.update_solidity()
|
||||
|
||||
def interact(self, player: Player) -> None:
|
||||
def interact(self, player: Player) -> bool:
|
||||
if self.has_given_content:
|
||||
return
|
||||
return False
|
||||
|
||||
if self.is_open:
|
||||
self.give_content(player)
|
||||
return
|
||||
return True
|
||||
|
||||
self.open()
|
||||
return True
|
||||
|
||||
def content_success(self) -> None:
|
||||
self.update_solidity()
|
||||
@@ -135,47 +138,59 @@ class Door(Entity):
|
||||
|
||||
|
||||
class KeyDoor(Door, InteractableMixin):
|
||||
auto_move_attempt_passing_through = True
|
||||
|
||||
closed_graphic = Graphic.KEY_DOOR
|
||||
|
||||
def interact(self, player: Player) -> None:
|
||||
def interact(self, player: Player) -> bool:
|
||||
if self.is_open:
|
||||
return
|
||||
return False
|
||||
|
||||
if not player.has_item(Item.KEY):
|
||||
return
|
||||
return False
|
||||
|
||||
player.remove_item(Item.KEY)
|
||||
|
||||
self.open()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class BreakableBlock(Door, InteractableMixin):
|
||||
auto_move_attempt_passing_through = True
|
||||
|
||||
closed_graphic = Graphic.BREAKABLE_BLOCK
|
||||
|
||||
def interact(self, player: Player) -> None:
|
||||
def interact(self, player: Player) -> bool:
|
||||
if self.is_open:
|
||||
return
|
||||
return False
|
||||
|
||||
if not player.has_item(Item.HAMMER):
|
||||
return
|
||||
return False
|
||||
|
||||
player.remove_item(Item.HAMMER)
|
||||
|
||||
self.open()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class Bush(Door, InteractableMixin):
|
||||
auto_move_attempt_passing_through = True
|
||||
|
||||
closed_graphic = Graphic.BUSH
|
||||
|
||||
def interact(self, player: Player) -> None:
|
||||
def interact(self, player: Player) -> bool:
|
||||
if self.is_open:
|
||||
return
|
||||
return False
|
||||
|
||||
if not player.has_item(Item.SWORD):
|
||||
return
|
||||
return False
|
||||
|
||||
self.open()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class Button(Entity, InteractableMixin):
|
||||
solid = True
|
||||
@@ -186,12 +201,13 @@ class Button(Entity, InteractableMixin):
|
||||
def __init__(self, activates: ActivatableMixin) -> None:
|
||||
self.activates = activates
|
||||
|
||||
def interact(self, player: Player) -> None:
|
||||
def interact(self, player: Player) -> bool:
|
||||
if self.activated:
|
||||
return
|
||||
return False
|
||||
|
||||
self.activated = True
|
||||
self.activates.activate(player)
|
||||
return True
|
||||
|
||||
@property
|
||||
def graphic(self) -> Graphic:
|
||||
@@ -240,9 +256,9 @@ class Enemy(Entity, InteractableMixin):
|
||||
return
|
||||
self.current_health = self.max_health
|
||||
|
||||
def interact(self, player: Player) -> None:
|
||||
def interact(self, player: Player) -> bool:
|
||||
if self.dead:
|
||||
return
|
||||
return False
|
||||
|
||||
if player.has_item(Item.SWORD):
|
||||
self.current_health = max(0, self.current_health - 1)
|
||||
@@ -250,9 +266,10 @@ class Enemy(Entity, InteractableMixin):
|
||||
if self.current_health == 0:
|
||||
if not self.dead:
|
||||
self.die()
|
||||
return
|
||||
return True
|
||||
|
||||
player.damage(2)
|
||||
return True
|
||||
|
||||
@property
|
||||
def graphic(self) -> Graphic:
|
||||
@@ -270,13 +287,15 @@ class EnemyWithLoot(Enemy, LocationMixin):
|
||||
self.dead = True
|
||||
self.solid = not self.has_given_content
|
||||
|
||||
def interact(self, player: Player) -> None:
|
||||
def interact(self, player: Player) -> bool:
|
||||
if self.dead:
|
||||
if not self.has_given_content:
|
||||
self.give_content(player)
|
||||
return
|
||||
return True
|
||||
return False
|
||||
|
||||
super().interact(player)
|
||||
return True
|
||||
|
||||
@property
|
||||
def graphic(self) -> Graphic:
|
||||
@@ -303,10 +322,12 @@ class FinalBoss(Enemy):
|
||||
}
|
||||
enemy_default_graphic = Graphic.BOSS_1_HEALTH
|
||||
|
||||
def interact(self, player: Player) -> None:
|
||||
def interact(self, player: Player) -> bool:
|
||||
dead_before = self.dead
|
||||
|
||||
super().interact(player)
|
||||
changed = super().interact(player)
|
||||
|
||||
if not dead_before and self.dead:
|
||||
player.victory()
|
||||
|
||||
return changed
|
||||
|
||||
+74
-10
@@ -23,6 +23,8 @@ class Game:
|
||||
active_math_problem: MathProblem | None
|
||||
active_math_problem_input: list[int] | None
|
||||
|
||||
auto_target_path: list[tuple[int, int]] = []
|
||||
|
||||
remotely_received_items: set[tuple[int, int, int]]
|
||||
|
||||
def __init__(
|
||||
@@ -32,6 +34,7 @@ class Game:
|
||||
self.gameboard = create_gameboard(hard_mode, hammer_exists, extra_chest)
|
||||
self.player = Player(self.gameboard, self.queued_events.append)
|
||||
self.active_math_problem = None
|
||||
self.active_math_problem_input = None
|
||||
self.remotely_received_items = set()
|
||||
|
||||
if random_object is None:
|
||||
@@ -94,29 +97,40 @@ class Game:
|
||||
|
||||
return tuple(graphics_array)
|
||||
|
||||
def attempt_player_movement(self, direction: Direction) -> None:
|
||||
def attempt_player_movement(self, direction: Direction, cancel_auto_move: bool = True) -> bool:
|
||||
if cancel_auto_move:
|
||||
self.cancel_auto_move()
|
||||
|
||||
self.player.facing = direction
|
||||
|
||||
delta_x, delta_y = direction.value
|
||||
new_x, new_y = self.player.current_x + delta_x, self.player.current_y + delta_y
|
||||
|
||||
if not self.gameboard.get_entity_at(new_x, new_y).solid:
|
||||
self.player.current_x = new_x
|
||||
self.player.current_y = new_y
|
||||
if self.gameboard.get_entity_at(new_x, new_y).solid:
|
||||
return False
|
||||
|
||||
def attempt_interact(self) -> None:
|
||||
self.player.current_x = new_x
|
||||
self.player.current_y = new_y
|
||||
return True
|
||||
|
||||
def attempt_interact(self) -> bool:
|
||||
delta_x, delta_y = self.player.facing.value
|
||||
entity_x, entity_y = self.player.current_x + delta_x, self.player.current_y + delta_y
|
||||
|
||||
entity = self.gameboard.get_entity_at(entity_x, entity_y)
|
||||
|
||||
if isinstance(entity, InteractableMixin):
|
||||
entity.interact(self.player)
|
||||
return entity.interact(self.player)
|
||||
|
||||
def attempt_fire_confetti_cannon(self) -> None:
|
||||
if self.player.has_item(Item.CONFETTI_CANNON):
|
||||
self.player.remove_item(Item.CONFETTI_CANNON)
|
||||
self.queued_events.append(ConfettiFired(self.player.current_x, self.player.current_y))
|
||||
return False
|
||||
|
||||
def attempt_fire_confetti_cannon(self) -> bool:
|
||||
if not self.player.has_item(Item.CONFETTI_CANNON):
|
||||
return False
|
||||
|
||||
self.player.remove_item(Item.CONFETTI_CANNON)
|
||||
self.queued_events.append(ConfettiFired(self.player.current_x, self.player.current_y))
|
||||
return True
|
||||
|
||||
def math_problem_success(self) -> None:
|
||||
self.active_math_problem = None
|
||||
@@ -154,6 +168,12 @@ class Game:
|
||||
self.active_math_problem_input.pop()
|
||||
self.check_math_problem_result()
|
||||
|
||||
def math_problem_replace(self, input: list[int]) -> None:
|
||||
if self.active_math_problem_input is None:
|
||||
return
|
||||
self.active_math_problem_input = input[:2]
|
||||
self.check_math_problem_result()
|
||||
|
||||
def input(self, input_key: Input) -> None:
|
||||
if not self.gameboard.ready:
|
||||
return
|
||||
@@ -201,3 +221,47 @@ class Game:
|
||||
def force_clear_location(self, location_id: int) -> None:
|
||||
location = Location(location_id)
|
||||
self.gameboard.force_clear_location(location)
|
||||
|
||||
def cancel_auto_move(self) -> None:
|
||||
self.auto_target_path = []
|
||||
|
||||
def queue_auto_move(self, target_x: int, target_y: int) -> None:
|
||||
self.cancel_auto_move()
|
||||
path = self.gameboard.calculate_shortest_path(self.player.current_x, self.player.current_y, target_x, target_y)
|
||||
self.auto_target_path = path
|
||||
|
||||
def do_auto_move(self) -> bool:
|
||||
if not self.auto_target_path:
|
||||
return False
|
||||
|
||||
target_x, target_y = self.auto_target_path.pop(0)
|
||||
movement = target_x - self.player.current_x, target_y - self.player.current_y
|
||||
direction = Direction(movement)
|
||||
moved = self.attempt_player_movement(direction, cancel_auto_move=False)
|
||||
|
||||
if moved:
|
||||
return True
|
||||
|
||||
# We are attempting to interact with something on the path.
|
||||
# First, make the player face it.
|
||||
if self.player.facing != direction:
|
||||
self.player.facing = direction
|
||||
self.auto_target_path.insert(0, (target_x, target_y))
|
||||
return True
|
||||
|
||||
# If we are facing it, attempt to interact with it.
|
||||
changed = self.attempt_interact()
|
||||
|
||||
if not changed:
|
||||
self.cancel_auto_move()
|
||||
return False
|
||||
|
||||
# If the interaction was successful, and this was the end of the path, stop
|
||||
# (i.e. don't try to attack the attacked enemy over and over until it's dead)
|
||||
if not self.auto_target_path:
|
||||
self.cancel_auto_move()
|
||||
return True
|
||||
|
||||
# If there is more to go, keep going along the path
|
||||
self.auto_target_path.insert(0, (target_x, target_y))
|
||||
return True
|
||||
|
||||
@@ -15,6 +15,7 @@ from .entities import (
|
||||
EnemyWithLoot,
|
||||
Entity,
|
||||
FinalBoss,
|
||||
InteractableMixin,
|
||||
KeyDoor,
|
||||
LocationMixin,
|
||||
Wall,
|
||||
@@ -23,6 +24,7 @@ from .generate_math_problem import MathProblem
|
||||
from .graphics import DIGIT_TO_GRAPHIC, DIGIT_TO_GRAPHIC_ZERO_EMPTY, MATH_PROBLEM_TYPE_TO_GRAPHIC, Graphic
|
||||
from .items import Item
|
||||
from .locations import DEFAULT_CONTENT, Location
|
||||
from .path_finding import find_path_or_closest
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .player import Player
|
||||
@@ -107,6 +109,21 @@ class Gameboard:
|
||||
|
||||
return tuple(graphics)
|
||||
|
||||
def as_traversability_bools(self) -> tuple[tuple[bool, ...], ...]:
|
||||
traversability = []
|
||||
|
||||
for y, row in enumerate(self.gameboard):
|
||||
traversable_row = []
|
||||
for x, entity in enumerate(row):
|
||||
traversable_row.append(
|
||||
not entity.solid
|
||||
or (isinstance(entity, InteractableMixin) and entity.auto_move_attempt_passing_through)
|
||||
)
|
||||
|
||||
traversability.append(tuple(traversable_row))
|
||||
|
||||
return tuple(traversability)
|
||||
|
||||
def render_math_problem(
|
||||
self, problem: MathProblem, current_input_digits: list[int], current_input_int: int | None
|
||||
) -> tuple[tuple[Graphic, ...], ...]:
|
||||
@@ -186,6 +203,23 @@ class Gameboard:
|
||||
entity = self.remote_entity_by_location_id[location]
|
||||
entity.force_clear()
|
||||
|
||||
def calculate_shortest_path(
|
||||
self, source_x: int, source_y: int, target_x: int, target_y: int
|
||||
) -> list[tuple[int, int]]:
|
||||
gameboard_traversability = self.as_traversability_bools()
|
||||
|
||||
path = find_path_or_closest(gameboard_traversability, source_x, source_y, target_x, target_y)
|
||||
|
||||
if not path:
|
||||
return path
|
||||
|
||||
# If the path stops just short of target, attempt interacting with it at the end
|
||||
if abs(path[-1][0] - target_x) + abs(path[-1][1] - target_y) == 1:
|
||||
if isinstance(self.gameboard[target_y][target_x], InteractableMixin):
|
||||
path.append((target_x, target_y))
|
||||
|
||||
return path[1:] # Cut off starting tile
|
||||
|
||||
@property
|
||||
def ready(self) -> bool:
|
||||
return self.content_filled
|
||||
|
||||
@@ -6,6 +6,7 @@ from typing import NamedTuple
|
||||
|
||||
_random = random.Random()
|
||||
|
||||
|
||||
class NumberChoiceConstraints(NamedTuple):
|
||||
num_1_min: int
|
||||
num_1_max: int
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
import heapq
|
||||
from collections.abc import Generator
|
||||
|
||||
Point = tuple[int, int]
|
||||
|
||||
|
||||
def heuristic(a: Point, b: Point) -> int:
|
||||
# Manhattan distance (good for 4-directional grids)
|
||||
return abs(a[0] - b[0]) + abs(a[1] - b[1])
|
||||
|
||||
|
||||
def reconstruct_path(came_from: dict[Point, Point], current: Point) -> list[Point]:
|
||||
path = [current]
|
||||
while current in came_from:
|
||||
current = came_from[current]
|
||||
path.append(current)
|
||||
path.reverse()
|
||||
return path
|
||||
|
||||
|
||||
def find_path_or_closest(
|
||||
grid: tuple[tuple[bool, ...], ...], source_x: int, source_y: int, target_x: int, target_y: int
|
||||
) -> list[Point]:
|
||||
start = source_x, source_y
|
||||
goal = target_x, target_y
|
||||
|
||||
rows, cols = len(grid), len(grid[0])
|
||||
|
||||
def in_bounds(p: Point) -> bool:
|
||||
return 0 <= p[0] < rows and 0 <= p[1] < cols
|
||||
|
||||
def passable(p: Point) -> bool:
|
||||
return grid[p[1]][p[0]]
|
||||
|
||||
def neighbors(p: Point) -> Generator[Point, None, None]:
|
||||
x, y = p
|
||||
for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
|
||||
np = (x + dx, y + dy)
|
||||
if in_bounds(np) and passable(np):
|
||||
yield np
|
||||
|
||||
open_heap: list[tuple[int, tuple[int, int]]] = []
|
||||
heapq.heappush(open_heap, (0, start))
|
||||
|
||||
came_from: dict[Point, Point] = {}
|
||||
g_score = {start: 0}
|
||||
|
||||
# Track best fallback node
|
||||
best_node = start
|
||||
best_dist = heuristic(start, goal)
|
||||
|
||||
visited = set()
|
||||
|
||||
while open_heap:
|
||||
_, current = heapq.heappop(open_heap)
|
||||
|
||||
if current in visited:
|
||||
continue
|
||||
visited.add(current)
|
||||
|
||||
# Check if we reached the goal
|
||||
if current == goal:
|
||||
return reconstruct_path(came_from, current)
|
||||
|
||||
# Update "closest node" fallback
|
||||
dist = heuristic(current, goal)
|
||||
if dist < best_dist or (dist == best_dist and g_score[current] < g_score.get(best_node, float("inf"))):
|
||||
best_node = current
|
||||
best_dist = dist
|
||||
|
||||
for neighbor in neighbors(current):
|
||||
tentative_g = g_score[current] + 1 # cost is 1 per move
|
||||
|
||||
if tentative_g < g_score.get(neighbor, float("inf")):
|
||||
came_from[neighbor] = current
|
||||
g_score[neighbor] = tentative_g
|
||||
f_score = tentative_g + heuristic(neighbor, goal)
|
||||
heapq.heappush(open_heap, (f_score, neighbor))
|
||||
|
||||
# Goal not reachable → return path to closest node
|
||||
if best_node is not None:
|
||||
return reconstruct_path(came_from, best_node)
|
||||
|
||||
return []
|
||||
@@ -116,7 +116,7 @@ def versum_hill_rave(state: CollectionState, player: int, limit: bool, glitched:
|
||||
else:
|
||||
return (
|
||||
graffitiL(state, player, limit, 85)
|
||||
and graffitiXL(state, player, limit, 48)
|
||||
and graffitiXL(state, player, limit, 49)
|
||||
)
|
||||
else:
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"game": "Bomb Rush Cyberfunk",
|
||||
"world_version": "1.0.6",
|
||||
"authors": ["TRPG"]
|
||||
}
|
||||
+105
-105
@@ -16,213 +16,213 @@ from .Locations import (
|
||||
)
|
||||
|
||||
|
||||
def create_regions(world: MultiWorld, options: CCCharlesOptions, player: int) -> None:
|
||||
menu_region = Region("Menu", player, world, "Aranearum")
|
||||
world.regions.append(menu_region)
|
||||
def create_regions(multiworld: MultiWorld, options: CCCharlesOptions, player: int) -> None:
|
||||
menu_region = Region("Menu", player, multiworld, "Aranearum")
|
||||
multiworld.regions.append(menu_region)
|
||||
|
||||
start_camp_region = Region("Start Camp", player, world)
|
||||
start_camp_region = Region("Start Camp", player, multiworld)
|
||||
start_camp_region.add_locations(loc_start_camp, CCCharlesLocation)
|
||||
world.regions.append(start_camp_region)
|
||||
multiworld.regions.append(start_camp_region)
|
||||
|
||||
tony_tiddle_mission_region = Region("Tony Tiddle Mission", player, world)
|
||||
tony_tiddle_mission_region = Region("Tony Tiddle Mission", player, multiworld)
|
||||
tony_tiddle_mission_region.add_locations(loc_tony_tiddle_mission, CCCharlesLocation)
|
||||
world.regions.append(tony_tiddle_mission_region)
|
||||
multiworld.regions.append(tony_tiddle_mission_region)
|
||||
|
||||
barn_region = Region("Barn", player, world)
|
||||
barn_region = Region("Barn", player, multiworld)
|
||||
barn_region.add_locations(loc_barn, CCCharlesLocation)
|
||||
world.regions.append(barn_region)
|
||||
multiworld.regions.append(barn_region)
|
||||
|
||||
candice_mission_region = Region("Candice Mission", player, world)
|
||||
candice_mission_region = Region("Candice Mission", player, multiworld)
|
||||
candice_mission_region.add_locations(loc_candice_mission, CCCharlesLocation)
|
||||
world.regions.append(candice_mission_region)
|
||||
multiworld.regions.append(candice_mission_region)
|
||||
|
||||
tutorial_house_region = Region("Tutorial House", player, world)
|
||||
tutorial_house_region = Region("Tutorial House", player, multiworld)
|
||||
tutorial_house_region.add_locations(loc_tutorial_house, CCCharlesLocation)
|
||||
world.regions.append(tutorial_house_region)
|
||||
multiworld.regions.append(tutorial_house_region)
|
||||
|
||||
swamp_edges_region = Region("Swamp Edges", player, world)
|
||||
swamp_edges_region = Region("Swamp Edges", player, multiworld)
|
||||
swamp_edges_region.add_locations(loc_swamp_edges, CCCharlesLocation)
|
||||
world.regions.append(swamp_edges_region)
|
||||
multiworld.regions.append(swamp_edges_region)
|
||||
|
||||
swamp_mission_region = Region("Swamp Mission", player, world)
|
||||
swamp_mission_region = Region("Swamp Mission", player, multiworld)
|
||||
swamp_mission_region.add_locations(loc_swamp_mission, CCCharlesLocation)
|
||||
world.regions.append(swamp_mission_region)
|
||||
multiworld.regions.append(swamp_mission_region)
|
||||
|
||||
junkyard_area_region = Region("Junkyard Area", player, world)
|
||||
junkyard_area_region = Region("Junkyard Area", player, multiworld)
|
||||
junkyard_area_region.add_locations(loc_junkyard_area, CCCharlesLocation)
|
||||
world.regions.append(junkyard_area_region)
|
||||
multiworld.regions.append(junkyard_area_region)
|
||||
|
||||
south_house_region = Region("South House", player, world)
|
||||
south_house_region = Region("South House", player, multiworld)
|
||||
south_house_region.add_locations(loc_south_house, CCCharlesLocation)
|
||||
world.regions.append(south_house_region)
|
||||
multiworld.regions.append(south_house_region)
|
||||
|
||||
junkyard_shed_region = Region("Junkyard Shed", player, world)
|
||||
junkyard_shed_region = Region("Junkyard Shed", player, multiworld)
|
||||
junkyard_shed_region.add_locations(loc_junkyard_shed, CCCharlesLocation)
|
||||
world.regions.append(junkyard_shed_region)
|
||||
multiworld.regions.append(junkyard_shed_region)
|
||||
|
||||
military_base_region = Region("Military Base", player, world)
|
||||
military_base_region = Region("Military Base", player, multiworld)
|
||||
military_base_region.add_locations(loc_military_base, CCCharlesLocation)
|
||||
world.regions.append(military_base_region)
|
||||
multiworld.regions.append(military_base_region)
|
||||
|
||||
south_mine_outside_region = Region("South Mine Outside", player, world)
|
||||
south_mine_outside_region = Region("South Mine Outside", player, multiworld)
|
||||
south_mine_outside_region.add_locations(loc_south_mine_outside, CCCharlesLocation)
|
||||
world.regions.append(south_mine_outside_region)
|
||||
multiworld.regions.append(south_mine_outside_region)
|
||||
|
||||
south_mine_inside_region = Region("South Mine Inside", player, world)
|
||||
south_mine_inside_region = Region("South Mine Inside", player, multiworld)
|
||||
south_mine_inside_region.add_locations(loc_south_mine_inside, CCCharlesLocation)
|
||||
world.regions.append(south_mine_inside_region)
|
||||
multiworld.regions.append(south_mine_inside_region)
|
||||
|
||||
middle_station_region = Region("Middle Station", player, world)
|
||||
middle_station_region = Region("Middle Station", player, multiworld)
|
||||
middle_station_region.add_locations(loc_middle_station, CCCharlesLocation)
|
||||
world.regions.append(middle_station_region)
|
||||
multiworld.regions.append(middle_station_region)
|
||||
|
||||
canyon_region = Region("Canyon", player, world)
|
||||
canyon_region = Region("Canyon", player, multiworld)
|
||||
canyon_region.add_locations(loc_canyon, CCCharlesLocation)
|
||||
world.regions.append(canyon_region)
|
||||
multiworld.regions.append(canyon_region)
|
||||
|
||||
watchtower_region = Region("Watchtower", player, world)
|
||||
watchtower_region = Region("Watchtower", player, multiworld)
|
||||
watchtower_region.add_locations(loc_watchtower, CCCharlesLocation)
|
||||
world.regions.append(watchtower_region)
|
||||
multiworld.regions.append(watchtower_region)
|
||||
|
||||
boulder_field_region = Region("Boulder Field", player, world)
|
||||
boulder_field_region = Region("Boulder Field", player, multiworld)
|
||||
boulder_field_region.add_locations(loc_boulder_field, CCCharlesLocation)
|
||||
world.regions.append(boulder_field_region)
|
||||
multiworld.regions.append(boulder_field_region)
|
||||
|
||||
haunted_house_region = Region("Haunted House", player, world)
|
||||
haunted_house_region = Region("Haunted House", player, multiworld)
|
||||
haunted_house_region.add_locations(loc_haunted_house, CCCharlesLocation)
|
||||
world.regions.append(haunted_house_region)
|
||||
multiworld.regions.append(haunted_house_region)
|
||||
|
||||
santiago_house_region = Region("Santiago House", player, world)
|
||||
santiago_house_region = Region("Santiago House", player, multiworld)
|
||||
santiago_house_region.add_locations(loc_santiago_house, CCCharlesLocation)
|
||||
world.regions.append(santiago_house_region)
|
||||
multiworld.regions.append(santiago_house_region)
|
||||
|
||||
port_region = Region("Port", player, world)
|
||||
port_region = Region("Port", player, multiworld)
|
||||
port_region.add_locations(loc_port, CCCharlesLocation)
|
||||
world.regions.append(port_region)
|
||||
multiworld.regions.append(port_region)
|
||||
|
||||
trench_house_region = Region("Trench House", player, world)
|
||||
trench_house_region = Region("Trench House", player, multiworld)
|
||||
trench_house_region.add_locations(loc_trench_house, CCCharlesLocation)
|
||||
world.regions.append(trench_house_region)
|
||||
multiworld.regions.append(trench_house_region)
|
||||
|
||||
doll_woods_region = Region("Doll Woods", player, world)
|
||||
doll_woods_region = Region("Doll Woods", player, multiworld)
|
||||
doll_woods_region.add_locations(loc_doll_woods, CCCharlesLocation)
|
||||
world.regions.append(doll_woods_region)
|
||||
multiworld.regions.append(doll_woods_region)
|
||||
|
||||
lost_stairs_region = Region("Lost Stairs", player, world)
|
||||
lost_stairs_region = Region("Lost Stairs", player, multiworld)
|
||||
lost_stairs_region.add_locations(loc_lost_stairs, CCCharlesLocation)
|
||||
world.regions.append(lost_stairs_region)
|
||||
multiworld.regions.append(lost_stairs_region)
|
||||
|
||||
east_house_region = Region("East House", player, world)
|
||||
east_house_region = Region("East House", player, multiworld)
|
||||
east_house_region.add_locations(loc_east_house, CCCharlesLocation)
|
||||
world.regions.append(east_house_region)
|
||||
multiworld.regions.append(east_house_region)
|
||||
|
||||
rockets_testing_ground_region = Region("Rockets Testing Ground", player, world)
|
||||
rockets_testing_ground_region = Region("Rockets Testing Ground", player, multiworld)
|
||||
rockets_testing_ground_region.add_locations(loc_rockets_testing_ground, CCCharlesLocation)
|
||||
world.regions.append(rockets_testing_ground_region)
|
||||
multiworld.regions.append(rockets_testing_ground_region)
|
||||
|
||||
rockets_testing_bunker_region = Region("Rockets Testing Bunker", player, world)
|
||||
rockets_testing_bunker_region = Region("Rockets Testing Bunker", player, multiworld)
|
||||
rockets_testing_bunker_region.add_locations(loc_rockets_testing_bunker, CCCharlesLocation)
|
||||
world.regions.append(rockets_testing_bunker_region)
|
||||
multiworld.regions.append(rockets_testing_bunker_region)
|
||||
|
||||
workshop_region = Region("Workshop", player, world)
|
||||
workshop_region = Region("Workshop", player, multiworld)
|
||||
workshop_region.add_locations(loc_workshop, CCCharlesLocation)
|
||||
world.regions.append(workshop_region)
|
||||
multiworld.regions.append(workshop_region)
|
||||
|
||||
east_tower_region = Region("East Tower", player, world)
|
||||
east_tower_region = Region("East Tower", player, multiworld)
|
||||
east_tower_region.add_locations(loc_east_tower, CCCharlesLocation)
|
||||
world.regions.append(east_tower_region)
|
||||
multiworld.regions.append(east_tower_region)
|
||||
|
||||
lighthouse_region = Region("Lighthouse", player, world)
|
||||
lighthouse_region = Region("Lighthouse", player, multiworld)
|
||||
lighthouse_region.add_locations(loc_lighthouse, CCCharlesLocation)
|
||||
world.regions.append(lighthouse_region)
|
||||
multiworld.regions.append(lighthouse_region)
|
||||
|
||||
north_mine_outside_region = Region("North Mine Outside", player, world)
|
||||
north_mine_outside_region = Region("North Mine Outside", player, multiworld)
|
||||
north_mine_outside_region.add_locations(loc_north_mine_outside, CCCharlesLocation)
|
||||
world.regions.append(north_mine_outside_region)
|
||||
multiworld.regions.append(north_mine_outside_region)
|
||||
|
||||
north_mine_inside_region = Region("North Mine Inside", player, world)
|
||||
north_mine_inside_region = Region("North Mine Inside", player, multiworld)
|
||||
north_mine_inside_region.add_locations(loc_north_mine_inside, CCCharlesLocation)
|
||||
world.regions.append(north_mine_inside_region)
|
||||
multiworld.regions.append(north_mine_inside_region)
|
||||
|
||||
wood_bridge_region = Region("Wood Bridge", player, world)
|
||||
wood_bridge_region = Region("Wood Bridge", player, multiworld)
|
||||
wood_bridge_region.add_locations(loc_wood_bridge, CCCharlesLocation)
|
||||
world.regions.append(wood_bridge_region)
|
||||
multiworld.regions.append(wood_bridge_region)
|
||||
|
||||
museum_region = Region("Museum", player, world)
|
||||
museum_region = Region("Museum", player, multiworld)
|
||||
museum_region.add_locations(loc_museum, CCCharlesLocation)
|
||||
world.regions.append(museum_region)
|
||||
multiworld.regions.append(museum_region)
|
||||
|
||||
barbed_shelter_region = Region("Barbed Shelter", player, world)
|
||||
barbed_shelter_region = Region("Barbed Shelter", player, multiworld)
|
||||
barbed_shelter_region.add_locations(loc_barbed_shelter, CCCharlesLocation)
|
||||
world.regions.append(barbed_shelter_region)
|
||||
multiworld.regions.append(barbed_shelter_region)
|
||||
|
||||
west_beach_region = Region("West Beach", player, world)
|
||||
west_beach_region = Region("West Beach", player, multiworld)
|
||||
west_beach_region.add_locations(loc_west_beach, CCCharlesLocation)
|
||||
world.regions.append(west_beach_region)
|
||||
multiworld.regions.append(west_beach_region)
|
||||
|
||||
church_region = Region("Church", player, world)
|
||||
church_region = Region("Church", player, multiworld)
|
||||
church_region.add_locations(loc_church, CCCharlesLocation)
|
||||
world.regions.append(church_region)
|
||||
multiworld.regions.append(church_region)
|
||||
|
||||
west_cottage_region = Region("West Cottage", player, world)
|
||||
west_cottage_region = Region("West Cottage", player, multiworld)
|
||||
west_cottage_region.add_locations(loc_west_cottage, CCCharlesLocation)
|
||||
world.regions.append(west_cottage_region)
|
||||
multiworld.regions.append(west_cottage_region)
|
||||
|
||||
caravan_region = Region("Caravan", player, world)
|
||||
caravan_region = Region("Caravan", player, multiworld)
|
||||
caravan_region.add_locations(loc_caravan, CCCharlesLocation)
|
||||
world.regions.append(caravan_region)
|
||||
multiworld.regions.append(caravan_region)
|
||||
|
||||
trailer_cabin_region = Region("Trailer Cabin", player, world)
|
||||
trailer_cabin_region = Region("Trailer Cabin", player, multiworld)
|
||||
trailer_cabin_region.add_locations(loc_trailer_cabin, CCCharlesLocation)
|
||||
world.regions.append(trailer_cabin_region)
|
||||
multiworld.regions.append(trailer_cabin_region)
|
||||
|
||||
towers_region = Region("Towers", player, world)
|
||||
towers_region = Region("Towers", player, multiworld)
|
||||
towers_region.add_locations(loc_towers, CCCharlesLocation)
|
||||
world.regions.append(towers_region)
|
||||
multiworld.regions.append(towers_region)
|
||||
|
||||
north_beach_region = Region("North beach", player, world)
|
||||
north_beach_region = Region("North beach", player, multiworld)
|
||||
north_beach_region.add_locations(loc_north_beach, CCCharlesLocation)
|
||||
world.regions.append(north_beach_region)
|
||||
multiworld.regions.append(north_beach_region)
|
||||
|
||||
mine_shaft_region = Region("Mine Shaft", player, world)
|
||||
mine_shaft_region = Region("Mine Shaft", player, multiworld)
|
||||
mine_shaft_region.add_locations(loc_mine_shaft, CCCharlesLocation)
|
||||
world.regions.append(mine_shaft_region)
|
||||
multiworld.regions.append(mine_shaft_region)
|
||||
|
||||
mob_camp_region = Region("Mob Camp", player, world)
|
||||
mob_camp_region = Region("Mob Camp", player, multiworld)
|
||||
mob_camp_region.add_locations(loc_mob_camp, CCCharlesLocation)
|
||||
world.regions.append(mob_camp_region)
|
||||
multiworld.regions.append(mob_camp_region)
|
||||
|
||||
mob_camp_locked_room_region = Region("Mob Camp Locked Room", player, world)
|
||||
mob_camp_locked_room_region = Region("Mob Camp Locked Room", player, multiworld)
|
||||
mob_camp_locked_room_region.add_locations(loc_mob_camp_locked_room, CCCharlesLocation)
|
||||
world.regions.append(mob_camp_locked_room_region)
|
||||
multiworld.regions.append(mob_camp_locked_room_region)
|
||||
|
||||
mine_elevator_exit_region = Region("Mine Elevator Exit", player, world)
|
||||
mine_elevator_exit_region = Region("Mine Elevator Exit", player, multiworld)
|
||||
mine_elevator_exit_region.add_locations(loc_mine_elevator_exit, CCCharlesLocation)
|
||||
world.regions.append(mine_elevator_exit_region)
|
||||
multiworld.regions.append(mine_elevator_exit_region)
|
||||
|
||||
mountain_ruin_outside_region = Region("Mountain Ruin Outside", player, world)
|
||||
mountain_ruin_outside_region = Region("Mountain Ruin Outside", player, multiworld)
|
||||
mountain_ruin_outside_region.add_locations(loc_mountain_ruin_outside, CCCharlesLocation)
|
||||
world.regions.append(mountain_ruin_outside_region)
|
||||
multiworld.regions.append(mountain_ruin_outside_region)
|
||||
|
||||
mountain_ruin_inside_region = Region("Mountain Ruin Inside", player, world)
|
||||
mountain_ruin_inside_region = Region("Mountain Ruin Inside", player, multiworld)
|
||||
mountain_ruin_inside_region.add_locations(loc_mountain_ruin_inside, CCCharlesLocation)
|
||||
world.regions.append(mountain_ruin_inside_region)
|
||||
multiworld.regions.append(mountain_ruin_inside_region)
|
||||
|
||||
prism_temple_region = Region("Prism Temple", player, world)
|
||||
prism_temple_region = Region("Prism Temple", player, multiworld)
|
||||
prism_temple_region.add_locations(loc_prism_temple, CCCharlesLocation)
|
||||
world.regions.append(prism_temple_region)
|
||||
multiworld.regions.append(prism_temple_region)
|
||||
|
||||
pickle_val_region = Region("Pickle Val", player, world)
|
||||
pickle_val_region = Region("Pickle Val", player, multiworld)
|
||||
pickle_val_region.add_locations(loc_pickle_val, CCCharlesLocation)
|
||||
world.regions.append(pickle_val_region)
|
||||
multiworld.regions.append(pickle_val_region)
|
||||
|
||||
shrine_near_temple_region = Region("Shrine Near Temple", player, world)
|
||||
shrine_near_temple_region = Region("Shrine Near Temple", player, multiworld)
|
||||
shrine_near_temple_region.add_locations(loc_shrine_near_temple, CCCharlesLocation)
|
||||
world.regions.append(shrine_near_temple_region)
|
||||
multiworld.regions.append(shrine_near_temple_region)
|
||||
|
||||
morse_bunker_region = Region("Morse Bunker", player, world)
|
||||
morse_bunker_region = Region("Morse Bunker", player, multiworld)
|
||||
morse_bunker_region.add_locations(loc_morse_bunker, CCCharlesLocation)
|
||||
world.regions.append(morse_bunker_region)
|
||||
multiworld.regions.append(morse_bunker_region)
|
||||
|
||||
# Place "Victory" event at "Final Boss" location
|
||||
loc_final_boss = CCCharlesLocation(player, "Final Boss", None, prism_temple_region)
|
||||
|
||||
+74
-74
@@ -4,212 +4,212 @@ from .Options import CCCharlesOptions
|
||||
|
||||
# Go mode: Green Egg + Blue Egg + Red Egg + Temple Key + Bug Spray (+ Remote Explosive x8 but the base game ignores it)
|
||||
|
||||
def set_rules(world: MultiWorld, options: CCCharlesOptions, player: int) -> None:
|
||||
def set_rules(multiworld: MultiWorld, options: CCCharlesOptions, player: int) -> None:
|
||||
# Tony Tiddle
|
||||
set_rule(world.get_entrance("Barn Door", player),
|
||||
set_rule(multiworld.get_entrance("Barn Door", player),
|
||||
lambda state: state.has("Barn Key", player))
|
||||
|
||||
# Candice
|
||||
set_rule(world.get_entrance("Tutorial House Door", player),
|
||||
set_rule(multiworld.get_entrance("Tutorial House Door", player),
|
||||
lambda state: state.has("Candice's Key", player))
|
||||
|
||||
# Lizbeth Murkwater
|
||||
set_rule(world.get_location("Swamp Lizbeth Murkwater Mission End", player),
|
||||
set_rule(multiworld.get_location("Swamp Lizbeth Murkwater Mission End", player),
|
||||
lambda state: state.has("Dead Fish", player))
|
||||
|
||||
# Daryl
|
||||
set_rule(world.get_location("Junkyard Area Chest Ancient Tablet", player),
|
||||
set_rule(multiworld.get_location("Junkyard Area Chest Ancient Tablet", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Junkyard Area Daryl Mission End", player),
|
||||
set_rule(multiworld.get_location("Junkyard Area Daryl Mission End", player),
|
||||
lambda state: state.has("Ancient Tablet", player))
|
||||
|
||||
# South House
|
||||
set_rule(world.get_location("South House Chest Scraps 1", player),
|
||||
set_rule(multiworld.get_location("South House Chest Scraps 1", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("South House Chest Scraps 2", player),
|
||||
set_rule(multiworld.get_location("South House Chest Scraps 2", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("South House Chest Scraps 3", player),
|
||||
set_rule(multiworld.get_location("South House Chest Scraps 3", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("South House Chest Scraps 4", player),
|
||||
set_rule(multiworld.get_location("South House Chest Scraps 4", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("South House Chest Scraps 5", player),
|
||||
set_rule(multiworld.get_location("South House Chest Scraps 5", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("South House Chest Scraps 6", player),
|
||||
set_rule(multiworld.get_location("South House Chest Scraps 6", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
|
||||
# South Mine
|
||||
set_rule(world.get_entrance("South Mine Gate", player),
|
||||
set_rule(multiworld.get_entrance("South Mine Gate", player),
|
||||
lambda state: state.has("South Mine Key", player))
|
||||
|
||||
set_rule(world.get_location("South Mine Inside Green Paint Can", player),
|
||||
set_rule(multiworld.get_location("South Mine Inside Green Paint Can", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
|
||||
# Theodore
|
||||
set_rule(world.get_location("Middle Station Theodore Mission End", player),
|
||||
set_rule(multiworld.get_location("Middle Station Theodore Mission End", player),
|
||||
lambda state: state.has("Blue Box", player))
|
||||
|
||||
# Watchtower
|
||||
set_rule(world.get_location("Watchtower Pink Paint Can", player),
|
||||
set_rule(multiworld.get_location("Watchtower Pink Paint Can", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
|
||||
# Sasha
|
||||
set_rule(world.get_location("Haunted House Sasha Mission End", player),
|
||||
set_rule(multiworld.get_location("Haunted House Sasha Mission End", player),
|
||||
lambda state: state.has("Page Drawing", player, 8))
|
||||
|
||||
# Santiago
|
||||
set_rule(world.get_location("Port Santiago Mission End", player),
|
||||
set_rule(multiworld.get_location("Port Santiago Mission End", player),
|
||||
lambda state: state.has("Journal", player))
|
||||
|
||||
# Trench House
|
||||
set_rule(world.get_location("Trench House Chest Scraps 1", player),
|
||||
set_rule(multiworld.get_location("Trench House Chest Scraps 1", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Trench House Chest Scraps 2", player),
|
||||
set_rule(multiworld.get_location("Trench House Chest Scraps 2", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Trench House Chest Scraps 3", player),
|
||||
set_rule(multiworld.get_location("Trench House Chest Scraps 3", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Trench House Chest Scraps 4", player),
|
||||
set_rule(multiworld.get_location("Trench House Chest Scraps 4", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Trench House Chest Scraps 5", player),
|
||||
set_rule(multiworld.get_location("Trench House Chest Scraps 5", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Trench House Chest Scraps 6", player),
|
||||
set_rule(multiworld.get_location("Trench House Chest Scraps 6", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
|
||||
# East House
|
||||
set_rule(world.get_location("East House Chest Scraps 1", player),
|
||||
set_rule(multiworld.get_location("East House Chest Scraps 1", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("East House Chest Scraps 2", player),
|
||||
set_rule(multiworld.get_location("East House Chest Scraps 2", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("East House Chest Scraps 3", player),
|
||||
set_rule(multiworld.get_location("East House Chest Scraps 3", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("East House Chest Scraps 4", player),
|
||||
set_rule(multiworld.get_location("East House Chest Scraps 4", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("East House Chest Scraps 5", player),
|
||||
set_rule(multiworld.get_location("East House Chest Scraps 5", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
|
||||
# Rocket Testing Bunker
|
||||
set_rule(world.get_entrance("Stuck Bunker Door", player),
|
||||
set_rule(multiworld.get_entrance("Stuck Bunker Door", player),
|
||||
lambda state: state.has("Timed Dynamite", player))
|
||||
|
||||
# John Smith
|
||||
set_rule(world.get_location("Workshop John Smith Mission End", player),
|
||||
set_rule(multiworld.get_location("Workshop John Smith Mission End", player),
|
||||
lambda state: state.has("Box of Rockets", player))
|
||||
|
||||
# Claire
|
||||
set_rule(world.get_location("Lighthouse Claire Mission End", player),
|
||||
set_rule(multiworld.get_location("Lighthouse Claire Mission End", player),
|
||||
lambda state: state.has("Breaker", player, 4))
|
||||
|
||||
# North Mine
|
||||
set_rule(world.get_entrance("North Mine Gate", player),
|
||||
set_rule(multiworld.get_entrance("North Mine Gate", player),
|
||||
lambda state: state.has("North Mine Key", player))
|
||||
|
||||
set_rule(world.get_location("North Mine Inside Blue Paint Can", player),
|
||||
set_rule(multiworld.get_location("North Mine Inside Blue Paint Can", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
|
||||
# Paul
|
||||
set_rule(world.get_location("Museum Paul Mission End", player),
|
||||
set_rule(multiworld.get_location("Museum Paul Mission End", player),
|
||||
lambda state: state.has("Remote Explosive x8", player))
|
||||
# lambda state: state.has("Remote Explosive", player, 8)) # TODO: Add an option to split remote explosives
|
||||
|
||||
# West Beach
|
||||
set_rule(world.get_location("West Beach Chest Scraps 1", player),
|
||||
set_rule(multiworld.get_location("West Beach Chest Scraps 1", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("West Beach Chest Scraps 2", player),
|
||||
set_rule(multiworld.get_location("West Beach Chest Scraps 2", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("West Beach Chest Scraps 3", player),
|
||||
set_rule(multiworld.get_location("West Beach Chest Scraps 3", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("West Beach Chest Scraps 4", player),
|
||||
set_rule(multiworld.get_location("West Beach Chest Scraps 4", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("West Beach Chest Scraps 5", player),
|
||||
set_rule(multiworld.get_location("West Beach Chest Scraps 5", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("West Beach Chest Scraps 6", player),
|
||||
set_rule(multiworld.get_location("West Beach Chest Scraps 6", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
|
||||
# Caravan
|
||||
set_rule(world.get_location("Caravan Chest Scraps 1", player),
|
||||
set_rule(multiworld.get_location("Caravan Chest Scraps 1", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Caravan Chest Scraps 2", player),
|
||||
set_rule(multiworld.get_location("Caravan Chest Scraps 2", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Caravan Chest Scraps 3", player),
|
||||
set_rule(multiworld.get_location("Caravan Chest Scraps 3", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Caravan Chest Scraps 4", player),
|
||||
set_rule(multiworld.get_location("Caravan Chest Scraps 4", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Caravan Chest Scraps 5", player),
|
||||
set_rule(multiworld.get_location("Caravan Chest Scraps 5", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
|
||||
# Ronny
|
||||
set_rule(world.get_location("Towers Ronny Mission End", player),
|
||||
set_rule(multiworld.get_location("Towers Ronny Mission End", player),
|
||||
lambda state: state.has("Employment Contracts", player))
|
||||
|
||||
# North Beach
|
||||
set_rule(world.get_location("North Beach Chest Scraps 1", player),
|
||||
set_rule(multiworld.get_location("North Beach Chest Scraps 1", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("North Beach Chest Scraps 2", player),
|
||||
set_rule(multiworld.get_location("North Beach Chest Scraps 2", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("North Beach Chest Scraps 3", player),
|
||||
set_rule(multiworld.get_location("North Beach Chest Scraps 3", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("North Beach Chest Scraps 4", player),
|
||||
set_rule(multiworld.get_location("North Beach Chest Scraps 4", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
|
||||
# Mine Shaft
|
||||
set_rule(world.get_location("Mine Shaft Chest Scraps 1", player),
|
||||
set_rule(multiworld.get_location("Mine Shaft Chest Scraps 1", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Mine Shaft Chest Scraps 2", player),
|
||||
set_rule(multiworld.get_location("Mine Shaft Chest Scraps 2", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Mine Shaft Chest Scraps 3", player),
|
||||
set_rule(multiworld.get_location("Mine Shaft Chest Scraps 3", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Mine Shaft Chest Scraps 4", player),
|
||||
set_rule(multiworld.get_location("Mine Shaft Chest Scraps 4", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Mine Shaft Chest Scraps 5", player),
|
||||
set_rule(multiworld.get_location("Mine Shaft Chest Scraps 5", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Mine Shaft Chest Scraps 6", player),
|
||||
set_rule(multiworld.get_location("Mine Shaft Chest Scraps 6", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Mine Shaft Chest Scraps 7", player),
|
||||
set_rule(multiworld.get_location("Mine Shaft Chest Scraps 7", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
|
||||
# Mob Camp
|
||||
set_rule(world.get_entrance("Mob Camp Locked Door", player),
|
||||
set_rule(multiworld.get_entrance("Mob Camp Locked Door", player),
|
||||
lambda state: state.has("Mob Camp Key", player))
|
||||
|
||||
set_rule(world.get_location("Mob Camp Locked Room Stolen Bob", player),
|
||||
set_rule(multiworld.get_location("Mob Camp Locked Room Stolen Bob", player),
|
||||
lambda state: state.has("Broken Bob", player))
|
||||
|
||||
# Mountain Ruin
|
||||
set_rule(world.get_entrance("Mountain Ruin Gate", player),
|
||||
set_rule(multiworld.get_entrance("Mountain Ruin Gate", player),
|
||||
lambda state: state.has("Mountain Ruin Key", player))
|
||||
|
||||
set_rule(world.get_location("Mountain Ruin Inside Red Paint Can", player),
|
||||
set_rule(multiworld.get_location("Mountain Ruin Inside Red Paint Can", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
|
||||
# Prism Temple
|
||||
set_rule(world.get_location("Prism Temple Chest Scraps 1", player),
|
||||
set_rule(multiworld.get_location("Prism Temple Chest Scraps 1", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Prism Temple Chest Scraps 2", player),
|
||||
set_rule(multiworld.get_location("Prism Temple Chest Scraps 2", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Prism Temple Chest Scraps 3", player),
|
||||
set_rule(multiworld.get_location("Prism Temple Chest Scraps 3", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
|
||||
# Pickle Lady
|
||||
set_rule(world.get_location("Pickle Val Jar of Pickles", player),
|
||||
set_rule(multiworld.get_location("Pickle Val Jar of Pickles", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Pickle Val Pickle Lady Mission End", player),
|
||||
set_rule(multiworld.get_location("Pickle Val Pickle Lady Mission End", player),
|
||||
lambda state: state.has("Jar of Pickles", player))
|
||||
|
||||
# Morse Bunker
|
||||
set_rule(world.get_location("Morse Bunker Chest Scraps 1", player),
|
||||
set_rule(multiworld.get_location("Morse Bunker Chest Scraps 1", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Morse Bunker Chest Scraps 2", player),
|
||||
set_rule(multiworld.get_location("Morse Bunker Chest Scraps 2", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Morse Bunker Chest Scraps 3", player),
|
||||
set_rule(multiworld.get_location("Morse Bunker Chest Scraps 3", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Morse Bunker Chest Scraps 4", player),
|
||||
set_rule(multiworld.get_location("Morse Bunker Chest Scraps 4", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
set_rule(world.get_location("Morse Bunker Chest Scraps 5", player),
|
||||
set_rule(multiworld.get_location("Morse Bunker Chest Scraps 5", player),
|
||||
lambda state: state.has("Lockpicks", player))
|
||||
|
||||
# Add rules to reach the "Go mode"
|
||||
set_rule(world.get_location("Final Boss", player),
|
||||
set_rule(multiworld.get_location("Final Boss", player),
|
||||
lambda state: state.has("Temple Key", player)
|
||||
and state.has("Green Egg", player)
|
||||
and state.has("Blue Egg", player)
|
||||
and state.has("Red Egg", player))
|
||||
world.completion_condition[player] = lambda state: state.has("Victory", player)
|
||||
multiworld.completion_condition[player] = lambda state: state.has("Victory", player)
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
# Donkey Kong Country 3 - Changelog
|
||||
|
||||
|
||||
## v1.1
|
||||
|
||||
### Features:
|
||||
|
||||
- KONGsanity option (Collect all KONG letters in each level for a check)
|
||||
- Autosave option
|
||||
- Difficulty option
|
||||
- MERRY option
|
||||
- Handle collected/co-op locations
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
- Fixed Mekanos softlock
|
||||
- Prevent Brothers Bear giving extra Banana Birds
|
||||
- Fixed Banana Bird Mother check sending prematurely
|
||||
- Fix Logic bug with Krematoa level costs
|
||||
|
||||
|
||||
## v1.0
|
||||
|
||||
### Features:
|
||||
|
||||
- Goal
|
||||
- Knautilus
|
||||
- Scuttle the Knautilus in Krematoa and defeat Baron K. Roolenstein to win
|
||||
- Banana Bird Hunt
|
||||
- Find the Banana Birds and rescue their mother to win
|
||||
- Locations included:
|
||||
- Level Flags
|
||||
- Bonuses
|
||||
- DK Coins
|
||||
- Banana Bird Caves
|
||||
- Items included:
|
||||
- Progressive Boat Upgrade
|
||||
- Three are placed into the item pool (Patch -> First Ski -> Second Ski)
|
||||
- Bonus Coins
|
||||
- DK Coins
|
||||
- Krematoa Cogs
|
||||
- Bear Coins
|
||||
- 1-Up Balloons
|
||||
- Level Shuffle is supported
|
||||
- Music Shuffle is supported
|
||||
- Kong Palette options are supported
|
||||
- Starting life count can be set
|
||||
@@ -1,229 +0,0 @@
|
||||
import logging
|
||||
|
||||
from NetUtils import ClientStatus, color
|
||||
from worlds.AutoSNIClient import SNIClient
|
||||
|
||||
snes_logger = logging.getLogger("SNES")
|
||||
|
||||
# FXPAK Pro protocol memory mapping used by SNI
|
||||
ROM_START = 0x000000
|
||||
WRAM_START = 0xF50000
|
||||
WRAM_SIZE = 0x20000
|
||||
SRAM_START = 0xE00000
|
||||
|
||||
DKC3_ROMNAME_START = 0x00FFC0
|
||||
DKC3_ROMHASH_START = 0x7FC0
|
||||
ROMNAME_SIZE = 0x15
|
||||
ROMHASH_SIZE = 0x15
|
||||
|
||||
DKC3_RECV_PROGRESS_ADDR = WRAM_START + 0x632
|
||||
DKC3_FILE_NAME_ADDR = WRAM_START + 0x5D9
|
||||
DEATH_LINK_ACTIVE_ADDR = DKC3_ROMNAME_START + 0x15 # DKC3_TODO: Find a permanent home for this
|
||||
|
||||
|
||||
class DKC3SNIClient(SNIClient):
|
||||
game = "Donkey Kong Country 3"
|
||||
patch_suffix = ".apdkc3"
|
||||
|
||||
async def deathlink_kill_player(self, ctx):
|
||||
pass
|
||||
# DKC3_TODO: Handle Receiving Deathlink
|
||||
|
||||
|
||||
async def validate_rom(self, ctx):
|
||||
from SNIClient import snes_read
|
||||
|
||||
rom_name = await snes_read(ctx, DKC3_ROMHASH_START, ROMHASH_SIZE)
|
||||
if rom_name is None or rom_name == bytes([0] * ROMHASH_SIZE) or rom_name[:2] != b"D3":
|
||||
return False
|
||||
|
||||
ctx.game = self.game
|
||||
ctx.items_handling = 0b111 # remote items
|
||||
|
||||
ctx.rom = rom_name
|
||||
|
||||
#death_link = await snes_read(ctx, DEATH_LINK_ACTIVE_ADDR, 1)
|
||||
## DKC3_TODO: Handle Deathlink
|
||||
#if death_link:
|
||||
# ctx.allow_collect = bool(death_link[0] & 0b100)
|
||||
# await ctx.update_death_link(bool(death_link[0] & 0b1))
|
||||
return True
|
||||
|
||||
|
||||
async def game_watcher(self, ctx):
|
||||
from SNIClient import snes_buffered_write, snes_flush_writes, snes_read
|
||||
# DKC3_TODO: Handle Deathlink
|
||||
save_file_name = await snes_read(ctx, DKC3_FILE_NAME_ADDR, 0x5)
|
||||
if save_file_name is None or save_file_name[0] == 0x00 or save_file_name == bytes([0x55] * 0x05):
|
||||
# We haven't loaded a save file
|
||||
return
|
||||
|
||||
new_checks = []
|
||||
from .Rom import location_rom_data, item_rom_data, boss_location_ids, level_unlock_map
|
||||
location_ram_data = await snes_read(ctx, WRAM_START + 0x5FE, 0x81)
|
||||
for loc_id, loc_data in location_rom_data.items():
|
||||
if loc_id not in ctx.locations_checked:
|
||||
data = location_ram_data[loc_data[0] - 0x5FE]
|
||||
masked_data = data & (1 << loc_data[1])
|
||||
bit_set = (masked_data != 0)
|
||||
invert_bit = ((len(loc_data) >= 3) and loc_data[2])
|
||||
if bit_set != invert_bit:
|
||||
# DKC3_TODO: Handle non-included checks
|
||||
new_checks.append(loc_id)
|
||||
|
||||
verify_save_file_name = await snes_read(ctx, DKC3_FILE_NAME_ADDR, 0x5)
|
||||
if verify_save_file_name is None or verify_save_file_name[0] == 0x00 or verify_save_file_name == bytes([0x55] * 0x05) or verify_save_file_name != save_file_name:
|
||||
# We have somehow exited the save file (or worse)
|
||||
ctx.rom = None
|
||||
return
|
||||
|
||||
rom = await snes_read(ctx, DKC3_ROMHASH_START, ROMHASH_SIZE)
|
||||
if rom != ctx.rom:
|
||||
ctx.rom = None
|
||||
# We have somehow loaded a different ROM
|
||||
return
|
||||
|
||||
for new_check_id in new_checks:
|
||||
ctx.locations_checked.add(new_check_id)
|
||||
location = ctx.location_names.lookup_in_game(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]}])
|
||||
|
||||
# DKC3_TODO: Make this actually visually display new things received (ASM Hook required)
|
||||
recv_count = await snes_read(ctx, DKC3_RECV_PROGRESS_ADDR, 1)
|
||||
recv_index = recv_count[0]
|
||||
|
||||
if recv_index < len(ctx.items_received):
|
||||
item = ctx.items_received[recv_index]
|
||||
recv_index += 1
|
||||
logging.info('Received %s from %s (%s) (%d/%d in list)' % (
|
||||
color(ctx.item_names.lookup_in_game(item.item), 'red', 'bold'),
|
||||
color(ctx.player_names[item.player], 'yellow'),
|
||||
ctx.location_names.lookup_in_slot(item.location, item.player), recv_index, len(ctx.items_received)))
|
||||
|
||||
snes_buffered_write(ctx, DKC3_RECV_PROGRESS_ADDR, bytes([recv_index]))
|
||||
if item.item in item_rom_data:
|
||||
item_count = await snes_read(ctx, WRAM_START + item_rom_data[item.item][0], 0x1)
|
||||
new_item_count = item_count[0] + 1
|
||||
for address in item_rom_data[item.item]:
|
||||
snes_buffered_write(ctx, WRAM_START + address, bytes([new_item_count]))
|
||||
|
||||
# Handle Coin Displays
|
||||
current_level = await snes_read(ctx, WRAM_START + 0x5E3, 0x5)
|
||||
overworld_locked = ((await snes_read(ctx, WRAM_START + 0x5FC, 0x1))[0] == 0x01)
|
||||
if item.item == 0xDC3002 and not overworld_locked and (current_level[0] == 0x0A and current_level[2] == 0x00 and current_level[4] == 0x03):
|
||||
# Bazaar and Barter
|
||||
item_count = await snes_read(ctx, WRAM_START + 0xB02, 0x1)
|
||||
new_item_count = item_count[0] + 1
|
||||
snes_buffered_write(ctx, WRAM_START + 0xB02, bytes([new_item_count]))
|
||||
elif item.item == 0xDC3002 and not overworld_locked and current_level[0] == 0x04:
|
||||
# Swanky
|
||||
item_count = await snes_read(ctx, WRAM_START + 0xA26, 0x1)
|
||||
new_item_count = item_count[0] + 1
|
||||
snes_buffered_write(ctx, WRAM_START + 0xA26, bytes([new_item_count]))
|
||||
elif item.item == 0xDC3003 and not overworld_locked and (current_level[0] == 0x0A and current_level[2] == 0x08 and current_level[4] == 0x01):
|
||||
# Boomer
|
||||
item_count = await snes_read(ctx, WRAM_START + 0xB02, 0x1)
|
||||
new_item_count = item_count[0] + 1
|
||||
snes_buffered_write(ctx, WRAM_START + 0xB02, bytes([new_item_count]))
|
||||
else:
|
||||
# Handle Patch and Skis
|
||||
if item.item == 0xDC3007:
|
||||
num_upgrades = 1
|
||||
inventory = await snes_read(ctx, WRAM_START + 0x605, 0xF)
|
||||
|
||||
if (inventory[0] & 0x02):
|
||||
num_upgrades = 3
|
||||
elif (inventory[13] & 0x08) or (inventory[0] & 0x01):
|
||||
num_upgrades = 2
|
||||
|
||||
if num_upgrades == 1:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x605, bytes([inventory[0] | 0x01]))
|
||||
if inventory[4] == 0:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x609, bytes([0x01]))
|
||||
elif inventory[6] == 0:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x60B, bytes([0x01]))
|
||||
elif inventory[8] == 0:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x60D, bytes([0x01]))
|
||||
elif inventory[10] == 0:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x60F, bytes([0x01]))
|
||||
|
||||
cove_mekanos_progress = await snes_read(ctx, WRAM_START + 0x691, 0x2)
|
||||
snes_buffered_write(ctx, WRAM_START + 0x691, bytes([cove_mekanos_progress[0] | 0x01]))
|
||||
snes_buffered_write(ctx, WRAM_START + 0x692, bytes([cove_mekanos_progress[1] | 0x01]))
|
||||
elif num_upgrades == 2:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x605, bytes([inventory[0] | 0x02]))
|
||||
if inventory[4] == 0:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x609, bytes([0x02]))
|
||||
elif inventory[6] == 0:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x60B, bytes([0x02]))
|
||||
elif inventory[8] == 0:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x60D, bytes([0x02]))
|
||||
elif inventory[10] == 0:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x60F, bytes([0x02]))
|
||||
elif num_upgrades == 3:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x606, bytes([inventory[1] | 0x20]))
|
||||
|
||||
k3_ridge_progress = await snes_read(ctx, WRAM_START + 0x693, 0x2)
|
||||
snes_buffered_write(ctx, WRAM_START + 0x693, bytes([k3_ridge_progress[0] | 0x01]))
|
||||
snes_buffered_write(ctx, WRAM_START + 0x694, bytes([k3_ridge_progress[1] | 0x01]))
|
||||
elif item.item == 0xDC3000:
|
||||
# Handle Victory
|
||||
if not ctx.finished_game:
|
||||
await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}])
|
||||
ctx.finished_game = True
|
||||
else:
|
||||
print("Item Not Recognized: ", item.item)
|
||||
pass
|
||||
|
||||
await snes_flush_writes(ctx)
|
||||
|
||||
# Handle Collected Locations
|
||||
levels_to_tiles = await snes_read(ctx, ROM_START + 0x3FF800, 0x60)
|
||||
tiles_to_levels = await snes_read(ctx, ROM_START + 0x3FF860, 0x60)
|
||||
for loc_id in ctx.checked_locations:
|
||||
if loc_id not in ctx.locations_checked and loc_id not in boss_location_ids:
|
||||
loc_data = location_rom_data[loc_id]
|
||||
data = await snes_read(ctx, WRAM_START + loc_data[0], 1)
|
||||
invert_bit = ((len(loc_data) >= 3) and loc_data[2])
|
||||
if not invert_bit:
|
||||
masked_data = data[0] | (1 << loc_data[1])
|
||||
snes_buffered_write(ctx, WRAM_START + loc_data[0], bytes([masked_data]))
|
||||
|
||||
if (loc_data[1] == 1):
|
||||
# Make the next levels accessible
|
||||
level_id = loc_data[0] - 0x632
|
||||
tile_id = levels_to_tiles[level_id] if levels_to_tiles[level_id] != 0xFF else level_id
|
||||
tile_id = tile_id + 0x632
|
||||
if tile_id in level_unlock_map:
|
||||
for next_level_address in level_unlock_map[tile_id]:
|
||||
next_level_id = next_level_address - 0x632
|
||||
next_tile_id = tiles_to_levels[next_level_id] if tiles_to_levels[next_level_id] != 0xFF else next_level_id
|
||||
next_tile_id = next_tile_id + 0x632
|
||||
next_data = await snes_read(ctx, WRAM_START + next_tile_id, 1)
|
||||
snes_buffered_write(ctx, WRAM_START + next_tile_id, bytes([next_data[0] | 0x01]))
|
||||
|
||||
await snes_flush_writes(ctx)
|
||||
else:
|
||||
masked_data = data[0] & ~(1 << loc_data[1])
|
||||
snes_buffered_write(ctx, WRAM_START + loc_data[0], bytes([masked_data]))
|
||||
await snes_flush_writes(ctx)
|
||||
ctx.locations_checked.add(loc_id)
|
||||
|
||||
# Calculate Boomer Cost Text
|
||||
boomer_cost_text = await snes_read(ctx, WRAM_START + 0xAAFD, 2)
|
||||
if boomer_cost_text[0] == 0x31 and boomer_cost_text[1] == 0x35:
|
||||
boomer_cost = await snes_read(ctx, ROM_START + 0x349857, 1)
|
||||
boomer_cost_tens = int(boomer_cost[0]) // 10
|
||||
boomer_cost_ones = int(boomer_cost[0]) % 10
|
||||
snes_buffered_write(ctx, WRAM_START + 0xAAFD, bytes([0x30 + boomer_cost_tens, 0x30 + boomer_cost_ones]))
|
||||
await snes_flush_writes(ctx)
|
||||
|
||||
boomer_final_cost_text = await snes_read(ctx, WRAM_START + 0xAB9B, 2)
|
||||
if boomer_final_cost_text[0] == 0x32 and boomer_final_cost_text[1] == 0x35:
|
||||
boomer_cost = await snes_read(ctx, ROM_START + 0x349857, 1)
|
||||
boomer_cost_tens = boomer_cost[0] // 10
|
||||
boomer_cost_ones = boomer_cost[0] % 10
|
||||
snes_buffered_write(ctx, WRAM_START + 0xAB9B, bytes([0x30 + boomer_cost_tens, 0x30 + boomer_cost_ones]))
|
||||
await snes_flush_writes(ctx)
|
||||
@@ -1,52 +0,0 @@
|
||||
import typing
|
||||
|
||||
from BaseClasses import Item
|
||||
from .Names import ItemName
|
||||
|
||||
|
||||
class ItemData(typing.NamedTuple):
|
||||
code: typing.Optional[int]
|
||||
progression: bool
|
||||
quantity: int = 1
|
||||
event: bool = False
|
||||
|
||||
|
||||
class DKC3Item(Item):
|
||||
game: str = "Donkey Kong Country 3"
|
||||
|
||||
|
||||
# Separate tables for each type of item.
|
||||
junk_table = {
|
||||
ItemName.one_up_balloon: ItemData(0xDC3001, False),
|
||||
ItemName.bear_coin: ItemData(0xDC3002, False),
|
||||
}
|
||||
|
||||
collectable_table = {
|
||||
ItemName.bonus_coin: ItemData(0xDC3003, True),
|
||||
ItemName.dk_coin: ItemData(0xDC3004, True),
|
||||
ItemName.banana_bird: ItemData(0xDC3005, True),
|
||||
ItemName.krematoa_cog: ItemData(0xDC3006, True),
|
||||
ItemName.progressive_boat: ItemData(0xDC3007, True),
|
||||
}
|
||||
|
||||
inventory_table = {
|
||||
ItemName.present: ItemData(0xDC3008, True),
|
||||
ItemName.bowling_ball: ItemData(0xDC3009, True),
|
||||
ItemName.shell: ItemData(0xDC300A, True),
|
||||
ItemName.mirror: ItemData(0xDC300B, True),
|
||||
ItemName.flower: ItemData(0xDC300C, True),
|
||||
ItemName.wrench: ItemData(0xDC300D, True),
|
||||
}
|
||||
|
||||
event_table = {
|
||||
ItemName.victory: ItemData(0xDC3000, True),
|
||||
}
|
||||
|
||||
# Complete item table.
|
||||
item_table = {
|
||||
**junk_table,
|
||||
**collectable_table,
|
||||
**event_table,
|
||||
}
|
||||
|
||||
lookup_id_to_name: typing.Dict[int, str] = {data.code: item_name for item_name, data in item_table.items() if data.code}
|
||||
@@ -1,27 +0,0 @@
|
||||
Modified MIT License
|
||||
|
||||
Copyright (c) 2025 PoryGone
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, and/or distribute copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
No copy or substantial portion of the Software shall be sublicensed or relicensed
|
||||
without the express written permission of the copyright holder(s)
|
||||
|
||||
No copy or substantial portion of the Software shall be sold without the express
|
||||
written permission of the copyright holder(s)
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,115 +0,0 @@
|
||||
|
||||
from .Names import LocationName
|
||||
|
||||
class DKC3Level():
|
||||
nameIDAddress: int
|
||||
levelIDAddress: int
|
||||
nameID: int
|
||||
levelID: int
|
||||
|
||||
def __init__(self, nameIDAddress: int, levelIDAddress: int, nameID: int, levelID: int):
|
||||
self.nameIDAddress = nameIDAddress
|
||||
self.levelIDAddress = levelIDAddress
|
||||
self.nameID = nameID
|
||||
self.levelID = levelID
|
||||
|
||||
|
||||
level_dict = {
|
||||
LocationName.lakeside_limbo_region: DKC3Level(0x34D19C, 0x34D19D, 0x01, 0x25),
|
||||
LocationName.doorstop_dash_region: DKC3Level(0x34D1A7, 0x34D1A8, 0x02, 0x28),
|
||||
LocationName.tidal_trouble_region: DKC3Level(0x34D1BD, 0x34D1BE, 0x04, 0x27),
|
||||
LocationName.skiddas_row_region: DKC3Level(0x34D1C8, 0x34D1C9, 0x05, 0x2B),
|
||||
LocationName.murky_mill_region: DKC3Level(0x34D1D3, 0x34D1D4, 0x0D, 0x2A),
|
||||
|
||||
LocationName.barrel_shield_bust_up_region: DKC3Level(0x34D217, 0x34D218, 0x0B, 0x30),
|
||||
LocationName.riverside_race_region: DKC3Level(0x34D22D, 0x34D22E, 0x0C, 0x32),
|
||||
LocationName.squeals_on_wheels_region: DKC3Level(0x34D238, 0x34D239, 0x06, 0x29),
|
||||
LocationName.springin_spiders_region: DKC3Level(0x34D24E, 0x34D24F, 0x0E, 0x2F),
|
||||
LocationName.bobbing_barrel_brawl_region: DKC3Level(0x34D264, 0x34D265, 0x37, 0x34),
|
||||
|
||||
LocationName.bazzas_blockade_region: DKC3Level(0x34D29D, 0x34D29E, 0x14, 0x35),
|
||||
LocationName.rocket_barrel_ride_region: DKC3Level(0x34D2A8, 0x34D2A9, 0x15, 0x38),
|
||||
LocationName.kreeping_klasps_region: DKC3Level(0x34D2BE, 0x34D2BF, 0x16, 0x26),
|
||||
LocationName.tracker_barrel_trek_region: DKC3Level(0x34D2D4, 0x34D2D5, 0x17, 0x39),
|
||||
LocationName.fish_food_frenzy_region: DKC3Level(0x34D2DF, 0x34D2E0, 0x18, 0x36),
|
||||
|
||||
LocationName.fire_ball_frenzy_region: DKC3Level(0x34D30D, 0x34D30E, 0x1B, 0x3B),
|
||||
LocationName.demolition_drain_pipe_region: DKC3Level(0x34D323, 0x34D324, 0x1D, 0x40),
|
||||
LocationName.ripsaw_rage_region: DKC3Level(0x34D339, 0x34D33A, 0x1E, 0x2E),
|
||||
LocationName.blazing_bazookas_region: DKC3Level(0x34D34F, 0x34D350, 0x1F, 0x3C),
|
||||
LocationName.low_g_labyrinth_region: DKC3Level(0x34D35A, 0x34D35B, 0x20, 0x3E),
|
||||
|
||||
LocationName.krevice_kreepers_region: DKC3Level(0x34D388, 0x34D389, 0x23, 0x41),
|
||||
LocationName.tearaway_toboggan_region: DKC3Level(0x34D393, 0x34D394, 0x24, 0x2D),
|
||||
LocationName.barrel_drop_bounce_region: DKC3Level(0x34D39E, 0x34D39F, 0x25, 0x3A),
|
||||
LocationName.krack_shot_kroc_region: DKC3Level(0x34D3A9, 0x34D3AA, 0x26, 0x3D),
|
||||
LocationName.lemguin_lunge_region: DKC3Level(0x34D3B4, 0x34D3B5, 0x27, 0x2C),
|
||||
|
||||
LocationName.buzzer_barrage_region: DKC3Level(0x34D40E, 0x34D40F, 0x2B, 0x44),
|
||||
LocationName.kong_fused_cliffs_region: DKC3Level(0x34D424, 0x34D425, 0x2D, 0x42),
|
||||
LocationName.floodlit_fish_region: DKC3Level(0x34D42F, 0x34D430, 0x2E, 0x37),
|
||||
LocationName.pothole_panic_region: DKC3Level(0x34D43A, 0x34D43B, 0x2F, 0x45),
|
||||
LocationName.ropey_rumpus_region: DKC3Level(0x34D450, 0x34D451, 0x30, 0x43),
|
||||
|
||||
LocationName.konveyor_rope_clash_region: DKC3Level(0x34D489, 0x34D48A, 0x38, 0x48),
|
||||
LocationName.creepy_caverns_region: DKC3Level(0x34D49F, 0x34D4A0, 0x36, 0x46),
|
||||
LocationName.lightning_lookout_region: DKC3Level(0x34D4AA, 0x34D4AB, 0x10, 0x33),
|
||||
LocationName.koindozer_klamber_region: DKC3Level(0x34D4C0, 0x34D4C1, 0x34, 0x47),
|
||||
LocationName.poisonous_pipeline_region: DKC3Level(0x34D4D6, 0x34D4D7, 0x39, 0x3F),
|
||||
|
||||
LocationName.stampede_sprint_region: DKC3Level(0x34D51A, 0x34D51B, 0x3D, 0x49),
|
||||
LocationName.criss_cross_cliffs_region: DKC3Level(0x34D525, 0x34D526, 0x3E, 0x4A),
|
||||
LocationName.tyrant_twin_tussle_region: DKC3Level(0x34D530, 0x34D531, 0x3F, 0x4B),
|
||||
LocationName.swoopy_salvo_region: DKC3Level(0x34D53B, 0x34D53C, 0x40, 0x31),
|
||||
#LocationName.rocket_rush_region: DKC3Level(0x34D546, 0x34D547, 0x05, 0x4C), # Rocket Rush is not getting shuffled
|
||||
}
|
||||
|
||||
level_list = [
|
||||
LocationName.lakeside_limbo_region,
|
||||
LocationName.doorstop_dash_region,
|
||||
LocationName.tidal_trouble_region,
|
||||
LocationName.skiddas_row_region,
|
||||
LocationName.murky_mill_region,
|
||||
|
||||
LocationName.barrel_shield_bust_up_region,
|
||||
LocationName.riverside_race_region,
|
||||
LocationName.squeals_on_wheels_region,
|
||||
LocationName.springin_spiders_region,
|
||||
LocationName.bobbing_barrel_brawl_region,
|
||||
|
||||
LocationName.bazzas_blockade_region,
|
||||
LocationName.rocket_barrel_ride_region,
|
||||
LocationName.kreeping_klasps_region,
|
||||
LocationName.tracker_barrel_trek_region,
|
||||
LocationName.fish_food_frenzy_region,
|
||||
|
||||
LocationName.fire_ball_frenzy_region,
|
||||
LocationName.demolition_drain_pipe_region,
|
||||
LocationName.ripsaw_rage_region,
|
||||
LocationName.blazing_bazookas_region,
|
||||
LocationName.low_g_labyrinth_region,
|
||||
|
||||
LocationName.krevice_kreepers_region,
|
||||
LocationName.tearaway_toboggan_region,
|
||||
LocationName.barrel_drop_bounce_region,
|
||||
LocationName.krack_shot_kroc_region,
|
||||
LocationName.lemguin_lunge_region,
|
||||
|
||||
LocationName.buzzer_barrage_region,
|
||||
LocationName.kong_fused_cliffs_region,
|
||||
LocationName.floodlit_fish_region,
|
||||
LocationName.pothole_panic_region,
|
||||
LocationName.ropey_rumpus_region,
|
||||
|
||||
LocationName.konveyor_rope_clash_region,
|
||||
LocationName.creepy_caverns_region,
|
||||
LocationName.lightning_lookout_region,
|
||||
LocationName.koindozer_klamber_region,
|
||||
LocationName.poisonous_pipeline_region,
|
||||
|
||||
LocationName.stampede_sprint_region,
|
||||
LocationName.criss_cross_cliffs_region,
|
||||
LocationName.tyrant_twin_tussle_region,
|
||||
LocationName.swoopy_salvo_region,
|
||||
#LocationName.rocket_rush_region,
|
||||
]
|
||||
@@ -1,337 +0,0 @@
|
||||
import typing
|
||||
|
||||
from BaseClasses import Location
|
||||
from .Names import LocationName
|
||||
from worlds.AutoWorld import World
|
||||
|
||||
|
||||
class DKC3Location(Location):
|
||||
game: str = "Donkey Kong Country 3"
|
||||
|
||||
progress_byte: int = 0x000000
|
||||
progress_bit: int = 0
|
||||
inverted_bit: bool = False
|
||||
|
||||
def __init__(self, player: int, name: str = '', address: int = None, parent=None, prog_byte: int = None, prog_bit: int = None, invert: bool = False):
|
||||
super().__init__(player, name, address, parent)
|
||||
self.progress_byte = prog_byte
|
||||
self.progress_bit = prog_bit
|
||||
self.inverted_bit = invert
|
||||
|
||||
|
||||
level_location_table = {
|
||||
LocationName.lakeside_limbo_flag: 0xDC3000,
|
||||
LocationName.lakeside_limbo_bonus_1: 0xDC3001,
|
||||
LocationName.lakeside_limbo_bonus_2: 0xDC3002,
|
||||
LocationName.lakeside_limbo_dk: 0xDC3003,
|
||||
|
||||
LocationName.doorstop_dash_flag: 0xDC3004,
|
||||
LocationName.doorstop_dash_bonus_1: 0xDC3005,
|
||||
LocationName.doorstop_dash_bonus_2: 0xDC3006,
|
||||
LocationName.doorstop_dash_dk: 0xDC3007,
|
||||
|
||||
LocationName.tidal_trouble_flag: 0xDC3008,
|
||||
LocationName.tidal_trouble_bonus_1: 0xDC3009,
|
||||
LocationName.tidal_trouble_bonus_2: 0xDC300A,
|
||||
LocationName.tidal_trouble_dk: 0xDC300B,
|
||||
|
||||
LocationName.skiddas_row_flag: 0xDC300C,
|
||||
LocationName.skiddas_row_bonus_1: 0xDC300D,
|
||||
LocationName.skiddas_row_bonus_2: 0xDC300E,
|
||||
LocationName.skiddas_row_dk: 0xDC300F,
|
||||
|
||||
LocationName.murky_mill_flag: 0xDC3010,
|
||||
LocationName.murky_mill_bonus_1: 0xDC3011,
|
||||
LocationName.murky_mill_bonus_2: 0xDC3012,
|
||||
LocationName.murky_mill_dk: 0xDC3013,
|
||||
|
||||
LocationName.barrel_shield_bust_up_flag: 0xDC3014,
|
||||
LocationName.barrel_shield_bust_up_bonus_1: 0xDC3015,
|
||||
LocationName.barrel_shield_bust_up_bonus_2: 0xDC3016,
|
||||
LocationName.barrel_shield_bust_up_dk: 0xDC3017,
|
||||
|
||||
LocationName.riverside_race_flag: 0xDC3018,
|
||||
LocationName.riverside_race_bonus_1: 0xDC3019,
|
||||
LocationName.riverside_race_bonus_2: 0xDC301A,
|
||||
LocationName.riverside_race_dk: 0xDC301B,
|
||||
|
||||
LocationName.squeals_on_wheels_flag: 0xDC301C,
|
||||
LocationName.squeals_on_wheels_bonus_1: 0xDC301D,
|
||||
LocationName.squeals_on_wheels_bonus_2: 0xDC301E,
|
||||
LocationName.squeals_on_wheels_dk: 0xDC301F,
|
||||
|
||||
LocationName.springin_spiders_flag: 0xDC3020,
|
||||
LocationName.springin_spiders_bonus_1: 0xDC3021,
|
||||
LocationName.springin_spiders_bonus_2: 0xDC3022,
|
||||
LocationName.springin_spiders_dk: 0xDC3023,
|
||||
|
||||
LocationName.bobbing_barrel_brawl_flag: 0xDC3024,
|
||||
LocationName.bobbing_barrel_brawl_bonus_1: 0xDC3025,
|
||||
LocationName.bobbing_barrel_brawl_bonus_2: 0xDC3026,
|
||||
LocationName.bobbing_barrel_brawl_dk: 0xDC3027,
|
||||
|
||||
LocationName.bazzas_blockade_flag: 0xDC3028,
|
||||
LocationName.bazzas_blockade_bonus_1: 0xDC3029,
|
||||
LocationName.bazzas_blockade_bonus_2: 0xDC302A,
|
||||
LocationName.bazzas_blockade_dk: 0xDC302B,
|
||||
|
||||
LocationName.rocket_barrel_ride_flag: 0xDC302C,
|
||||
LocationName.rocket_barrel_ride_bonus_1: 0xDC302D,
|
||||
LocationName.rocket_barrel_ride_bonus_2: 0xDC302E,
|
||||
LocationName.rocket_barrel_ride_dk: 0xDC302F,
|
||||
|
||||
LocationName.kreeping_klasps_flag: 0xDC3030,
|
||||
LocationName.kreeping_klasps_bonus_1: 0xDC3031,
|
||||
LocationName.kreeping_klasps_bonus_2: 0xDC3032,
|
||||
LocationName.kreeping_klasps_dk: 0xDC3033,
|
||||
|
||||
LocationName.tracker_barrel_trek_flag: 0xDC3034,
|
||||
LocationName.tracker_barrel_trek_bonus_1: 0xDC3035,
|
||||
LocationName.tracker_barrel_trek_bonus_2: 0xDC3036,
|
||||
LocationName.tracker_barrel_trek_dk: 0xDC3037,
|
||||
|
||||
LocationName.fish_food_frenzy_flag: 0xDC3038,
|
||||
LocationName.fish_food_frenzy_bonus_1: 0xDC3039,
|
||||
LocationName.fish_food_frenzy_bonus_2: 0xDC303A,
|
||||
LocationName.fish_food_frenzy_dk: 0xDC303B,
|
||||
|
||||
LocationName.fire_ball_frenzy_flag: 0xDC303C,
|
||||
LocationName.fire_ball_frenzy_bonus_1: 0xDC303D,
|
||||
LocationName.fire_ball_frenzy_bonus_2: 0xDC303E,
|
||||
LocationName.fire_ball_frenzy_dk: 0xDC303F,
|
||||
|
||||
LocationName.demolition_drain_pipe_flag: 0xDC3040,
|
||||
LocationName.demolition_drain_pipe_bonus_1: 0xDC3041,
|
||||
LocationName.demolition_drain_pipe_bonus_2: 0xDC3042,
|
||||
LocationName.demolition_drain_pipe_dk: 0xDC3043,
|
||||
|
||||
LocationName.ripsaw_rage_flag: 0xDC3044,
|
||||
LocationName.ripsaw_rage_bonus_1: 0xDC3045,
|
||||
LocationName.ripsaw_rage_bonus_2: 0xDC3046,
|
||||
LocationName.ripsaw_rage_dk: 0xDC3047,
|
||||
|
||||
LocationName.blazing_bazookas_flag: 0xDC3048,
|
||||
LocationName.blazing_bazookas_bonus_1: 0xDC3049,
|
||||
LocationName.blazing_bazookas_bonus_2: 0xDC304A,
|
||||
LocationName.blazing_bazookas_dk: 0xDC304B,
|
||||
|
||||
LocationName.low_g_labyrinth_flag: 0xDC304C,
|
||||
LocationName.low_g_labyrinth_bonus_1: 0xDC304D,
|
||||
LocationName.low_g_labyrinth_bonus_2: 0xDC304E,
|
||||
LocationName.low_g_labyrinth_dk: 0xDC304F,
|
||||
|
||||
LocationName.krevice_kreepers_flag: 0xDC3050,
|
||||
LocationName.krevice_kreepers_bonus_1: 0xDC3051,
|
||||
LocationName.krevice_kreepers_bonus_2: 0xDC3052,
|
||||
LocationName.krevice_kreepers_dk: 0xDC3053,
|
||||
|
||||
LocationName.tearaway_toboggan_flag: 0xDC3054,
|
||||
LocationName.tearaway_toboggan_bonus_1: 0xDC3055,
|
||||
LocationName.tearaway_toboggan_bonus_2: 0xDC3056,
|
||||
LocationName.tearaway_toboggan_dk: 0xDC3057,
|
||||
|
||||
LocationName.barrel_drop_bounce_flag: 0xDC3058,
|
||||
LocationName.barrel_drop_bounce_bonus_1: 0xDC3059,
|
||||
LocationName.barrel_drop_bounce_bonus_2: 0xDC305A,
|
||||
LocationName.barrel_drop_bounce_dk: 0xDC305B,
|
||||
|
||||
LocationName.krack_shot_kroc_flag: 0xDC305C,
|
||||
LocationName.krack_shot_kroc_bonus_1: 0xDC305D,
|
||||
LocationName.krack_shot_kroc_bonus_2: 0xDC305E,
|
||||
LocationName.krack_shot_kroc_dk: 0xDC305F,
|
||||
|
||||
LocationName.lemguin_lunge_flag: 0xDC3060,
|
||||
LocationName.lemguin_lunge_bonus_1: 0xDC3061,
|
||||
LocationName.lemguin_lunge_bonus_2: 0xDC3062,
|
||||
LocationName.lemguin_lunge_dk: 0xDC3063,
|
||||
|
||||
LocationName.buzzer_barrage_flag: 0xDC3064,
|
||||
LocationName.buzzer_barrage_bonus_1: 0xDC3065,
|
||||
LocationName.buzzer_barrage_bonus_2: 0xDC3066,
|
||||
LocationName.buzzer_barrage_dk: 0xDC3067,
|
||||
|
||||
LocationName.kong_fused_cliffs_flag: 0xDC3068,
|
||||
LocationName.kong_fused_cliffs_bonus_1: 0xDC3069,
|
||||
LocationName.kong_fused_cliffs_bonus_2: 0xDC306A,
|
||||
LocationName.kong_fused_cliffs_dk: 0xDC306B,
|
||||
|
||||
LocationName.floodlit_fish_flag: 0xDC306C,
|
||||
LocationName.floodlit_fish_bonus_1: 0xDC306D,
|
||||
LocationName.floodlit_fish_bonus_2: 0xDC306E,
|
||||
LocationName.floodlit_fish_dk: 0xDC306F,
|
||||
|
||||
LocationName.pothole_panic_flag: 0xDC3070,
|
||||
LocationName.pothole_panic_bonus_1: 0xDC3071,
|
||||
LocationName.pothole_panic_bonus_2: 0xDC3072,
|
||||
LocationName.pothole_panic_dk: 0xDC3073,
|
||||
|
||||
LocationName.ropey_rumpus_flag: 0xDC3074,
|
||||
LocationName.ropey_rumpus_bonus_1: 0xDC3075,
|
||||
LocationName.ropey_rumpus_bonus_2: 0xDC3076,
|
||||
LocationName.ropey_rumpus_dk: 0xDC3077,
|
||||
|
||||
LocationName.konveyor_rope_clash_flag: 0xDC3078,
|
||||
LocationName.konveyor_rope_clash_bonus_1: 0xDC3079,
|
||||
LocationName.konveyor_rope_clash_bonus_2: 0xDC307A,
|
||||
LocationName.konveyor_rope_clash_dk: 0xDC307B,
|
||||
|
||||
LocationName.creepy_caverns_flag: 0xDC307C,
|
||||
LocationName.creepy_caverns_bonus_1: 0xDC307D,
|
||||
LocationName.creepy_caverns_bonus_2: 0xDC307E,
|
||||
LocationName.creepy_caverns_dk: 0xDC307F,
|
||||
|
||||
LocationName.lightning_lookout_flag: 0xDC3080,
|
||||
LocationName.lightning_lookout_bonus_1: 0xDC3081,
|
||||
LocationName.lightning_lookout_bonus_2: 0xDC3082,
|
||||
LocationName.lightning_lookout_dk: 0xDC3083,
|
||||
|
||||
LocationName.koindozer_klamber_flag: 0xDC3084,
|
||||
LocationName.koindozer_klamber_bonus_1: 0xDC3085,
|
||||
LocationName.koindozer_klamber_bonus_2: 0xDC3086,
|
||||
LocationName.koindozer_klamber_dk: 0xDC3087,
|
||||
|
||||
LocationName.poisonous_pipeline_flag: 0xDC3088,
|
||||
LocationName.poisonous_pipeline_bonus_1: 0xDC3089,
|
||||
LocationName.poisonous_pipeline_bonus_2: 0xDC308A,
|
||||
LocationName.poisonous_pipeline_dk: 0xDC308B,
|
||||
|
||||
LocationName.stampede_sprint_flag: 0xDC308C,
|
||||
LocationName.stampede_sprint_bonus_1: 0xDC308D,
|
||||
LocationName.stampede_sprint_bonus_2: 0xDC308E,
|
||||
LocationName.stampede_sprint_bonus_3: 0xDC308F,
|
||||
LocationName.stampede_sprint_dk: 0xDC3090,
|
||||
|
||||
LocationName.criss_cross_cliffs_flag: 0xDC3091,
|
||||
LocationName.criss_cross_cliffs_bonus_1: 0xDC3092,
|
||||
LocationName.criss_cross_cliffs_bonus_2: 0xDC3093,
|
||||
LocationName.criss_cross_cliffs_dk: 0xDC3094,
|
||||
|
||||
LocationName.tyrant_twin_tussle_flag: 0xDC3095,
|
||||
LocationName.tyrant_twin_tussle_bonus_1: 0xDC3096,
|
||||
LocationName.tyrant_twin_tussle_bonus_2: 0xDC3097,
|
||||
LocationName.tyrant_twin_tussle_bonus_3: 0xDC3098,
|
||||
LocationName.tyrant_twin_tussle_dk: 0xDC3099,
|
||||
|
||||
LocationName.swoopy_salvo_flag: 0xDC309A,
|
||||
LocationName.swoopy_salvo_bonus_1: 0xDC309B,
|
||||
LocationName.swoopy_salvo_bonus_2: 0xDC309C,
|
||||
LocationName.swoopy_salvo_bonus_3: 0xDC309D,
|
||||
LocationName.swoopy_salvo_dk: 0xDC309E,
|
||||
|
||||
LocationName.rocket_rush_flag: 0xDC309F,
|
||||
LocationName.rocket_rush_dk: 0xDC30A0,
|
||||
}
|
||||
|
||||
kong_location_table = {
|
||||
LocationName.lakeside_limbo_kong: 0xDC3100,
|
||||
LocationName.doorstop_dash_kong: 0xDC3104,
|
||||
LocationName.tidal_trouble_kong: 0xDC3108,
|
||||
LocationName.skiddas_row_kong: 0xDC310C,
|
||||
LocationName.murky_mill_kong: 0xDC3110,
|
||||
|
||||
LocationName.barrel_shield_bust_up_kong: 0xDC3114,
|
||||
LocationName.riverside_race_kong: 0xDC3118,
|
||||
LocationName.squeals_on_wheels_kong: 0xDC311C,
|
||||
LocationName.springin_spiders_kong: 0xDC3120,
|
||||
LocationName.bobbing_barrel_brawl_kong: 0xDC3124,
|
||||
|
||||
LocationName.bazzas_blockade_kong: 0xDC3128,
|
||||
LocationName.rocket_barrel_ride_kong: 0xDC312C,
|
||||
LocationName.kreeping_klasps_kong: 0xDC3130,
|
||||
LocationName.tracker_barrel_trek_kong: 0xDC3134,
|
||||
LocationName.fish_food_frenzy_kong: 0xDC3138,
|
||||
|
||||
LocationName.fire_ball_frenzy_kong: 0xDC313C,
|
||||
LocationName.demolition_drain_pipe_kong: 0xDC3140,
|
||||
LocationName.ripsaw_rage_kong: 0xDC3144,
|
||||
LocationName.blazing_bazookas_kong: 0xDC3148,
|
||||
LocationName.low_g_labyrinth_kong: 0xDC314C,
|
||||
|
||||
LocationName.krevice_kreepers_kong: 0xDC3150,
|
||||
LocationName.tearaway_toboggan_kong: 0xDC3154,
|
||||
LocationName.barrel_drop_bounce_kong: 0xDC3158,
|
||||
LocationName.krack_shot_kroc_kong: 0xDC315C,
|
||||
LocationName.lemguin_lunge_kong: 0xDC3160,
|
||||
|
||||
LocationName.buzzer_barrage_kong: 0xDC3164,
|
||||
LocationName.kong_fused_cliffs_kong: 0xDC3168,
|
||||
LocationName.floodlit_fish_kong: 0xDC316C,
|
||||
LocationName.pothole_panic_kong: 0xDC3170,
|
||||
LocationName.ropey_rumpus_kong: 0xDC3174,
|
||||
|
||||
LocationName.konveyor_rope_clash_kong: 0xDC3178,
|
||||
LocationName.creepy_caverns_kong: 0xDC317C,
|
||||
LocationName.lightning_lookout_kong: 0xDC3180,
|
||||
LocationName.koindozer_klamber_kong: 0xDC3184,
|
||||
LocationName.poisonous_pipeline_kong: 0xDC3188,
|
||||
|
||||
LocationName.stampede_sprint_kong: 0xDC318C,
|
||||
LocationName.criss_cross_cliffs_kong: 0xDC3191,
|
||||
LocationName.tyrant_twin_tussle_kong: 0xDC3195,
|
||||
LocationName.swoopy_salvo_kong: 0xDC319A,
|
||||
}
|
||||
|
||||
|
||||
boss_location_table = {
|
||||
LocationName.belchas_barn: 0xDC30A1,
|
||||
LocationName.arichs_ambush: 0xDC30A2,
|
||||
LocationName.squirts_showdown: 0xDC30A3,
|
||||
LocationName.kaos_karnage: 0xDC30A4,
|
||||
LocationName.bleaks_house: 0xDC30A5,
|
||||
LocationName.barboss_barrier: 0xDC30A6,
|
||||
LocationName.kastle_kaos: 0xDC30A7,
|
||||
LocationName.knautilus: 0xDC30A8,
|
||||
}
|
||||
|
||||
secret_cave_location_table = {
|
||||
LocationName.belchas_burrow: 0xDC30A9,
|
||||
LocationName.kong_cave: 0xDC30AA,
|
||||
LocationName.undercover_cove: 0xDC30AB,
|
||||
LocationName.ks_cache: 0xDC30AC,
|
||||
LocationName.hill_top_hoard: 0xDC30AD,
|
||||
LocationName.bounty_beach: 0xDC30AE,
|
||||
LocationName.smugglers_cove: 0xDC30AF,
|
||||
LocationName.arichs_hoard: 0xDC30B0,
|
||||
LocationName.bounty_bay: 0xDC30B1,
|
||||
LocationName.sky_high_secret: 0xDC30B2,
|
||||
LocationName.glacial_grotto: 0xDC30B3,
|
||||
LocationName.cifftop_cache: 0xDC30B4,
|
||||
LocationName.sewer_stockpile: 0xDC30B5,
|
||||
LocationName.banana_bird_mother: 0xDC30B6,
|
||||
}
|
||||
|
||||
brothers_bear_location_table = {
|
||||
LocationName.bazaars_general_store_1: 0xDC30B7,
|
||||
LocationName.bazaars_general_store_2: 0xDC30B8,
|
||||
LocationName.brambles_bungalow: 0xDC30B9,
|
||||
LocationName.flower_spot: 0xDC30BA,
|
||||
LocationName.barters_swap_shop: 0xDC30BB,
|
||||
LocationName.barnacles_island: 0xDC30BC,
|
||||
LocationName.blues_beach_hut: 0xDC30BD,
|
||||
LocationName.blizzards_basecamp: 0xDC30BE,
|
||||
}
|
||||
|
||||
all_locations = {
|
||||
**level_location_table,
|
||||
**boss_location_table,
|
||||
**secret_cave_location_table,
|
||||
**brothers_bear_location_table,
|
||||
**kong_location_table,
|
||||
}
|
||||
|
||||
location_table = {}
|
||||
|
||||
|
||||
def setup_locations(world: World):
|
||||
location_table = {**level_location_table, **boss_location_table, **secret_cave_location_table}
|
||||
|
||||
if False:#world.options.include_trade_sequence:
|
||||
location_table.update({**brothers_bear_location_table})
|
||||
|
||||
if world.options.kongsanity:
|
||||
location_table.update({**kong_location_table})
|
||||
|
||||
return location_table
|
||||
|
||||
|
||||
lookup_id_to_name: typing.Dict[int, str] = {id: name for name, _ in all_locations.items()}
|
||||
@@ -1,21 +0,0 @@
|
||||
# Junk Definitions
|
||||
one_up_balloon = "1-Up Balloon"
|
||||
bear_coin = "Bear Coin"
|
||||
|
||||
# Collectable Definitions
|
||||
bonus_coin = "Bonus Coin"
|
||||
dk_coin = "DK Coin"
|
||||
banana_bird = "Banana Bird"
|
||||
krematoa_cog = "Krematoa Cog"
|
||||
|
||||
# Inventory Definitions
|
||||
progressive_boat = "Progressive Boat Upgrade"
|
||||
present = "Present"
|
||||
bowling_ball = "Bowling Ball"
|
||||
shell = "Shell"
|
||||
mirror = "Mirror"
|
||||
flower = "Flupperius Petallus Pongus"
|
||||
wrench = "No. 6 Wrench"
|
||||
|
||||
# Other Definitions
|
||||
victory = "Donkey Kong"
|
||||
@@ -1,375 +0,0 @@
|
||||
# Level Definitions
|
||||
lakeside_limbo_flag = "Lakeside Limbo - Flag"
|
||||
lakeside_limbo_kong = "Lakeside Limbo - KONG"
|
||||
lakeside_limbo_bonus_1 = "Lakeside Limbo - Bonus 1"
|
||||
lakeside_limbo_bonus_2 = "Lakeside Limbo - Bonus 2"
|
||||
lakeside_limbo_dk = "Lakeside Limbo - DK Coin"
|
||||
|
||||
doorstop_dash_flag = "Doorstop Dash - Flag"
|
||||
doorstop_dash_kong = "Doorstop Dash - KONG"
|
||||
doorstop_dash_bonus_1 = "Doorstop Dash - Bonus 1"
|
||||
doorstop_dash_bonus_2 = "Doorstop Dash - Bonus 2"
|
||||
doorstop_dash_dk = "Doorstop Dash - DK Coin"
|
||||
|
||||
tidal_trouble_flag = "Tidal Trouble - Flag"
|
||||
tidal_trouble_kong = "Tidal Trouble - KONG"
|
||||
tidal_trouble_bonus_1 = "Tidal Trouble - Bonus 1"
|
||||
tidal_trouble_bonus_2 = "Tidal Trouble - Bonus 2"
|
||||
tidal_trouble_dk = "Tidal Trouble - DK Coin"
|
||||
|
||||
skiddas_row_flag = "Skidda's Row - Flag"
|
||||
skiddas_row_kong = "Skidda's Row - KONG"
|
||||
skiddas_row_bonus_1 = "Skidda's Row - Bonus 1"
|
||||
skiddas_row_bonus_2 = "Skidda's Row - Bonus 2"
|
||||
skiddas_row_dk = "Skidda's Row - DK Coin"
|
||||
|
||||
murky_mill_flag = "Murky Mill - Flag"
|
||||
murky_mill_kong = "Murky Mill - KONG"
|
||||
murky_mill_bonus_1 = "Murky Mill - Bonus 1"
|
||||
murky_mill_bonus_2 = "Murky Mill - Bonus 2"
|
||||
murky_mill_dk = "Murky Mill - DK Coin"
|
||||
|
||||
barrel_shield_bust_up_flag = "Barrel Shield Bust-Up - Flag"
|
||||
barrel_shield_bust_up_kong = "Barrel Shield Bust-Up - KONG"
|
||||
barrel_shield_bust_up_bonus_1 = "Barrel Shield Bust-Up - Bonus 1"
|
||||
barrel_shield_bust_up_bonus_2 = "Barrel Shield Bust-Up - Bonus 2"
|
||||
barrel_shield_bust_up_dk = "Barrel Shield Bust-Up - DK Coin"
|
||||
|
||||
riverside_race_flag = "Riverside Race - Flag"
|
||||
riverside_race_kong = "Riverside Race - KONG"
|
||||
riverside_race_bonus_1 = "Riverside Race - Bonus 1"
|
||||
riverside_race_bonus_2 = "Riverside Race - Bonus 2"
|
||||
riverside_race_dk = "Riverside Race - DK Coin"
|
||||
|
||||
squeals_on_wheels_flag = "Squeals On Wheels - Flag"
|
||||
squeals_on_wheels_kong = "Squeals On Wheels - KONG"
|
||||
squeals_on_wheels_bonus_1 = "Squeals On Wheels - Bonus 1"
|
||||
squeals_on_wheels_bonus_2 = "Squeals On Wheels - Bonus 2"
|
||||
squeals_on_wheels_dk = "Squeals On Wheels - DK Coin"
|
||||
|
||||
springin_spiders_flag = "Springin' Spiders - Flag"
|
||||
springin_spiders_kong = "Springin' Spiders - KONG"
|
||||
springin_spiders_bonus_1 = "Springin' Spiders - Bonus 1"
|
||||
springin_spiders_bonus_2 = "Springin' Spiders - Bonus 2"
|
||||
springin_spiders_dk = "Springin' Spiders - DK Coin"
|
||||
|
||||
bobbing_barrel_brawl_flag = "Bobbing Barrel Brawl - Flag"
|
||||
bobbing_barrel_brawl_kong = "Bobbing Barrel Brawl - KONG"
|
||||
bobbing_barrel_brawl_bonus_1 = "Bobbing Barrel Brawl - Bonus 1"
|
||||
bobbing_barrel_brawl_bonus_2 = "Bobbing Barrel Brawl - Bonus 2"
|
||||
bobbing_barrel_brawl_dk = "Bobbing Barrel Brawl - DK Coin"
|
||||
|
||||
bazzas_blockade_flag = "Bazza's Blockade - Flag"
|
||||
bazzas_blockade_kong = "Bazza's Blockade - KONG"
|
||||
bazzas_blockade_bonus_1 = "Bazza's Blockade - Bonus 1"
|
||||
bazzas_blockade_bonus_2 = "Bazza's Blockade - Bonus 2"
|
||||
bazzas_blockade_dk = "Bazza's Blockade - DK Coin"
|
||||
|
||||
rocket_barrel_ride_flag = "Rocket Barrel Ride - Flag"
|
||||
rocket_barrel_ride_kong = "Rocket Barrel Ride - KONG"
|
||||
rocket_barrel_ride_bonus_1 = "Rocket Barrel Ride - Bonus 1"
|
||||
rocket_barrel_ride_bonus_2 = "Rocket Barrel Ride - Bonus 2"
|
||||
rocket_barrel_ride_dk = "Rocket Barrel Ride - DK Coin"
|
||||
|
||||
kreeping_klasps_flag = "Kreeping Klasps - Flag"
|
||||
kreeping_klasps_kong = "Kreeping Klasps - KONG"
|
||||
kreeping_klasps_bonus_1 = "Kreeping Klasps - Bonus 1"
|
||||
kreeping_klasps_bonus_2 = "Kreeping Klasps - Bonus 2"
|
||||
kreeping_klasps_dk = "Kreeping Klasps - DK Coin"
|
||||
|
||||
tracker_barrel_trek_flag = "Tracker Barrel Trek - Flag"
|
||||
tracker_barrel_trek_kong = "Tracker Barrel Trek - KONG"
|
||||
tracker_barrel_trek_bonus_1 = "Tracker Barrel Trek - Bonus 1"
|
||||
tracker_barrel_trek_bonus_2 = "Tracker Barrel Trek - Bonus 2"
|
||||
tracker_barrel_trek_dk = "Tracker Barrel Trek - DK Coin"
|
||||
|
||||
fish_food_frenzy_flag = "Fish Food Frenzy - Flag"
|
||||
fish_food_frenzy_kong = "Fish Food Frenzy - KONG"
|
||||
fish_food_frenzy_bonus_1 = "Fish Food Frenzy - Bonus 1"
|
||||
fish_food_frenzy_bonus_2 = "Fish Food Frenzy - Bonus 2"
|
||||
fish_food_frenzy_dk = "Fish Food Frenzy - DK Coin"
|
||||
|
||||
fire_ball_frenzy_flag = "Fire-Ball Frenzy - Flag"
|
||||
fire_ball_frenzy_kong = "Fire-Ball Frenzy - KONG"
|
||||
fire_ball_frenzy_bonus_1 = "Fire-Ball Frenzy - Bonus 1"
|
||||
fire_ball_frenzy_bonus_2 = "Fire-Ball Frenzy - Bonus 2"
|
||||
fire_ball_frenzy_dk = "Fire-Ball Frenzy - DK Coin"
|
||||
|
||||
demolition_drain_pipe_flag = "Demolition Drain-Pipe - Flag"
|
||||
demolition_drain_pipe_kong = "Demolition Drain-Pipe - KONG"
|
||||
demolition_drain_pipe_bonus_1 = "Demolition Drain-Pipe - Bonus 1"
|
||||
demolition_drain_pipe_bonus_2 = "Demolition Drain-Pipe - Bonus 2"
|
||||
demolition_drain_pipe_dk = "Demolition Drain-Pipe - DK Coin"
|
||||
|
||||
ripsaw_rage_flag = "Ripsaw Rage - Flag"
|
||||
ripsaw_rage_kong = "Ripsaw Rage - KONG"
|
||||
ripsaw_rage_bonus_1 = "Ripsaw Rage - Bonus 1"
|
||||
ripsaw_rage_bonus_2 = "Ripsaw Rage - Bonus 2"
|
||||
ripsaw_rage_dk = "Ripsaw Rage - DK Coin"
|
||||
|
||||
blazing_bazookas_flag = "Blazing Bazukas - Flag"
|
||||
blazing_bazookas_kong = "Blazing Bazukas - KONG"
|
||||
blazing_bazookas_bonus_1 = "Blazing Bazukas - Bonus 1"
|
||||
blazing_bazookas_bonus_2 = "Blazing Bazukas - Bonus 2"
|
||||
blazing_bazookas_dk = "Blazing Bazukas - DK Coin"
|
||||
|
||||
low_g_labyrinth_flag = "Low-G Labyrinth - Flag"
|
||||
low_g_labyrinth_kong = "Low-G Labyrinth - KONG"
|
||||
low_g_labyrinth_bonus_1 = "Low-G Labyrinth - Bonus 1"
|
||||
low_g_labyrinth_bonus_2 = "Low-G Labyrinth - Bonus 2"
|
||||
low_g_labyrinth_dk = "Low-G Labyrinth - DK Coin"
|
||||
|
||||
krevice_kreepers_flag = "Krevice Kreepers - Flag"
|
||||
krevice_kreepers_kong = "Krevice Kreepers - KONG"
|
||||
krevice_kreepers_bonus_1 = "Krevice Kreepers - Bonus 1"
|
||||
krevice_kreepers_bonus_2 = "Krevice Kreepers - Bonus 2"
|
||||
krevice_kreepers_dk = "Krevice Kreepers - DK Coin"
|
||||
|
||||
tearaway_toboggan_flag = "Tearaway Toboggan - Flag"
|
||||
tearaway_toboggan_kong = "Tearaway Toboggan - KONG"
|
||||
tearaway_toboggan_bonus_1 = "Tearaway Toboggan - Bonus 1"
|
||||
tearaway_toboggan_bonus_2 = "Tearaway Toboggan - Bonus 2"
|
||||
tearaway_toboggan_dk = "Tearaway Toboggan - DK Coin"
|
||||
|
||||
barrel_drop_bounce_flag = "Barrel Drop Bounce - Flag"
|
||||
barrel_drop_bounce_kong = "Barrel Drop Bounce - KONG"
|
||||
barrel_drop_bounce_bonus_1 = "Barrel Drop Bounce - Bonus 1"
|
||||
barrel_drop_bounce_bonus_2 = "Barrel Drop Bounce - Bonus 2"
|
||||
barrel_drop_bounce_dk = "Barrel Drop Bounce - DK Coin"
|
||||
|
||||
krack_shot_kroc_flag = "Krack-Shot Kroc - Flag"
|
||||
krack_shot_kroc_kong = "Krack-Shot Kroc - KONG"
|
||||
krack_shot_kroc_bonus_1 = "Krack-Shot Kroc - Bonus 1"
|
||||
krack_shot_kroc_bonus_2 = "Krack-Shot Kroc - Bonus 2"
|
||||
krack_shot_kroc_dk = "Krack-Shot Kroc - DK Coin"
|
||||
|
||||
lemguin_lunge_flag = "Lemguin Lunge - Flag"
|
||||
lemguin_lunge_kong = "Lemguin Lunge - KONG"
|
||||
lemguin_lunge_bonus_1 = "Lemguin Lunge - Bonus 1"
|
||||
lemguin_lunge_bonus_2 = "Lemguin Lunge - Bonus 2"
|
||||
lemguin_lunge_dk = "Lemguin Lunge - DK Coin"
|
||||
|
||||
buzzer_barrage_flag = "Buzzer Barrage - Flag"
|
||||
buzzer_barrage_kong = "Buzzer Barrage - KONG"
|
||||
buzzer_barrage_bonus_1 = "Buzzer Barrage - Bonus 1"
|
||||
buzzer_barrage_bonus_2 = "Buzzer Barrage - Bonus 2"
|
||||
buzzer_barrage_dk = "Buzzer Barrage - DK Coin"
|
||||
|
||||
kong_fused_cliffs_flag = "Kong-Fused Cliffs - Flag"
|
||||
kong_fused_cliffs_kong = "Kong-Fused Cliffs - KONG"
|
||||
kong_fused_cliffs_bonus_1 = "Kong-Fused Cliffs - Bonus 1"
|
||||
kong_fused_cliffs_bonus_2 = "Kong-Fused Cliffs - Bonus 2"
|
||||
kong_fused_cliffs_dk = "Kong-Fused Cliffs - DK Coin"
|
||||
|
||||
floodlit_fish_flag = "Floodlit Fish - Flag"
|
||||
floodlit_fish_kong = "Floodlit Fish - KONG"
|
||||
floodlit_fish_bonus_1 = "Floodlit Fish - Bonus 1"
|
||||
floodlit_fish_bonus_2 = "Floodlit Fish - Bonus 2"
|
||||
floodlit_fish_dk = "Floodlit Fish - DK Coin"
|
||||
|
||||
pothole_panic_flag = "Pothole Panic - Flag"
|
||||
pothole_panic_kong = "Pothole Panic - KONG"
|
||||
pothole_panic_bonus_1 = "Pothole Panic - Bonus 1"
|
||||
pothole_panic_bonus_2 = "Pothole Panic - Bonus 2"
|
||||
pothole_panic_dk = "Pothole Panic - DK Coin"
|
||||
|
||||
ropey_rumpus_flag = "Ropey Rumpus - Flag"
|
||||
ropey_rumpus_kong = "Ropey Rumpus - KONG"
|
||||
ropey_rumpus_bonus_1 = "Ropey Rumpus - Bonus 1"
|
||||
ropey_rumpus_bonus_2 = "Ropey Rumpus - Bonus 2"
|
||||
ropey_rumpus_dk = "Ropey Rumpus - DK Coin"
|
||||
|
||||
konveyor_rope_clash_flag = "Konveyor Rope Klash - Flag"
|
||||
konveyor_rope_clash_kong = "Konveyor Rope Klash - KONG"
|
||||
konveyor_rope_clash_bonus_1 = "Konveyor Rope Klash - Bonus 1"
|
||||
konveyor_rope_clash_bonus_2 = "Konveyor Rope Klash - Bonus 2"
|
||||
konveyor_rope_clash_dk = "Konveyor Rope Klash - DK Coin"
|
||||
|
||||
creepy_caverns_flag = "Creepy Caverns - Flag"
|
||||
creepy_caverns_kong = "Creepy Caverns - KONG"
|
||||
creepy_caverns_bonus_1 = "Creepy Caverns - Bonus 1"
|
||||
creepy_caverns_bonus_2 = "Creepy Caverns - Bonus 2"
|
||||
creepy_caverns_dk = "Creepy Caverns - DK Coin"
|
||||
|
||||
lightning_lookout_flag = "Lightning Lookout - Flag"
|
||||
lightning_lookout_kong = "Lightning Lookout - KONG"
|
||||
lightning_lookout_bonus_1 = "Lightning Lookout - Bonus 1"
|
||||
lightning_lookout_bonus_2 = "Lightning Lookout - Bonus 2"
|
||||
lightning_lookout_dk = "Lightning Lookout - DK Coin"
|
||||
|
||||
koindozer_klamber_flag = "Koindozer Klamber - Flag"
|
||||
koindozer_klamber_kong = "Koindozer Klamber - KONG"
|
||||
koindozer_klamber_bonus_1 = "Koindozer Klamber - Bonus 1"
|
||||
koindozer_klamber_bonus_2 = "Koindozer Klamber - Bonus 2"
|
||||
koindozer_klamber_dk = "Koindozer Klamber - DK Coin"
|
||||
|
||||
poisonous_pipeline_flag = "Poisonous Pipeline - Flag"
|
||||
poisonous_pipeline_kong = "Poisonous Pipeline - KONG"
|
||||
poisonous_pipeline_bonus_1 = "Poisonous Pipeline - Bonus 1"
|
||||
poisonous_pipeline_bonus_2 = "Poisonous Pipeline - Bonus 2"
|
||||
poisonous_pipeline_dk = "Poisonous Pipeline - DK Coin"
|
||||
|
||||
stampede_sprint_flag = "Stampede Sprint - Flag"
|
||||
stampede_sprint_kong = "Stampede Sprint - KONG"
|
||||
stampede_sprint_bonus_1 = "Stampede Sprint - Bonus 1"
|
||||
stampede_sprint_bonus_2 = "Stampede Sprint - Bonus 2"
|
||||
stampede_sprint_bonus_3 = "Stampede Sprint - Bonus 3"
|
||||
stampede_sprint_dk = "Stampede Sprint - DK Coin"
|
||||
|
||||
criss_cross_cliffs_flag = "Criss Kross Cliffs - Flag"
|
||||
criss_cross_cliffs_kong = "Criss Kross Cliffs - KONG"
|
||||
criss_cross_cliffs_bonus_1 = "Criss Kross Cliffs - Bonus 1"
|
||||
criss_cross_cliffs_bonus_2 = "Criss Kross Cliffs - Bonus 2"
|
||||
criss_cross_cliffs_dk = "Criss Kross Cliffs - DK Coin"
|
||||
|
||||
tyrant_twin_tussle_flag = "Tyrant Twin Tussle - Flag"
|
||||
tyrant_twin_tussle_kong = "Tyrant Twin Tussle - KONG"
|
||||
tyrant_twin_tussle_bonus_1 = "Tyrant Twin Tussle - Bonus 1"
|
||||
tyrant_twin_tussle_bonus_2 = "Tyrant Twin Tussle - Bonus 2"
|
||||
tyrant_twin_tussle_bonus_3 = "Tyrant Twin Tussle - Bonus 3"
|
||||
tyrant_twin_tussle_dk = "Tyrant Twin Tussle - DK Coin"
|
||||
|
||||
swoopy_salvo_flag = "Swoopy Salvo - Flag"
|
||||
swoopy_salvo_kong = "Swoopy Salvo - KONG"
|
||||
swoopy_salvo_bonus_1 = "Swoopy Salvo - Bonus 1"
|
||||
swoopy_salvo_bonus_2 = "Swoopy Salvo - Bonus 2"
|
||||
swoopy_salvo_bonus_3 = "Swoopy Salvo - Bonus 3"
|
||||
swoopy_salvo_dk = "Swoopy Salvo - DK Coin"
|
||||
|
||||
rocket_rush_flag = "Rocket Rush - Flag"
|
||||
rocket_rush_dk = "Rocket Rush - DK Coin"
|
||||
|
||||
# Boss Definitions
|
||||
belchas_barn = "Belcha's Barn"
|
||||
arichs_ambush = "Arich's Ambush"
|
||||
squirts_showdown = "Squirt's Showdown"
|
||||
kaos_karnage = "KAOS Karnage"
|
||||
bleaks_house = "Bleak's House"
|
||||
barboss_barrier = "Barbos's Barrier"
|
||||
kastle_kaos = "Kastle KAOS"
|
||||
knautilus = "Knautilus"
|
||||
|
||||
|
||||
# Banana Bird Cave Definitions
|
||||
belchas_burrow = "Belcha's Burrow"
|
||||
kong_cave = "Kong Cave"
|
||||
undercover_cove = "Undercover Cove"
|
||||
ks_cache = "K's Cache"
|
||||
hill_top_hoard = "Hill-Top Hoard"
|
||||
bounty_beach = "Bounty Beach"
|
||||
smugglers_cove = "Smuggler's Cove"
|
||||
arichs_hoard = "Arich's Hoard"
|
||||
bounty_bay = "Bounty Bay"
|
||||
sky_high_secret = "Sky-High Secret"
|
||||
glacial_grotto = "Glacial Grotto"
|
||||
cifftop_cache = "Clifftop Cache"
|
||||
sewer_stockpile = "Sewer Stockpile"
|
||||
|
||||
banana_bird_mother = "Banana Bird Mother"
|
||||
|
||||
|
||||
# Brothers Bear Definitions
|
||||
bazaars_general_store_1 = "Bazaar's General Store - 1"
|
||||
bazaars_general_store_2 = "Bazaar's General Store - 2"
|
||||
brambles_bungalow = "Bramble's Bungalow"
|
||||
flower_spot = "Flower Spot"
|
||||
barters_swap_shop = "Barter's Swap Shop"
|
||||
barnacles_island = "Barnacle's Island"
|
||||
blues_beach_hut = "Blue's Beach Hut"
|
||||
blizzards_basecamp = "Bizzard's Basecamp"
|
||||
|
||||
|
||||
# Region Definitions
|
||||
menu_region = "Menu"
|
||||
overworld_1_region = "Overworld 1"
|
||||
overworld_2_region = "Overworld 2"
|
||||
overworld_3_region = "Overworld 3"
|
||||
overworld_4_region = "Overworld 4"
|
||||
|
||||
bazaar_region = "Bazaar's General Store Region"
|
||||
bramble_region = "Bramble's Bungalow Region"
|
||||
flower_spot_region = "Flower Spot Region"
|
||||
barter_region = "Barter's Swap Shop Region"
|
||||
barnacle_region = "Barnacle's Island Region"
|
||||
blue_region = "Blue's Beach Hut Region"
|
||||
blizzard_region = "Bizzard's Basecamp Region"
|
||||
|
||||
lake_orangatanga_region = "Lake Orangatanga"
|
||||
kremwood_forest_region = "Kremwood Forest"
|
||||
cotton_top_cove_region = "Cotton-Top Cove"
|
||||
mekanos_region = "Mekanos"
|
||||
k3_region = "K3"
|
||||
razor_ridge_region = "Razor Ridge"
|
||||
kaos_kore_region = "KAOS Kore"
|
||||
krematoa_region = "Krematoa"
|
||||
|
||||
belchas_barn_region = "Belcha's Barn Region"
|
||||
arichs_ambush_region = "Arich's Ambush Region"
|
||||
squirts_showdown_region = "Squirt's Showdown Region"
|
||||
kaos_karnage_region = "KAOS Karnage Region"
|
||||
bleaks_house_region = "Bleak's House Region"
|
||||
barboss_barrier_region = "Barbos's Barrier Region"
|
||||
kastle_kaos_region = "Kastle KAOS Region"
|
||||
knautilus_region = "Knautilus Region"
|
||||
|
||||
belchas_burrow_region = "Belcha's Burrow Region"
|
||||
kong_cave_region = "Kong Cave Region"
|
||||
undercover_cove_region = "Undercover Cove Region"
|
||||
ks_cache_region = "K's Cache Region"
|
||||
hill_top_hoard_region = "Hill-Top Hoard Region"
|
||||
bounty_beach_region = "Bounty Beach Region"
|
||||
smugglers_cove_region = "Smuggler's Cove Region"
|
||||
arichs_hoard_region = "Arich's Hoard Region"
|
||||
bounty_bay_region = "Bounty Bay Region"
|
||||
sky_high_secret_region = "Sky-High Secret Region"
|
||||
glacial_grotto_region = "Glacial Grotto Region"
|
||||
cifftop_cache_region = "Clifftop Cache Region"
|
||||
sewer_stockpile_region = "Sewer Stockpile Region"
|
||||
|
||||
lakeside_limbo_region = "Lakeside Limbo"
|
||||
doorstop_dash_region = "Doorstop Dash"
|
||||
tidal_trouble_region = "Tidal Trouble"
|
||||
skiddas_row_region = "Skidda's Row"
|
||||
murky_mill_region = "Murky Mill"
|
||||
|
||||
barrel_shield_bust_up_region = "Barrel Shield Bust-Up"
|
||||
riverside_race_region = "Riverside Race"
|
||||
squeals_on_wheels_region = "Squeals On Wheels"
|
||||
springin_spiders_region = "Springin' Spiders"
|
||||
bobbing_barrel_brawl_region = "Bobbing Barrel Brawl"
|
||||
|
||||
bazzas_blockade_region = "Bazza's Blockade"
|
||||
rocket_barrel_ride_region = "Rocket Barrel Ride"
|
||||
kreeping_klasps_region = "Kreeping Klasps"
|
||||
tracker_barrel_trek_region = "Tracker Barrel Trek"
|
||||
fish_food_frenzy_region = "Fish Food Frenzy"
|
||||
|
||||
fire_ball_frenzy_region = "Fire-Ball Frenzy"
|
||||
demolition_drain_pipe_region = "Demolition Drain-Pipe"
|
||||
ripsaw_rage_region = "Ripsaw Rage"
|
||||
blazing_bazookas_region = "Blazing Bazukas"
|
||||
low_g_labyrinth_region = "Low-G Labyrinth"
|
||||
|
||||
krevice_kreepers_region = "Krevice Kreepers"
|
||||
tearaway_toboggan_region = "Tearaway Toboggan"
|
||||
barrel_drop_bounce_region = "Barrel Drop Bounce"
|
||||
krack_shot_kroc_region = "Krack-Shot Kroc"
|
||||
lemguin_lunge_region = "Lemguin Lunge"
|
||||
|
||||
buzzer_barrage_region = "Buzzer Barrage"
|
||||
kong_fused_cliffs_region = "Kong-Fused Cliffs"
|
||||
floodlit_fish_region = "Floodlit Fish"
|
||||
pothole_panic_region = "Pothole Panic"
|
||||
ropey_rumpus_region = "Ropey Rumpus"
|
||||
|
||||
konveyor_rope_clash_region = "Konveyor Rope Klash"
|
||||
creepy_caverns_region = "Creepy Caverns"
|
||||
lightning_lookout_region = "Lightning Lookout"
|
||||
koindozer_klamber_region = "Koindozer Klamber"
|
||||
poisonous_pipeline_region = "Poisonous Pipeline"
|
||||
|
||||
stampede_sprint_region = "Stampede Sprint"
|
||||
criss_cross_cliffs_region = "Criss Kross Cliffs"
|
||||
tyrant_twin_tussle_region = "Tyrant Twin Tussle"
|
||||
swoopy_salvo_region = "Swoopy Salvo"
|
||||
rocket_rush_region = "Rocket Rush"
|
||||
@@ -1,203 +0,0 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from Options import Choice, Range, Toggle, DefaultOnToggle, OptionGroup, PerGameCommonOptions
|
||||
|
||||
|
||||
class Goal(Choice):
|
||||
"""
|
||||
Determines the goal of the seed
|
||||
|
||||
Knautilus: Scuttle the Knautilus in Krematoa and defeat Baron K. Roolenstein
|
||||
|
||||
Banana Bird Hunt: Find a certain number of Banana Birds and rescue their mother
|
||||
"""
|
||||
display_name = "Goal"
|
||||
option_knautilus = 0
|
||||
option_banana_bird_hunt = 1
|
||||
default = 0
|
||||
|
||||
|
||||
class IncludeTradeSequence(Toggle):
|
||||
"""
|
||||
Allows logic to place items at the various steps of the trade sequence
|
||||
"""
|
||||
display_name = "Include Trade Sequence"
|
||||
|
||||
|
||||
class DKCoinsForGyrocopter(Range):
|
||||
"""
|
||||
How many DK Coins are needed to unlock the Gyrocopter
|
||||
|
||||
Note: Achieving this number before unlocking the Turbo Ski will cause the game to grant you a
|
||||
one-time upgrade to the next non-unlocked boat, until you return to Funky. Logic does not assume
|
||||
that you will use this.
|
||||
"""
|
||||
display_name = "DK Coins for Gyrocopter"
|
||||
range_start = 10
|
||||
range_end = 41
|
||||
default = 30
|
||||
|
||||
|
||||
class KrematoaBonusCoinCost(Range):
|
||||
"""
|
||||
How many Bonus Coins are needed to unlock each level in Krematoa
|
||||
"""
|
||||
display_name = "Krematoa Bonus Coins Cost"
|
||||
range_start = 1
|
||||
range_end = 17
|
||||
default = 15
|
||||
|
||||
|
||||
class PercentageOfExtraBonusCoins(Range):
|
||||
"""
|
||||
What Percentage of unneeded Bonus Coins are included in the item pool
|
||||
"""
|
||||
display_name = "Percentage of Extra Bonus Coins"
|
||||
range_start = 0
|
||||
range_end = 100
|
||||
default = 100
|
||||
|
||||
|
||||
class NumberOfBananaBirds(Range):
|
||||
"""
|
||||
How many Banana Birds are put into the item pool
|
||||
"""
|
||||
display_name = "Number of Banana Birds"
|
||||
range_start = 5
|
||||
range_end = 15
|
||||
default = 15
|
||||
|
||||
|
||||
class PercentageOfBananaBirds(Range):
|
||||
"""
|
||||
What Percentage of Banana Birds in the item pool are required for Banana Bird Hunt
|
||||
"""
|
||||
display_name = "Percentage of Banana Birds"
|
||||
range_start = 20
|
||||
range_end = 100
|
||||
default = 100
|
||||
|
||||
|
||||
class KONGsanity(Toggle):
|
||||
"""
|
||||
Whether collecting all four KONG letters in each level grants a check
|
||||
"""
|
||||
display_name = "KONGsanity"
|
||||
|
||||
|
||||
class LevelShuffle(Toggle):
|
||||
"""
|
||||
Whether levels are shuffled
|
||||
"""
|
||||
display_name = "Level Shuffle"
|
||||
|
||||
|
||||
class Difficulty(Choice):
|
||||
"""
|
||||
Which Difficulty Level to use
|
||||
|
||||
NORML: The Normal Difficulty
|
||||
HARDR: Many DK Barrels are removed
|
||||
TUFST: Most DK Barrels and all Midway Barrels are removed
|
||||
"""
|
||||
display_name = "Difficulty"
|
||||
option_norml = 0
|
||||
option_hardr = 1
|
||||
option_tufst = 2
|
||||
default = 0
|
||||
|
||||
@classmethod
|
||||
def get_option_name(cls, value) -> str:
|
||||
if cls.auto_display_name:
|
||||
return cls.name_lookup[value].upper()
|
||||
else:
|
||||
return cls.name_lookup[value]
|
||||
|
||||
|
||||
class Autosave(DefaultOnToggle):
|
||||
"""
|
||||
Whether the game should autosave after each level
|
||||
"""
|
||||
display_name = "Autosave"
|
||||
|
||||
|
||||
class MERRY(Toggle):
|
||||
"""
|
||||
Whether the Bonus Barrels will be Christmas-themed
|
||||
"""
|
||||
display_name = "MERRY"
|
||||
|
||||
|
||||
class MusicShuffle(Toggle):
|
||||
"""
|
||||
Whether music is shuffled
|
||||
"""
|
||||
display_name = "Music Shuffle"
|
||||
|
||||
|
||||
class KongPaletteSwap(Choice):
|
||||
"""
|
||||
Which Palette to use for the Kongs
|
||||
"""
|
||||
display_name = "Kong Palette Swap"
|
||||
option_default = 0
|
||||
option_purple = 1
|
||||
option_spooky = 2
|
||||
option_dark = 3
|
||||
option_chocolate = 4
|
||||
option_shadow = 5
|
||||
option_red_gold = 6
|
||||
option_gbc = 7
|
||||
option_halloween = 8
|
||||
default = 0
|
||||
|
||||
|
||||
class StartingLifeCount(Range):
|
||||
"""
|
||||
How many extra lives to start the game with
|
||||
"""
|
||||
display_name = "Starting Life Count"
|
||||
range_start = 1
|
||||
range_end = 99
|
||||
default = 5
|
||||
|
||||
|
||||
dkc3_option_groups = [
|
||||
OptionGroup("Goal Options", [
|
||||
Goal,
|
||||
KrematoaBonusCoinCost,
|
||||
PercentageOfExtraBonusCoins,
|
||||
NumberOfBananaBirds,
|
||||
PercentageOfBananaBirds,
|
||||
]),
|
||||
OptionGroup("Aesthetics", [
|
||||
Autosave,
|
||||
MERRY,
|
||||
MusicShuffle,
|
||||
KongPaletteSwap,
|
||||
StartingLifeCount,
|
||||
]),
|
||||
]
|
||||
|
||||
|
||||
@dataclass
|
||||
class DKC3Options(PerGameCommonOptions):
|
||||
#death_link: DeathLink # Disabled
|
||||
#include_trade_sequence: IncludeTradeSequence # Disabled
|
||||
|
||||
goal: Goal
|
||||
krematoa_bonus_coin_cost: KrematoaBonusCoinCost
|
||||
percentage_of_extra_bonus_coins: PercentageOfExtraBonusCoins
|
||||
number_of_banana_birds: NumberOfBananaBirds
|
||||
percentage_of_banana_birds: PercentageOfBananaBirds
|
||||
|
||||
dk_coins_for_gyrocopter: DKCoinsForGyrocopter
|
||||
kongsanity: KONGsanity
|
||||
level_shuffle: LevelShuffle
|
||||
difficulty: Difficulty
|
||||
|
||||
autosave: Autosave
|
||||
merry: MERRY
|
||||
music_shuffle: MusicShuffle
|
||||
kong_palette_swap: KongPaletteSwap
|
||||
starting_life_count: StartingLifeCount
|
||||
@@ -1,954 +0,0 @@
|
||||
import typing
|
||||
|
||||
from BaseClasses import Region, Entrance
|
||||
from worlds.AutoWorld import World
|
||||
from .Locations import DKC3Location
|
||||
from .Names import LocationName, ItemName
|
||||
|
||||
|
||||
def create_regions(world: World, active_locations):
|
||||
menu_region = create_region(world, active_locations, 'Menu', None)
|
||||
|
||||
overworld_1_region_locations = {}
|
||||
if world.options.goal != "knautilus":
|
||||
overworld_1_region_locations.update({LocationName.banana_bird_mother: []})
|
||||
overworld_1_region = create_region(world, active_locations, LocationName.overworld_1_region,
|
||||
overworld_1_region_locations)
|
||||
|
||||
overworld_2_region_locations = {}
|
||||
overworld_2_region = create_region(world, active_locations, LocationName.overworld_2_region,
|
||||
overworld_2_region_locations)
|
||||
|
||||
overworld_3_region_locations = {}
|
||||
overworld_3_region = create_region(world, active_locations, LocationName.overworld_3_region,
|
||||
overworld_3_region_locations)
|
||||
|
||||
overworld_4_region_locations = {}
|
||||
overworld_4_region = create_region(world, active_locations, LocationName.overworld_4_region,
|
||||
overworld_4_region_locations)
|
||||
|
||||
|
||||
lake_orangatanga_region = create_region(world, active_locations, LocationName.lake_orangatanga_region, None)
|
||||
kremwood_forest_region = create_region(world, active_locations, LocationName.kremwood_forest_region, None)
|
||||
cotton_top_cove_region = create_region(world, active_locations, LocationName.cotton_top_cove_region, None)
|
||||
mekanos_region = create_region(world, active_locations, LocationName.mekanos_region, None)
|
||||
k3_region = create_region(world, active_locations, LocationName.k3_region, None)
|
||||
razor_ridge_region = create_region(world, active_locations, LocationName.razor_ridge_region, None)
|
||||
kaos_kore_region = create_region(world, active_locations, LocationName.kaos_kore_region, None)
|
||||
krematoa_region = create_region(world, active_locations, LocationName.krematoa_region, None)
|
||||
|
||||
|
||||
lakeside_limbo_region_locations = {
|
||||
LocationName.lakeside_limbo_flag : [0x657, 1],
|
||||
LocationName.lakeside_limbo_bonus_1 : [0x657, 2],
|
||||
LocationName.lakeside_limbo_bonus_2 : [0x657, 3],
|
||||
LocationName.lakeside_limbo_dk : [0x657, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
lakeside_limbo_region_locations[LocationName.lakeside_limbo_kong] = []
|
||||
lakeside_limbo_region = create_region(world, active_locations, LocationName.lakeside_limbo_region,
|
||||
lakeside_limbo_region_locations)
|
||||
|
||||
doorstop_dash_region_locations = {
|
||||
LocationName.doorstop_dash_flag : [0x65A, 1],
|
||||
LocationName.doorstop_dash_bonus_1 : [0x65A, 2],
|
||||
LocationName.doorstop_dash_bonus_2 : [0x65A, 3],
|
||||
LocationName.doorstop_dash_dk : [0x65A, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
doorstop_dash_region_locations[LocationName.doorstop_dash_kong] = []
|
||||
doorstop_dash_region = create_region(world, active_locations, LocationName.doorstop_dash_region,
|
||||
doorstop_dash_region_locations)
|
||||
|
||||
tidal_trouble_region_locations = {
|
||||
LocationName.tidal_trouble_flag : [0x659, 1],
|
||||
LocationName.tidal_trouble_bonus_1 : [0x659, 2],
|
||||
LocationName.tidal_trouble_bonus_2 : [0x659, 3],
|
||||
LocationName.tidal_trouble_dk : [0x659, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
tidal_trouble_region_locations[LocationName.tidal_trouble_kong] = []
|
||||
tidal_trouble_region = create_region(world, active_locations, LocationName.tidal_trouble_region,
|
||||
tidal_trouble_region_locations)
|
||||
|
||||
skiddas_row_region_locations = {
|
||||
LocationName.skiddas_row_flag : [0x65D, 1],
|
||||
LocationName.skiddas_row_bonus_1 : [0x65D, 2],
|
||||
LocationName.skiddas_row_bonus_2 : [0x65D, 3],
|
||||
LocationName.skiddas_row_dk : [0x65D, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
skiddas_row_region_locations[LocationName.skiddas_row_kong] = []
|
||||
skiddas_row_region = create_region(world, active_locations, LocationName.skiddas_row_region,
|
||||
skiddas_row_region_locations)
|
||||
|
||||
murky_mill_region_locations = {
|
||||
LocationName.murky_mill_flag : [0x65C, 1],
|
||||
LocationName.murky_mill_bonus_1 : [0x65C, 2],
|
||||
LocationName.murky_mill_bonus_2 : [0x65C, 3],
|
||||
LocationName.murky_mill_dk : [0x65C, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
murky_mill_region_locations[LocationName.murky_mill_kong] = []
|
||||
murky_mill_region = create_region(world, active_locations, LocationName.murky_mill_region,
|
||||
murky_mill_region_locations)
|
||||
|
||||
barrel_shield_bust_up_region_locations = {
|
||||
LocationName.barrel_shield_bust_up_flag : [0x662, 1],
|
||||
LocationName.barrel_shield_bust_up_bonus_1 : [0x662, 2],
|
||||
LocationName.barrel_shield_bust_up_bonus_2 : [0x662, 3],
|
||||
LocationName.barrel_shield_bust_up_dk : [0x662, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
barrel_shield_bust_up_region_locations[LocationName.barrel_shield_bust_up_kong] = []
|
||||
barrel_shield_bust_up_region = create_region(world, active_locations,
|
||||
LocationName.barrel_shield_bust_up_region,
|
||||
barrel_shield_bust_up_region_locations)
|
||||
|
||||
riverside_race_region_locations = {
|
||||
LocationName.riverside_race_flag : [0x664, 1],
|
||||
LocationName.riverside_race_bonus_1 : [0x664, 2],
|
||||
LocationName.riverside_race_bonus_2 : [0x664, 3],
|
||||
LocationName.riverside_race_dk : [0x664, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
riverside_race_region_locations[LocationName.riverside_race_kong] = []
|
||||
riverside_race_region = create_region(world, active_locations, LocationName.riverside_race_region,
|
||||
riverside_race_region_locations)
|
||||
|
||||
squeals_on_wheels_region_locations = {
|
||||
LocationName.squeals_on_wheels_flag : [0x65B, 1],
|
||||
LocationName.squeals_on_wheels_bonus_1 : [0x65B, 2],
|
||||
LocationName.squeals_on_wheels_bonus_2 : [0x65B, 3],
|
||||
LocationName.squeals_on_wheels_dk : [0x65B, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
squeals_on_wheels_region_locations[LocationName.squeals_on_wheels_kong] = []
|
||||
squeals_on_wheels_region = create_region(world, active_locations, LocationName.squeals_on_wheels_region,
|
||||
squeals_on_wheels_region_locations)
|
||||
|
||||
springin_spiders_region_locations = {
|
||||
LocationName.springin_spiders_flag : [0x661, 1],
|
||||
LocationName.springin_spiders_bonus_1 : [0x661, 2],
|
||||
LocationName.springin_spiders_bonus_2 : [0x661, 3],
|
||||
LocationName.springin_spiders_dk : [0x661, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
springin_spiders_region_locations[LocationName.springin_spiders_kong] = []
|
||||
springin_spiders_region = create_region(world, active_locations, LocationName.springin_spiders_region,
|
||||
springin_spiders_region_locations)
|
||||
|
||||
bobbing_barrel_brawl_region_locations = {
|
||||
LocationName.bobbing_barrel_brawl_flag : [0x666, 1],
|
||||
LocationName.bobbing_barrel_brawl_bonus_1 : [0x666, 2],
|
||||
LocationName.bobbing_barrel_brawl_bonus_2 : [0x666, 3],
|
||||
LocationName.bobbing_barrel_brawl_dk : [0x666, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
bobbing_barrel_brawl_region_locations[LocationName.bobbing_barrel_brawl_kong] = []
|
||||
bobbing_barrel_brawl_region = create_region(world, active_locations,
|
||||
LocationName.bobbing_barrel_brawl_region,
|
||||
bobbing_barrel_brawl_region_locations)
|
||||
|
||||
bazzas_blockade_region_locations = {
|
||||
LocationName.bazzas_blockade_flag : [0x667, 1],
|
||||
LocationName.bazzas_blockade_bonus_1 : [0x667, 2],
|
||||
LocationName.bazzas_blockade_bonus_2 : [0x667, 3],
|
||||
LocationName.bazzas_blockade_dk : [0x667, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
bazzas_blockade_region_locations[LocationName.bazzas_blockade_kong] = []
|
||||
bazzas_blockade_region = create_region(world, active_locations, LocationName.bazzas_blockade_region,
|
||||
bazzas_blockade_region_locations)
|
||||
|
||||
rocket_barrel_ride_region_locations = {
|
||||
LocationName.rocket_barrel_ride_flag : [0x66A, 1],
|
||||
LocationName.rocket_barrel_ride_bonus_1 : [0x66A, 2],
|
||||
LocationName.rocket_barrel_ride_bonus_2 : [0x66A, 3],
|
||||
LocationName.rocket_barrel_ride_dk : [0x66A, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
rocket_barrel_ride_region_locations[LocationName.rocket_barrel_ride_kong] = []
|
||||
rocket_barrel_ride_region = create_region(world, active_locations, LocationName.rocket_barrel_ride_region,
|
||||
rocket_barrel_ride_region_locations)
|
||||
|
||||
kreeping_klasps_region_locations = {
|
||||
LocationName.kreeping_klasps_flag : [0x658, 1],
|
||||
LocationName.kreeping_klasps_bonus_1 : [0x658, 2],
|
||||
LocationName.kreeping_klasps_bonus_2 : [0x658, 3],
|
||||
LocationName.kreeping_klasps_dk : [0x658, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
kreeping_klasps_region_locations[LocationName.kreeping_klasps_kong] = []
|
||||
kreeping_klasps_region = create_region(world, active_locations, LocationName.kreeping_klasps_region,
|
||||
kreeping_klasps_region_locations)
|
||||
|
||||
tracker_barrel_trek_region_locations = {
|
||||
LocationName.tracker_barrel_trek_flag : [0x66B, 1],
|
||||
LocationName.tracker_barrel_trek_bonus_1 : [0x66B, 2],
|
||||
LocationName.tracker_barrel_trek_bonus_2 : [0x66B, 3],
|
||||
LocationName.tracker_barrel_trek_dk : [0x66B, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
tracker_barrel_trek_region_locations[LocationName.tracker_barrel_trek_kong] = []
|
||||
tracker_barrel_trek_region = create_region(world, active_locations, LocationName.tracker_barrel_trek_region,
|
||||
tracker_barrel_trek_region_locations)
|
||||
|
||||
fish_food_frenzy_region_locations = {
|
||||
LocationName.fish_food_frenzy_flag : [0x668, 1],
|
||||
LocationName.fish_food_frenzy_bonus_1 : [0x668, 2],
|
||||
LocationName.fish_food_frenzy_bonus_2 : [0x668, 3],
|
||||
LocationName.fish_food_frenzy_dk : [0x668, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
fish_food_frenzy_region_locations[LocationName.fish_food_frenzy_kong] = []
|
||||
fish_food_frenzy_region = create_region(world, active_locations, LocationName.fish_food_frenzy_region,
|
||||
fish_food_frenzy_region_locations)
|
||||
|
||||
fire_ball_frenzy_region_locations = {
|
||||
LocationName.fire_ball_frenzy_flag : [0x66D, 1],
|
||||
LocationName.fire_ball_frenzy_bonus_1 : [0x66D, 2],
|
||||
LocationName.fire_ball_frenzy_bonus_2 : [0x66D, 3],
|
||||
LocationName.fire_ball_frenzy_dk : [0x66D, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
fire_ball_frenzy_region_locations[LocationName.fire_ball_frenzy_kong] = []
|
||||
fire_ball_frenzy_region = create_region(world, active_locations, LocationName.fire_ball_frenzy_region,
|
||||
fire_ball_frenzy_region_locations)
|
||||
|
||||
demolition_drain_pipe_region_locations = {
|
||||
LocationName.demolition_drain_pipe_flag : [0x672, 1],
|
||||
LocationName.demolition_drain_pipe_bonus_1 : [0x672, 2],
|
||||
LocationName.demolition_drain_pipe_bonus_2 : [0x672, 3],
|
||||
LocationName.demolition_drain_pipe_dk : [0x672, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
demolition_drain_pipe_region_locations[LocationName.demolition_drain_pipe_kong] = []
|
||||
demolition_drain_pipe_region = create_region(world, active_locations,
|
||||
LocationName.demolition_drain_pipe_region,
|
||||
demolition_drain_pipe_region_locations)
|
||||
|
||||
ripsaw_rage_region_locations = {
|
||||
LocationName.ripsaw_rage_flag : [0x660, 1],
|
||||
LocationName.ripsaw_rage_bonus_1 : [0x660, 2],
|
||||
LocationName.ripsaw_rage_bonus_2 : [0x660, 3],
|
||||
LocationName.ripsaw_rage_dk : [0x660, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
ripsaw_rage_region_locations[LocationName.ripsaw_rage_kong] = []
|
||||
ripsaw_rage_region = create_region(world, active_locations, LocationName.ripsaw_rage_region,
|
||||
ripsaw_rage_region_locations)
|
||||
|
||||
blazing_bazookas_region_locations = {
|
||||
LocationName.blazing_bazookas_flag : [0x66E, 1],
|
||||
LocationName.blazing_bazookas_bonus_1 : [0x66E, 2],
|
||||
LocationName.blazing_bazookas_bonus_2 : [0x66E, 3],
|
||||
LocationName.blazing_bazookas_dk : [0x66E, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
blazing_bazookas_region_locations[LocationName.blazing_bazookas_kong] = []
|
||||
blazing_bazookas_region = create_region(world, active_locations, LocationName.blazing_bazookas_region,
|
||||
blazing_bazookas_region_locations)
|
||||
|
||||
low_g_labyrinth_region_locations = {
|
||||
LocationName.low_g_labyrinth_flag : [0x670, 1],
|
||||
LocationName.low_g_labyrinth_bonus_1 : [0x670, 2],
|
||||
LocationName.low_g_labyrinth_bonus_2 : [0x670, 3],
|
||||
LocationName.low_g_labyrinth_dk : [0x670, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
low_g_labyrinth_region_locations[LocationName.low_g_labyrinth_kong] = []
|
||||
low_g_labyrinth_region = create_region(world, active_locations, LocationName.low_g_labyrinth_region,
|
||||
low_g_labyrinth_region_locations)
|
||||
|
||||
krevice_kreepers_region_locations = {
|
||||
LocationName.krevice_kreepers_flag : [0x673, 1],
|
||||
LocationName.krevice_kreepers_bonus_1 : [0x673, 2],
|
||||
LocationName.krevice_kreepers_bonus_2 : [0x673, 3],
|
||||
LocationName.krevice_kreepers_dk : [0x673, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
krevice_kreepers_region_locations[LocationName.krevice_kreepers_kong] = []
|
||||
krevice_kreepers_region = create_region(world, active_locations, LocationName.krevice_kreepers_region,
|
||||
krevice_kreepers_region_locations)
|
||||
|
||||
tearaway_toboggan_region_locations = {
|
||||
LocationName.tearaway_toboggan_flag : [0x65F, 1],
|
||||
LocationName.tearaway_toboggan_bonus_1 : [0x65F, 2],
|
||||
LocationName.tearaway_toboggan_bonus_2 : [0x65F, 3],
|
||||
LocationName.tearaway_toboggan_dk : [0x65F, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
tearaway_toboggan_region_locations[LocationName.tearaway_toboggan_kong] = []
|
||||
tearaway_toboggan_region = create_region(world, active_locations, LocationName.tearaway_toboggan_region,
|
||||
tearaway_toboggan_region_locations)
|
||||
|
||||
barrel_drop_bounce_region_locations = {
|
||||
LocationName.barrel_drop_bounce_flag : [0x66C, 1],
|
||||
LocationName.barrel_drop_bounce_bonus_1 : [0x66C, 2],
|
||||
LocationName.barrel_drop_bounce_bonus_2 : [0x66C, 3],
|
||||
LocationName.barrel_drop_bounce_dk : [0x66C, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
barrel_drop_bounce_region_locations[LocationName.barrel_drop_bounce_kong] = []
|
||||
barrel_drop_bounce_region = create_region(world, active_locations, LocationName.barrel_drop_bounce_region,
|
||||
barrel_drop_bounce_region_locations)
|
||||
|
||||
krack_shot_kroc_region_locations = {
|
||||
LocationName.krack_shot_kroc_flag : [0x66F, 1],
|
||||
LocationName.krack_shot_kroc_bonus_1 : [0x66F, 2],
|
||||
LocationName.krack_shot_kroc_bonus_2 : [0x66F, 3],
|
||||
LocationName.krack_shot_kroc_dk : [0x66F, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
krack_shot_kroc_region_locations[LocationName.krack_shot_kroc_kong] = []
|
||||
krack_shot_kroc_region = create_region(world, active_locations, LocationName.krack_shot_kroc_region,
|
||||
krack_shot_kroc_region_locations)
|
||||
|
||||
lemguin_lunge_region_locations = {
|
||||
LocationName.lemguin_lunge_flag : [0x65E, 1],
|
||||
LocationName.lemguin_lunge_bonus_1 : [0x65E, 2],
|
||||
LocationName.lemguin_lunge_bonus_2 : [0x65E, 3],
|
||||
LocationName.lemguin_lunge_dk : [0x65E, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
lemguin_lunge_region_locations[LocationName.lemguin_lunge_kong] = []
|
||||
lemguin_lunge_region = create_region(world, active_locations, LocationName.lemguin_lunge_region,
|
||||
lemguin_lunge_region_locations)
|
||||
|
||||
buzzer_barrage_region_locations = {
|
||||
LocationName.buzzer_barrage_flag : [0x676, 1],
|
||||
LocationName.buzzer_barrage_bonus_1 : [0x676, 2],
|
||||
LocationName.buzzer_barrage_bonus_2 : [0x676, 3],
|
||||
LocationName.buzzer_barrage_dk : [0x676, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
buzzer_barrage_region_locations[LocationName.buzzer_barrage_kong] = []
|
||||
buzzer_barrage_region = create_region(world, active_locations, LocationName.buzzer_barrage_region,
|
||||
buzzer_barrage_region_locations)
|
||||
|
||||
kong_fused_cliffs_region_locations = {
|
||||
LocationName.kong_fused_cliffs_flag : [0x674, 1],
|
||||
LocationName.kong_fused_cliffs_bonus_1 : [0x674, 2],
|
||||
LocationName.kong_fused_cliffs_bonus_2 : [0x674, 3],
|
||||
LocationName.kong_fused_cliffs_dk : [0x674, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
kong_fused_cliffs_region_locations[LocationName.kong_fused_cliffs_kong] = []
|
||||
kong_fused_cliffs_region = create_region(world, active_locations, LocationName.kong_fused_cliffs_region,
|
||||
kong_fused_cliffs_region_locations)
|
||||
|
||||
floodlit_fish_region_locations = {
|
||||
LocationName.floodlit_fish_flag : [0x669, 1],
|
||||
LocationName.floodlit_fish_bonus_1 : [0x669, 2],
|
||||
LocationName.floodlit_fish_bonus_2 : [0x669, 3],
|
||||
LocationName.floodlit_fish_dk : [0x669, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
floodlit_fish_region_locations[LocationName.floodlit_fish_kong] = []
|
||||
floodlit_fish_region = create_region(world, active_locations, LocationName.floodlit_fish_region,
|
||||
floodlit_fish_region_locations)
|
||||
|
||||
pothole_panic_region_locations = {
|
||||
LocationName.pothole_panic_flag : [0x677, 1],
|
||||
LocationName.pothole_panic_bonus_1 : [0x677, 2],
|
||||
LocationName.pothole_panic_bonus_2 : [0x677, 3],
|
||||
LocationName.pothole_panic_dk : [0x677, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
pothole_panic_region_locations[LocationName.pothole_panic_kong] = []
|
||||
pothole_panic_region = create_region(world, active_locations, LocationName.pothole_panic_region,
|
||||
pothole_panic_region_locations)
|
||||
|
||||
ropey_rumpus_region_locations = {
|
||||
LocationName.ropey_rumpus_flag : [0x675, 1],
|
||||
LocationName.ropey_rumpus_bonus_1 : [0x675, 2],
|
||||
LocationName.ropey_rumpus_bonus_2 : [0x675, 3],
|
||||
LocationName.ropey_rumpus_dk : [0x675, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
ropey_rumpus_region_locations[LocationName.ropey_rumpus_kong] = []
|
||||
ropey_rumpus_region = create_region(world, active_locations, LocationName.ropey_rumpus_region,
|
||||
ropey_rumpus_region_locations)
|
||||
|
||||
konveyor_rope_clash_region_locations = {
|
||||
LocationName.konveyor_rope_clash_flag : [0x657, 1],
|
||||
LocationName.konveyor_rope_clash_bonus_1 : [0x657, 2],
|
||||
LocationName.konveyor_rope_clash_bonus_2 : [0x657, 3],
|
||||
LocationName.konveyor_rope_clash_dk : [0x657, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
konveyor_rope_clash_region_locations[LocationName.konveyor_rope_clash_kong] = []
|
||||
konveyor_rope_clash_region = create_region(world, active_locations, LocationName.konveyor_rope_clash_region,
|
||||
konveyor_rope_clash_region_locations)
|
||||
|
||||
creepy_caverns_region_locations = {
|
||||
LocationName.creepy_caverns_flag : [0x678, 1],
|
||||
LocationName.creepy_caverns_bonus_1 : [0x678, 2],
|
||||
LocationName.creepy_caverns_bonus_2 : [0x678, 3],
|
||||
LocationName.creepy_caverns_dk : [0x678, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
creepy_caverns_region_locations[LocationName.creepy_caverns_kong] = []
|
||||
creepy_caverns_region = create_region(world, active_locations, LocationName.creepy_caverns_region,
|
||||
creepy_caverns_region_locations)
|
||||
|
||||
lightning_lookout_region_locations = {
|
||||
LocationName.lightning_lookout_flag : [0x665, 1],
|
||||
LocationName.lightning_lookout_bonus_1 : [0x665, 2],
|
||||
LocationName.lightning_lookout_bonus_2 : [0x665, 3],
|
||||
LocationName.lightning_lookout_dk : [0x665, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
lightning_lookout_region_locations[LocationName.lightning_lookout_kong] = []
|
||||
lightning_lookout_region = create_region(world, active_locations, LocationName.lightning_lookout_region,
|
||||
lightning_lookout_region_locations)
|
||||
|
||||
koindozer_klamber_region_locations = {
|
||||
LocationName.koindozer_klamber_flag : [0x679, 1],
|
||||
LocationName.koindozer_klamber_bonus_1 : [0x679, 2],
|
||||
LocationName.koindozer_klamber_bonus_2 : [0x679, 3],
|
||||
LocationName.koindozer_klamber_dk : [0x679, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
koindozer_klamber_region_locations[LocationName.koindozer_klamber_kong] = []
|
||||
koindozer_klamber_region = create_region(world, active_locations, LocationName.koindozer_klamber_region,
|
||||
koindozer_klamber_region_locations)
|
||||
|
||||
poisonous_pipeline_region_locations = {
|
||||
LocationName.poisonous_pipeline_flag : [0x671, 1],
|
||||
LocationName.poisonous_pipeline_bonus_1 : [0x671, 2],
|
||||
LocationName.poisonous_pipeline_bonus_2 : [0x671, 3],
|
||||
LocationName.poisonous_pipeline_dk : [0x671, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
poisonous_pipeline_region_locations[LocationName.poisonous_pipeline_kong] = []
|
||||
poisonous_pipeline_region = create_region(world, active_locations, LocationName.poisonous_pipeline_region,
|
||||
poisonous_pipeline_region_locations)
|
||||
|
||||
stampede_sprint_region_locations = {
|
||||
LocationName.stampede_sprint_flag : [0x67B, 1],
|
||||
LocationName.stampede_sprint_bonus_1 : [0x67B, 2],
|
||||
LocationName.stampede_sprint_bonus_2 : [0x67B, 3],
|
||||
LocationName.stampede_sprint_bonus_3 : [0x67B, 4],
|
||||
LocationName.stampede_sprint_dk : [0x67B, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
stampede_sprint_region_locations[LocationName.stampede_sprint_kong] = []
|
||||
stampede_sprint_region = create_region(world, active_locations, LocationName.stampede_sprint_region,
|
||||
stampede_sprint_region_locations)
|
||||
|
||||
criss_cross_cliffs_region_locations = {
|
||||
LocationName.criss_cross_cliffs_flag : [0x67C, 1],
|
||||
LocationName.criss_cross_cliffs_bonus_1 : [0x67C, 2],
|
||||
LocationName.criss_cross_cliffs_bonus_2 : [0x67C, 3],
|
||||
LocationName.criss_cross_cliffs_dk : [0x67C, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
criss_cross_cliffs_region_locations[LocationName.criss_cross_cliffs_kong] = []
|
||||
criss_cross_cliffs_region = create_region(world, active_locations, LocationName.criss_cross_cliffs_region,
|
||||
criss_cross_cliffs_region_locations)
|
||||
|
||||
tyrant_twin_tussle_region_locations = {
|
||||
LocationName.tyrant_twin_tussle_flag : [0x67D, 1],
|
||||
LocationName.tyrant_twin_tussle_bonus_1 : [0x67D, 2],
|
||||
LocationName.tyrant_twin_tussle_bonus_2 : [0x67D, 3],
|
||||
LocationName.tyrant_twin_tussle_bonus_3 : [0x67D, 4],
|
||||
LocationName.tyrant_twin_tussle_dk : [0x67D, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
tyrant_twin_tussle_region_locations[LocationName.tyrant_twin_tussle_kong] = []
|
||||
tyrant_twin_tussle_region = create_region(world, active_locations, LocationName.tyrant_twin_tussle_region,
|
||||
tyrant_twin_tussle_region_locations)
|
||||
|
||||
swoopy_salvo_region_locations = {
|
||||
LocationName.swoopy_salvo_flag : [0x663, 1],
|
||||
LocationName.swoopy_salvo_bonus_1 : [0x663, 2],
|
||||
LocationName.swoopy_salvo_bonus_2 : [0x663, 3],
|
||||
LocationName.swoopy_salvo_bonus_3 : [0x663, 4],
|
||||
LocationName.swoopy_salvo_dk : [0x663, 5],
|
||||
}
|
||||
if world.options.kongsanity:
|
||||
swoopy_salvo_region_locations[LocationName.swoopy_salvo_kong] = []
|
||||
swoopy_salvo_region = create_region(world, active_locations, LocationName.swoopy_salvo_region,
|
||||
swoopy_salvo_region_locations)
|
||||
|
||||
rocket_rush_region_locations = {
|
||||
LocationName.rocket_rush_flag : [0x67E, 1],
|
||||
LocationName.rocket_rush_dk : [0x67E, 5],
|
||||
}
|
||||
rocket_rush_region = create_region(world, active_locations, LocationName.rocket_rush_region,
|
||||
rocket_rush_region_locations)
|
||||
|
||||
belchas_barn_region_locations = {
|
||||
LocationName.belchas_barn: [0x64F, 1],
|
||||
}
|
||||
belchas_barn_region = create_region(world, active_locations, LocationName.belchas_barn_region,
|
||||
belchas_barn_region_locations)
|
||||
|
||||
arichs_ambush_region_locations = {
|
||||
LocationName.arichs_ambush: [0x650, 1],
|
||||
}
|
||||
arichs_ambush_region = create_region(world, active_locations, LocationName.arichs_ambush_region,
|
||||
arichs_ambush_region_locations)
|
||||
|
||||
squirts_showdown_region_locations = {
|
||||
LocationName.squirts_showdown: [0x651, 1],
|
||||
}
|
||||
squirts_showdown_region = create_region(world, active_locations, LocationName.squirts_showdown_region,
|
||||
squirts_showdown_region_locations)
|
||||
|
||||
kaos_karnage_region_locations = {
|
||||
LocationName.kaos_karnage: [0x652, 1],
|
||||
}
|
||||
kaos_karnage_region = create_region(world, active_locations, LocationName.kaos_karnage_region,
|
||||
kaos_karnage_region_locations)
|
||||
|
||||
bleaks_house_region_locations = {
|
||||
LocationName.bleaks_house: [0x653, 1],
|
||||
}
|
||||
bleaks_house_region = create_region(world, active_locations, LocationName.bleaks_house_region,
|
||||
bleaks_house_region_locations)
|
||||
|
||||
barboss_barrier_region_locations = {
|
||||
LocationName.barboss_barrier: [0x654, 1],
|
||||
}
|
||||
barboss_barrier_region = create_region(world, active_locations, LocationName.barboss_barrier_region,
|
||||
barboss_barrier_region_locations)
|
||||
|
||||
kastle_kaos_region_locations = {
|
||||
LocationName.kastle_kaos: [0x655, 1],
|
||||
}
|
||||
kastle_kaos_region = create_region(world, active_locations, LocationName.kastle_kaos_region,
|
||||
kastle_kaos_region_locations)
|
||||
|
||||
knautilus_region_locations = {
|
||||
LocationName.knautilus: [0x656, 1],
|
||||
}
|
||||
knautilus_region = create_region(world, active_locations, LocationName.knautilus_region,
|
||||
knautilus_region_locations)
|
||||
|
||||
belchas_burrow_region_locations = {
|
||||
LocationName.belchas_burrow: [0x647, 1],
|
||||
}
|
||||
belchas_burrow_region = create_region(world, active_locations, LocationName.belchas_burrow_region,
|
||||
belchas_burrow_region_locations)
|
||||
|
||||
kong_cave_region_locations = {
|
||||
LocationName.kong_cave: [0x645, 1],
|
||||
}
|
||||
kong_cave_region = create_region(world, active_locations, LocationName.kong_cave_region,
|
||||
kong_cave_region_locations)
|
||||
|
||||
undercover_cove_region_locations = {
|
||||
LocationName.undercover_cove: [0x644, 1],
|
||||
}
|
||||
undercover_cove_region = create_region(world, active_locations, LocationName.undercover_cove_region,
|
||||
undercover_cove_region_locations)
|
||||
|
||||
ks_cache_region_locations = {
|
||||
LocationName.ks_cache: [0x642, 1],
|
||||
}
|
||||
ks_cache_region = create_region(world, active_locations, LocationName.ks_cache_region,
|
||||
ks_cache_region_locations)
|
||||
|
||||
hill_top_hoard_region_locations = {
|
||||
LocationName.hill_top_hoard: [0x643, 1],
|
||||
}
|
||||
hill_top_hoard_region = create_region(world, active_locations, LocationName.hill_top_hoard_region,
|
||||
hill_top_hoard_region_locations)
|
||||
|
||||
bounty_beach_region_locations = {
|
||||
LocationName.bounty_beach: [0x646, 1],
|
||||
}
|
||||
bounty_beach_region = create_region(world, active_locations, LocationName.bounty_beach_region,
|
||||
bounty_beach_region_locations)
|
||||
|
||||
smugglers_cove_region_locations = {
|
||||
LocationName.smugglers_cove: [0x648, 1],
|
||||
}
|
||||
smugglers_cove_region = create_region(world, active_locations, LocationName.smugglers_cove_region,
|
||||
smugglers_cove_region_locations)
|
||||
|
||||
arichs_hoard_region_locations = {
|
||||
LocationName.arichs_hoard: [0x649, 1],
|
||||
}
|
||||
arichs_hoard_region = create_region(world, active_locations, LocationName.arichs_hoard_region,
|
||||
arichs_hoard_region_locations)
|
||||
|
||||
bounty_bay_region_locations = {
|
||||
LocationName.bounty_bay: [0x64A, 1],
|
||||
}
|
||||
bounty_bay_region = create_region(world, active_locations, LocationName.bounty_bay_region,
|
||||
bounty_bay_region_locations)
|
||||
|
||||
sky_high_secret_region_locations = {}
|
||||
if False:#world.options.include_trade_sequence:
|
||||
sky_high_secret_region_locations[LocationName.sky_high_secret] = [0x64B, 1]
|
||||
sky_high_secret_region = create_region(world, active_locations, LocationName.sky_high_secret_region,
|
||||
sky_high_secret_region_locations)
|
||||
|
||||
glacial_grotto_region_locations = {
|
||||
LocationName.glacial_grotto: [0x64C, 1],
|
||||
}
|
||||
glacial_grotto_region = create_region(world, active_locations, LocationName.glacial_grotto_region,
|
||||
glacial_grotto_region_locations)
|
||||
|
||||
cifftop_cache_region_locations = {}
|
||||
if False:#world.options.include_trade_sequence:
|
||||
cifftop_cache_region_locations[LocationName.cifftop_cache] = [0x64D, 1]
|
||||
cifftop_cache_region = create_region(world, active_locations, LocationName.cifftop_cache_region,
|
||||
cifftop_cache_region_locations)
|
||||
|
||||
sewer_stockpile_region_locations = {
|
||||
LocationName.sewer_stockpile: [0x64E, 1],
|
||||
}
|
||||
sewer_stockpile_region = create_region(world, active_locations, LocationName.sewer_stockpile_region,
|
||||
sewer_stockpile_region_locations)
|
||||
|
||||
|
||||
# Set up the regions correctly.
|
||||
world.multiworld.regions += [
|
||||
menu_region,
|
||||
overworld_1_region,
|
||||
overworld_2_region,
|
||||
overworld_3_region,
|
||||
overworld_4_region,
|
||||
lake_orangatanga_region,
|
||||
kremwood_forest_region,
|
||||
cotton_top_cove_region,
|
||||
mekanos_region,
|
||||
k3_region,
|
||||
razor_ridge_region,
|
||||
kaos_kore_region,
|
||||
krematoa_region,
|
||||
lakeside_limbo_region,
|
||||
doorstop_dash_region,
|
||||
tidal_trouble_region,
|
||||
skiddas_row_region,
|
||||
murky_mill_region,
|
||||
barrel_shield_bust_up_region,
|
||||
riverside_race_region,
|
||||
squeals_on_wheels_region,
|
||||
springin_spiders_region,
|
||||
bobbing_barrel_brawl_region,
|
||||
bazzas_blockade_region,
|
||||
rocket_barrel_ride_region,
|
||||
kreeping_klasps_region,
|
||||
tracker_barrel_trek_region,
|
||||
fish_food_frenzy_region,
|
||||
fire_ball_frenzy_region,
|
||||
demolition_drain_pipe_region,
|
||||
ripsaw_rage_region,
|
||||
blazing_bazookas_region,
|
||||
low_g_labyrinth_region,
|
||||
krevice_kreepers_region,
|
||||
tearaway_toboggan_region,
|
||||
barrel_drop_bounce_region,
|
||||
krack_shot_kroc_region,
|
||||
lemguin_lunge_region,
|
||||
buzzer_barrage_region,
|
||||
kong_fused_cliffs_region,
|
||||
floodlit_fish_region,
|
||||
pothole_panic_region,
|
||||
ropey_rumpus_region,
|
||||
konveyor_rope_clash_region,
|
||||
creepy_caverns_region,
|
||||
lightning_lookout_region,
|
||||
koindozer_klamber_region,
|
||||
poisonous_pipeline_region,
|
||||
stampede_sprint_region,
|
||||
criss_cross_cliffs_region,
|
||||
tyrant_twin_tussle_region,
|
||||
swoopy_salvo_region,
|
||||
rocket_rush_region,
|
||||
belchas_barn_region,
|
||||
arichs_ambush_region,
|
||||
squirts_showdown_region,
|
||||
kaos_karnage_region,
|
||||
bleaks_house_region,
|
||||
barboss_barrier_region,
|
||||
kastle_kaos_region,
|
||||
knautilus_region,
|
||||
belchas_burrow_region,
|
||||
kong_cave_region,
|
||||
undercover_cove_region,
|
||||
ks_cache_region,
|
||||
hill_top_hoard_region,
|
||||
bounty_beach_region,
|
||||
smugglers_cove_region,
|
||||
arichs_hoard_region,
|
||||
bounty_bay_region,
|
||||
sky_high_secret_region,
|
||||
glacial_grotto_region,
|
||||
cifftop_cache_region,
|
||||
sewer_stockpile_region,
|
||||
]
|
||||
|
||||
bazaar_region_locations = {}
|
||||
bramble_region_locations = {}
|
||||
flower_spot_region_locations = {}
|
||||
barter_region_locations = {}
|
||||
barnacle_region_locations = {}
|
||||
blue_region_locations = {}
|
||||
blizzard_region_locations = {}
|
||||
|
||||
if False:#world.options.include_trade_sequence:
|
||||
bazaar_region_locations.update({
|
||||
LocationName.bazaars_general_store_1: [0x615, 2, True],
|
||||
LocationName.bazaars_general_store_2: [0x615, 3, True],
|
||||
})
|
||||
|
||||
bramble_region_locations[LocationName.brambles_bungalow] = [0x619, 2]
|
||||
|
||||
#flower_spot_region_locations.update({
|
||||
# LocationName.flower_spot: [0x615, 3, True],
|
||||
#})
|
||||
|
||||
barter_region_locations[LocationName.barters_swap_shop] = [0x61B, 3]
|
||||
|
||||
barnacle_region_locations[LocationName.barnacles_island] = [0x61D, 2]
|
||||
|
||||
blue_region_locations[LocationName.blues_beach_hut] = [0x621, 4]
|
||||
|
||||
blizzard_region_locations[LocationName.blizzards_basecamp] = [0x625, 4, True]
|
||||
|
||||
bazaar_region = create_region(world, active_locations, LocationName.bazaar_region, bazaar_region_locations)
|
||||
bramble_region = create_region(world, active_locations, LocationName.bramble_region,
|
||||
bramble_region_locations)
|
||||
flower_spot_region = create_region(world, active_locations, LocationName.flower_spot_region,
|
||||
flower_spot_region_locations)
|
||||
barter_region = create_region(world, active_locations, LocationName.barter_region, barter_region_locations)
|
||||
barnacle_region = create_region(world, active_locations, LocationName.barnacle_region,
|
||||
barnacle_region_locations)
|
||||
blue_region = create_region(world, active_locations, LocationName.blue_region, blue_region_locations)
|
||||
blizzard_region = create_region(world, active_locations, LocationName.blizzard_region,
|
||||
blizzard_region_locations)
|
||||
|
||||
world.multiworld.regions += [
|
||||
bazaar_region,
|
||||
bramble_region,
|
||||
flower_spot_region,
|
||||
barter_region,
|
||||
barnacle_region,
|
||||
blue_region,
|
||||
blizzard_region,
|
||||
]
|
||||
|
||||
|
||||
def connect_regions(world: World, level_list):
|
||||
names: typing.Dict[str, int] = {}
|
||||
|
||||
# Overworld
|
||||
connect(world, world.player, names, 'Menu', LocationName.overworld_1_region)
|
||||
connect(world, world.player, names, LocationName.overworld_1_region, LocationName.overworld_2_region,
|
||||
lambda state: (state.has(ItemName.progressive_boat, world.player, 1)))
|
||||
connect(world, world.player, names, LocationName.overworld_2_region, LocationName.overworld_3_region,
|
||||
lambda state: (state.has(ItemName.progressive_boat, world.player, 3)))
|
||||
connect(world, world.player, names, LocationName.overworld_1_region, LocationName.overworld_4_region,
|
||||
lambda state: (state.has(ItemName.dk_coin, world.player, world.options.dk_coins_for_gyrocopter.value) and
|
||||
state.has(ItemName.progressive_boat, world.player, 3)))
|
||||
|
||||
# World Connections
|
||||
connect(world, world.player, names, LocationName.overworld_1_region, LocationName.lake_orangatanga_region)
|
||||
connect(world, world.player, names, LocationName.overworld_1_region, LocationName.kremwood_forest_region)
|
||||
connect(world, world.player, names, LocationName.overworld_1_region, LocationName.bounty_beach_region)
|
||||
connect(world, world.player, names, LocationName.overworld_1_region, LocationName.bazaar_region)
|
||||
|
||||
connect(world, world.player, names, LocationName.overworld_2_region, LocationName.cotton_top_cove_region)
|
||||
connect(world, world.player, names, LocationName.overworld_2_region, LocationName.mekanos_region)
|
||||
connect(world, world.player, names, LocationName.overworld_2_region, LocationName.kong_cave_region)
|
||||
connect(world, world.player, names, LocationName.overworld_2_region, LocationName.bramble_region)
|
||||
|
||||
connect(world, world.player, names, LocationName.overworld_3_region, LocationName.k3_region)
|
||||
connect(world, world.player, names, LocationName.overworld_3_region, LocationName.razor_ridge_region)
|
||||
connect(world, world.player, names, LocationName.overworld_3_region, LocationName.kaos_kore_region)
|
||||
connect(world, world.player, names, LocationName.overworld_3_region, LocationName.krematoa_region)
|
||||
connect(world, world.player, names, LocationName.overworld_3_region, LocationName.undercover_cove_region)
|
||||
connect(world, world.player, names, LocationName.overworld_3_region, LocationName.flower_spot_region)
|
||||
connect(world, world.player, names, LocationName.overworld_3_region, LocationName.barter_region)
|
||||
|
||||
connect(world, world.player, names, LocationName.overworld_4_region, LocationName.belchas_burrow_region)
|
||||
connect(world, world.player, names, LocationName.overworld_4_region, LocationName.ks_cache_region)
|
||||
connect(world, world.player, names, LocationName.overworld_4_region, LocationName.hill_top_hoard_region)
|
||||
|
||||
|
||||
# Lake Orangatanga Connections
|
||||
lake_orangatanga_levels = [
|
||||
level_list[0],
|
||||
level_list[1],
|
||||
level_list[2],
|
||||
level_list[3],
|
||||
level_list[4],
|
||||
LocationName.belchas_barn_region,
|
||||
LocationName.barnacle_region,
|
||||
LocationName.smugglers_cove_region,
|
||||
]
|
||||
|
||||
for i in range(0, len(lake_orangatanga_levels)):
|
||||
connect(world, world.player, names, LocationName.lake_orangatanga_region, lake_orangatanga_levels[i])
|
||||
|
||||
# Kremwood Forest Connections
|
||||
kremwood_forest_levels = [
|
||||
level_list[5],
|
||||
level_list[6],
|
||||
level_list[7],
|
||||
level_list[8],
|
||||
level_list[9],
|
||||
LocationName.arichs_ambush_region,
|
||||
LocationName.arichs_hoard_region,
|
||||
]
|
||||
|
||||
for i in range(0, len(kremwood_forest_levels) - 1):
|
||||
connect(world, world.player, names, LocationName.kremwood_forest_region, kremwood_forest_levels[i])
|
||||
|
||||
connection = connect(world, world.player, names, LocationName.kremwood_forest_region, kremwood_forest_levels[-1],
|
||||
lambda state: (state.can_reach(LocationName.riverside_race_flag, "Location", world.player)))
|
||||
world.multiworld.register_indirect_condition(world.get_location(LocationName.riverside_race_flag).parent_region,
|
||||
connection)
|
||||
|
||||
# Cotton-Top Cove Connections
|
||||
cotton_top_cove_levels = [
|
||||
LocationName.blue_region,
|
||||
level_list[10],
|
||||
level_list[11],
|
||||
level_list[12],
|
||||
level_list[13],
|
||||
level_list[14],
|
||||
LocationName.squirts_showdown_region,
|
||||
LocationName.bounty_bay_region,
|
||||
]
|
||||
|
||||
for i in range(0, len(cotton_top_cove_levels)):
|
||||
connect(world, world.player, names, LocationName.cotton_top_cove_region, cotton_top_cove_levels[i])
|
||||
|
||||
# Mekanos Connections
|
||||
mekanos_levels = [
|
||||
level_list[15],
|
||||
level_list[16],
|
||||
level_list[17],
|
||||
level_list[18],
|
||||
level_list[19],
|
||||
LocationName.kaos_karnage_region,
|
||||
]
|
||||
|
||||
for i in range(0, len(mekanos_levels)):
|
||||
connect(world, world.player, names, LocationName.mekanos_region, mekanos_levels[i])
|
||||
|
||||
if False:#world.options.include_trade_sequence:
|
||||
connect(world, world.player, names, LocationName.mekanos_region, LocationName.sky_high_secret_region,
|
||||
lambda state: (state.has(ItemName.bowling_ball, world.player, 1)))
|
||||
else:
|
||||
connection = connect(world, world.player, names, LocationName.mekanos_region,
|
||||
LocationName.sky_high_secret_region,
|
||||
lambda state: (state.can_reach(LocationName.bleaks_house, "Location", world.player)))
|
||||
world.multiworld.register_indirect_condition(world.get_location(LocationName.bleaks_house).parent_region,
|
||||
connection)
|
||||
|
||||
# K3 Connections
|
||||
k3_levels = [
|
||||
level_list[20],
|
||||
level_list[21],
|
||||
level_list[22],
|
||||
level_list[23],
|
||||
level_list[24],
|
||||
LocationName.bleaks_house_region,
|
||||
LocationName.blizzard_region,
|
||||
LocationName.glacial_grotto_region,
|
||||
]
|
||||
|
||||
for i in range(0, len(k3_levels)):
|
||||
connect(world, world.player, names, LocationName.k3_region, k3_levels[i])
|
||||
|
||||
# Razor Ridge Connections
|
||||
razor_ridge_levels = [
|
||||
level_list[25],
|
||||
level_list[26],
|
||||
level_list[27],
|
||||
level_list[28],
|
||||
level_list[29],
|
||||
LocationName.barboss_barrier_region,
|
||||
]
|
||||
|
||||
for i in range(0, len(razor_ridge_levels)):
|
||||
connect(world, world.player, names, LocationName.razor_ridge_region, razor_ridge_levels[i])
|
||||
|
||||
if False:#world.options.include_trade_sequence:
|
||||
connect(world, world.player, names, LocationName.razor_ridge_region, LocationName.cifftop_cache_region,
|
||||
lambda state: (state.has(ItemName.wrench, world.player, 1)))
|
||||
else:
|
||||
connect(world, world.player, names, LocationName.razor_ridge_region, LocationName.cifftop_cache_region)
|
||||
|
||||
# KAOS Kore Connections
|
||||
kaos_kore_levels = [
|
||||
level_list[30],
|
||||
level_list[31],
|
||||
level_list[32],
|
||||
level_list[33],
|
||||
level_list[34],
|
||||
LocationName.sewer_stockpile_region,
|
||||
]
|
||||
|
||||
for i in range(0, len(kaos_kore_levels)):
|
||||
connect(world, world.player, names, LocationName.kaos_kore_region, kaos_kore_levels[i])
|
||||
|
||||
# Krematoa Connections
|
||||
krematoa_levels = [
|
||||
level_list[35],
|
||||
level_list[36],
|
||||
level_list[37],
|
||||
level_list[38],
|
||||
LocationName.rocket_rush_region,
|
||||
]
|
||||
|
||||
for i in range(0, len(krematoa_levels)):
|
||||
connect(world, world.player, names, LocationName.krematoa_region, krematoa_levels[i],
|
||||
lambda state, i=i: (state.has(ItemName.bonus_coin, world.player, world.options.krematoa_bonus_coin_cost.value * (i+1))))
|
||||
|
||||
if world.options.goal == "knautilus":
|
||||
connect(world, world.player, names, LocationName.kaos_kore_region, LocationName.knautilus_region)
|
||||
connect(world, world.player, names, LocationName.krematoa_region, LocationName.kastle_kaos_region,
|
||||
lambda state: (state.has(ItemName.krematoa_cog, world.player, 5)))
|
||||
else:
|
||||
connect(world, world.player, names, LocationName.kaos_kore_region, LocationName.kastle_kaos_region)
|
||||
connect(world, world.player, names, LocationName.krematoa_region, LocationName.knautilus_region,
|
||||
lambda state: (state.has(ItemName.krematoa_cog, world.player, 5)))
|
||||
|
||||
|
||||
def create_region(world: World, active_locations, name: str, locations=None):
|
||||
# Shamelessly stolen from the ROR2 definition
|
||||
ret = Region(name, world.player, world.multiworld)
|
||||
if locations:
|
||||
for locationName, locationData in locations.items():
|
||||
loc_id = active_locations.get(locationName, 0)
|
||||
if loc_id:
|
||||
loc_byte = locationData[0] if (len(locationData) > 0) else 0
|
||||
loc_bit = locationData[1] if (len(locationData) > 1) else 0
|
||||
loc_invert = locationData[2] if (len(locationData) > 2) else False
|
||||
|
||||
location = DKC3Location(world.player, locationName, loc_id, ret, loc_byte, loc_bit, loc_invert)
|
||||
ret.locations.append(location)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def connect(world: World, player: int, used_names: typing.Dict[str, int], source: str, target: str,
|
||||
rule: typing.Optional[typing.Callable] = None):
|
||||
source_region = world.multiworld.get_region(source, player)
|
||||
target_region = world.multiworld.get_region(target, player)
|
||||
|
||||
if target not in used_names:
|
||||
used_names[target] = 1
|
||||
name = target
|
||||
else:
|
||||
used_names[target] += 1
|
||||
name = target + (' ' * used_names[target])
|
||||
|
||||
connection = Entrance(player, name, source_region)
|
||||
|
||||
if rule:
|
||||
connection.access_rule = rule
|
||||
|
||||
source_region.exits.append(connection)
|
||||
connection.connect(target_region)
|
||||
return connection
|
||||
@@ -1,744 +0,0 @@
|
||||
|
||||
import Utils
|
||||
from Utils import read_snes_rom
|
||||
from worlds.AutoWorld import World
|
||||
from worlds.Files import APDeltaPatch
|
||||
from .Levels import level_list, level_dict
|
||||
|
||||
USHASH = '120abf304f0c40fe059f6a192ed4f947'
|
||||
ROM_PLAYER_LIMIT = 65535
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import math
|
||||
|
||||
|
||||
level_unlock_map = {
|
||||
0x657: [0x65A],
|
||||
0x65A: [0x680, 0x639, 0x659],
|
||||
0x659: [0x65D],
|
||||
0x65D: [0x65C],
|
||||
0x65C: [0x688, 0x64F],
|
||||
|
||||
0x662: [0x681, 0x664],
|
||||
0x664: [0x65B],
|
||||
0x65B: [0x689, 0x661],
|
||||
0x661: [0x63A, 0x666],
|
||||
0x666: [0x650, 0x649],
|
||||
|
||||
0x667: [0x66A],
|
||||
0x66A: [0x682, 0x658],
|
||||
0x658: [0x68A, 0x66B],
|
||||
0x66B: [0x668],
|
||||
0x668: [0x651],
|
||||
|
||||
0x66D: [0x63C, 0x672],
|
||||
0x672: [0x68B, 0x660],
|
||||
0x660: [0x683, 0x66E],
|
||||
0x66E: [0x670],
|
||||
0x670: [0x652],
|
||||
|
||||
0x673: [0x684, 0x65F],
|
||||
0x65F: [0x66C],
|
||||
0x66C: [0x66F],
|
||||
0x66F: [0x65E],
|
||||
0x65E: [0x63D, 0x653, 0x68C, 0x64C],
|
||||
|
||||
0x676: [0x63E, 0x674, 0x685],
|
||||
0x674: [0x63F, 0x669],
|
||||
0x669: [0x677],
|
||||
0x677: [0x68D, 0x675],
|
||||
0x675: [0x654],
|
||||
|
||||
0x67A: [0x640, 0x678],
|
||||
0x678: [0x665],
|
||||
0x665: [0x686, 0x679],
|
||||
0x679: [0x68E, 0x671],
|
||||
|
||||
0x67B: [0x67C],
|
||||
0x67C: [0x67D],
|
||||
0x67D: [0x663],
|
||||
0x663: [0x67E],
|
||||
}
|
||||
|
||||
location_rom_data = {
|
||||
0xDC3000: [0x657, 1], # Lakeside Limbo
|
||||
0xDC3001: [0x657, 2],
|
||||
0xDC3002: [0x657, 3],
|
||||
0xDC3003: [0x657, 5],
|
||||
0xDC3100: [0x657, 7],
|
||||
|
||||
0xDC3004: [0x65A, 1], # Doorstop Dash
|
||||
0xDC3005: [0x65A, 2],
|
||||
0xDC3006: [0x65A, 3],
|
||||
0xDC3007: [0x65A, 5],
|
||||
0xDC3104: [0x65A, 7],
|
||||
|
||||
0xDC3008: [0x659, 1], # Tidal Trouble
|
||||
0xDC3009: [0x659, 2],
|
||||
0xDC300A: [0x659, 3],
|
||||
0xDC300B: [0x659, 5],
|
||||
0xDC3108: [0x659, 7],
|
||||
|
||||
0xDC300C: [0x65D, 1], # Skidda's Row
|
||||
0xDC300D: [0x65D, 2],
|
||||
0xDC300E: [0x65D, 3],
|
||||
0xDC300F: [0x65D, 5],
|
||||
0xDC310C: [0x65D, 7],
|
||||
|
||||
0xDC3010: [0x65C, 1], # Murky Mill
|
||||
0xDC3011: [0x65C, 2],
|
||||
0xDC3012: [0x65C, 3],
|
||||
0xDC3013: [0x65C, 5],
|
||||
0xDC3110: [0x65C, 7],
|
||||
|
||||
|
||||
0xDC3014: [0x662, 1], # Barrel Shield Bust-Up
|
||||
0xDC3015: [0x662, 2],
|
||||
0xDC3016: [0x662, 3],
|
||||
0xDC3017: [0x662, 5],
|
||||
0xDC3114: [0x662, 7],
|
||||
|
||||
0xDC3018: [0x664, 1], # Riverside Race
|
||||
0xDC3019: [0x664, 2],
|
||||
0xDC301A: [0x664, 3],
|
||||
0xDC301B: [0x664, 5],
|
||||
0xDC3118: [0x664, 7],
|
||||
|
||||
0xDC301C: [0x65B, 1], # Squeals on Wheels
|
||||
0xDC301D: [0x65B, 2],
|
||||
0xDC301E: [0x65B, 3],
|
||||
0xDC301F: [0x65B, 5],
|
||||
0xDC311C: [0x65B, 7],
|
||||
|
||||
0xDC3020: [0x661, 1], # Springin' Spiders
|
||||
0xDC3021: [0x661, 2],
|
||||
0xDC3022: [0x661, 3],
|
||||
0xDC3023: [0x661, 5],
|
||||
0xDC3120: [0x661, 7],
|
||||
|
||||
0xDC3024: [0x666, 1], # Bobbing Barrel Brawl
|
||||
0xDC3025: [0x666, 2],
|
||||
0xDC3026: [0x666, 3],
|
||||
0xDC3027: [0x666, 5],
|
||||
0xDC3124: [0x666, 7],
|
||||
|
||||
|
||||
0xDC3028: [0x667, 1], # Bazza's Blockade
|
||||
0xDC3029: [0x667, 2],
|
||||
0xDC302A: [0x667, 3],
|
||||
0xDC302B: [0x667, 5],
|
||||
0xDC3128: [0x667, 7],
|
||||
|
||||
0xDC302C: [0x66A, 1], # Rocket Barrel Ride
|
||||
0xDC302D: [0x66A, 2],
|
||||
0xDC302E: [0x66A, 3],
|
||||
0xDC302F: [0x66A, 5],
|
||||
0xDC312C: [0x66A, 7],
|
||||
|
||||
0xDC3030: [0x658, 1], # Kreeping Klasps
|
||||
0xDC3031: [0x658, 2],
|
||||
0xDC3032: [0x658, 3],
|
||||
0xDC3033: [0x658, 5],
|
||||
0xDC3130: [0x658, 7],
|
||||
|
||||
0xDC3034: [0x66B, 1], # Tracker Barrel Trek
|
||||
0xDC3035: [0x66B, 2],
|
||||
0xDC3036: [0x66B, 3],
|
||||
0xDC3037: [0x66B, 5],
|
||||
0xDC3134: [0x66B, 7],
|
||||
|
||||
0xDC3038: [0x668, 1], # Fish Food Frenzy
|
||||
0xDC3039: [0x668, 2],
|
||||
0xDC303A: [0x668, 3],
|
||||
0xDC303B: [0x668, 5],
|
||||
0xDC3138: [0x668, 7],
|
||||
|
||||
|
||||
0xDC303C: [0x66D, 1], # Fire-ball Frenzy
|
||||
0xDC303D: [0x66D, 2],
|
||||
0xDC303E: [0x66D, 3],
|
||||
0xDC303F: [0x66D, 5],
|
||||
0xDC313C: [0x66D, 7],
|
||||
|
||||
0xDC3040: [0x672, 1], # Demolition Drainpipe
|
||||
0xDC3041: [0x672, 2],
|
||||
0xDC3042: [0x672, 3],
|
||||
0xDC3043: [0x672, 5],
|
||||
0xDC3140: [0x672, 7],
|
||||
|
||||
0xDC3044: [0x660, 1], # Ripsaw Rage
|
||||
0xDC3045: [0x660, 2],
|
||||
0xDC3046: [0x660, 3],
|
||||
0xDC3047: [0x660, 5],
|
||||
0xDC3144: [0x660, 7],
|
||||
|
||||
0xDC3048: [0x66E, 1], # Blazing Bazukas
|
||||
0xDC3049: [0x66E, 2],
|
||||
0xDC304A: [0x66E, 3],
|
||||
0xDC304B: [0x66E, 5],
|
||||
0xDC3148: [0x66E, 7],
|
||||
|
||||
0xDC304C: [0x670, 1], # Low-G Labyrinth
|
||||
0xDC304D: [0x670, 2],
|
||||
0xDC304E: [0x670, 3],
|
||||
0xDC304F: [0x670, 5],
|
||||
0xDC314C: [0x670, 7],
|
||||
|
||||
|
||||
0xDC3050: [0x673, 1], # Krevice Kreepers
|
||||
0xDC3051: [0x673, 2],
|
||||
0xDC3052: [0x673, 3],
|
||||
0xDC3053: [0x673, 5],
|
||||
0xDC3150: [0x673, 7],
|
||||
|
||||
0xDC3054: [0x65F, 1], # Tearaway Toboggan
|
||||
0xDC3055: [0x65F, 2],
|
||||
0xDC3056: [0x65F, 3],
|
||||
0xDC3057: [0x65F, 5],
|
||||
0xDC3154: [0x65F, 7],
|
||||
|
||||
0xDC3058: [0x66C, 1], # Barrel Drop Bounce
|
||||
0xDC3059: [0x66C, 2],
|
||||
0xDC305A: [0x66C, 3],
|
||||
0xDC305B: [0x66C, 5],
|
||||
0xDC3158: [0x66C, 7],
|
||||
|
||||
0xDC305C: [0x66F, 1], # Krack-Shot Kroc
|
||||
0xDC305D: [0x66F, 2],
|
||||
0xDC305E: [0x66F, 3],
|
||||
0xDC305F: [0x66F, 5],
|
||||
0xDC315C: [0x66F, 7],
|
||||
|
||||
0xDC3060: [0x65E, 1], # Lemguin Lunge
|
||||
0xDC3061: [0x65E, 2],
|
||||
0xDC3062: [0x65E, 3],
|
||||
0xDC3063: [0x65E, 5],
|
||||
0xDC3160: [0x65E, 7],
|
||||
|
||||
|
||||
0xDC3064: [0x676, 1], # Buzzer Barrage
|
||||
0xDC3065: [0x676, 2],
|
||||
0xDC3066: [0x676, 3],
|
||||
0xDC3067: [0x676, 5],
|
||||
0xDC3164: [0x676, 7],
|
||||
|
||||
0xDC3068: [0x674, 1], # Kong-Fused Cliffs
|
||||
0xDC3069: [0x674, 2],
|
||||
0xDC306A: [0x674, 3],
|
||||
0xDC306B: [0x674, 5],
|
||||
0xDC3168: [0x674, 7],
|
||||
|
||||
0xDC306C: [0x669, 1], # Floodlit Fish
|
||||
0xDC306D: [0x669, 2],
|
||||
0xDC306E: [0x669, 3],
|
||||
0xDC306F: [0x669, 5],
|
||||
0xDC316C: [0x669, 7],
|
||||
|
||||
0xDC3070: [0x677, 1], # Pothole Panic
|
||||
0xDC3071: [0x677, 2],
|
||||
0xDC3072: [0x677, 3],
|
||||
0xDC3073: [0x677, 5],
|
||||
0xDC3170: [0x677, 7],
|
||||
|
||||
0xDC3074: [0x675, 1], # Ropey Rumpus
|
||||
0xDC3075: [0x675, 2],
|
||||
0xDC3076: [0x675, 3],
|
||||
0xDC3077: [0x675, 5],
|
||||
0xDC3174: [0x675, 7],
|
||||
|
||||
|
||||
0xDC3078: [0x67A, 1], # Konveyor Rope Klash
|
||||
0xDC3079: [0x67A, 2],
|
||||
0xDC307A: [0x67A, 3],
|
||||
0xDC307B: [0x67A, 5],
|
||||
0xDC3178: [0x67A, 7],
|
||||
|
||||
0xDC307C: [0x678, 1], # Creepy Caverns
|
||||
0xDC307D: [0x678, 2],
|
||||
0xDC307E: [0x678, 3],
|
||||
0xDC307F: [0x678, 5],
|
||||
0xDC317C: [0x678, 7],
|
||||
|
||||
0xDC3080: [0x665, 1], # Lightning Lookout
|
||||
0xDC3081: [0x665, 2],
|
||||
0xDC3082: [0x665, 3],
|
||||
0xDC3083: [0x665, 5],
|
||||
0xDC3180: [0x665, 7],
|
||||
|
||||
0xDC3084: [0x679, 1], # Koindozer Klamber
|
||||
0xDC3085: [0x679, 2],
|
||||
0xDC3086: [0x679, 3],
|
||||
0xDC3087: [0x679, 5],
|
||||
0xDC3184: [0x679, 7],
|
||||
|
||||
0xDC3088: [0x671, 1], # Poisonous Pipeline
|
||||
0xDC3089: [0x671, 2],
|
||||
0xDC308A: [0x671, 3],
|
||||
0xDC308B: [0x671, 5],
|
||||
0xDC3188: [0x671, 7],
|
||||
|
||||
|
||||
0xDC308C: [0x67B, 1], # Stampede Sprint
|
||||
0xDC308D: [0x67B, 2],
|
||||
0xDC308E: [0x67B, 3],
|
||||
0xDC308F: [0x67B, 4],
|
||||
0xDC3090: [0x67B, 5],
|
||||
0xDC318C: [0x67B, 7],
|
||||
|
||||
0xDC3091: [0x67C, 1], # Criss Kross Cliffs
|
||||
0xDC3092: [0x67C, 2],
|
||||
0xDC3093: [0x67C, 3],
|
||||
0xDC3094: [0x67C, 5],
|
||||
0xDC3191: [0x67C, 7],
|
||||
|
||||
0xDC3095: [0x67D, 1], # Tyrant Twin Tussle
|
||||
0xDC3096: [0x67D, 2],
|
||||
0xDC3097: [0x67D, 3],
|
||||
0xDC3098: [0x67D, 4],
|
||||
0xDC3099: [0x67D, 5],
|
||||
0xDC3195: [0x67D, 7],
|
||||
|
||||
0xDC309A: [0x663, 1], # Swoopy Salvo
|
||||
0xDC309B: [0x663, 2],
|
||||
0xDC309C: [0x663, 3],
|
||||
0xDC309D: [0x663, 4],
|
||||
0xDC309E: [0x663, 5],
|
||||
0xDC319A: [0x663, 7],
|
||||
|
||||
0xDC309F: [0x67E, 1], # Rocket Rush
|
||||
0xDC30A0: [0x67E, 5],
|
||||
|
||||
0xDC30A1: [0x64F, 1], # Bosses
|
||||
0xDC30A2: [0x650, 1],
|
||||
0xDC30A3: [0x651, 1],
|
||||
0xDC30A4: [0x652, 1],
|
||||
0xDC30A5: [0x653, 1],
|
||||
0xDC30A6: [0x654, 1],
|
||||
0xDC30A7: [0x655, 1],
|
||||
0xDC30A8: [0x656, 1],
|
||||
|
||||
0xDC30A9: [0x647, 1], # Banana Bird Caves
|
||||
0xDC30AA: [0x645, 1],
|
||||
0xDC30AB: [0x644, 1],
|
||||
0xDC30AC: [0x642, 1],
|
||||
0xDC30AD: [0x643, 1],
|
||||
0xDC30AE: [0x646, 1],
|
||||
0xDC30AF: [0x648, 1],
|
||||
0xDC30B0: [0x649, 1],
|
||||
0xDC30B1: [0x64A, 1],
|
||||
#0xDC30B2: [0x64B, 1], # Disabled until Trade Sequence
|
||||
0xDC30B3: [0x64C, 1],
|
||||
#0xDC30B4: [0x64D, 1], # Disabled until Trade Sequence
|
||||
0xDC30B5: [0x64E, 1],
|
||||
|
||||
0xDC30B6: [0x5FE, 4], # Banana Bird Mother
|
||||
|
||||
# DKC3_TODO: Disabled until Trade Sequence
|
||||
#0xDC30B7: [0x615, 2, True],
|
||||
#0xDC30B8: [0x615, 3, True],
|
||||
#0xDC30B9: [0x619, 2],
|
||||
##0xDC30BA:
|
||||
#0xDC30BB: [0x61B, 3],
|
||||
#0xDC30BC: [0x61D, 2],
|
||||
#0xDC30BD: [0x621, 4],
|
||||
#0xDC30BE: [0x625, 4, True],
|
||||
}
|
||||
|
||||
boss_location_ids = [
|
||||
0xDC30A1,
|
||||
0xDC30A2,
|
||||
0xDC30A3,
|
||||
0xDC30A4,
|
||||
0xDC30A5,
|
||||
0xDC30A6,
|
||||
0xDC30A7,
|
||||
0xDC30A8,
|
||||
0xDC30B6,
|
||||
]
|
||||
|
||||
|
||||
item_rom_data = {
|
||||
0xDC3001: [0x5D5], # 1-Up Balloon
|
||||
0xDC3002: [0x5C9], # Bear Coin
|
||||
0xDC3003: [0x5CB], # Bonus Coin
|
||||
0xDC3004: [0x5CF], # DK Coin
|
||||
0xDC3005: [0x5CD], # Banana Bird
|
||||
0xDC3006: [0x5D1, 0x603], # Cog
|
||||
}
|
||||
|
||||
music_rom_data = [
|
||||
0x3D06B1,
|
||||
0x3D0753,
|
||||
0x3D071D,
|
||||
0x3D07FA,
|
||||
0x3D07C4,
|
||||
|
||||
0x3D08FE,
|
||||
0x3D096C,
|
||||
0x3D078E,
|
||||
0x3D08CD,
|
||||
0x3D09DD,
|
||||
|
||||
0x3D0A0E,
|
||||
0x3D0AB3,
|
||||
0x3D06E7,
|
||||
0x3D0AE4,
|
||||
0x3D0A45,
|
||||
|
||||
0x3D0B46,
|
||||
0x3D0C40,
|
||||
0x3D0897,
|
||||
0x3D0B77,
|
||||
0x3D0BD9,
|
||||
|
||||
0x3D0C71,
|
||||
0x3D0866,
|
||||
0x3D0B15,
|
||||
0x3D0BA8,
|
||||
0x3D0830,
|
||||
|
||||
0x3D0D04,
|
||||
0x3D0CA2,
|
||||
0x3D0A7C,
|
||||
0x3D0D35,
|
||||
0x3D0CD3,
|
||||
|
||||
0x3D0DC8,
|
||||
0x3D0D66,
|
||||
0x3D09AC,
|
||||
0x3D0D97,
|
||||
0x3D0C0F,
|
||||
|
||||
0x3D0DF9,
|
||||
0x3D0E31,
|
||||
0x3D0E62,
|
||||
0x3D0934,
|
||||
0x3D0E9A,
|
||||
]
|
||||
|
||||
level_music_ids = [
|
||||
0x06,
|
||||
0x07,
|
||||
0x08,
|
||||
0x0A,
|
||||
0x0B,
|
||||
0x0E,
|
||||
0x0F,
|
||||
0x10,
|
||||
0x17,
|
||||
0x19,
|
||||
0x1C,
|
||||
0x1D,
|
||||
0x1E,
|
||||
0x21,
|
||||
]
|
||||
|
||||
class LocalRom:
|
||||
|
||||
def __init__(self, file, name=None, hash=None):
|
||||
self.name = name
|
||||
self.hash = hash
|
||||
self.orig_buffer = None
|
||||
|
||||
with open(file, 'rb') as stream:
|
||||
self.buffer = read_snes_rom(stream)
|
||||
#if patch:
|
||||
# self.patch_rom()
|
||||
# self.orig_buffer = self.buffer.copy()
|
||||
#if vanillaRom:
|
||||
# with open(vanillaRom, 'rb') as vanillaStream:
|
||||
# self.orig_buffer = read_snes_rom(vanillaStream)
|
||||
|
||||
def read_bit(self, address: int, bit_number: int) -> bool:
|
||||
bitflag = (1 << bit_number)
|
||||
return ((self.buffer[address] & bitflag) != 0)
|
||||
|
||||
def read_byte(self, address: int) -> int:
|
||||
return self.buffer[address]
|
||||
|
||||
def read_bytes(self, startaddress: int, length: int) -> bytearray:
|
||||
return self.buffer[startaddress:startaddress + length]
|
||||
|
||||
def write_byte(self, address: int, value: int):
|
||||
self.buffer[address] = value
|
||||
|
||||
def write_bytes(self, startaddress: int, values):
|
||||
self.buffer[startaddress:startaddress + len(values)] = values
|
||||
|
||||
def write_to_file(self, file):
|
||||
with open(file, 'wb') as outfile:
|
||||
outfile.write(self.buffer)
|
||||
|
||||
def read_from_file(self, file):
|
||||
with open(file, 'rb') as stream:
|
||||
self.buffer = bytearray(stream.read())
|
||||
|
||||
|
||||
|
||||
def patch_rom(world: World, rom: LocalRom, active_level_list):
|
||||
|
||||
# Boomer Costs
|
||||
bonus_coin_cost = world.options.krematoa_bonus_coin_cost
|
||||
inverted_bonus_coin_cost = 0x100 - bonus_coin_cost
|
||||
rom.write_byte(0x3498B9, inverted_bonus_coin_cost)
|
||||
rom.write_byte(0x3498BA, inverted_bonus_coin_cost)
|
||||
rom.write_byte(0x3498BB, inverted_bonus_coin_cost)
|
||||
rom.write_byte(0x3498BC, inverted_bonus_coin_cost)
|
||||
rom.write_byte(0x3498BD, inverted_bonus_coin_cost)
|
||||
|
||||
rom.write_byte(0x349857, bonus_coin_cost)
|
||||
rom.write_byte(0x349862, bonus_coin_cost)
|
||||
|
||||
# Gyrocopter Costs
|
||||
dk_coin_cost = world.options.dk_coins_for_gyrocopter
|
||||
rom.write_byte(0x3484A6, dk_coin_cost)
|
||||
rom.write_byte(0x3484D5, dk_coin_cost)
|
||||
rom.write_byte(0x3484D7, 0x90)
|
||||
rom.write_byte(0x3484DC, 0xEA)
|
||||
rom.write_byte(0x3484DD, 0xEA)
|
||||
rom.write_byte(0x3484DE, 0xEA)
|
||||
rom.write_byte(0x348528, 0x80) # Prevent Single-Ski Lock
|
||||
|
||||
# Make Swanky free
|
||||
rom.write_byte(0x348C48, 0x00)
|
||||
|
||||
rom.write_bytes(0x34AB70, bytearray([0xEA, 0xEA]))
|
||||
rom.write_bytes(0x34ABF7, bytearray([0xEA, 0xEA]))
|
||||
rom.write_bytes(0x34ACD0, bytearray([0xEA, 0xEA]))
|
||||
|
||||
# Banana Bird Costs
|
||||
if world.options.goal == "banana_bird_hunt":
|
||||
banana_bird_cost = math.floor(world.options.number_of_banana_birds * world.options.percentage_of_banana_birds / 100.0)
|
||||
rom.write_byte(0x34AB85, banana_bird_cost)
|
||||
rom.write_byte(0x329FD8, banana_bird_cost)
|
||||
rom.write_byte(0x32A025, banana_bird_cost)
|
||||
rom.write_byte(0x329FDA, 0xB0)
|
||||
else:
|
||||
# rom.write_byte(0x34AB84, 0x20) # These cause hangs at Wrinkly's
|
||||
# rom.write_byte(0x329FD8, 0x20)
|
||||
# rom.write_byte(0x32A025, 0x20)
|
||||
rom.write_byte(0x329FDA, 0xB0)
|
||||
|
||||
# Baffle Mirror Fix
|
||||
rom.write_byte(0x9133, 0x08)
|
||||
rom.write_byte(0x9135, 0x0C)
|
||||
rom.write_byte(0x9136, 0x2B)
|
||||
rom.write_byte(0x9137, 0x06)
|
||||
|
||||
# Palette Swap
|
||||
rom.write_byte(0x3B96A5, 0xD0)
|
||||
if world.options.kong_palette_swap == "default":
|
||||
rom.write_byte(0x3B96A9, 0x00)
|
||||
rom.write_byte(0x3B96A8, 0x00)
|
||||
elif world.options.kong_palette_swap == "purple":
|
||||
rom.write_byte(0x3B96A9, 0x00)
|
||||
rom.write_byte(0x3B96A8, 0x3C)
|
||||
elif world.options.kong_palette_swap == "spooky":
|
||||
rom.write_byte(0x3B96A9, 0x00)
|
||||
rom.write_byte(0x3B96A8, 0xA0)
|
||||
elif world.options.kong_palette_swap == "dark":
|
||||
rom.write_byte(0x3B96A9, 0x05)
|
||||
rom.write_byte(0x3B96A8, 0xA0)
|
||||
elif world.options.kong_palette_swap == "chocolate":
|
||||
rom.write_byte(0x3B96A9, 0x1D)
|
||||
rom.write_byte(0x3B96A8, 0xA0)
|
||||
elif world.options.kong_palette_swap == "shadow":
|
||||
rom.write_byte(0x3B96A9, 0x45)
|
||||
rom.write_byte(0x3B96A8, 0xA0)
|
||||
elif world.options.kong_palette_swap == "red_gold":
|
||||
rom.write_byte(0x3B96A9, 0x5D)
|
||||
rom.write_byte(0x3B96A8, 0xA0)
|
||||
elif world.options.kong_palette_swap == "gbc":
|
||||
rom.write_byte(0x3B96A9, 0x20)
|
||||
rom.write_byte(0x3B96A8, 0x3C)
|
||||
elif world.options.kong_palette_swap == "halloween":
|
||||
rom.write_byte(0x3B96A9, 0x70)
|
||||
rom.write_byte(0x3B96A8, 0x3C)
|
||||
|
||||
if world.options.music_shuffle:
|
||||
for address in music_rom_data:
|
||||
rand_song = world.random.choice(level_music_ids)
|
||||
rom.write_byte(address, rand_song)
|
||||
|
||||
# Starting Lives
|
||||
rom.write_byte(0x9130, world.options.starting_life_count.value)
|
||||
rom.write_byte(0x913B, world.options.starting_life_count.value)
|
||||
|
||||
# Cheat options
|
||||
cheat_bytes = [0x00, 0x00]
|
||||
|
||||
if world.options.merry:
|
||||
cheat_bytes[0] |= 0x01
|
||||
|
||||
if world.options.autosave:
|
||||
cheat_bytes[0] |= 0x02
|
||||
|
||||
if world.options.difficulty == "tufst":
|
||||
cheat_bytes[0] |= 0x80
|
||||
cheat_bytes[1] |= 0x80
|
||||
elif world.options.difficulty == "hardr":
|
||||
cheat_bytes[0] |= 0x00
|
||||
cheat_bytes[1] |= 0x00
|
||||
elif world.options.difficulty == "norml":
|
||||
cheat_bytes[1] |= 0x40
|
||||
|
||||
rom.write_bytes(0x8303, bytearray(cheat_bytes))
|
||||
|
||||
# Handle Level Shuffle Here
|
||||
if world.options.level_shuffle:
|
||||
for i in range(len(active_level_list)):
|
||||
rom.write_byte(level_dict[level_list[i]].nameIDAddress, level_dict[active_level_list[i]].nameID)
|
||||
rom.write_byte(level_dict[level_list[i]].levelIDAddress, level_dict[active_level_list[i]].levelID)
|
||||
|
||||
rom.write_byte(0x3FF800 + level_dict[active_level_list[i]].levelID, level_dict[level_list[i]].levelID)
|
||||
rom.write_byte(0x3FF860 + level_dict[level_list[i]].levelID, level_dict[active_level_list[i]].levelID)
|
||||
|
||||
# First levels of each world
|
||||
rom.write_byte(0x34BC3E, (0x32 + level_dict[active_level_list[0]].levelID))
|
||||
rom.write_byte(0x34BC47, (0x32 + level_dict[active_level_list[5]].levelID))
|
||||
rom.write_byte(0x34BC4A, (0x32 + level_dict[active_level_list[10]].levelID))
|
||||
rom.write_byte(0x34BC53, (0x32 + level_dict[active_level_list[15]].levelID))
|
||||
rom.write_byte(0x34BC59, (0x32 + level_dict[active_level_list[20]].levelID))
|
||||
rom.write_byte(0x34BC5C, (0x32 + level_dict[active_level_list[25]].levelID))
|
||||
rom.write_byte(0x34BC65, (0x32 + level_dict[active_level_list[30]].levelID))
|
||||
rom.write_byte(0x34BC6E, (0x32 + level_dict[active_level_list[35]].levelID))
|
||||
|
||||
# Cotton-Top Cove Boss Unlock
|
||||
rom.write_byte(0x34C02A, (0x32 + level_dict[active_level_list[14]].levelID))
|
||||
|
||||
# Kong-Fused Cliffs Unlock
|
||||
rom.write_byte(0x34C213, (0x32 + level_dict[active_level_list[25]].levelID))
|
||||
rom.write_byte(0x34C21B, (0x32 + level_dict[active_level_list[26]].levelID))
|
||||
|
||||
if world.options.goal == "knautilus":
|
||||
# Swap Kastle KAOS and Knautilus
|
||||
rom.write_byte(0x34D4E1, 0xC2)
|
||||
rom.write_byte(0x34D4E2, 0x24)
|
||||
rom.write_byte(0x34D551, 0xBA)
|
||||
rom.write_byte(0x34D552, 0x23)
|
||||
|
||||
rom.write_byte(0x32F339, 0x55)
|
||||
|
||||
# Handle KONGsanity Here
|
||||
if world.options.kongsanity:
|
||||
# Arich's Hoard KONGsanity fix
|
||||
rom.write_bytes(0x34BA8C, bytearray([0xEA, 0xEA]))
|
||||
|
||||
# Don't hide the level flag if the 0x80 bit is set
|
||||
rom.write_bytes(0x34CE92, bytearray([0x80]))
|
||||
|
||||
# Use the `!` next to level name for indicating KONG letters
|
||||
rom.write_bytes(0x34B8F0, bytearray([0x80]))
|
||||
rom.write_bytes(0x34B8F3, bytearray([0x80]))
|
||||
|
||||
# Hijack to code to set the 0x80 flag for the level when you complete KONG
|
||||
rom.write_bytes(0x3BCD4B, bytearray([0x22, 0x80, 0xFA, 0XB8])) # JSL $B8FA80
|
||||
|
||||
rom.write_bytes(0x38FA80, bytearray([0xDA])) # PHX
|
||||
rom.write_bytes(0x38FA81, bytearray([0x48])) # PHA
|
||||
rom.write_bytes(0x38FA82, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(0x38FA83, bytearray([0xE2, 0x20])) # SEP #20
|
||||
rom.write_bytes(0x38FA85, bytearray([0x48])) # PHA
|
||||
rom.write_bytes(0x38FA86, bytearray([0x18])) # CLC
|
||||
rom.write_bytes(0x38FA87, bytearray([0x6D, 0xD3, 0x18])) # ADC $18D3
|
||||
rom.write_bytes(0x38FA8A, bytearray([0x8D, 0xD3, 0x18])) # STA $18D3
|
||||
rom.write_bytes(0x38FA8D, bytearray([0x68])) # PLA
|
||||
rom.write_bytes(0x38FA8E, bytearray([0xC2, 0x20])) # REP 20
|
||||
rom.write_bytes(0x38FA90, bytearray([0X18])) # CLC
|
||||
rom.write_bytes(0x38FA91, bytearray([0x6D, 0xD5, 0x05])) # ADC $05D5
|
||||
rom.write_bytes(0x38FA94, bytearray([0x8D, 0xD5, 0x05])) # STA $05D5
|
||||
rom.write_bytes(0x38FA97, bytearray([0xAE, 0xB9, 0x05])) # LDX $05B9
|
||||
rom.write_bytes(0x38FA9A, bytearray([0xBD, 0x32, 0x06])) # LDA $0632, X
|
||||
rom.write_bytes(0x38FA9D, bytearray([0x09, 0x80, 0x00])) # ORA #8000
|
||||
rom.write_bytes(0x38FAA0, bytearray([0x9D, 0x32, 0x06])) # STA $0632, X
|
||||
rom.write_bytes(0x38FAA3, bytearray([0xAD, 0xD5, 0x18])) # LDA $18D5
|
||||
rom.write_bytes(0x38FAA6, bytearray([0xD0, 0x03])) # BNE $80EA
|
||||
rom.write_bytes(0x38FAA8, bytearray([0x9C, 0xD9, 0x18])) # STZ $18D9
|
||||
rom.write_bytes(0x38FAAB, bytearray([0xA9, 0x78, 0x00])) # LDA #0078
|
||||
rom.write_bytes(0x38FAAE, bytearray([0x8D, 0xD5, 0x18])) # STA $18D5
|
||||
rom.write_bytes(0x38FAB1, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(0x38FAB2, bytearray([0x68])) # PLA
|
||||
rom.write_bytes(0x38FAB3, bytearray([0xFA])) # PLX
|
||||
rom.write_bytes(0x38FAB4, bytearray([0x6B])) # RTL
|
||||
# End Handle KONGsanity
|
||||
|
||||
# Handle Credits
|
||||
rom.write_bytes(0x32A5DF, bytearray([0x41, 0x52, 0x43, 0x48, 0x49, 0x50, 0x45, 0x4C, 0x41, 0x47, 0x4F, 0x20, 0x4D, 0x4F, 0xC4])) # "ARCHIPELAGO MOD"
|
||||
rom.write_bytes(0x32A5EE, bytearray([0x00, 0x03, 0x50, 0x4F, 0x52, 0x59, 0x47, 0x4F, 0x4E, 0xC5])) # "PORYGONE"
|
||||
|
||||
from Utils import __version__
|
||||
rom.name = bytearray(f'D3{__version__.replace(".", "")[0:3]}_{world.player}_{world.multiworld.seed:11}\0', 'utf8')[:21]
|
||||
rom.name.extend([0] * (21 - len(rom.name)))
|
||||
rom.write_bytes(0x7FC0, rom.name)
|
||||
|
||||
# DKC3_TODO: This is a hack, reconsider
|
||||
# Don't grant (DK, Bonus, Bear) Coins
|
||||
rom.write_byte(0x3BD454, 0xEA)
|
||||
rom.write_byte(0x3BD455, 0xEA)
|
||||
|
||||
# Don't grant Cogs
|
||||
rom.write_byte(0x3BD574, 0xEA)
|
||||
rom.write_byte(0x3BD575, 0xEA)
|
||||
rom.write_byte(0x3BD576, 0xEA)
|
||||
|
||||
# Don't grant Banana Birds at their caves
|
||||
rom.write_byte(0x32DD62, 0xEA)
|
||||
rom.write_byte(0x32DD63, 0xEA)
|
||||
rom.write_byte(0x32DD64, 0xEA)
|
||||
|
||||
# Don't grant Banana Birds at Bears
|
||||
rom.write_byte(0x3492DB, 0xEA)
|
||||
rom.write_byte(0x3492DC, 0xEA)
|
||||
rom.write_byte(0x3492DD, 0xEA)
|
||||
rom.write_byte(0x3493F4, 0xEA)
|
||||
rom.write_byte(0x3493F5, 0xEA)
|
||||
rom.write_byte(0x3493F6, 0xEA)
|
||||
|
||||
# Don't grant present at Blizzard
|
||||
rom.write_byte(0x8454, 0x00)
|
||||
|
||||
# Don't grant Patch and Skis from their bosses
|
||||
rom.write_byte(0x3F3762, 0x00)
|
||||
rom.write_byte(0x3F377B, 0x00)
|
||||
rom.write_byte(0x3F3797, 0x00)
|
||||
|
||||
# Always allow Start+Select
|
||||
rom.write_byte(0x8BAB, 0x01)
|
||||
|
||||
# Handle Alt Palettes in Krematoa
|
||||
rom.write_byte(0x3B97E9, 0x80)
|
||||
rom.write_byte(0x3B97EA, 0xEA)
|
||||
|
||||
|
||||
class DKC3DeltaPatch(APDeltaPatch):
|
||||
hash = USHASH
|
||||
game = "Donkey Kong Country 3"
|
||||
patch_file_ending = ".apdkc3"
|
||||
|
||||
@classmethod
|
||||
def get_source_data(cls) -> bytes:
|
||||
return get_base_rom_bytes()
|
||||
|
||||
|
||||
def get_base_rom_bytes(file_name: str = "") -> bytes:
|
||||
base_rom_bytes = getattr(get_base_rom_bytes, "base_rom_bytes", None)
|
||||
if not base_rom_bytes:
|
||||
file_name = get_base_rom_path(file_name)
|
||||
base_rom_bytes = bytes(read_snes_rom(open(file_name, "rb")))
|
||||
|
||||
basemd5 = hashlib.md5()
|
||||
basemd5.update(base_rom_bytes)
|
||||
if USHASH != basemd5.hexdigest():
|
||||
raise Exception('Supplied Base Rom does not match known MD5 for US(1.0) 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:
|
||||
if not file_name:
|
||||
from settings import get_settings
|
||||
file_name = get_settings()["dkc3_options"]["rom_file"]
|
||||
if not os.path.exists(file_name):
|
||||
file_name = Utils.user_path(file_name)
|
||||
return file_name
|
||||
@@ -1,31 +0,0 @@
|
||||
import math
|
||||
|
||||
from worlds.AutoWorld import World
|
||||
from worlds.generic.Rules import add_rule
|
||||
from .Names import LocationName, ItemName
|
||||
|
||||
|
||||
def set_rules(world: World):
|
||||
|
||||
if False:#world.options.include_trade_sequence:
|
||||
add_rule(world.multiworld.get_location(LocationName.barnacles_island, world.player),
|
||||
lambda state: state.has(ItemName.shell, world.player))
|
||||
|
||||
add_rule(world.multiworld.get_location(LocationName.blues_beach_hut, world.player),
|
||||
lambda state: state.has(ItemName.present, world.player))
|
||||
|
||||
add_rule(world.multiworld.get_location(LocationName.brambles_bungalow, world.player),
|
||||
lambda state: state.has(ItemName.flower, world.player))
|
||||
|
||||
add_rule(world.multiworld.get_location(LocationName.barters_swap_shop, world.player),
|
||||
lambda state: state.has(ItemName.mirror, world.player))
|
||||
|
||||
|
||||
if world.options.goal != "knautilus":
|
||||
required_banana_birds = math.floor(
|
||||
world.options.number_of_banana_birds.value * (world.options.percentage_of_banana_birds.value / 100.0))
|
||||
|
||||
add_rule(world.multiworld.get_location(LocationName.banana_bird_mother, world.player),
|
||||
lambda state: state.has(ItemName.banana_bird, world.player, required_banana_birds))
|
||||
|
||||
world.multiworld.completion_condition[world.player] = lambda state: state.has(ItemName.victory, world.player)
|
||||
@@ -1,233 +0,0 @@
|
||||
import dataclasses
|
||||
import math
|
||||
import os
|
||||
import threading
|
||||
import typing
|
||||
|
||||
import settings
|
||||
from BaseClasses import Item, MultiWorld, Tutorial, ItemClassification
|
||||
from Options import PerGameCommonOptions
|
||||
from worlds.AutoWorld import WebWorld, World
|
||||
from .Client import DKC3SNIClient
|
||||
from .Items import DKC3Item, ItemData, item_table, inventory_table, junk_table
|
||||
from .Levels import level_list
|
||||
from .Locations import DKC3Location, all_locations, setup_locations
|
||||
from .Names import ItemName, LocationName
|
||||
from .Options import DKC3Options, dkc3_option_groups
|
||||
from .Regions import create_regions, connect_regions
|
||||
from .Rom import LocalRom, patch_rom, get_base_rom_path, DKC3DeltaPatch
|
||||
from .Rules import set_rules
|
||||
|
||||
|
||||
class DK3Settings(settings.Group):
|
||||
class RomFile(settings.UserFilePath):
|
||||
"""File name of the DKC3 US rom"""
|
||||
copy_to = "Donkey Kong Country 3 - Dixie Kong's Double Trouble! (USA) (En,Fr).sfc"
|
||||
description = "DKC3 (US) ROM File"
|
||||
md5s = [DKC3DeltaPatch.hash]
|
||||
|
||||
rom_file: RomFile = RomFile(RomFile.copy_to)
|
||||
|
||||
|
||||
class DKC3Web(WebWorld):
|
||||
theme = "jungle"
|
||||
|
||||
setup_en = Tutorial(
|
||||
"Multiworld Setup Guide",
|
||||
"A guide to setting up the Donkey Kong Country 3 randomizer connected to an Archipelago Multiworld.",
|
||||
"English",
|
||||
"setup_en.md",
|
||||
"setup/en",
|
||||
["PoryGone"]
|
||||
)
|
||||
|
||||
tutorials = [setup_en]
|
||||
|
||||
option_groups = dkc3_option_groups
|
||||
|
||||
|
||||
class DKC3World(World):
|
||||
"""
|
||||
Donkey Kong Country 3 is an action platforming game.
|
||||
Play as Dixie Kong and her baby cousin Kiddy as they try to solve the
|
||||
mystery of why Donkey Kong and Diddy disappeared while on vacation.
|
||||
"""
|
||||
game: str = "Donkey Kong Country 3"
|
||||
settings: typing.ClassVar[DK3Settings]
|
||||
|
||||
options_dataclass = DKC3Options
|
||||
options: DKC3Options
|
||||
|
||||
topology_present = False
|
||||
#hint_blacklist = {LocationName.rocket_rush_flag}
|
||||
|
||||
item_name_to_id = {name: data.code for name, data in item_table.items()}
|
||||
location_name_to_id = all_locations
|
||||
|
||||
active_level_list: typing.List[str]
|
||||
web = DKC3Web()
|
||||
|
||||
def __init__(self, world: MultiWorld, player: int):
|
||||
self.rom_name_available_event = threading.Event()
|
||||
super().__init__(world, player)
|
||||
|
||||
@classmethod
|
||||
def stage_assert_generate(cls, multiworld: MultiWorld):
|
||||
rom_file = get_base_rom_path()
|
||||
if not os.path.exists(rom_file):
|
||||
raise FileNotFoundError(rom_file)
|
||||
|
||||
def _get_slot_data(self):
|
||||
return {
|
||||
#"death_link": self.options.death_link.value,
|
||||
"active_levels": self.active_level_list,
|
||||
}
|
||||
|
||||
def fill_slot_data(self) -> dict:
|
||||
slot_data = self._get_slot_data()
|
||||
for option_name in (attr.name for attr in dataclasses.fields(DKC3Options)
|
||||
if attr not in dataclasses.fields(PerGameCommonOptions)):
|
||||
option = getattr(self.options, option_name)
|
||||
slot_data[option_name] = option.value
|
||||
|
||||
return slot_data
|
||||
|
||||
def create_regions(self):
|
||||
location_table = setup_locations(self)
|
||||
create_regions(self, location_table)
|
||||
|
||||
# Not generate basic
|
||||
self.topology_present = self.options.level_shuffle.value
|
||||
itempool: typing.List[DKC3Item] = []
|
||||
|
||||
# Levels
|
||||
total_required_locations = 159
|
||||
|
||||
number_of_banana_birds = 0
|
||||
# Rocket Rush Cog
|
||||
total_required_locations -= 1
|
||||
number_of_cogs = 4
|
||||
self.multiworld.get_location(LocationName.rocket_rush_flag, self.player).place_locked_item(self.create_item(ItemName.krematoa_cog))
|
||||
number_of_bosses = 8
|
||||
if self.options.goal == "knautilus":
|
||||
self.multiworld.get_location(LocationName.kastle_kaos, self.player).place_locked_item(self.create_item(ItemName.victory))
|
||||
number_of_bosses = 7
|
||||
else:
|
||||
self.multiworld.get_location(LocationName.banana_bird_mother, self.player).place_locked_item(self.create_item(ItemName.victory))
|
||||
number_of_banana_birds = self.options.number_of_banana_birds
|
||||
|
||||
# Bosses
|
||||
total_required_locations += number_of_bosses
|
||||
|
||||
# Secret Caves
|
||||
total_required_locations += 13
|
||||
|
||||
if self.options.kongsanity:
|
||||
total_required_locations += 39
|
||||
|
||||
## Brothers Bear
|
||||
if False:#self.options.include_trade_sequence:
|
||||
total_required_locations += 10
|
||||
|
||||
number_of_bonus_coins = (self.options.krematoa_bonus_coin_cost * 5)
|
||||
number_of_bonus_coins += math.ceil((85 - number_of_bonus_coins) * self.options.percentage_of_extra_bonus_coins / 100)
|
||||
|
||||
itempool += [self.create_item(ItemName.bonus_coin) for _ in range(number_of_bonus_coins)]
|
||||
itempool += [self.create_item(ItemName.dk_coin) for _ in range(41)]
|
||||
itempool += [self.create_item(ItemName.banana_bird) for _ in range(number_of_banana_birds)]
|
||||
itempool += [self.create_item(ItemName.krematoa_cog) for _ in range(number_of_cogs)]
|
||||
itempool += [self.create_item(ItemName.progressive_boat) for _ in range(3)]
|
||||
|
||||
total_junk_count = total_required_locations - len(itempool)
|
||||
|
||||
junk_pool = []
|
||||
for item_name in self.multiworld.random.choices(list(junk_table.keys()), k=total_junk_count):
|
||||
junk_pool.append(self.create_item(item_name))
|
||||
|
||||
itempool += junk_pool
|
||||
|
||||
self.active_level_list = level_list.copy()
|
||||
|
||||
if self.options.level_shuffle:
|
||||
self.random.shuffle(self.active_level_list)
|
||||
|
||||
connect_regions(self, self.active_level_list)
|
||||
|
||||
self.multiworld.itempool += itempool
|
||||
|
||||
def generate_output(self, output_directory: str):
|
||||
try:
|
||||
rom = LocalRom(get_base_rom_path())
|
||||
patch_rom(self, rom, self.active_level_list)
|
||||
|
||||
self.active_level_list.append(LocationName.rocket_rush_region)
|
||||
|
||||
rompath = os.path.join(output_directory, f"{self.multiworld.get_out_file_name_base(self.player)}.sfc")
|
||||
rom.write_to_file(rompath)
|
||||
self.rom_name = rom.name
|
||||
|
||||
patch = DKC3DeltaPatch(os.path.splitext(rompath)[0]+DKC3DeltaPatch.patch_file_ending, player=self.player,
|
||||
player_name=self.multiworld.player_name[self.player], patched_path=rompath)
|
||||
patch.write()
|
||||
except:
|
||||
raise
|
||||
finally:
|
||||
self.rom_name_available_event.set() # make sure threading continues and errors are collected
|
||||
if os.path.exists(rompath):
|
||||
os.unlink(rompath)
|
||||
|
||||
def modify_multidata(self, multidata: dict):
|
||||
import base64
|
||||
# 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 extend_hint_information(self, hint_data: typing.Dict[int, typing.Dict[int, str]]):
|
||||
if self.topology_present:
|
||||
world_names = [
|
||||
LocationName.lake_orangatanga_region,
|
||||
LocationName.kremwood_forest_region,
|
||||
LocationName.cotton_top_cove_region,
|
||||
LocationName.mekanos_region,
|
||||
LocationName.k3_region,
|
||||
LocationName.razor_ridge_region,
|
||||
LocationName.kaos_kore_region,
|
||||
LocationName.krematoa_region,
|
||||
]
|
||||
er_hint_data = {}
|
||||
for world_index in range(len(world_names)):
|
||||
for level_index in range(5):
|
||||
level_id: int = world_index * 5 + level_index
|
||||
|
||||
if level_id >= len(self.active_level_list):
|
||||
break
|
||||
|
||||
level_region = self.multiworld.get_region(self.active_level_list[level_id], self.player)
|
||||
for location in level_region.locations:
|
||||
er_hint_data[location.address] = world_names[world_index]
|
||||
|
||||
hint_data[self.player] = er_hint_data
|
||||
|
||||
def create_item(self, name: str, force_non_progression=False) -> Item:
|
||||
data = item_table[name]
|
||||
|
||||
if force_non_progression:
|
||||
classification = ItemClassification.filler
|
||||
elif data.progression:
|
||||
classification = ItemClassification.progression
|
||||
else:
|
||||
classification = ItemClassification.filler
|
||||
|
||||
created_item = DKC3Item(name, classification, data.code, self.player)
|
||||
|
||||
return created_item
|
||||
|
||||
def get_filler_item_name(self) -> str:
|
||||
return self.multiworld.random.choice(list(junk_table.keys()))
|
||||
|
||||
def set_rules(self):
|
||||
set_rules(self)
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"game": "Donkey Kong Country 3",
|
||||
"authors": [ "PoryGone" ],
|
||||
"minimum_ap_version": "0.6.3",
|
||||
"world_version": "1.1.0"
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
# Donkey Kong Country 3
|
||||
|
||||
## Where is the options page?
|
||||
|
||||
The [player options page for this game](../player-options) contains all the options you need to configure and export a config file.
|
||||
|
||||
## What does randomization do to this game?
|
||||
|
||||
Items which the player would normally acquire throughout the game have been moved around. Logic remains, so the game is
|
||||
always able to be completed, but because of the item shuffle the player may need to access certain areas before they
|
||||
would in the vanilla game.
|
||||
|
||||
## What is the goal of Donkey Kong Country 3 when randomized?
|
||||
|
||||
There are two goals which can be chosen:
|
||||
- `Knautilus`: Collect Bonus Coins and Krematoa Cogs to reach K. Rool's submarine in Krematoa
|
||||
- `Banana Bird Hunt`: Collect Banana Birds to free the Banana Bird Mother
|
||||
|
||||
## What items and locations get shuffled?
|
||||
|
||||
All Bonus Coins, DK Coins, and Banana Birds (if on a `Banana Bird Hunt` goal) are randomized. Additionally, level clears award a location check.
|
||||
The Patch and two Skis for upgrading the boat are included. Bear Coins are provided if additional items are needed for the item pool.
|
||||
Four of the Five Krematoa Cogs are randomized, but the final one is always in its vanilla location at the Flag of Rocket Rush in Krematoa
|
||||
|
||||
## Which items can be in another player's world?
|
||||
|
||||
Any shuffled item can be in other players' worlds.
|
||||
|
||||
## What does another world's item look like in Donkey Kong Country 3
|
||||
|
||||
Items pickups all retain their original appearance. You won't know if an item belongs to another player until you collect.
|
||||
|
||||
## When the player receives an item, what happens?
|
||||
|
||||
Currently, the items are silently added to the player's inventory, which can be seen when saving the game.
|
||||
@@ -1,162 +0,0 @@
|
||||
# Donkey Kong Country 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 such as:
|
||||
- snes9x-rr from: [snes9x rr](https://github.com/gocha/snes9x-rr/releases),
|
||||
- BizHawk from: [TASVideos](https://tasvideos.org/BizHawk)
|
||||
- RetroArch 1.10.3 or newer from: [RetroArch Website](https://retroarch.com?page=platforms). Or,
|
||||
- An SD2SNES, FXPak Pro ([FXPak Pro Store Page](https://krikzz.com/store/home/54-fxpak-pro.html)), or other
|
||||
compatible hardware
|
||||
- Your legally obtained Donkey Kong Country 3 ROM file, probably named `Donkey Kong Country 3 - Dixie Kong's Double Trouble! (USA) (En,Fr).sfc`
|
||||
|
||||
## Optional Software
|
||||
- Donkey Kong Country 3 Tracker
|
||||
- PopTracker from: [PopTracker Releases Page](https://github.com/black-sliver/PopTracker/releases/)
|
||||
- Donkey Kong Country 3 Archipelago PopTracker pack from: [DKC3 AP Tracker Releases Page](https://github.com/PoryGone/DKC3_AP_Tracker/releases/)
|
||||
|
||||
## Installation Procedures
|
||||
|
||||
### Windows Setup
|
||||
|
||||
1. Download and install [Archipelago](<https://github.com/ArchipelagoMW/Archipelago/releases/latest>). **The installer
|
||||
file is located in the assets section at the bottom of the version information.**
|
||||
2. The first time you do local generation or patch your game, you will be asked to locate your base ROM file.
|
||||
This is your Donkey Kong Country 3 ROM file. This only needs to be done once.
|
||||
3. If you are using an emulator, you should assign your Lua capable 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?
|
||||
|
||||
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 Options page on the website allows you to configure your personal options and export a config file from
|
||||
them. Player options page: [Donkey Kong Country 3 Player Options Page](/games/Donkey%20Kong%20Country%203/player-options)
|
||||
|
||||
### 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 page. YAML
|
||||
validator page: [YAML Validation page](/check)
|
||||
|
||||
## Generating a Single-Player Game
|
||||
|
||||
1. Navigate to the Player Options page, configure your options, and click the "Generate Game" button.
|
||||
- Player Options page: [Donkey Kong Country 3 Player Options Page](/games/Donkey%20Kong%20Country%203/player-options)
|
||||
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 the Donkey Kong Country 3 Client 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 `.apdkc3` 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. This is done with the main menubar, under:
|
||||
- (≤ 2.8) `Config` 〉 `Cores` 〉 `SNES` 〉 `BSNES`
|
||||
- (≥ 2.9) `Config` 〉 `Preferred Cores` 〉 `SNES` 〉 `BSNESv115+`
|
||||
2. Load your ROM file if it hasn't already been loaded.
|
||||
If you changed your core preference after loading the ROM, don't forget to reload it (default hotkey: Ctrl+R).
|
||||
3. Drag+drop the `Connector.lua` file included with your client onto the main EmuHawk window.
|
||||
- Look in the Archipelago folder for `/SNI/lua/Connector.lua`.
|
||||
- You could instead open the Lua Console manually, click `Script` 〉 `Open Script`, and navigate to `Connector.lua`
|
||||
with the file picker.
|
||||
|
||||
##### RetroArch 1.10.3 or newer
|
||||
|
||||
You only have to do these steps once. Note, RetroArch 1.9.x will not work as it is older than 1.10.3.
|
||||
|
||||
1. Enter the RetroArch main menu screen.
|
||||
2. Go to Settings --> User Interface. Set "Show Advanced Settings" to ON.
|
||||
3. Go to Settings --> Network. Set "Network Commands" to ON. (It is found below Request Device 16.) Leave the default
|
||||
Network Command Port at 55355. \
|
||||

|
||||
4. Go to Main Menu --> Online Updater --> Core Downloader. Scroll down and select "Nintendo - SNES / SFC (bsnes-mercury
|
||||
Performance)".
|
||||
|
||||
When loading a ROM, be sure to select a **bsnes-mercury** core. These are the only cores that allow external tools to
|
||||
read ROM data.
|
||||
|
||||
#### 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 on the SD2SNES releases page. SD2SNES
|
||||
releases page: [SD2SNES Releases Page](https://github.com/RedGuyyyy/sd2snes/releases)
|
||||
|
||||
Other hardware may find helpful information on the usb2snes platforms
|
||||
page: [usb2snes Supported Platforms 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!
|
||||
|
||||
## Hosting a MultiWorld game
|
||||
|
||||
The recommended way to host a game is to use our hosting service. 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 Generate page above.
|
||||
- Generate page: [WebHost Seed Generation Page](/generate)
|
||||
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.
|
||||
+29
-29
@@ -45,35 +45,35 @@ def create_regions(multiworld: MultiWorld, player: int, world_options: Options.D
|
||||
|
||||
|
||||
def create_regions_basic_campaign(has_campaign_basic: bool, region_menu: Region, has_item_shuffle: bool, has_coinsanity: bool,
|
||||
coin_bundle_size: int, player: int, world: MultiWorld):
|
||||
coin_bundle_size: int, player: int, multiworld: MultiWorld):
|
||||
if not has_campaign_basic:
|
||||
return
|
||||
|
||||
region_menu.exits += [Entrance(player, "DLC Quest Basic", region_menu)]
|
||||
locations_move_right = ["Movement Pack", "Animation Pack", "Audio Pack", "Pause Menu Pack"]
|
||||
region_move_right = create_region_and_locations_basic("Move Right", locations_move_right, ["Moving"], player, world, 4)
|
||||
region_move_right = create_region_and_locations_basic("Move Right", locations_move_right, ["Moving"], player, multiworld, 4)
|
||||
create_coinsanity_locations_dlc_quest(has_coinsanity, coin_bundle_size, player, region_move_right)
|
||||
locations_movement_pack = ["Time is Money Pack", "Psychological Warfare Pack", "Armor for your Horse Pack", "Shepherd Sheep"]
|
||||
locations_movement_pack += conditional_location(has_item_shuffle, "Sword")
|
||||
create_region_and_locations_basic("Movement Pack", locations_movement_pack, ["Tree", "Cloud"], player, world, 46)
|
||||
create_region_and_locations_basic("Movement Pack", locations_movement_pack, ["Tree", "Cloud"], player, multiworld, 46)
|
||||
locations_behind_tree = ["Double Jump Pack", "Map Pack", "Between Trees Sheep", "Hole in the Wall Sheep"] + conditional_location(has_item_shuffle, "Gun")
|
||||
create_region_and_locations_basic("Behind Tree", locations_behind_tree, ["Behind Tree Double Jump", "Forest Entrance"], player, world, 60)
|
||||
create_region_and_locations_basic("Psychological Warfare", ["West Cave Sheep"], ["Cloud Double Jump"], player, world, 100)
|
||||
create_region_and_locations_basic("Behind Tree", locations_behind_tree, ["Behind Tree Double Jump", "Forest Entrance"], player, multiworld, 60)
|
||||
create_region_and_locations_basic("Psychological Warfare", ["West Cave Sheep"], ["Cloud Double Jump"], player, multiworld, 100)
|
||||
locations_double_jump_left = ["Pet Pack", "Top Hat Pack", "North West Alcove Sheep"]
|
||||
create_region_and_locations_basic("Double Jump Total Left", locations_double_jump_left, ["Cave Tree", "Cave Roof"], player, world, 50)
|
||||
create_region_and_locations_basic("Double Jump Total Left Cave", ["Top Hat Sheep"], [], player, world, 9)
|
||||
create_region_and_locations_basic("Double Jump Total Left Roof", ["North West Ceiling Sheep"], [], player, world, 10)
|
||||
create_region_and_locations_basic("Double Jump Total Left", locations_double_jump_left, ["Cave Tree", "Cave Roof"], player, multiworld, 50)
|
||||
create_region_and_locations_basic("Double Jump Total Left Cave", ["Top Hat Sheep"], [], player, multiworld, 9)
|
||||
create_region_and_locations_basic("Double Jump Total Left Roof", ["North West Ceiling Sheep"], [], player, multiworld, 10)
|
||||
locations_double_jump_left_ceiling = ["Sexy Outfits Pack", "Double Jump Alcove Sheep", "Sexy Outfits Sheep"]
|
||||
create_region_and_locations_basic("Double Jump Behind Tree", locations_double_jump_left_ceiling, ["True Double Jump"], player, world, 89)
|
||||
create_region_and_locations_basic("True Double Jump Behind Tree", ["Double Jump Floating Sheep", "Cutscene Sheep"], [], player, world, 7)
|
||||
create_region_and_locations_basic("The Forest", ["Gun Pack", "Night Map Pack"], ["Behind Ogre", "Forest Double Jump"], player, world, 171)
|
||||
create_region_and_locations_basic("The Forest with double Jump", ["The Zombie Pack", "Forest Low Sheep"], ["Forest True Double Jump"], player, world, 76)
|
||||
create_region_and_locations_basic("The Forest with double Jump Part 2", ["Forest High Sheep"], [], player, world, 203)
|
||||
region_final_boss_room = create_region_and_locations_basic("The Final Boss Room", ["Finish the Fight Pack"], [], player, world)
|
||||
create_region_and_locations_basic("Double Jump Behind Tree", locations_double_jump_left_ceiling, ["True Double Jump"], player, multiworld, 89)
|
||||
create_region_and_locations_basic("True Double Jump Behind Tree", ["Double Jump Floating Sheep", "Cutscene Sheep"], [], player, multiworld, 7)
|
||||
create_region_and_locations_basic("The Forest", ["Gun Pack", "Night Map Pack"], ["Behind Ogre", "Forest Double Jump"], player, multiworld, 171)
|
||||
create_region_and_locations_basic("The Forest with double Jump", ["The Zombie Pack", "Forest Low Sheep"], ["Forest True Double Jump"], player, multiworld, 76)
|
||||
create_region_and_locations_basic("The Forest with double Jump Part 2", ["Forest High Sheep"], [], player, multiworld, 203)
|
||||
region_final_boss_room = create_region_and_locations_basic("The Final Boss Room", ["Finish the Fight Pack"], [], player, multiworld)
|
||||
|
||||
create_victory_event(region_final_boss_room, "Winning Basic", "Victory Basic", player)
|
||||
|
||||
connect_entrances_basic(player, world)
|
||||
connect_entrances_basic(player, multiworld)
|
||||
|
||||
|
||||
def create_regions_lfod_campaign(coin_bundle_size, has_campaign_lfod, has_coinsanity, has_item_shuffle, multiworld, player, region_menu):
|
||||
@@ -141,20 +141,20 @@ def create_victory_event(region_victory: Region, event_name: str, item_name: str
|
||||
location_victory.place_locked_item(create_event(player, item_name))
|
||||
|
||||
|
||||
def connect_entrances_basic(player, world):
|
||||
world.get_entrance("DLC Quest Basic", player).connect(world.get_region("Move Right", player))
|
||||
world.get_entrance("Moving", player).connect(world.get_region("Movement Pack", player))
|
||||
world.get_entrance("Tree", player).connect(world.get_region("Behind Tree", player))
|
||||
world.get_entrance("Cloud", player).connect(world.get_region("Psychological Warfare", player))
|
||||
world.get_entrance("Cloud Double Jump", player).connect(world.get_region("Double Jump Total Left", player))
|
||||
world.get_entrance("Cave Tree", player).connect(world.get_region("Double Jump Total Left Cave", player))
|
||||
world.get_entrance("Cave Roof", player).connect(world.get_region("Double Jump Total Left Roof", player))
|
||||
world.get_entrance("Forest Entrance", player).connect(world.get_region("The Forest", player))
|
||||
world.get_entrance("Behind Tree Double Jump", player).connect(world.get_region("Double Jump Behind Tree", player))
|
||||
world.get_entrance("Behind Ogre", player).connect(world.get_region("The Final Boss Room", player))
|
||||
world.get_entrance("Forest Double Jump", player).connect(world.get_region("The Forest with double Jump", player))
|
||||
world.get_entrance("Forest True Double Jump", player).connect(world.get_region("The Forest with double Jump Part 2", player))
|
||||
world.get_entrance("True Double Jump", player).connect(world.get_region("True Double Jump Behind Tree", player))
|
||||
def connect_entrances_basic(player, multiworld):
|
||||
multiworld.get_entrance("DLC Quest Basic", player).connect(multiworld.get_region("Move Right", player))
|
||||
multiworld.get_entrance("Moving", player).connect(multiworld.get_region("Movement Pack", player))
|
||||
multiworld.get_entrance("Tree", player).connect(multiworld.get_region("Behind Tree", player))
|
||||
multiworld.get_entrance("Cloud", player).connect(multiworld.get_region("Psychological Warfare", player))
|
||||
multiworld.get_entrance("Cloud Double Jump", player).connect(multiworld.get_region("Double Jump Total Left", player))
|
||||
multiworld.get_entrance("Cave Tree", player).connect(multiworld.get_region("Double Jump Total Left Cave", player))
|
||||
multiworld.get_entrance("Cave Roof", player).connect(multiworld.get_region("Double Jump Total Left Roof", player))
|
||||
multiworld.get_entrance("Forest Entrance", player).connect(multiworld.get_region("The Forest", player))
|
||||
multiworld.get_entrance("Behind Tree Double Jump", player).connect(multiworld.get_region("Double Jump Behind Tree", player))
|
||||
multiworld.get_entrance("Behind Ogre", player).connect(multiworld.get_region("The Final Boss Room", player))
|
||||
multiworld.get_entrance("Forest Double Jump", player).connect(multiworld.get_region("The Forest with double Jump", player))
|
||||
multiworld.get_entrance("Forest True Double Jump", player).connect(multiworld.get_region("The Forest with double Jump Part 2", player))
|
||||
multiworld.get_entrance("True Double Jump", player).connect(multiworld.get_region("True Double Jump Behind Tree", player))
|
||||
|
||||
|
||||
def connect_entrances_lfod(multiworld, player):
|
||||
|
||||
+194
-194
@@ -18,251 +18,251 @@ def has_enough_coin_freemium(player: int, coin: int):
|
||||
return lambda state: state.prog_items[player][" coins freemium"] >= coin
|
||||
|
||||
|
||||
def set_rules(world, player, world_options: Options.DLCQuestOptions):
|
||||
set_basic_rules(world_options, player, world)
|
||||
set_lfod_rules(world_options, player, world)
|
||||
set_completion_condition(world_options, player, world)
|
||||
def set_rules(multiworld, player, world_options: Options.DLCQuestOptions):
|
||||
set_basic_rules(world_options, player, multiworld)
|
||||
set_lfod_rules(world_options, player, multiworld)
|
||||
set_completion_condition(world_options, player, multiworld)
|
||||
|
||||
|
||||
def set_basic_rules(world_options, player, world):
|
||||
def set_basic_rules(world_options, player, multiworld):
|
||||
if world_options.campaign == Options.Campaign.option_live_freemium_or_die:
|
||||
return
|
||||
set_basic_entrance_rules(player, world)
|
||||
set_basic_self_obtained_items_rules(world_options, player, world)
|
||||
set_basic_shuffled_items_rules(world_options, player, world)
|
||||
set_double_jump_glitchless_rules(world_options, player, world)
|
||||
set_easy_double_jump_glitch_rules(world_options, player, world)
|
||||
self_basic_coinsanity_funded_purchase_rules(world_options, player, world)
|
||||
set_basic_self_funded_purchase_rules(world_options, player, world)
|
||||
self_basic_win_condition(world_options, player, world)
|
||||
set_basic_entrance_rules(player, multiworld)
|
||||
set_basic_self_obtained_items_rules(world_options, player, multiworld)
|
||||
set_basic_shuffled_items_rules(world_options, player, multiworld)
|
||||
set_double_jump_glitchless_rules(world_options, player, multiworld)
|
||||
set_easy_double_jump_glitch_rules(world_options, player, multiworld)
|
||||
self_basic_coinsanity_funded_purchase_rules(world_options, player, multiworld)
|
||||
set_basic_self_funded_purchase_rules(world_options, player, multiworld)
|
||||
self_basic_win_condition(world_options, player, multiworld)
|
||||
|
||||
|
||||
def set_basic_entrance_rules(player, world):
|
||||
set_rule(world.get_entrance("Moving", player),
|
||||
def set_basic_entrance_rules(player, multiworld):
|
||||
set_rule(multiworld.get_entrance("Moving", player),
|
||||
lambda state: state.has("Movement Pack", player))
|
||||
set_rule(world.get_entrance("Cloud", player),
|
||||
set_rule(multiworld.get_entrance("Cloud", player),
|
||||
lambda state: state.has("Psychological Warfare Pack", player))
|
||||
set_rule(world.get_entrance("Forest Entrance", player),
|
||||
set_rule(multiworld.get_entrance("Forest Entrance", player),
|
||||
lambda state: state.has("Map Pack", player))
|
||||
set_rule(world.get_entrance("Forest True Double Jump", player),
|
||||
set_rule(multiworld.get_entrance("Forest True Double Jump", player),
|
||||
lambda state: state.has("Double Jump Pack", player))
|
||||
|
||||
|
||||
def set_basic_self_obtained_items_rules(world_options, player, world):
|
||||
def set_basic_self_obtained_items_rules(world_options, player, multiworld):
|
||||
if world_options.item_shuffle != Options.ItemShuffle.option_disabled:
|
||||
return
|
||||
set_rule(world.get_entrance("Behind Ogre", player),
|
||||
set_rule(multiworld.get_entrance("Behind Ogre", player),
|
||||
lambda state: state.has("Gun Pack", player))
|
||||
|
||||
if world_options.time_is_money == Options.TimeIsMoney.option_required:
|
||||
set_rule(world.get_entrance("Tree", player),
|
||||
set_rule(multiworld.get_entrance("Tree", player),
|
||||
lambda state: state.has("Time is Money Pack", player))
|
||||
set_rule(world.get_entrance("Cave Tree", player),
|
||||
set_rule(multiworld.get_entrance("Cave Tree", player),
|
||||
lambda state: state.has("Time is Money Pack", player))
|
||||
set_rule(world.get_location("Shepherd Sheep", player),
|
||||
set_rule(multiworld.get_location("Shepherd Sheep", player),
|
||||
lambda state: state.has("Time is Money Pack", player))
|
||||
set_rule(world.get_location("North West Ceiling Sheep", player),
|
||||
set_rule(multiworld.get_location("North West Ceiling Sheep", player),
|
||||
lambda state: state.has("Time is Money Pack", player))
|
||||
set_rule(world.get_location("North West Alcove Sheep", player),
|
||||
set_rule(multiworld.get_location("North West Alcove Sheep", player),
|
||||
lambda state: state.has("Time is Money Pack", player))
|
||||
set_rule(world.get_location("West Cave Sheep", player),
|
||||
set_rule(multiworld.get_location("West Cave Sheep", player),
|
||||
lambda state: state.has("Time is Money Pack", player))
|
||||
|
||||
|
||||
def set_basic_shuffled_items_rules(world_options, player, world):
|
||||
def set_basic_shuffled_items_rules(world_options, player, multiworld):
|
||||
if world_options.item_shuffle != Options.ItemShuffle.option_shuffled:
|
||||
return
|
||||
set_rule(world.get_entrance("Behind Ogre", player),
|
||||
set_rule(multiworld.get_entrance("Behind Ogre", player),
|
||||
lambda state: state.has("DLC Quest: Progressive Weapon", player, 2))
|
||||
set_rule(world.get_entrance("Tree", player),
|
||||
set_rule(multiworld.get_entrance("Tree", player),
|
||||
lambda state: state.has("DLC Quest: Progressive Weapon", player))
|
||||
set_rule(world.get_entrance("Cave Tree", player),
|
||||
set_rule(multiworld.get_entrance("Cave Tree", player),
|
||||
lambda state: state.has("DLC Quest: Progressive Weapon", player))
|
||||
set_rule(world.get_entrance("True Double Jump", player),
|
||||
set_rule(multiworld.get_entrance("True Double Jump", player),
|
||||
lambda state: state.has("Double Jump Pack", player))
|
||||
set_rule(world.get_location("Shepherd Sheep", player),
|
||||
set_rule(multiworld.get_location("Shepherd Sheep", player),
|
||||
lambda state: state.has("DLC Quest: Progressive Weapon", player))
|
||||
set_rule(world.get_location("North West Ceiling Sheep", player),
|
||||
set_rule(multiworld.get_location("North West Ceiling Sheep", player),
|
||||
lambda state: state.has("DLC Quest: Progressive Weapon", player))
|
||||
set_rule(world.get_location("North West Alcove Sheep", player),
|
||||
set_rule(multiworld.get_location("North West Alcove Sheep", player),
|
||||
lambda state: state.has("DLC Quest: Progressive Weapon", player))
|
||||
set_rule(world.get_location("West Cave Sheep", player),
|
||||
set_rule(multiworld.get_location("West Cave Sheep", player),
|
||||
lambda state: state.has("DLC Quest: Progressive Weapon", player))
|
||||
set_rule(world.get_location("Gun", player),
|
||||
set_rule(multiworld.get_location("Gun", player),
|
||||
lambda state: state.has("Gun Pack", player))
|
||||
|
||||
if world_options.time_is_money == Options.TimeIsMoney.option_required:
|
||||
set_rule(world.get_location("Sword", player),
|
||||
set_rule(multiworld.get_location("Sword", player),
|
||||
lambda state: state.has("Time is Money Pack", player))
|
||||
|
||||
|
||||
def set_double_jump_glitchless_rules(world_options, player, world):
|
||||
def set_double_jump_glitchless_rules(world_options, player, multiworld):
|
||||
if world_options.double_jump_glitch != Options.DoubleJumpGlitch.option_none:
|
||||
return
|
||||
set_rule(world.get_entrance("Cloud Double Jump", player),
|
||||
set_rule(multiworld.get_entrance("Cloud Double Jump", player),
|
||||
lambda state: state.has("Double Jump Pack", player))
|
||||
set_rule(world.get_entrance("Forest Double Jump", player),
|
||||
set_rule(multiworld.get_entrance("Forest Double Jump", player),
|
||||
lambda state: state.has("Double Jump Pack", player))
|
||||
|
||||
|
||||
def set_easy_double_jump_glitch_rules(world_options, player, world):
|
||||
def set_easy_double_jump_glitch_rules(world_options, player, multiworld):
|
||||
if world_options.double_jump_glitch == Options.DoubleJumpGlitch.option_all:
|
||||
return
|
||||
set_rule(world.get_entrance("Behind Tree Double Jump", player),
|
||||
set_rule(multiworld.get_entrance("Behind Tree Double Jump", player),
|
||||
lambda state: state.has("Double Jump Pack", player))
|
||||
set_rule(world.get_entrance("Cave Roof", player),
|
||||
set_rule(multiworld.get_entrance("Cave Roof", player),
|
||||
lambda state: state.has("Double Jump Pack", player))
|
||||
|
||||
|
||||
def self_basic_coinsanity_funded_purchase_rules(world_options, player, world):
|
||||
def self_basic_coinsanity_funded_purchase_rules(world_options, player, multiworld):
|
||||
if world_options.coinsanity != Options.CoinSanity.option_coin:
|
||||
return
|
||||
if world_options.coinbundlequantity == -1:
|
||||
self_basic_coinsanity_piece_rules(player, world)
|
||||
self_basic_coinsanity_piece_rules(player, multiworld)
|
||||
return
|
||||
number_of_bundle = math.floor(825 / world_options.coinbundlequantity)
|
||||
for i in range(number_of_bundle):
|
||||
|
||||
item_coin = f"DLC Quest: {world_options.coinbundlequantity * (i + 1)} Coin"
|
||||
set_rule(world.get_location(item_coin, player),
|
||||
set_rule(multiworld.get_location(item_coin, player),
|
||||
has_enough_coin(player, world_options.coinbundlequantity * (i + 1)))
|
||||
if 825 % world_options.coinbundlequantity != 0:
|
||||
set_rule(world.get_location("DLC Quest: 825 Coin", player),
|
||||
set_rule(multiworld.get_location("DLC Quest: 825 Coin", player),
|
||||
has_enough_coin(player, 825))
|
||||
|
||||
set_rule(world.get_location("Movement Pack", player),
|
||||
set_rule(multiworld.get_location("Movement Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Bundle", player,
|
||||
math.ceil(4 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Animation Pack", player),
|
||||
set_rule(multiworld.get_location("Animation Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Bundle", player,
|
||||
math.ceil(5 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Audio Pack", player),
|
||||
set_rule(multiworld.get_location("Audio Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Bundle", player,
|
||||
math.ceil(5 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Pause Menu Pack", player),
|
||||
set_rule(multiworld.get_location("Pause Menu Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Bundle", player,
|
||||
math.ceil(5 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Time is Money Pack", player),
|
||||
set_rule(multiworld.get_location("Time is Money Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Bundle", player,
|
||||
math.ceil(20 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Double Jump Pack", player),
|
||||
set_rule(multiworld.get_location("Double Jump Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Bundle", player,
|
||||
math.ceil(100 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Pet Pack", player),
|
||||
set_rule(multiworld.get_location("Pet Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Bundle", player,
|
||||
math.ceil(5 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Sexy Outfits Pack", player),
|
||||
set_rule(multiworld.get_location("Sexy Outfits Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Bundle", player,
|
||||
math.ceil(5 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Top Hat Pack", player),
|
||||
set_rule(multiworld.get_location("Top Hat Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Bundle", player,
|
||||
math.ceil(5 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Map Pack", player),
|
||||
set_rule(multiworld.get_location("Map Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Bundle", player,
|
||||
math.ceil(140 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Gun Pack", player),
|
||||
set_rule(multiworld.get_location("Gun Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Bundle", player,
|
||||
math.ceil(75 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("The Zombie Pack", player),
|
||||
set_rule(multiworld.get_location("The Zombie Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Bundle", player,
|
||||
math.ceil(5 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Night Map Pack", player),
|
||||
set_rule(multiworld.get_location("Night Map Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Bundle", player,
|
||||
math.ceil(75 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Psychological Warfare Pack", player),
|
||||
set_rule(multiworld.get_location("Psychological Warfare Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Bundle", player,
|
||||
math.ceil(50 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Armor for your Horse Pack", player),
|
||||
set_rule(multiworld.get_location("Armor for your Horse Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Bundle", player,
|
||||
math.ceil(250 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Finish the Fight Pack", player),
|
||||
set_rule(multiworld.get_location("Finish the Fight Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Bundle", player,
|
||||
math.ceil(5 / world_options.coinbundlequantity)))
|
||||
|
||||
|
||||
def set_basic_self_funded_purchase_rules(world_options, player, world):
|
||||
def set_basic_self_funded_purchase_rules(world_options, player, multiworld):
|
||||
if world_options.coinsanity != Options.CoinSanity.option_none:
|
||||
return
|
||||
set_rule(world.get_location("Movement Pack", player),
|
||||
set_rule(multiworld.get_location("Movement Pack", player),
|
||||
has_enough_coin(player, 4))
|
||||
set_rule(world.get_location("Animation Pack", player),
|
||||
set_rule(multiworld.get_location("Animation Pack", player),
|
||||
has_enough_coin(player, 5))
|
||||
set_rule(world.get_location("Audio Pack", player),
|
||||
set_rule(multiworld.get_location("Audio Pack", player),
|
||||
has_enough_coin(player, 5))
|
||||
set_rule(world.get_location("Pause Menu Pack", player),
|
||||
set_rule(multiworld.get_location("Pause Menu Pack", player),
|
||||
has_enough_coin(player, 5))
|
||||
set_rule(world.get_location("Time is Money Pack", player),
|
||||
set_rule(multiworld.get_location("Time is Money Pack", player),
|
||||
has_enough_coin(player, 20))
|
||||
set_rule(world.get_location("Double Jump Pack", player),
|
||||
set_rule(multiworld.get_location("Double Jump Pack", player),
|
||||
has_enough_coin(player, 100))
|
||||
set_rule(world.get_location("Pet Pack", player),
|
||||
set_rule(multiworld.get_location("Pet Pack", player),
|
||||
has_enough_coin(player, 5))
|
||||
set_rule(world.get_location("Sexy Outfits Pack", player),
|
||||
set_rule(multiworld.get_location("Sexy Outfits Pack", player),
|
||||
has_enough_coin(player, 5))
|
||||
set_rule(world.get_location("Top Hat Pack", player),
|
||||
set_rule(multiworld.get_location("Top Hat Pack", player),
|
||||
has_enough_coin(player, 5))
|
||||
set_rule(world.get_location("Map Pack", player),
|
||||
set_rule(multiworld.get_location("Map Pack", player),
|
||||
has_enough_coin(player, 140))
|
||||
set_rule(world.get_location("Gun Pack", player),
|
||||
set_rule(multiworld.get_location("Gun Pack", player),
|
||||
has_enough_coin(player, 75))
|
||||
set_rule(world.get_location("The Zombie Pack", player),
|
||||
set_rule(multiworld.get_location("The Zombie Pack", player),
|
||||
has_enough_coin(player, 5))
|
||||
set_rule(world.get_location("Night Map Pack", player),
|
||||
set_rule(multiworld.get_location("Night Map Pack", player),
|
||||
has_enough_coin(player, 75))
|
||||
set_rule(world.get_location("Psychological Warfare Pack", player),
|
||||
set_rule(multiworld.get_location("Psychological Warfare Pack", player),
|
||||
has_enough_coin(player, 50))
|
||||
set_rule(world.get_location("Armor for your Horse Pack", player),
|
||||
set_rule(multiworld.get_location("Armor for your Horse Pack", player),
|
||||
has_enough_coin(player, 250))
|
||||
set_rule(world.get_location("Finish the Fight Pack", player),
|
||||
set_rule(multiworld.get_location("Finish the Fight Pack", player),
|
||||
has_enough_coin(player, 5))
|
||||
|
||||
|
||||
def self_basic_win_condition(world_options, player, world):
|
||||
def self_basic_win_condition(world_options, player, multiworld):
|
||||
if world_options.ending_choice == Options.EndingChoice.option_any:
|
||||
set_rule(world.get_location("Winning Basic", player),
|
||||
set_rule(multiworld.get_location("Winning Basic", player),
|
||||
lambda state: state.has("Finish the Fight Pack", player))
|
||||
if world_options.ending_choice == Options.EndingChoice.option_true:
|
||||
set_rule(world.get_location("Winning Basic", player),
|
||||
set_rule(multiworld.get_location("Winning Basic", player),
|
||||
lambda state: state.has("Armor for your Horse Pack", player) and state.has("Finish the Fight Pack",
|
||||
player))
|
||||
|
||||
|
||||
def set_lfod_rules(world_options, player, world):
|
||||
def set_lfod_rules(world_options, player, multiworld):
|
||||
if world_options.campaign == Options.Campaign.option_basic:
|
||||
return
|
||||
set_lfod_entrance_rules(player, world)
|
||||
set_boss_door_requirements_rules(player, world)
|
||||
set_lfod_self_obtained_items_rules(world_options, player, world)
|
||||
set_lfod_shuffled_items_rules(world_options, player, world)
|
||||
self_lfod_coinsanity_funded_purchase_rules(world_options, player, world)
|
||||
set_lfod_self_funded_purchase_rules(world_options, has_enough_coin_freemium, player, world)
|
||||
set_lfod_entrance_rules(player, multiworld)
|
||||
set_boss_door_requirements_rules(player, multiworld)
|
||||
set_lfod_self_obtained_items_rules(world_options, player, multiworld)
|
||||
set_lfod_shuffled_items_rules(world_options, player, multiworld)
|
||||
self_lfod_coinsanity_funded_purchase_rules(world_options, player, multiworld)
|
||||
set_lfod_self_funded_purchase_rules(world_options, has_enough_coin_freemium, player, multiworld)
|
||||
|
||||
|
||||
def set_lfod_entrance_rules(player, world):
|
||||
set_rule(world.get_entrance("Wall Jump Entrance", player),
|
||||
def set_lfod_entrance_rules(player, multiworld):
|
||||
set_rule(multiworld.get_entrance("Wall Jump Entrance", player),
|
||||
lambda state: state.has("Wall Jump Pack", player))
|
||||
set_rule(world.get_entrance("Harmless Plants", player),
|
||||
set_rule(multiworld.get_entrance("Harmless Plants", player),
|
||||
lambda state: state.has("Harmless Plants Pack", player))
|
||||
set_rule(world.get_entrance("Name Change Entrance", player),
|
||||
set_rule(multiworld.get_entrance("Name Change Entrance", player),
|
||||
lambda state: state.has("Name Change Pack", player))
|
||||
set_rule(world.get_entrance("Cut Content Entrance", player),
|
||||
set_rule(multiworld.get_entrance("Cut Content Entrance", player),
|
||||
lambda state: state.has("Cut Content Pack", player))
|
||||
set_rule(world.get_entrance("Blizzard", player),
|
||||
set_rule(multiworld.get_entrance("Blizzard", player),
|
||||
lambda state: state.has("Season Pass", player))
|
||||
set_rule(world.get_location("I Get That Reference!", player),
|
||||
set_rule(multiworld.get_location("I Get That Reference!", player),
|
||||
lambda state: state.has("Death of Comedy Pack", player))
|
||||
set_rule(world.get_location("Story is Important", player),
|
||||
set_rule(multiworld.get_location("Story is Important", player),
|
||||
lambda state: state.has("DLC NPC Pack", player))
|
||||
|
||||
|
||||
def set_boss_door_requirements_rules(player, world):
|
||||
def set_boss_door_requirements_rules(player, multiworld):
|
||||
sword_1 = "Big Sword Pack"
|
||||
sword_2 = "Really Big Sword Pack"
|
||||
sword_3 = "Unfathomable Sword Pack"
|
||||
|
||||
big_sword_location = world.get_location(sword_1, player)
|
||||
really_big_sword_location = world.get_location(sword_2, player)
|
||||
unfathomable_sword_location = world.get_location(sword_3, player)
|
||||
big_sword_location = multiworld.get_location(sword_1, player)
|
||||
really_big_sword_location = multiworld.get_location(sword_2, player)
|
||||
unfathomable_sword_location = multiworld.get_location(sword_3, player)
|
||||
|
||||
big_sword_valid_locations = [big_sword_location]
|
||||
really_big_sword_valid_locations = [big_sword_location, really_big_sword_location]
|
||||
@@ -277,7 +277,7 @@ def set_boss_door_requirements_rules(player, world):
|
||||
has_3_swords = lambda state: ((state.has(sword_1, player) or big_sword_during_boss_fight) and
|
||||
(state.has(sword_2, player) or really_big_sword_during_boss_fight) and
|
||||
(state.has(sword_3, player) or unfathomable_sword_during_boss_fight))
|
||||
set_rule(world.get_entrance("Boss Door", player), has_3_swords)
|
||||
set_rule(multiworld.get_entrance("Boss Door", player), has_3_swords)
|
||||
|
||||
|
||||
def set_lfod_self_obtained_items_rules(world_options, player, multiworld):
|
||||
@@ -295,234 +295,234 @@ def set_lfod_self_obtained_items_rules(world_options, player, multiworld):
|
||||
multiworld.register_indirect_condition(world.get_region("Cut Content"), world.get_entrance("Pickaxe Hard Cave"))
|
||||
|
||||
|
||||
def set_lfod_shuffled_items_rules(world_options, player, world):
|
||||
def set_lfod_shuffled_items_rules(world_options, player, multiworld):
|
||||
if world_options.item_shuffle != Options.ItemShuffle.option_shuffled:
|
||||
return
|
||||
set_rule(world.get_entrance("Vines", player),
|
||||
set_rule(multiworld.get_entrance("Vines", player),
|
||||
lambda state: state.has("Live Freemium or Die: Progressive Weapon", player))
|
||||
set_rule(world.get_entrance("Behind Rocks", player),
|
||||
set_rule(multiworld.get_entrance("Behind Rocks", player),
|
||||
lambda state: state.has("Live Freemium or Die: Progressive Weapon", player, 2))
|
||||
set_rule(world.get_entrance("Pickaxe Hard Cave", player),
|
||||
set_rule(multiworld.get_entrance("Pickaxe Hard Cave", player),
|
||||
lambda state: state.has("Live Freemium or Die: Progressive Weapon", player, 2))
|
||||
|
||||
set_rule(world.get_location("Wooden Sword", player),
|
||||
set_rule(multiworld.get_location("Wooden Sword", player),
|
||||
lambda state: state.has("Incredibly Important Pack", player))
|
||||
set_rule(world.get_location("Pickaxe", player),
|
||||
set_rule(multiworld.get_location("Pickaxe", player),
|
||||
lambda state: state.has("Humble Indie Bindle", player))
|
||||
set_rule(world.get_location("Humble Indie Bindle", player),
|
||||
set_rule(multiworld.get_location("Humble Indie Bindle", player),
|
||||
lambda state: state.has("Box of Various Supplies", player) and
|
||||
state.can_reach("Cut Content", 'region', player))
|
||||
set_rule(world.get_location("Box of Various Supplies", player),
|
||||
set_rule(multiworld.get_location("Box of Various Supplies", player),
|
||||
lambda state: state.can_reach("Cut Content", 'region', player))
|
||||
|
||||
|
||||
def self_lfod_coinsanity_funded_purchase_rules(world_options, player, world):
|
||||
def self_lfod_coinsanity_funded_purchase_rules(world_options, player, multiworld):
|
||||
if world_options.coinsanity != Options.CoinSanity.option_coin:
|
||||
return
|
||||
if world_options.coinbundlequantity == -1:
|
||||
self_lfod_coinsanity_piece_rules(player, world)
|
||||
self_lfod_coinsanity_piece_rules(player, multiworld)
|
||||
return
|
||||
number_of_bundle = math.floor(889 / world_options.coinbundlequantity)
|
||||
for i in range(number_of_bundle):
|
||||
|
||||
item_coin_freemium = f"Live Freemium or Die: {world_options.coinbundlequantity * (i + 1)} Coin"
|
||||
set_rule(world.get_location(item_coin_freemium, player),
|
||||
set_rule(multiworld.get_location(item_coin_freemium, player),
|
||||
has_enough_coin_freemium(player, world_options.coinbundlequantity * (i + 1)))
|
||||
if 889 % world_options.coinbundlequantity != 0:
|
||||
set_rule(world.get_location("Live Freemium or Die: 889 Coin", player),
|
||||
set_rule(multiworld.get_location("Live Freemium or Die: 889 Coin", player),
|
||||
has_enough_coin_freemium(player, 889))
|
||||
|
||||
add_rule(world.get_entrance("Boss Door", player),
|
||||
add_rule(multiworld.get_entrance("Boss Door", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Bundle", player,
|
||||
math.ceil(200 / world_options.coinbundlequantity)))
|
||||
|
||||
set_rule(world.get_location("Particles Pack", player),
|
||||
set_rule(multiworld.get_location("Particles Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Bundle", player,
|
||||
math.ceil(5 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Day One Patch Pack", player),
|
||||
set_rule(multiworld.get_location("Day One Patch Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Bundle", player,
|
||||
math.ceil(5 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Checkpoint Pack", player),
|
||||
set_rule(multiworld.get_location("Checkpoint Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Bundle", player,
|
||||
math.ceil(5 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Incredibly Important Pack", player),
|
||||
set_rule(multiworld.get_location("Incredibly Important Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Bundle", player,
|
||||
math.ceil(15 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Wall Jump Pack", player),
|
||||
set_rule(multiworld.get_location("Wall Jump Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Bundle", player,
|
||||
math.ceil(35 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Health Bar Pack", player),
|
||||
set_rule(multiworld.get_location("Health Bar Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Bundle", player,
|
||||
math.ceil(5 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Parallax Pack", player),
|
||||
set_rule(multiworld.get_location("Parallax Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Bundle", player,
|
||||
math.ceil(5 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Harmless Plants Pack", player),
|
||||
set_rule(multiworld.get_location("Harmless Plants Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Bundle", player,
|
||||
math.ceil(130 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Death of Comedy Pack", player),
|
||||
set_rule(multiworld.get_location("Death of Comedy Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Bundle", player,
|
||||
math.ceil(15 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Canadian Dialog Pack", player),
|
||||
set_rule(multiworld.get_location("Canadian Dialog Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Bundle", player,
|
||||
math.ceil(10 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("DLC NPC Pack", player),
|
||||
set_rule(multiworld.get_location("DLC NPC Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Bundle", player,
|
||||
math.ceil(15 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Cut Content Pack", player),
|
||||
set_rule(multiworld.get_location("Cut Content Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Bundle", player,
|
||||
math.ceil(40 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Name Change Pack", player),
|
||||
set_rule(multiworld.get_location("Name Change Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Bundle", player,
|
||||
math.ceil(150 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Season Pass", player),
|
||||
set_rule(multiworld.get_location("Season Pass", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Bundle", player,
|
||||
math.ceil(199 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("High Definition Next Gen Pack", player),
|
||||
set_rule(multiworld.get_location("High Definition Next Gen Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Bundle", player,
|
||||
math.ceil(20 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Increased HP Pack", player),
|
||||
set_rule(multiworld.get_location("Increased HP Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Bundle", player,
|
||||
math.ceil(10 / world_options.coinbundlequantity)))
|
||||
set_rule(world.get_location("Remove Ads Pack", player),
|
||||
set_rule(multiworld.get_location("Remove Ads Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Bundle", player,
|
||||
math.ceil(25 / world_options.coinbundlequantity)))
|
||||
|
||||
|
||||
def set_lfod_self_funded_purchase_rules(world_options, has_enough_coin_freemium, player, world):
|
||||
def set_lfod_self_funded_purchase_rules(world_options, has_enough_coin_freemium, player, multiworld):
|
||||
if world_options.coinsanity != Options.CoinSanity.option_none:
|
||||
return
|
||||
add_rule(world.get_entrance("Boss Door", player),
|
||||
add_rule(multiworld.get_entrance("Boss Door", player),
|
||||
has_enough_coin_freemium(player, 200))
|
||||
|
||||
set_rule(world.get_location("Particles Pack", player),
|
||||
set_rule(multiworld.get_location("Particles Pack", player),
|
||||
has_enough_coin_freemium(player, 5))
|
||||
set_rule(world.get_location("Day One Patch Pack", player),
|
||||
set_rule(multiworld.get_location("Day One Patch Pack", player),
|
||||
has_enough_coin_freemium(player, 5))
|
||||
set_rule(world.get_location("Checkpoint Pack", player),
|
||||
set_rule(multiworld.get_location("Checkpoint Pack", player),
|
||||
has_enough_coin_freemium(player, 5))
|
||||
set_rule(world.get_location("Incredibly Important Pack", player),
|
||||
set_rule(multiworld.get_location("Incredibly Important Pack", player),
|
||||
has_enough_coin_freemium(player, 15))
|
||||
set_rule(world.get_location("Wall Jump Pack", player),
|
||||
set_rule(multiworld.get_location("Wall Jump Pack", player),
|
||||
has_enough_coin_freemium(player, 35))
|
||||
set_rule(world.get_location("Health Bar Pack", player),
|
||||
set_rule(multiworld.get_location("Health Bar Pack", player),
|
||||
has_enough_coin_freemium(player, 5))
|
||||
set_rule(world.get_location("Parallax Pack", player),
|
||||
set_rule(multiworld.get_location("Parallax Pack", player),
|
||||
has_enough_coin_freemium(player, 5))
|
||||
set_rule(world.get_location("Harmless Plants Pack", player),
|
||||
set_rule(multiworld.get_location("Harmless Plants Pack", player),
|
||||
has_enough_coin_freemium(player, 130))
|
||||
set_rule(world.get_location("Death of Comedy Pack", player),
|
||||
set_rule(multiworld.get_location("Death of Comedy Pack", player),
|
||||
has_enough_coin_freemium(player, 15))
|
||||
set_rule(world.get_location("Canadian Dialog Pack", player),
|
||||
set_rule(multiworld.get_location("Canadian Dialog Pack", player),
|
||||
has_enough_coin_freemium(player, 10))
|
||||
set_rule(world.get_location("DLC NPC Pack", player),
|
||||
set_rule(multiworld.get_location("DLC NPC Pack", player),
|
||||
has_enough_coin_freemium(player, 15))
|
||||
set_rule(world.get_location("Cut Content Pack", player),
|
||||
set_rule(multiworld.get_location("Cut Content Pack", player),
|
||||
has_enough_coin_freemium(player, 40))
|
||||
set_rule(world.get_location("Name Change Pack", player),
|
||||
set_rule(multiworld.get_location("Name Change Pack", player),
|
||||
has_enough_coin_freemium(player, 150))
|
||||
set_rule(world.get_location("Season Pass", player),
|
||||
set_rule(multiworld.get_location("Season Pass", player),
|
||||
has_enough_coin_freemium(player, 199))
|
||||
set_rule(world.get_location("High Definition Next Gen Pack", player),
|
||||
set_rule(multiworld.get_location("High Definition Next Gen Pack", player),
|
||||
has_enough_coin_freemium(player, 20))
|
||||
set_rule(world.get_location("Increased HP Pack", player),
|
||||
set_rule(multiworld.get_location("Increased HP Pack", player),
|
||||
has_enough_coin_freemium(player, 10))
|
||||
set_rule(world.get_location("Remove Ads Pack", player),
|
||||
set_rule(multiworld.get_location("Remove Ads Pack", player),
|
||||
has_enough_coin_freemium(player, 25))
|
||||
|
||||
|
||||
def set_completion_condition(world_options, player, world):
|
||||
def set_completion_condition(world_options, player, multiworld):
|
||||
if world_options.campaign == Options.Campaign.option_basic:
|
||||
world.completion_condition[player] = lambda state: state.has("Victory Basic", player)
|
||||
multiworld.completion_condition[player] = lambda state: state.has("Victory Basic", player)
|
||||
if world_options.campaign == Options.Campaign.option_live_freemium_or_die:
|
||||
world.completion_condition[player] = lambda state: state.has("Victory Freemium", player)
|
||||
multiworld.completion_condition[player] = lambda state: state.has("Victory Freemium", player)
|
||||
if world_options.campaign == Options.Campaign.option_both:
|
||||
world.completion_condition[player] = lambda state: state.has("Victory Basic", player) and state.has(
|
||||
multiworld.completion_condition[player] = lambda state: state.has("Victory Basic", player) and state.has(
|
||||
"Victory Freemium", player)
|
||||
|
||||
|
||||
def self_basic_coinsanity_piece_rules(player, world):
|
||||
def self_basic_coinsanity_piece_rules(player, multiworld):
|
||||
for i in range(1,8251):
|
||||
|
||||
item_coin = f"DLC Quest: {i} Coin Piece"
|
||||
set_rule(world.get_location(item_coin, player),
|
||||
set_rule(multiworld.get_location(item_coin, player),
|
||||
has_enough_coin(player, math.ceil(i / 10)))
|
||||
|
||||
set_rule(world.get_location("Movement Pack", player),
|
||||
set_rule(multiworld.get_location("Movement Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Piece", player, 40))
|
||||
set_rule(world.get_location("Animation Pack", player),
|
||||
set_rule(multiworld.get_location("Animation Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Piece", player, 50))
|
||||
set_rule(world.get_location("Audio Pack", player),
|
||||
set_rule(multiworld.get_location("Audio Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Piece", player, 50))
|
||||
set_rule(world.get_location("Pause Menu Pack", player),
|
||||
set_rule(multiworld.get_location("Pause Menu Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Piece", player, 50))
|
||||
set_rule(world.get_location("Time is Money Pack", player),
|
||||
set_rule(multiworld.get_location("Time is Money Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Piece", player, 200))
|
||||
set_rule(world.get_location("Double Jump Pack", player),
|
||||
set_rule(multiworld.get_location("Double Jump Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Piece", player, 100))
|
||||
set_rule(world.get_location("Pet Pack", player),
|
||||
set_rule(multiworld.get_location("Pet Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Piece", player, 50))
|
||||
set_rule(world.get_location("Sexy Outfits Pack", player),
|
||||
set_rule(multiworld.get_location("Sexy Outfits Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Piece", player, 50))
|
||||
set_rule(world.get_location("Top Hat Pack", player),
|
||||
set_rule(multiworld.get_location("Top Hat Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Piece", player, 50))
|
||||
set_rule(world.get_location("Map Pack", player),
|
||||
set_rule(multiworld.get_location("Map Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Piece", player, 1400))
|
||||
set_rule(world.get_location("Gun Pack", player),
|
||||
set_rule(multiworld.get_location("Gun Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Piece", player, 750))
|
||||
set_rule(world.get_location("The Zombie Pack", player),
|
||||
set_rule(multiworld.get_location("The Zombie Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Piece", player, 50))
|
||||
set_rule(world.get_location("Night Map Pack", player),
|
||||
set_rule(multiworld.get_location("Night Map Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Piece", player, 750))
|
||||
set_rule(world.get_location("Psychological Warfare Pack", player),
|
||||
set_rule(multiworld.get_location("Psychological Warfare Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Piece", player, 500))
|
||||
set_rule(world.get_location("Armor for your Horse Pack", player),
|
||||
set_rule(multiworld.get_location("Armor for your Horse Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Piece", player, 2500))
|
||||
set_rule(world.get_location("Finish the Fight Pack", player),
|
||||
set_rule(multiworld.get_location("Finish the Fight Pack", player),
|
||||
lambda state: state.has("DLC Quest: Coin Piece", player, 50))
|
||||
|
||||
|
||||
def self_lfod_coinsanity_piece_rules(player, world):
|
||||
def self_lfod_coinsanity_piece_rules(player, multiworld):
|
||||
for i in range(1, 8891):
|
||||
|
||||
item_coin_freemium = f"Live Freemium or Die: {i} Coin Piece"
|
||||
set_rule(world.get_location(item_coin_freemium, player),
|
||||
set_rule(multiworld.get_location(item_coin_freemium, player),
|
||||
has_enough_coin_freemium(player, math.ceil(i / 10)))
|
||||
|
||||
add_rule(world.get_entrance("Boss Door", player),
|
||||
add_rule(multiworld.get_entrance("Boss Door", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Piece", player, 2000))
|
||||
|
||||
set_rule(world.get_location("Particles Pack", player),
|
||||
set_rule(multiworld.get_location("Particles Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Piece", player, 50))
|
||||
set_rule(world.get_location("Day One Patch Pack", player),
|
||||
set_rule(multiworld.get_location("Day One Patch Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Piece", player, 50))
|
||||
set_rule(world.get_location("Checkpoint Pack", player),
|
||||
set_rule(multiworld.get_location("Checkpoint Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Piece", player, 50))
|
||||
set_rule(world.get_location("Incredibly Important Pack", player),
|
||||
set_rule(multiworld.get_location("Incredibly Important Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Piece", player, 150))
|
||||
set_rule(world.get_location("Wall Jump Pack", player),
|
||||
set_rule(multiworld.get_location("Wall Jump Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Piece", player, 350))
|
||||
set_rule(world.get_location("Health Bar Pack", player),
|
||||
set_rule(multiworld.get_location("Health Bar Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Piece", player, 50))
|
||||
set_rule(world.get_location("Parallax Pack", player),
|
||||
set_rule(multiworld.get_location("Parallax Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Piece", player, 50))
|
||||
set_rule(world.get_location("Harmless Plants Pack", player),
|
||||
set_rule(multiworld.get_location("Harmless Plants Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Piece", player, 1300))
|
||||
set_rule(world.get_location("Death of Comedy Pack", player),
|
||||
set_rule(multiworld.get_location("Death of Comedy Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Piece", player, 150))
|
||||
set_rule(world.get_location("Canadian Dialog Pack", player),
|
||||
set_rule(multiworld.get_location("Canadian Dialog Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Piece", player, 100))
|
||||
set_rule(world.get_location("DLC NPC Pack", player),
|
||||
set_rule(multiworld.get_location("DLC NPC Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Piece", player, 150))
|
||||
set_rule(world.get_location("Cut Content Pack", player),
|
||||
set_rule(multiworld.get_location("Cut Content Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Piece", player, 400))
|
||||
set_rule(world.get_location("Name Change Pack", player),
|
||||
set_rule(multiworld.get_location("Name Change Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Piece", player, 1500))
|
||||
set_rule(world.get_location("Season Pass", player),
|
||||
set_rule(multiworld.get_location("Season Pass", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Piece", player, 199))
|
||||
set_rule(world.get_location("High Definition Next Gen Pack", player),
|
||||
set_rule(multiworld.get_location("High Definition Next Gen Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Piece", player, 20))
|
||||
set_rule(world.get_location("Increased HP Pack", player),
|
||||
set_rule(multiworld.get_location("Increased HP Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Piece", player, 100))
|
||||
set_rule(world.get_location("Remove Ads Pack", player),
|
||||
set_rule(multiworld.get_location("Remove Ads Pack", player),
|
||||
lambda state: state.has("Live Freemium or Die: Coin Piece", player, 250))
|
||||
|
||||
@@ -43,7 +43,7 @@ class FaxanaduWorld(World):
|
||||
item_name_to_item = {item.name: item for item in Items.items}
|
||||
location_name_to_id = {loc.name: loc.id for loc in Locations.locations if loc.id is not None}
|
||||
|
||||
def __init__(self, world: MultiWorld, player: int):
|
||||
def __init__(self, multiworld: MultiWorld, player: int):
|
||||
self.filler_ratios: Dict[str, int] = {
|
||||
item.name: item.count
|
||||
for item in Items.items
|
||||
@@ -51,7 +51,7 @@ class FaxanaduWorld(World):
|
||||
}
|
||||
# Remove poison by default to respect itemlinking
|
||||
self.filler_ratios["Poison"] = 0
|
||||
super().__init__(world, player)
|
||||
super().__init__(multiworld, player)
|
||||
|
||||
def create_regions(self):
|
||||
Regions.create_regions(self)
|
||||
|
||||
@@ -41,8 +41,8 @@ class FF1Locations:
|
||||
|
||||
@staticmethod
|
||||
def create_menu_region(player: int, locations: Dict[str, int],
|
||||
rules: Dict[str, List[List[str]]], world: MultiWorld) -> Region:
|
||||
menu_region = Region("Menu", player, world)
|
||||
rules: Dict[str, List[List[str]]], multiworld: MultiWorld) -> Region:
|
||||
menu_region = Region("Menu", player, multiworld)
|
||||
for name, address in locations.items():
|
||||
location = Location(player, name, address, menu_region)
|
||||
## TODO REMOVE WHEN LOGIC FOR TOFR IS CORRECT
|
||||
|
||||
@@ -50,8 +50,8 @@ class FF1World(World):
|
||||
|
||||
web = FF1Web()
|
||||
|
||||
def __init__(self, world: MultiWorld, player: int):
|
||||
super().__init__(world, player)
|
||||
def __init__(self, multiworld: MultiWorld, player: int):
|
||||
super().__init__(multiworld, player)
|
||||
self.locked_items = []
|
||||
self.locked_locations = []
|
||||
|
||||
|
||||
@@ -33,10 +33,10 @@ def process_rules(spot, access):
|
||||
add_rule(spot, lambda state: state.has_all(access, spot.player))
|
||||
|
||||
|
||||
def create_region(world: MultiWorld, player: int, name: str, room_id=None, locations=None, links=None):
|
||||
def create_region(multiworld: MultiWorld, player: int, name: str, room_id=None, locations=None, links=None):
|
||||
if links is None:
|
||||
links = []
|
||||
ret = Region(name, player, world)
|
||||
ret = Region(name, player, multiworld)
|
||||
if locations:
|
||||
for location in locations:
|
||||
location.parent_region = ret
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
from .ExtractedData import region_names, exits, connectors
|
||||
|
||||
|
||||
def create_regions(world, player: int):
|
||||
from . import create_region, HKLocation, HKItem
|
||||
world.regions.append(create_region(world, player, 'Menu', None, ['Hollow Nest S&Q']))
|
||||
for region in region_names:
|
||||
world.regions.append(create_region(world, player, region, [],
|
||||
exits.get(region, [])))
|
||||
for entrance_name, exit_name in connectors.items():
|
||||
if exit_name:
|
||||
target_region = world.get_entrance(exit_name, player).parent_region
|
||||
world.get_entrance(entrance_name, player).connect(target_region)
|
||||
if not entrance_name.endswith("_R"):
|
||||
# a traversable entrance puts the name of the target door "into logic".
|
||||
loc = HKLocation(player, exit_name, None, target_region)
|
||||
loc.place_locked_item(HKItem(exit_name,
|
||||
not exit_name.startswith("White_Palace_"),
|
||||
None, "Event", player))
|
||||
target_region.locations.append(loc)
|
||||
else:
|
||||
ent = world.get_entrance(entrance_name, player)
|
||||
ent.parent_region.exits.remove(ent)
|
||||
|
||||
|
||||
+144
-144
@@ -126,7 +126,7 @@ def enter_hylemxylem(state: CollectionState, player: int) -> bool:
|
||||
|
||||
|
||||
def set_rules(hylics2world):
|
||||
world = hylics2world.multiworld
|
||||
multiworld = hylics2world.multiworld
|
||||
player = hylics2world.player
|
||||
|
||||
extra = hylics2world.options.extra_items_in_logic
|
||||
@@ -135,23 +135,23 @@ def set_rules(hylics2world):
|
||||
start_location = hylics2world.options.start_location
|
||||
|
||||
# Afterlife
|
||||
add_rule(world.get_location("Afterlife: TV", player),
|
||||
add_rule(multiworld.get_location("Afterlife: TV", player),
|
||||
lambda state: cave_key(state, player))
|
||||
|
||||
# New Muldul
|
||||
add_rule(world.get_location("New Muldul: Underground Chest", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Underground Chest", player),
|
||||
lambda state: air_dash(state, player))
|
||||
add_rule(world.get_location("New Muldul: TV", player),
|
||||
add_rule(multiworld.get_location("New Muldul: TV", player),
|
||||
lambda state: house_key(state, player))
|
||||
add_rule(world.get_location("New Muldul: Upper House Chest 1", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Upper House Chest 1", player),
|
||||
lambda state: upper_house_key(state, player))
|
||||
add_rule(world.get_location("New Muldul: Upper House Chest 2", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Upper House Chest 2", player),
|
||||
lambda state: upper_house_key(state, player))
|
||||
add_rule(world.get_location("New Muldul: Pot above Vault", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Pot above Vault", player),
|
||||
lambda state: air_dash(state, player))
|
||||
|
||||
# New Muldul Vault
|
||||
add_rule(world.get_location("New Muldul: Rescued Blerol 1", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Rescued Blerol 1", player),
|
||||
lambda state: (
|
||||
(
|
||||
(
|
||||
@@ -165,7 +165,7 @@ def set_rules(hylics2world):
|
||||
)
|
||||
or enter_hylemxylem(state, player)
|
||||
))
|
||||
add_rule(world.get_location("New Muldul: Rescued Blerol 2", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Rescued Blerol 2", player),
|
||||
lambda state: (
|
||||
(
|
||||
(
|
||||
@@ -179,194 +179,194 @@ def set_rules(hylics2world):
|
||||
)
|
||||
or enter_hylemxylem(state, player)
|
||||
))
|
||||
add_rule(world.get_location("New Muldul: Vault Left Chest", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Vault Left Chest", player),
|
||||
lambda state: enter_hylemxylem(state, player))
|
||||
add_rule(world.get_location("New Muldul: Vault Right Chest", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Vault Right Chest", player),
|
||||
lambda state: enter_hylemxylem(state, player))
|
||||
add_rule(world.get_location("New Muldul: Vault Bomb", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Vault Bomb", player),
|
||||
lambda state: enter_hylemxylem(state, player))
|
||||
|
||||
# Viewax's Edifice
|
||||
add_rule(world.get_location("Viewax's Edifice: Canopic Jar", player),
|
||||
add_rule(multiworld.get_location("Viewax's Edifice: Canopic Jar", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Viewax's Edifice: Cave Sarcophagus", player),
|
||||
add_rule(multiworld.get_location("Viewax's Edifice: Cave Sarcophagus", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Viewax's Edifice: Shielded Key", player),
|
||||
add_rule(multiworld.get_location("Viewax's Edifice: Shielded Key", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Viewax's Edifice: Shielded Key", player),
|
||||
add_rule(multiworld.get_location("Viewax's Edifice: Shielded Key", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Viewax's Edifice: Tower Pot", player),
|
||||
add_rule(multiworld.get_location("Viewax's Edifice: Tower Pot", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Viewax's Edifice: Tower Jar", player),
|
||||
add_rule(multiworld.get_location("Viewax's Edifice: Tower Jar", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Viewax's Edifice: Tower Chest", player),
|
||||
add_rule(multiworld.get_location("Viewax's Edifice: Tower Chest", player),
|
||||
lambda state: (
|
||||
paddle(state, player)
|
||||
and tower_key(state, player)
|
||||
))
|
||||
add_rule(world.get_location("Viewax's Edifice: Viewax Pot", player),
|
||||
add_rule(multiworld.get_location("Viewax's Edifice: Viewax Pot", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Viewax's Edifice: Defeat Viewax", player),
|
||||
add_rule(multiworld.get_location("Viewax's Edifice: Defeat Viewax", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Viewax's Edifice: TV", player),
|
||||
add_rule(multiworld.get_location("Viewax's Edifice: TV", player),
|
||||
lambda state: (
|
||||
paddle(state, player)
|
||||
and jail_key(state, player)
|
||||
))
|
||||
add_rule(world.get_location("Viewax's Edifice: Sage Fridge", player),
|
||||
add_rule(multiworld.get_location("Viewax's Edifice: Sage Fridge", player),
|
||||
lambda state: air_dash(state, player))
|
||||
add_rule(world.get_location("Viewax's Edifice: Sage Item 1", player),
|
||||
add_rule(multiworld.get_location("Viewax's Edifice: Sage Item 1", player),
|
||||
lambda state: air_dash(state, player))
|
||||
add_rule(world.get_location("Viewax's Edifice: Sage Item 2", player),
|
||||
add_rule(multiworld.get_location("Viewax's Edifice: Sage Item 2", player),
|
||||
lambda state: air_dash(state, player))
|
||||
|
||||
# Arcade 1
|
||||
add_rule(world.get_location("Arcade 1: Key", player),
|
||||
add_rule(multiworld.get_location("Arcade 1: Key", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Arcade 1: Coin Dash", player),
|
||||
add_rule(multiworld.get_location("Arcade 1: Coin Dash", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Arcade 1: Burrito Alcove 1", player),
|
||||
add_rule(multiworld.get_location("Arcade 1: Burrito Alcove 1", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Arcade 1: Burrito Alcove 2", player),
|
||||
add_rule(multiworld.get_location("Arcade 1: Burrito Alcove 2", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Arcade 1: Behind Spikes Banana", player),
|
||||
add_rule(multiworld.get_location("Arcade 1: Behind Spikes Banana", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Arcade 1: Pyramid Banana", player),
|
||||
add_rule(multiworld.get_location("Arcade 1: Pyramid Banana", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Arcade 1: Moving Platforms Muscle Applique", player),
|
||||
add_rule(multiworld.get_location("Arcade 1: Moving Platforms Muscle Applique", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Arcade 1: Bed Banana", player),
|
||||
add_rule(multiworld.get_location("Arcade 1: Bed Banana", player),
|
||||
lambda state: paddle(state, player))
|
||||
|
||||
# Airship
|
||||
add_rule(world.get_location("Airship: Talk to Somsnosa", player),
|
||||
add_rule(multiworld.get_location("Airship: Talk to Somsnosa", player),
|
||||
lambda state: worm_room_key(state, player))
|
||||
|
||||
# Foglast
|
||||
add_rule(world.get_location("Foglast: Underground Sarcophagus", player),
|
||||
add_rule(multiworld.get_location("Foglast: Underground Sarcophagus", player),
|
||||
lambda state: air_dash(state, player))
|
||||
add_rule(world.get_location("Foglast: Shielded Key", player),
|
||||
add_rule(multiworld.get_location("Foglast: Shielded Key", player),
|
||||
lambda state: air_dash(state, player))
|
||||
add_rule(world.get_location("Foglast: TV", player),
|
||||
add_rule(multiworld.get_location("Foglast: TV", player),
|
||||
lambda state: (
|
||||
air_dash(state, player)
|
||||
and clicker(state, player)
|
||||
))
|
||||
add_rule(world.get_location("Foglast: Buy Clicker", player),
|
||||
add_rule(multiworld.get_location("Foglast: Buy Clicker", player),
|
||||
lambda state: air_dash(state, player))
|
||||
add_rule(world.get_location("Foglast: Shielded Chest", player),
|
||||
add_rule(multiworld.get_location("Foglast: Shielded Chest", player),
|
||||
lambda state: air_dash(state, player))
|
||||
add_rule(world.get_location("Foglast: Cave Fridge", player),
|
||||
add_rule(multiworld.get_location("Foglast: Cave Fridge", player),
|
||||
lambda state: air_dash(state, player))
|
||||
add_rule(world.get_location("Foglast: Roof Sarcophagus", player),
|
||||
add_rule(multiworld.get_location("Foglast: Roof Sarcophagus", player),
|
||||
lambda state: (
|
||||
air_dash(state, player)
|
||||
and bridge_key(state, player)
|
||||
))
|
||||
add_rule(world.get_location("Foglast: Under Lair Sarcophagus 1", player),
|
||||
add_rule(multiworld.get_location("Foglast: Under Lair Sarcophagus 1", player),
|
||||
lambda state: (
|
||||
air_dash(state, player)
|
||||
and bridge_key(state, player)
|
||||
))
|
||||
add_rule(world.get_location("Foglast: Under Lair Sarcophagus 2", player),
|
||||
add_rule(multiworld.get_location("Foglast: Under Lair Sarcophagus 2", player),
|
||||
lambda state: (
|
||||
air_dash(state, player)
|
||||
and bridge_key(state, player)
|
||||
))
|
||||
add_rule(world.get_location("Foglast: Under Lair Sarcophagus 3", player),
|
||||
add_rule(multiworld.get_location("Foglast: Under Lair Sarcophagus 3", player),
|
||||
lambda state: (
|
||||
air_dash(state, player)
|
||||
and bridge_key(state, player)
|
||||
))
|
||||
add_rule(world.get_location("Foglast: Sage Sarcophagus", player),
|
||||
add_rule(multiworld.get_location("Foglast: Sage Sarcophagus", player),
|
||||
lambda state: (
|
||||
air_dash(state, player)
|
||||
and bridge_key(state, player)
|
||||
))
|
||||
add_rule(world.get_location("Foglast: Sage Item 1", player),
|
||||
add_rule(multiworld.get_location("Foglast: Sage Item 1", player),
|
||||
lambda state: (
|
||||
air_dash(state, player)
|
||||
and bridge_key(state, player)
|
||||
))
|
||||
add_rule(world.get_location("Foglast: Sage Item 2", player),
|
||||
add_rule(multiworld.get_location("Foglast: Sage Item 2", player),
|
||||
lambda state: (
|
||||
air_dash(state, player)
|
||||
and bridge_key(state, player)
|
||||
))
|
||||
|
||||
# Drill Castle
|
||||
add_rule(world.get_location("Drill Castle: Island Banana", player),
|
||||
add_rule(multiworld.get_location("Drill Castle: Island Banana", player),
|
||||
lambda state: air_dash(state, player))
|
||||
add_rule(world.get_location("Drill Castle: Island Pot", player),
|
||||
add_rule(multiworld.get_location("Drill Castle: Island Pot", player),
|
||||
lambda state: air_dash(state, player))
|
||||
add_rule(world.get_location("Drill Castle: Cave Sarcophagus", player),
|
||||
add_rule(multiworld.get_location("Drill Castle: Cave Sarcophagus", player),
|
||||
lambda state: air_dash(state, player))
|
||||
add_rule(world.get_location("Drill Castle: TV", player),
|
||||
add_rule(multiworld.get_location("Drill Castle: TV", player),
|
||||
lambda state: air_dash(state, player))
|
||||
|
||||
# Sage Labyrinth
|
||||
add_rule(world.get_location("Sage Labyrinth: Sage Item 1", player),
|
||||
add_rule(multiworld.get_location("Sage Labyrinth: Sage Item 1", player),
|
||||
lambda state: deep_key(state, player))
|
||||
add_rule(world.get_location("Sage Labyrinth: Sage Item 2", player),
|
||||
add_rule(multiworld.get_location("Sage Labyrinth: Sage Item 2", player),
|
||||
lambda state: deep_key(state, player))
|
||||
add_rule(world.get_location("Sage Labyrinth: Sage Left Arm", player),
|
||||
add_rule(multiworld.get_location("Sage Labyrinth: Sage Left Arm", player),
|
||||
lambda state: deep_key(state, player))
|
||||
add_rule(world.get_location("Sage Labyrinth: Sage Right Arm", player),
|
||||
add_rule(multiworld.get_location("Sage Labyrinth: Sage Right Arm", player),
|
||||
lambda state: deep_key(state, player))
|
||||
add_rule(world.get_location("Sage Labyrinth: Sage Left Leg", player),
|
||||
add_rule(multiworld.get_location("Sage Labyrinth: Sage Left Leg", player),
|
||||
lambda state: deep_key(state, player))
|
||||
add_rule(world.get_location("Sage Labyrinth: Sage Right Leg", player),
|
||||
add_rule(multiworld.get_location("Sage Labyrinth: Sage Right Leg", player),
|
||||
lambda state: deep_key(state, player))
|
||||
|
||||
# Sage Airship
|
||||
add_rule(world.get_location("Sage Airship: TV", player),
|
||||
add_rule(multiworld.get_location("Sage Airship: TV", player),
|
||||
lambda state: all_tokens(state, player))
|
||||
|
||||
# Hylemxylem
|
||||
add_rule(world.get_location("Hylemxylem: Upper Chamber Banana", player),
|
||||
add_rule(multiworld.get_location("Hylemxylem: Upper Chamber Banana", player),
|
||||
lambda state: upper_chamber_key(state, player))
|
||||
add_rule(world.get_location("Hylemxylem: Across Upper Reservoir Chest", player),
|
||||
add_rule(multiworld.get_location("Hylemxylem: Across Upper Reservoir Chest", player),
|
||||
lambda state: upper_chamber_key(state, player))
|
||||
add_rule(world.get_location("Hylemxylem: Drained Lower Reservoir Chest", player),
|
||||
add_rule(multiworld.get_location("Hylemxylem: Drained Lower Reservoir Chest", player),
|
||||
lambda state: upper_chamber_key(state, player))
|
||||
add_rule(world.get_location("Hylemxylem: Drained Lower Reservoir Burrito 1", player),
|
||||
add_rule(multiworld.get_location("Hylemxylem: Drained Lower Reservoir Burrito 1", player),
|
||||
lambda state: upper_chamber_key(state, player))
|
||||
add_rule(world.get_location("Hylemxylem: Drained Lower Reservoir Burrito 2", player),
|
||||
add_rule(multiworld.get_location("Hylemxylem: Drained Lower Reservoir Burrito 2", player),
|
||||
lambda state: upper_chamber_key(state, player))
|
||||
add_rule(world.get_location("Hylemxylem: Lower Reservoir Hole Pot 1", player),
|
||||
add_rule(multiworld.get_location("Hylemxylem: Lower Reservoir Hole Pot 1", player),
|
||||
lambda state: upper_chamber_key(state, player))
|
||||
add_rule(world.get_location("Hylemxylem: Lower Reservoir Hole Pot 2", player),
|
||||
add_rule(multiworld.get_location("Hylemxylem: Lower Reservoir Hole Pot 2", player),
|
||||
lambda state: upper_chamber_key(state, player))
|
||||
add_rule(world.get_location("Hylemxylem: Lower Reservoir Hole Pot 3", player),
|
||||
add_rule(multiworld.get_location("Hylemxylem: Lower Reservoir Hole Pot 3", player),
|
||||
lambda state: upper_chamber_key(state, player))
|
||||
add_rule(world.get_location("Hylemxylem: Lower Reservoir Hole Sarcophagus", player),
|
||||
add_rule(multiworld.get_location("Hylemxylem: Lower Reservoir Hole Sarcophagus", player),
|
||||
lambda state: upper_chamber_key(state, player))
|
||||
add_rule(world.get_location("Hylemxylem: Drained Upper Reservoir Burrito 1", player),
|
||||
add_rule(multiworld.get_location("Hylemxylem: Drained Upper Reservoir Burrito 1", player),
|
||||
lambda state: upper_chamber_key(state, player))
|
||||
add_rule(world.get_location("Hylemxylem: Drained Upper Reservoir Burrito 2", player),
|
||||
add_rule(multiworld.get_location("Hylemxylem: Drained Upper Reservoir Burrito 2", player),
|
||||
lambda state: upper_chamber_key(state, player))
|
||||
add_rule(world.get_location("Hylemxylem: Drained Upper Reservoir Burrito 3", player),
|
||||
add_rule(multiworld.get_location("Hylemxylem: Drained Upper Reservoir Burrito 3", player),
|
||||
lambda state: upper_chamber_key(state, player))
|
||||
add_rule(world.get_location("Hylemxylem: Upper Reservoir Hole Key", player),
|
||||
add_rule(multiworld.get_location("Hylemxylem: Upper Reservoir Hole Key", player),
|
||||
lambda state: upper_chamber_key(state, player))
|
||||
|
||||
# extra rules if Extra Items in Logic is enabled
|
||||
if extra:
|
||||
for i in world.get_region("Foglast", player).entrances:
|
||||
for i in multiworld.get_region("Foglast", player).entrances:
|
||||
add_rule(i, lambda state: charge_up(state, player))
|
||||
for i in world.get_region("Sage Airship", player).entrances:
|
||||
for i in multiworld.get_region("Sage Airship", player).entrances:
|
||||
add_rule(i, lambda state: (
|
||||
charge_up(state, player)
|
||||
and paper_cup(state, player)
|
||||
and worm_room_key(state, player)
|
||||
))
|
||||
for i in world.get_region("Hylemxylem", player).entrances:
|
||||
for i in multiworld.get_region("Hylemxylem", player).entrances:
|
||||
add_rule(i, lambda state: (
|
||||
charge_up(state, player)
|
||||
and paper_cup(state, player)
|
||||
))
|
||||
|
||||
add_rule(world.get_location("Sage Labyrinth: Motor Hunter Sarcophagus", player),
|
||||
add_rule(multiworld.get_location("Sage Labyrinth: Motor Hunter Sarcophagus", player),
|
||||
lambda state: (
|
||||
charge_up(state, player)
|
||||
and paper_cup(state, player)
|
||||
@@ -374,9 +374,9 @@ def set_rules(hylics2world):
|
||||
|
||||
# extra rules if Shuffle Party Members is enabled
|
||||
if party:
|
||||
for i in world.get_region("Arcade Island", player).entrances:
|
||||
for i in multiworld.get_region("Arcade Island", player).entrances:
|
||||
add_rule(i, lambda state: party_3(state, player))
|
||||
for i in world.get_region("Foglast", player).entrances:
|
||||
for i in multiworld.get_region("Foglast", player).entrances:
|
||||
add_rule(i, lambda state: (
|
||||
party_3(state, player)
|
||||
or (
|
||||
@@ -384,197 +384,197 @@ def set_rules(hylics2world):
|
||||
and jail_key(state, player)
|
||||
)
|
||||
))
|
||||
for i in world.get_region("Sage Airship", player).entrances:
|
||||
for i in multiworld.get_region("Sage Airship", player).entrances:
|
||||
add_rule(i, lambda state: party_3(state, player))
|
||||
for i in world.get_region("Hylemxylem", player).entrances:
|
||||
for i in multiworld.get_region("Hylemxylem", player).entrances:
|
||||
add_rule(i, lambda state: party_3(state, player))
|
||||
|
||||
add_rule(world.get_location("Viewax's Edifice: Defeat Viewax", player),
|
||||
add_rule(multiworld.get_location("Viewax's Edifice: Defeat Viewax", player),
|
||||
lambda state: party_2(state, player))
|
||||
add_rule(world.get_location("New Muldul: Rescued Blerol 1", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Rescued Blerol 1", player),
|
||||
lambda state: party_2(state, player))
|
||||
add_rule(world.get_location("New Muldul: Rescued Blerol 2", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Rescued Blerol 2", player),
|
||||
lambda state: party_2(state, player))
|
||||
add_rule(world.get_location("New Muldul: Vault Left Chest", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Vault Left Chest", player),
|
||||
lambda state: party_3(state, player))
|
||||
add_rule(world.get_location("New Muldul: Vault Right Chest", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Vault Right Chest", player),
|
||||
lambda state: party_3(state, player))
|
||||
add_rule(world.get_location("New Muldul: Vault Bomb", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Vault Bomb", player),
|
||||
lambda state: party_3(state, player))
|
||||
add_rule(world.get_location("Juice Ranch: Battle with Somsnosa", player),
|
||||
add_rule(multiworld.get_location("Juice Ranch: Battle with Somsnosa", player),
|
||||
lambda state: party_2(state, player))
|
||||
add_rule(world.get_location("Juice Ranch: Somsnosa Joins", player),
|
||||
add_rule(multiworld.get_location("Juice Ranch: Somsnosa Joins", player),
|
||||
lambda state: party_2(state, player))
|
||||
add_rule(world.get_location("Airship: Talk to Somsnosa", player),
|
||||
add_rule(multiworld.get_location("Airship: Talk to Somsnosa", player),
|
||||
lambda state: party_3(state, player))
|
||||
add_rule(world.get_location("Sage Labyrinth: Motor Hunter Sarcophagus", player),
|
||||
add_rule(multiworld.get_location("Sage Labyrinth: Motor Hunter Sarcophagus", player),
|
||||
lambda state: party_3(state, player))
|
||||
|
||||
# extra rules if Shuffle Red Medallions is enabled
|
||||
if medallion:
|
||||
add_rule(world.get_location("New Muldul: Upper House Medallion", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Upper House Medallion", player),
|
||||
lambda state: upper_house_key(state, player))
|
||||
add_rule(world.get_location("New Muldul: Vault Rear Left Medallion", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Vault Rear Left Medallion", player),
|
||||
lambda state: (
|
||||
enter_foglast(state, player)
|
||||
and bridge_key(state, player)
|
||||
and air_dash(state, player)
|
||||
))
|
||||
add_rule(world.get_location("New Muldul: Vault Rear Right Medallion", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Vault Rear Right Medallion", player),
|
||||
lambda state: (
|
||||
enter_foglast(state, player)
|
||||
and bridge_key(state, player)
|
||||
and air_dash(state, player)
|
||||
))
|
||||
add_rule(world.get_location("New Muldul: Vault Center Medallion", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Vault Center Medallion", player),
|
||||
lambda state: (
|
||||
enter_foglast(state, player)
|
||||
and bridge_key(state, player)
|
||||
and air_dash(state, player)
|
||||
))
|
||||
add_rule(world.get_location("New Muldul: Vault Front Left Medallion", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Vault Front Left Medallion", player),
|
||||
lambda state: (
|
||||
enter_foglast(state, player)
|
||||
and bridge_key(state, player)
|
||||
and air_dash(state, player)
|
||||
))
|
||||
add_rule(world.get_location("New Muldul: Vault Front Right Medallion", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Vault Front Right Medallion", player),
|
||||
lambda state: (
|
||||
enter_foglast(state, player)
|
||||
and bridge_key(state, player)
|
||||
and air_dash(state, player)
|
||||
))
|
||||
add_rule(world.get_location("Viewax's Edifice: Fort Wall Medallion", player),
|
||||
add_rule(multiworld.get_location("Viewax's Edifice: Fort Wall Medallion", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Viewax's Edifice: Jar Medallion", player),
|
||||
add_rule(multiworld.get_location("Viewax's Edifice: Jar Medallion", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Viewax's Edifice: Sage Chair Medallion", player),
|
||||
add_rule(multiworld.get_location("Viewax's Edifice: Sage Chair Medallion", player),
|
||||
lambda state: air_dash(state, player))
|
||||
add_rule(world.get_location("Arcade 1: Lonely Medallion", player),
|
||||
add_rule(multiworld.get_location("Arcade 1: Lonely Medallion", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Arcade 1: Alcove Medallion", player),
|
||||
add_rule(multiworld.get_location("Arcade 1: Alcove Medallion", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Arcade 1: Lava Medallion", player),
|
||||
add_rule(multiworld.get_location("Arcade 1: Lava Medallion", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Foglast: Under Lair Medallion", player),
|
||||
add_rule(multiworld.get_location("Foglast: Under Lair Medallion", player),
|
||||
lambda state: bridge_key(state, player))
|
||||
add_rule(world.get_location("Foglast: Mid-Air Medallion", player),
|
||||
add_rule(multiworld.get_location("Foglast: Mid-Air Medallion", player),
|
||||
lambda state: air_dash(state, player))
|
||||
add_rule(world.get_location("Foglast: Top of Tower Medallion", player),
|
||||
add_rule(multiworld.get_location("Foglast: Top of Tower Medallion", player),
|
||||
lambda state: paddle(state, player))
|
||||
add_rule(world.get_location("Hylemxylem: Lower Reservoir Hole Medallion", player),
|
||||
add_rule(multiworld.get_location("Hylemxylem: Lower Reservoir Hole Medallion", player),
|
||||
lambda state: upper_chamber_key(state, player))
|
||||
|
||||
# extra rules if Shuffle Red Medallions and Party Shuffle are enabled
|
||||
if party and medallion:
|
||||
add_rule(world.get_location("New Muldul: Vault Rear Left Medallion", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Vault Rear Left Medallion", player),
|
||||
lambda state: party_3(state, player))
|
||||
add_rule(world.get_location("New Muldul: Vault Rear Right Medallion", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Vault Rear Right Medallion", player),
|
||||
lambda state: party_3(state, player))
|
||||
add_rule(world.get_location("New Muldul: Vault Center Medallion", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Vault Center Medallion", player),
|
||||
lambda state: party_3(state, player))
|
||||
add_rule(world.get_location("New Muldul: Vault Front Left Medallion", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Vault Front Left Medallion", player),
|
||||
lambda state: party_3(state, player))
|
||||
add_rule(world.get_location("New Muldul: Vault Front Right Medallion", player),
|
||||
add_rule(multiworld.get_location("New Muldul: Vault Front Right Medallion", player),
|
||||
lambda state: party_3(state, player))
|
||||
|
||||
# entrances
|
||||
for i in world.get_region("Airship", player).entrances:
|
||||
for i in multiworld.get_region("Airship", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
for i in world.get_region("Arcade Island", player).entrances:
|
||||
for i in multiworld.get_region("Arcade Island", player).entrances:
|
||||
add_rule(i, lambda state: (
|
||||
airship(state, player)
|
||||
and air_dash(state, player)
|
||||
))
|
||||
for i in world.get_region("Worm Pod", player).entrances:
|
||||
for i in multiworld.get_region("Worm Pod", player).entrances:
|
||||
add_rule(i, lambda state: enter_wormpod(state, player))
|
||||
for i in world.get_region("Foglast", player).entrances:
|
||||
for i in multiworld.get_region("Foglast", player).entrances:
|
||||
add_rule(i, lambda state: enter_foglast(state, player))
|
||||
for i in world.get_region("Sage Labyrinth", player).entrances:
|
||||
for i in multiworld.get_region("Sage Labyrinth", player).entrances:
|
||||
add_rule(i, lambda state: skull_bomb(state, player))
|
||||
for i in world.get_region("Sage Airship", player).entrances:
|
||||
for i in multiworld.get_region("Sage Airship", player).entrances:
|
||||
add_rule(i, lambda state: enter_sageship(state, player))
|
||||
for i in world.get_region("Hylemxylem", player).entrances:
|
||||
for i in multiworld.get_region("Hylemxylem", player).entrances:
|
||||
add_rule(i, lambda state: enter_hylemxylem(state, player))
|
||||
|
||||
# random start logic (default)
|
||||
if start_location == "waynehouse":
|
||||
# entrances
|
||||
for i in world.get_region("Viewax", player).entrances:
|
||||
for i in multiworld.get_region("Viewax", player).entrances:
|
||||
add_rule(i, lambda state: (
|
||||
air_dash(state, player)
|
||||
and airship(state, player)
|
||||
))
|
||||
for i in world.get_region("TV Island", player).entrances:
|
||||
for i in multiworld.get_region("TV Island", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
for i in world.get_region("Shield Facility", player).entrances:
|
||||
for i in multiworld.get_region("Shield Facility", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
for i in world.get_region("Juice Ranch", player).entrances:
|
||||
for i in multiworld.get_region("Juice Ranch", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
|
||||
# random start logic (Viewax's Edifice)
|
||||
elif start_location == "viewaxs_edifice":
|
||||
for i in world.get_region("Waynehouse", player).entrances:
|
||||
for i in multiworld.get_region("Waynehouse", player).entrances:
|
||||
add_rule(i, lambda state: (
|
||||
air_dash(state, player)
|
||||
or airship(state, player)
|
||||
))
|
||||
for i in world.get_region("New Muldul", player).entrances:
|
||||
for i in multiworld.get_region("New Muldul", player).entrances:
|
||||
add_rule(i, lambda state: (
|
||||
air_dash(state, player)
|
||||
or airship(state, player)
|
||||
))
|
||||
for i in world.get_region("New Muldul Vault", player).entrances:
|
||||
for i in multiworld.get_region("New Muldul Vault", player).entrances:
|
||||
add_rule(i, lambda state: (
|
||||
air_dash(state, player)
|
||||
or airship(state, player)
|
||||
))
|
||||
for i in world.get_region("Drill Castle", player).entrances:
|
||||
for i in multiworld.get_region("Drill Castle", player).entrances:
|
||||
add_rule(i, lambda state: (
|
||||
air_dash(state, player)
|
||||
or airship(state, player)
|
||||
))
|
||||
for i in world.get_region("TV Island", player).entrances:
|
||||
for i in multiworld.get_region("TV Island", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
for i in world.get_region("Shield Facility", player).entrances:
|
||||
for i in multiworld.get_region("Shield Facility", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
for i in world.get_region("Juice Ranch", player).entrances:
|
||||
for i in multiworld.get_region("Juice Ranch", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
for i in world.get_region("Sage Labyrinth", player).entrances:
|
||||
for i in multiworld.get_region("Sage Labyrinth", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
|
||||
# start logic (TV Island)
|
||||
elif start_location == "tv_island":
|
||||
for i in world.get_region("Waynehouse", player).entrances:
|
||||
for i in multiworld.get_region("Waynehouse", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
for i in world.get_region("New Muldul", player).entrances:
|
||||
for i in multiworld.get_region("New Muldul", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
for i in world.get_region("New Muldul Vault", player).entrances:
|
||||
for i in multiworld.get_region("New Muldul Vault", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
for i in world.get_region("Drill Castle", player).entrances:
|
||||
for i in multiworld.get_region("Drill Castle", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
for i in world.get_region("Viewax", player).entrances:
|
||||
for i in multiworld.get_region("Viewax", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
for i in world.get_region("Shield Facility", player).entrances:
|
||||
for i in multiworld.get_region("Shield Facility", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
for i in world.get_region("Juice Ranch", player).entrances:
|
||||
for i in multiworld.get_region("Juice Ranch", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
for i in world.get_region("Sage Labyrinth", player).entrances:
|
||||
for i in multiworld.get_region("Sage Labyrinth", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
|
||||
# start logic (Shield Facility)
|
||||
elif start_location == "shield_facility":
|
||||
for i in world.get_region("Waynehouse", player).entrances:
|
||||
for i in multiworld.get_region("Waynehouse", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
for i in world.get_region("New Muldul", player).entrances:
|
||||
for i in multiworld.get_region("New Muldul", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
for i in world.get_region("New Muldul Vault", player).entrances:
|
||||
for i in multiworld.get_region("New Muldul Vault", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
for i in world.get_region("Drill Castle", player).entrances:
|
||||
for i in multiworld.get_region("Drill Castle", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
for i in world.get_region("Viewax", player).entrances:
|
||||
for i in multiworld.get_region("Viewax", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
for i in world.get_region("TV Island", player).entrances:
|
||||
for i in multiworld.get_region("TV Island", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
for i in world.get_region("Sage Labyrinth", player).entrances:
|
||||
for i in multiworld.get_region("Sage Labyrinth", player).entrances:
|
||||
add_rule(i, lambda state: airship(state, player))
|
||||
|
||||
@@ -95,10 +95,10 @@ class MM3World(World):
|
||||
web = MM3WebWorld()
|
||||
rom_name: bytearray
|
||||
|
||||
def __init__(self, world: MultiWorld, player: int):
|
||||
def __init__(self, multiworld: MultiWorld, player: int):
|
||||
self.rom_name = bytearray()
|
||||
self.rom_name_available_event = threading.Event()
|
||||
super().__init__(world, player)
|
||||
super().__init__(multiworld, player)
|
||||
self.weapon_damage = deepcopy(weapon_damage)
|
||||
self.wily_4_weapons: dict[int, list[int]] = {}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"game": "Mega Man 3",
|
||||
"authors": ["Silvris"],
|
||||
"world_version": "0.1.7",
|
||||
"world_version": "0.1.8",
|
||||
"minimum_ap_version": "0.6.4"
|
||||
}
|
||||
|
||||
@@ -463,13 +463,13 @@ class MMBN3World(World):
|
||||
rompath: str = ""
|
||||
|
||||
try:
|
||||
world = self.multiworld
|
||||
multiworld = self.multiworld
|
||||
player = self.player
|
||||
|
||||
rom = LocalRom(get_base_rom_path())
|
||||
|
||||
for location_name in location_table.keys():
|
||||
location = world.get_location(location_name, player)
|
||||
location = multiworld.get_location(location_name, player)
|
||||
ap_item = location.item
|
||||
item_id = ap_item.code
|
||||
if item_id is not None:
|
||||
@@ -511,7 +511,7 @@ class MMBN3World(World):
|
||||
|
||||
rom.insert_hint_text(location_data, item_name_text, long_item_text)
|
||||
|
||||
rom.inject_name(world.player_name[player])
|
||||
rom.inject_name(self.player_name)
|
||||
|
||||
rompath = os.path.join(output_directory, f"{self.multiworld.get_out_file_name_base(self.player)}.gba")
|
||||
|
||||
@@ -519,7 +519,7 @@ class MMBN3World(World):
|
||||
rom.write_to_file(rompath)
|
||||
|
||||
patch = MMBN3DeltaPatch(os.path.splitext(rompath)[0]+MMBN3DeltaPatch.patch_file_ending, player=player,
|
||||
player_name=world.player_name[player], patched_path=rompath)
|
||||
player_name=self.player_name, patched_path=rompath)
|
||||
patch.write()
|
||||
except:
|
||||
raise
|
||||
|
||||
@@ -8,9 +8,9 @@ from .Hints import get_hint_area, HintAreaNotFound
|
||||
from .Regions import TimeOfDay
|
||||
|
||||
|
||||
def set_all_entrances_data(world, player):
|
||||
def set_all_entrances_data(multiworld, player):
|
||||
for type, forward_entry, *return_entry in entrance_shuffle_table:
|
||||
forward_entrance = world.get_entrance(forward_entry[0], player)
|
||||
forward_entrance = multiworld.get_entrance(forward_entry[0], player)
|
||||
forward_entrance.data = forward_entry[1]
|
||||
forward_entrance.type = type
|
||||
forward_entrance.primary = True
|
||||
@@ -18,7 +18,7 @@ def set_all_entrances_data(world, player):
|
||||
forward_entrance.data['index'] = 0x1000 + forward_entrance.data['grotto_id']
|
||||
if return_entry:
|
||||
return_entry = return_entry[0]
|
||||
return_entrance = world.get_entrance(return_entry[0], player)
|
||||
return_entrance = multiworld.get_entrance(return_entry[0], player)
|
||||
return_entrance.data = return_entry[1]
|
||||
return_entrance.type = type
|
||||
forward_entrance.bind_two_way(return_entrance)
|
||||
|
||||
@@ -336,10 +336,10 @@ def replace_max_item(items, item, max, rand):
|
||||
|
||||
|
||||
def generate_itempool(ootworld):
|
||||
world = ootworld.multiworld
|
||||
multiworld = ootworld.multiworld
|
||||
player = ootworld.player
|
||||
global random
|
||||
random = world.random
|
||||
random = multiworld.random
|
||||
|
||||
junk_pool = get_junk_pool(ootworld)
|
||||
|
||||
@@ -347,7 +347,7 @@ def generate_itempool(ootworld):
|
||||
(pool, placed_items) = get_pool_core(ootworld)
|
||||
ootworld.itempool = [ootworld.create_item(item) for item in pool]
|
||||
for (location_name, item) in placed_items.items():
|
||||
location = world.get_location(location_name, player)
|
||||
location = multiworld.get_location(location_name, player)
|
||||
location.place_locked_item(ootworld.create_item(item, allow_arbitrary_name=True))
|
||||
|
||||
|
||||
|
||||
@@ -199,8 +199,8 @@ class Overcooked2Test(unittest.TestCase):
|
||||
|
||||
self.assertIn("Overcooked! 2", AutoWorldRegister.world_types.keys())
|
||||
world_type = AutoWorldRegister.world_types["Overcooked! 2"]
|
||||
world = setup_solo_multiworld(world_type)
|
||||
state = world.get_all_state(False)
|
||||
multiworld = setup_solo_multiworld(world_type)
|
||||
state = multiworld.get_all_state(False)
|
||||
|
||||
# Test region logic
|
||||
for logic in overworld_region_logic.values():
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
# 2.5.0
|
||||
|
||||
### Features
|
||||
|
||||
- Added a new option `dexsanity_encounter_types` to enable/disable dexsanity locations based on whether they can be
|
||||
found in the allowed encounters. In other words, if Bulbasaur can only be found by fishing and fishing is not enabled,
|
||||
a dexsanity location will not be created for Bulbasaur.
|
||||
|
||||
### Fixes
|
||||
|
||||
- Fixed generator error if Wailord or Relicanth are blacklisted during a dexsanity seed.
|
||||
- Fixed generator error if player greatly restricts allowed opponent pokemon while force fully evolved is active.
|
||||
|
||||
# 2.4.1
|
||||
|
||||
### Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"game": "Pokemon Emerald",
|
||||
"world_version": "2.4.1",
|
||||
"world_version": "2.5.0",
|
||||
"minimum_ap_version": "0.6.1",
|
||||
"authors": ["Zunawe"]
|
||||
}
|
||||
|
||||
@@ -236,8 +236,8 @@ class RaftWorld(World):
|
||||
"DeathLink": bool(self.options.death_link)
|
||||
}
|
||||
|
||||
def create_region(world: MultiWorld, player: int, name: str, locations=None, exits=None):
|
||||
ret = Region(name, player, world)
|
||||
def create_region(multiworld: MultiWorld, player: int, name: str, locations=None, exits=None):
|
||||
ret = Region(name, player, multiworld)
|
||||
if locations:
|
||||
for location in locations:
|
||||
loc_id = locations_lookup_name_to_id.get(location, 0)
|
||||
|
||||
+10
-10
@@ -116,10 +116,10 @@ class SMWorld(World):
|
||||
|
||||
Logic.factory('vanilla')
|
||||
|
||||
def __init__(self, world: MultiWorld, player: int):
|
||||
def __init__(self, multiworld: MultiWorld, player: int):
|
||||
self.rom_name_available_event = threading.Event()
|
||||
self.locations = {}
|
||||
super().__init__(world, player)
|
||||
super().__init__(multiworld, player)
|
||||
|
||||
def generate_early(self):
|
||||
Logic.factory('vanilla')
|
||||
@@ -233,8 +233,8 @@ class SMWorld(World):
|
||||
for key, value1 in accessPoint.intraTransitions.items():
|
||||
set_entrance_rule(self.multiworld.get_entrance(accessPoint.Name + "->" + key, self.player), self.player, value1)
|
||||
|
||||
def create_region(self, world: MultiWorld, player: int, name: str, locations=None, exits=None):
|
||||
ret = Region(name, player, world)
|
||||
def create_region(self, multiworld: MultiWorld, player: int, name: str, locations=None, exits=None):
|
||||
ret = Region(name, player, multiworld)
|
||||
if locations:
|
||||
for loc in locations:
|
||||
location = self.locations[loc]
|
||||
@@ -420,10 +420,10 @@ class SMWorld(World):
|
||||
self.variaRando.randoExec.postProcessItemLocs(self.itemLocs, self.variaRando.args.hideItems)
|
||||
|
||||
@classmethod
|
||||
def stage_post_fill(cls, world):
|
||||
new_state = CollectionState(world)
|
||||
def stage_post_fill(cls, multiworld):
|
||||
new_state = CollectionState(multiworld)
|
||||
progitempool = []
|
||||
for item in world.itempool:
|
||||
for item in multiworld.itempool:
|
||||
if item.game == "Super Metroid" and item.advancement:
|
||||
progitempool.append(item)
|
||||
|
||||
@@ -431,10 +431,10 @@ class SMWorld(World):
|
||||
new_state.collect(item, True)
|
||||
|
||||
bossesLoc = ['Draygon', 'Kraid', 'Ridley', 'Phantoon', 'Mother Brain']
|
||||
for player in world.get_game_players("Super Metroid"):
|
||||
for player in multiworld.get_game_players("Super Metroid"):
|
||||
for bossLoc in bossesLoc:
|
||||
if not world.get_location(bossLoc, player).can_reach(new_state):
|
||||
world.state.smbm[player].onlyBossLeft = True
|
||||
if not multiworld.get_location(bossLoc, player).can_reach(new_state):
|
||||
multiworld.state.smbm[player].onlyBossLeft = True
|
||||
break
|
||||
|
||||
def getWordArray(self, w: int) -> List[int]:
|
||||
|
||||
+39
-39
@@ -79,12 +79,12 @@ sm64_secrets_to_level = {secret: level for (level,secret) in sm64_level_to_secre
|
||||
sm64_entrances_to_level = {**sm64_paintings_to_level, **sm64_secrets_to_level }
|
||||
sm64_level_to_entrances = {**sm64_level_to_paintings, **sm64_level_to_secrets }
|
||||
|
||||
def create_regions(world: MultiWorld, options: SM64Options, player: int):
|
||||
regSS = Region("Menu", player, world, "Castle Area")
|
||||
def create_regions(multiworld: MultiWorld, options: SM64Options, player: int):
|
||||
regSS = Region("Menu", player, multiworld, "Castle Area")
|
||||
create_default_locs(regSS, locSS_table)
|
||||
world.regions.append(regSS)
|
||||
multiworld.regions.append(regSS)
|
||||
|
||||
regBoB = create_region("Bob-omb Battlefield", player, world)
|
||||
regBoB = create_region("Bob-omb Battlefield", player, multiworld)
|
||||
create_locs(regBoB, "BoB: Big Bob-Omb on the Summit", "BoB: Footrace with Koopa The Quick",
|
||||
"BoB: Mario Wings to the Sky", "BoB: Behind Chain Chomp's Gate", "BoB: Bob-omb Buddy")
|
||||
bob_island = create_subregion(regBoB, "BoB: Island", "BoB: Shoot to the Island in the Sky", "BoB: Find the 8 Red Coins")
|
||||
@@ -92,7 +92,7 @@ def create_regions(world: MultiWorld, options: SM64Options, player: int):
|
||||
if options.enable_coin_stars:
|
||||
create_locs(regBoB, "BoB: 100 Coins")
|
||||
|
||||
regWhomp = create_region("Whomp's Fortress", player, world)
|
||||
regWhomp = create_region("Whomp's Fortress", player, multiworld)
|
||||
create_locs(regWhomp, "WF: Chip Off Whomp's Block", "WF: Shoot into the Wild Blue", "WF: Red Coins on the Floating Isle",
|
||||
"WF: Fall onto the Caged Island", "WF: Blast Away the Wall")
|
||||
wf_tower = create_subregion(regWhomp, "WF: Tower", "WF: To the Top of the Fortress", "WF: Bob-omb Buddy")
|
||||
@@ -100,8 +100,8 @@ def create_regions(world: MultiWorld, options: SM64Options, player: int):
|
||||
if options.enable_coin_stars:
|
||||
create_locs(regWhomp, "WF: 100 Coins")
|
||||
|
||||
regJRBDoor = create_region("Jolly Roger Bay Door", player, world)
|
||||
regJRB = create_region("Jolly Roger Bay", player, world)
|
||||
regJRBDoor = create_region("Jolly Roger Bay Door", player, multiworld)
|
||||
regJRB = create_region("Jolly Roger Bay", player, multiworld)
|
||||
create_locs(regJRB, "JRB: Plunder in the Sunken Ship", "JRB: Can the Eel Come Out to Play?", "JRB: Treasure of the Ocean Cave",
|
||||
"JRB: Blast to the Stone Pillar", "JRB: Through the Jet Stream", "JRB: Bob-omb Buddy")
|
||||
jrb_upper = create_subregion(regJRB, 'JRB: Upper', "JRB: Red Coins on the Ship Afloat")
|
||||
@@ -109,12 +109,12 @@ def create_regions(world: MultiWorld, options: SM64Options, player: int):
|
||||
if options.enable_coin_stars:
|
||||
create_locs(jrb_upper, "JRB: 100 Coins")
|
||||
|
||||
regCCM = create_region("Cool, Cool Mountain", player, world)
|
||||
regCCM = create_region("Cool, Cool Mountain", player, multiworld)
|
||||
create_default_locs(regCCM, locCCM_table)
|
||||
if options.enable_coin_stars:
|
||||
create_locs(regCCM, "CCM: 100 Coins")
|
||||
|
||||
regBBH = create_region("Big Boo's Haunt", player, world)
|
||||
regBBH = create_region("Big Boo's Haunt", player, multiworld)
|
||||
create_locs(regBBH, "BBH: Go on a Ghost Hunt", "BBH: Ride Big Boo's Merry-Go-Round",
|
||||
"BBH: Secret of the Haunted Books", "BBH: Seek the 8 Red Coins")
|
||||
bbh_third_floor = create_subregion(regBBH, "BBH: Third Floor", "BBH: Eye to Eye in the Secret Room")
|
||||
@@ -123,21 +123,21 @@ def create_regions(world: MultiWorld, options: SM64Options, player: int):
|
||||
if options.enable_coin_stars:
|
||||
create_locs(regBBH, "BBH: 100 Coins")
|
||||
|
||||
regPSS = create_region("The Princess's Secret Slide", player, world)
|
||||
regPSS = create_region("The Princess's Secret Slide", player, multiworld)
|
||||
create_default_locs(regPSS, locPSS_table)
|
||||
|
||||
regSA = create_region("The Secret Aquarium", player, world)
|
||||
regSA = create_region("The Secret Aquarium", player, multiworld)
|
||||
create_default_locs(regSA, locSA_table)
|
||||
|
||||
regTotWC = create_region("Tower of the Wing Cap", player, world)
|
||||
regTotWC = create_region("Tower of the Wing Cap", player, multiworld)
|
||||
create_default_locs(regTotWC, locTotWC_table)
|
||||
|
||||
regBitDW = create_region("Bowser in the Dark World", player, world)
|
||||
regBitDW = create_region("Bowser in the Dark World", player, multiworld)
|
||||
create_default_locs(regBitDW, locBitDW_table)
|
||||
|
||||
create_region("Basement", player, world)
|
||||
create_region("Basement", player, multiworld)
|
||||
|
||||
regHMC = create_region("Hazy Maze Cave", player, world)
|
||||
regHMC = create_region("Hazy Maze Cave", player, multiworld)
|
||||
create_locs(regHMC, "HMC: Swimming Beast in the Cavern", "HMC: Metal-Head Mario Can Move!",
|
||||
"HMC: Watch for Rolling Rocks", "HMC: Navigating the Toxic Maze","HMC: 1Up Block Past Rolling Rocks")
|
||||
hmc_red_coin_area = create_subregion(regHMC, "HMC: Red Coin Area", "HMC: Elevate for 8 Red Coins")
|
||||
@@ -146,7 +146,7 @@ def create_regions(world: MultiWorld, options: SM64Options, player: int):
|
||||
if options.enable_coin_stars:
|
||||
create_locs(hmc_red_coin_area, "HMC: 100 Coins")
|
||||
|
||||
regLLL = create_region("Lethal Lava Land", player, world)
|
||||
regLLL = create_region("Lethal Lava Land", player, multiworld)
|
||||
create_locs(regLLL, "LLL: Boil the Big Bully", "LLL: Bully the Bullies",
|
||||
"LLL: 8-Coin Puzzle with 15 Pieces", "LLL: Red-Hot Log Rolling")
|
||||
lll_upper_volcano = create_subregion(regLLL, "LLL: Upper Volcano", "LLL: Hot-Foot-It into the Volcano", "LLL: Elevator Tour in the Volcano")
|
||||
@@ -154,7 +154,7 @@ def create_regions(world: MultiWorld, options: SM64Options, player: int):
|
||||
if options.enable_coin_stars:
|
||||
create_locs(regLLL, "LLL: 100 Coins")
|
||||
|
||||
regSSL = create_region("Shifting Sand Land", player, world)
|
||||
regSSL = create_region("Shifting Sand Land", player, multiworld)
|
||||
create_locs(regSSL, "SSL: In the Talons of the Big Bird", "SSL: Shining Atop the Pyramid",
|
||||
"SSL: Free Flying for 8 Red Coins", "SSL: Bob-omb Buddy",
|
||||
"SSL: 1Up Block Outside Pyramid", "SSL: 1Up Block Pyramid Left Path", "SSL: 1Up Block Pyramid Back")
|
||||
@@ -164,30 +164,30 @@ def create_regions(world: MultiWorld, options: SM64Options, player: int):
|
||||
if options.enable_coin_stars:
|
||||
create_locs(regSSL, "SSL: 100 Coins")
|
||||
|
||||
regDDD = create_region("Dire, Dire Docks", player, world)
|
||||
regDDD = create_region("Dire, Dire Docks", player, multiworld)
|
||||
create_locs(regDDD, "DDD: Board Bowser's Sub", "DDD: Chests in the Current", "DDD: Through the Jet Stream",
|
||||
"DDD: The Manta Ray's Reward", "DDD: Collect the Caps...", "DDD: Pole-Jumping for Red Coins")
|
||||
if options.enable_coin_stars:
|
||||
create_locs(regDDD, "DDD: 100 Coins")
|
||||
|
||||
regCotMC = create_region("Cavern of the Metal Cap", player, world)
|
||||
regCotMC = create_region("Cavern of the Metal Cap", player, multiworld)
|
||||
create_default_locs(regCotMC, locCotMC_table)
|
||||
|
||||
regVCutM = create_region("Vanish Cap under the Moat", player, world)
|
||||
regVCutM = create_region("Vanish Cap under the Moat", player, multiworld)
|
||||
create_default_locs(regVCutM, locVCutM_table)
|
||||
|
||||
regBitFS = create_region("Bowser in the Fire Sea", player, world)
|
||||
regBitFS = create_region("Bowser in the Fire Sea", player, multiworld)
|
||||
bitfs_upper = create_subregion(regBitFS, "BitFS: Upper", *locBitFS_table.keys())
|
||||
regBitFS.subregions = [bitfs_upper]
|
||||
|
||||
create_region("Second Floor", player, world)
|
||||
create_region("Second Floor", player, multiworld)
|
||||
|
||||
regSL = create_region("Snowman's Land", player, world)
|
||||
regSL = create_region("Snowman's Land", player, multiworld)
|
||||
create_default_locs(regSL, locSL_table)
|
||||
if options.enable_coin_stars:
|
||||
create_locs(regSL, "SL: 100 Coins")
|
||||
|
||||
regWDW = create_region("Wet-Dry World", player, world)
|
||||
regWDW = create_region("Wet-Dry World", player, multiworld)
|
||||
create_locs(regWDW, "WDW: Express Elevator--Hurry Up!")
|
||||
wdw_top = create_subregion(regWDW, "WDW: Top", "WDW: Shocking Arrow Lifts!", "WDW: Top o' the Town",
|
||||
"WDW: Secrets in the Shallows & Sky", "WDW: Bob-omb Buddy")
|
||||
@@ -196,7 +196,7 @@ def create_regions(world: MultiWorld, options: SM64Options, player: int):
|
||||
if options.enable_coin_stars:
|
||||
create_locs(wdw_top, "WDW: 100 Coins")
|
||||
|
||||
regTTM = create_region("Tall, Tall Mountain", player, world)
|
||||
regTTM = create_region("Tall, Tall Mountain", player, multiworld)
|
||||
ttm_middle = create_subregion(regTTM, "TTM: Middle", "TTM: Scary 'Shrooms, Red Coins", "TTM: Blast to the Lonely Mushroom",
|
||||
"TTM: Bob-omb Buddy", "TTM: 1Up Block on Red Mushroom")
|
||||
ttm_top = create_subregion(ttm_middle, "TTM: Top", "TTM: Scale the Mountain", "TTM: Mystery of the Monkey Cage",
|
||||
@@ -205,9 +205,9 @@ def create_regions(world: MultiWorld, options: SM64Options, player: int):
|
||||
if options.enable_coin_stars:
|
||||
create_locs(ttm_top, "TTM: 100 Coins")
|
||||
|
||||
create_region("Tiny-Huge Island (Huge)", player, world)
|
||||
create_region("Tiny-Huge Island (Tiny)", player, world)
|
||||
regTHI = create_region("Tiny-Huge Island", player, world)
|
||||
create_region("Tiny-Huge Island (Huge)", player, multiworld)
|
||||
create_region("Tiny-Huge Island (Tiny)", player, multiworld)
|
||||
regTHI = create_region("Tiny-Huge Island", player, multiworld)
|
||||
create_locs(regTHI, "THI: 1Up Block THI Small near Start")
|
||||
thi_pipes = create_subregion(regTHI, "THI: Pipes", "THI: The Tip Top of the Huge Island", "THI: Pluck the Piranha Flower", "THI: Rematch with Koopa the Quick",
|
||||
"THI: Five Itty Bitty Secrets", "THI: Wiggler's Red Coins", "THI: Bob-omb Buddy",
|
||||
@@ -217,9 +217,9 @@ def create_regions(world: MultiWorld, options: SM64Options, player: int):
|
||||
if options.enable_coin_stars:
|
||||
create_locs(thi_large_top, "THI: 100 Coins")
|
||||
|
||||
regFloor3 = create_region("Third Floor", player, world)
|
||||
regFloor3 = create_region("Third Floor", player, multiworld)
|
||||
|
||||
regTTC = create_region("Tick Tock Clock", player, world)
|
||||
regTTC = create_region("Tick Tock Clock", player, multiworld)
|
||||
create_locs(regTTC, "TTC: Stop Time for Red Coins")
|
||||
ttc_lower = create_subregion(regTTC, "TTC: Lower", "TTC: Roll into the Cage", "TTC: Get a Hand")
|
||||
ttc_upper = create_subregion(ttc_lower, "TTC: Upper", "TTC: Timed Jumps on Moving Bars", "TTC: The Pit and the Pendulums")
|
||||
@@ -228,7 +228,7 @@ def create_regions(world: MultiWorld, options: SM64Options, player: int):
|
||||
if options.enable_coin_stars:
|
||||
create_locs(ttc_top, "TTC: 100 Coins")
|
||||
|
||||
regRR = create_region("Rainbow Ride", player, world)
|
||||
regRR = create_region("Rainbow Ride", player, multiworld)
|
||||
create_locs(regRR, "RR: Swingin' in the Breeze", "RR: Tricky Triangles!",
|
||||
"RR: 1Up Block Top of Red Coin Maze", "RR: 1Up Block Under Fly Guy", "RR: Bob-omb Buddy")
|
||||
rr_maze = create_subregion(regRR, "RR: Maze", "RR: Coins Amassed in a Maze")
|
||||
@@ -238,24 +238,24 @@ def create_regions(world: MultiWorld, options: SM64Options, player: int):
|
||||
if options.enable_coin_stars:
|
||||
create_locs(rr_maze, "RR: 100 Coins")
|
||||
|
||||
regWMotR = create_region("Wing Mario over the Rainbow", player, world)
|
||||
regWMotR = create_region("Wing Mario over the Rainbow", player, multiworld)
|
||||
create_default_locs(regWMotR, locWMotR_table)
|
||||
|
||||
regBitS = create_region("Bowser in the Sky", player, world)
|
||||
regBitS = create_region("Bowser in the Sky", player, multiworld)
|
||||
create_locs(regBitS, "Bowser in the Sky 1Up Block")
|
||||
bits_top = create_subregion(regBitS, "BitS: Top", "Bowser in the Sky Red Coins")
|
||||
regBitS.subregions = [bits_top]
|
||||
|
||||
|
||||
def connect_regions(world: MultiWorld, player: int, source: str, target: str, rule=None) -> Entrance:
|
||||
sourceRegion = world.get_region(source, player)
|
||||
targetRegion = world.get_region(target, player)
|
||||
def connect_regions(multiworld: MultiWorld, player: int, source: str, target: str, rule=None) -> Entrance:
|
||||
sourceRegion = multiworld.get_region(source, player)
|
||||
targetRegion = multiworld.get_region(target, player)
|
||||
return sourceRegion.connect(targetRegion, rule=rule)
|
||||
|
||||
|
||||
def create_region(name: str, player: int, world: MultiWorld) -> SM64Region:
|
||||
region = SM64Region(name, player, world)
|
||||
world.regions.append(region)
|
||||
def create_region(name: str, player: int, multiworld: MultiWorld) -> SM64Region:
|
||||
region = SM64Region(name, player, multiworld)
|
||||
multiworld.regions.append(region)
|
||||
return region
|
||||
|
||||
|
||||
|
||||
+61
-61
@@ -8,24 +8,24 @@ from .Regions import connect_regions, SM64Levels, sm64_level_to_paintings, sm64_
|
||||
sm64_level_to_secrets, sm64_secrets_to_level, sm64_entrances_to_level, sm64_level_to_entrances
|
||||
from .Items import action_item_data_table
|
||||
|
||||
def shuffle_dict_keys(world, dictionary: dict) -> dict:
|
||||
def shuffle_dict_keys(multiworld: MultiWorld, dictionary: dict) -> dict:
|
||||
keys = list(dictionary.keys())
|
||||
values = list(dictionary.values())
|
||||
world.random.shuffle(keys)
|
||||
multiworld.random.shuffle(keys)
|
||||
return dict(zip(keys, values))
|
||||
|
||||
def fix_reg(entrance_map: Dict[SM64Levels, str], entrance: SM64Levels, invalid_regions: Set[str],
|
||||
swapdict: Dict[SM64Levels, str], world):
|
||||
swapdict: Dict[SM64Levels, str], multiworld: MultiWorld):
|
||||
if entrance_map[entrance] in invalid_regions: # Unlucky :C
|
||||
replacement_regions = [(rand_entrance, rand_region) for rand_entrance, rand_region in swapdict.items()
|
||||
if rand_region not in invalid_regions]
|
||||
rand_entrance, rand_region = world.random.choice(replacement_regions)
|
||||
rand_entrance, rand_region = multiworld.random.choice(replacement_regions)
|
||||
old_dest = entrance_map[entrance]
|
||||
entrance_map[entrance], entrance_map[rand_entrance] = rand_region, old_dest
|
||||
swapdict[entrance], swapdict[rand_entrance] = rand_region, old_dest
|
||||
swapdict.pop(entrance)
|
||||
|
||||
def set_rules(world, options: SM64Options, player: int, area_connections: dict, star_costs: dict, move_rando_bitvec: int):
|
||||
def set_rules(multiworld: MultiWorld, options: SM64Options, player: int, area_connections: dict, star_costs: dict, move_rando_bitvec: int):
|
||||
randomized_level_to_paintings = sm64_level_to_paintings.copy()
|
||||
randomized_level_to_secrets = sm64_level_to_secrets.copy()
|
||||
valid_move_randomizer_start_courses = [
|
||||
@@ -34,100 +34,100 @@ def set_rules(world, options: SM64Options, player: int, area_connections: dict,
|
||||
"Dire, Dire Docks", "Snowman's Land"
|
||||
] # Excluding WF, HMC, WDW, TTM, THI, TTC, and RR
|
||||
if options.area_rando >= 1: # Some randomization is happening, randomize Courses
|
||||
randomized_level_to_paintings = shuffle_dict_keys(world,sm64_level_to_paintings)
|
||||
randomized_level_to_paintings = shuffle_dict_keys(multiworld,sm64_level_to_paintings)
|
||||
# If not shuffling later, ensure a valid start course on move randomizer
|
||||
if options.area_rando < 3 and move_rando_bitvec > 0:
|
||||
swapdict = randomized_level_to_paintings.copy()
|
||||
invalid_start_courses = {course for course in randomized_level_to_paintings.values() if course not in valid_move_randomizer_start_courses}
|
||||
fix_reg(randomized_level_to_paintings, SM64Levels.BOB_OMB_BATTLEFIELD, invalid_start_courses, swapdict, world)
|
||||
fix_reg(randomized_level_to_paintings, SM64Levels.WHOMPS_FORTRESS, invalid_start_courses, swapdict, world)
|
||||
fix_reg(randomized_level_to_paintings, SM64Levels.BOB_OMB_BATTLEFIELD, invalid_start_courses, swapdict, multiworld)
|
||||
fix_reg(randomized_level_to_paintings, SM64Levels.WHOMPS_FORTRESS, invalid_start_courses, swapdict, multiworld)
|
||||
|
||||
if options.area_rando == 2: # Randomize Secrets as well
|
||||
randomized_level_to_secrets = shuffle_dict_keys(world,sm64_level_to_secrets)
|
||||
randomized_level_to_secrets = shuffle_dict_keys(multiworld, sm64_level_to_secrets)
|
||||
randomized_entrances = {**randomized_level_to_paintings, **randomized_level_to_secrets}
|
||||
if options.area_rando == 3: # Randomize Courses and Secrets in one pool
|
||||
randomized_entrances = shuffle_dict_keys(world, randomized_entrances)
|
||||
randomized_entrances = shuffle_dict_keys(multiworld, randomized_entrances)
|
||||
# Guarantee first entrance is a course
|
||||
swapdict = randomized_entrances.copy()
|
||||
if move_rando_bitvec == 0:
|
||||
fix_reg(randomized_entrances, SM64Levels.BOB_OMB_BATTLEFIELD, sm64_secrets_to_level.keys(), swapdict, world)
|
||||
fix_reg(randomized_entrances, SM64Levels.BOB_OMB_BATTLEFIELD, sm64_secrets_to_level.keys(), swapdict, multiworld)
|
||||
else:
|
||||
invalid_start_courses = {course for course in randomized_entrances.values() if course not in valid_move_randomizer_start_courses}
|
||||
fix_reg(randomized_entrances, SM64Levels.BOB_OMB_BATTLEFIELD, invalid_start_courses, swapdict, world)
|
||||
fix_reg(randomized_entrances, SM64Levels.WHOMPS_FORTRESS, invalid_start_courses, swapdict, world)
|
||||
fix_reg(randomized_entrances, SM64Levels.BOB_OMB_BATTLEFIELD, invalid_start_courses, swapdict, multiworld)
|
||||
fix_reg(randomized_entrances, SM64Levels.WHOMPS_FORTRESS, invalid_start_courses, swapdict, multiworld)
|
||||
# Guarantee BITFS is not mapped to DDD
|
||||
fix_reg(randomized_entrances, SM64Levels.BOWSER_IN_THE_FIRE_SEA, {"Dire, Dire Docks"}, swapdict, world)
|
||||
fix_reg(randomized_entrances, SM64Levels.BOWSER_IN_THE_FIRE_SEA, {"Dire, Dire Docks"}, swapdict, multiworld)
|
||||
# Guarantee COTMC is not mapped to HMC, cuz thats impossible. If BitFS -> HMC, also no COTMC -> DDD.
|
||||
if randomized_entrances[SM64Levels.BOWSER_IN_THE_FIRE_SEA] == "Hazy Maze Cave":
|
||||
fix_reg(randomized_entrances, SM64Levels.CAVERN_OF_THE_METAL_CAP, {"Hazy Maze Cave", "Dire, Dire Docks"}, swapdict, world)
|
||||
fix_reg(randomized_entrances, SM64Levels.CAVERN_OF_THE_METAL_CAP, {"Hazy Maze Cave", "Dire, Dire Docks"}, swapdict, multiworld)
|
||||
else:
|
||||
fix_reg(randomized_entrances, SM64Levels.CAVERN_OF_THE_METAL_CAP, {"Hazy Maze Cave"}, swapdict, world)
|
||||
fix_reg(randomized_entrances, SM64Levels.CAVERN_OF_THE_METAL_CAP, {"Hazy Maze Cave"}, swapdict, multiworld)
|
||||
|
||||
# Destination Format: LVL | AREA with LVL = LEVEL_x, AREA = Area as used in sm64 code
|
||||
# Cast to int to not rely on availability of SM64Levels enum. Will cause crash in MultiServer otherwise
|
||||
area_connections.update({int(entrance_lvl): int(sm64_entrances_to_level[destination]) for (entrance_lvl,destination) in randomized_entrances.items()})
|
||||
randomized_entrances_s = {sm64_level_to_entrances[entrance_lvl]: destination for (entrance_lvl,destination) in randomized_entrances.items()}
|
||||
|
||||
rf = RuleFactory(world, options, player, move_rando_bitvec)
|
||||
rf = RuleFactory(multiworld, options, player, move_rando_bitvec)
|
||||
|
||||
connect_regions(world, player, "Menu", randomized_entrances_s["Bob-omb Battlefield"])
|
||||
connect_regions(world, player, "Menu", randomized_entrances_s["Whomp's Fortress"],
|
||||
connect_regions(multiworld, player, "Menu", randomized_entrances_s["Bob-omb Battlefield"])
|
||||
connect_regions(multiworld, player, "Menu", randomized_entrances_s["Whomp's Fortress"],
|
||||
rf.build_rule("", painting_lvl_name="WF", star_num_req=1))
|
||||
# JRB door is separated from JRB itself because the secret aquarium can be accessed without entering the painting
|
||||
connect_regions(world, player, "Menu", "Jolly Roger Bay Door", rf.build_rule("", star_num_req=3))
|
||||
connect_regions(world, player, "Jolly Roger Bay Door", randomized_entrances_s["Jolly Roger Bay"],
|
||||
connect_regions(multiworld, player, "Menu", "Jolly Roger Bay Door", rf.build_rule("", star_num_req=3))
|
||||
connect_regions(multiworld, player, "Jolly Roger Bay Door", randomized_entrances_s["Jolly Roger Bay"],
|
||||
rf.build_rule("", painting_lvl_name="JRB"))
|
||||
connect_regions(world, player, "Menu", randomized_entrances_s["Cool, Cool Mountain"],
|
||||
connect_regions(multiworld, player, "Menu", randomized_entrances_s["Cool, Cool Mountain"],
|
||||
rf.build_rule("", painting_lvl_name="CCM", star_num_req=3))
|
||||
connect_regions(world, player, "Menu", randomized_entrances_s["Big Boo's Haunt"], lambda state: state.has("Power Star", player, 12))
|
||||
connect_regions(world, player, "Menu", randomized_entrances_s["The Princess's Secret Slide"], lambda state: state.has("Power Star", player, 1))
|
||||
connect_regions(world, player, "Jolly Roger Bay Door", randomized_entrances_s["The Secret Aquarium"],
|
||||
connect_regions(multiworld, player, "Menu", randomized_entrances_s["Big Boo's Haunt"], lambda state: state.has("Power Star", player, 12))
|
||||
connect_regions(multiworld, player, "Menu", randomized_entrances_s["The Princess's Secret Slide"], lambda state: state.has("Power Star", player, 1))
|
||||
connect_regions(multiworld, player, "Jolly Roger Bay Door", randomized_entrances_s["The Secret Aquarium"],
|
||||
rf.build_rule("SF/BF | TJ & LG | MOVELESS & TJ"))
|
||||
connect_regions(world, player, "Menu", randomized_entrances_s["Tower of the Wing Cap"], lambda state: state.has("Power Star", player, 10))
|
||||
connect_regions(world, player, "Menu", randomized_entrances_s["Bowser in the Dark World"],
|
||||
connect_regions(multiworld, player, "Menu", randomized_entrances_s["Tower of the Wing Cap"], lambda state: state.has("Power Star", player, 10))
|
||||
connect_regions(multiworld, player, "Menu", randomized_entrances_s["Bowser in the Dark World"],
|
||||
lambda state: state.has("Power Star", player, star_costs["FirstBowserDoorCost"]))
|
||||
|
||||
connect_regions(world, player, "Menu", "Basement", lambda state: state.has("Basement Key", player) or state.has("Progressive Key", player, 1))
|
||||
connect_regions(multiworld, player, "Menu", "Basement", lambda state: state.has("Basement Key", player) or state.has("Progressive Key", player, 1))
|
||||
|
||||
connect_regions(world, player, "Basement", randomized_entrances_s["Hazy Maze Cave"])
|
||||
connect_regions(world, player, "Basement", randomized_entrances_s["Lethal Lava Land"],
|
||||
connect_regions(multiworld, player, "Basement", randomized_entrances_s["Hazy Maze Cave"])
|
||||
connect_regions(multiworld, player, "Basement", randomized_entrances_s["Lethal Lava Land"],
|
||||
rf.build_rule("", painting_lvl_name="LLL"))
|
||||
connect_regions(world, player, "Basement", randomized_entrances_s["Shifting Sand Land"],
|
||||
connect_regions(multiworld, player, "Basement", randomized_entrances_s["Shifting Sand Land"],
|
||||
rf.build_rule("", painting_lvl_name="SSL"))
|
||||
connect_regions(world, player, "Basement", randomized_entrances_s["Dire, Dire Docks"],
|
||||
connect_regions(multiworld, player, "Basement", randomized_entrances_s["Dire, Dire Docks"],
|
||||
rf.build_rule("", painting_lvl_name="DDD", star_num_req=star_costs["BasementDoorCost"]))
|
||||
connect_regions(world, player, "Hazy Maze Cave", randomized_entrances_s["Cavern of the Metal Cap"])
|
||||
connect_regions(world, player, "Basement", randomized_entrances_s["Vanish Cap under the Moat"],
|
||||
connect_regions(multiworld, player, "Hazy Maze Cave", randomized_entrances_s["Cavern of the Metal Cap"])
|
||||
connect_regions(multiworld, player, "Basement", randomized_entrances_s["Vanish Cap under the Moat"],
|
||||
rf.build_rule("GP"))
|
||||
entrance = connect_regions(world, player, "Basement", randomized_entrances_s["Bowser in the Fire Sea"],
|
||||
entrance = connect_regions(multiworld, player, "Basement", randomized_entrances_s["Bowser in the Fire Sea"],
|
||||
lambda state: state.has("Power Star", player, star_costs["BasementDoorCost"]) and
|
||||
state.can_reach("DDD: Board Bowser's Sub", 'Location', player))
|
||||
# Access to "DDD: Board Bowser's Sub" does not require access to other locations or regions, so the only region that
|
||||
# needs to be registered is its parent region.
|
||||
world.register_indirect_condition(world.get_location("DDD: Board Bowser's Sub", player).parent_region, entrance)
|
||||
multiworld.register_indirect_condition(multiworld.get_location("DDD: Board Bowser's Sub", player).parent_region, entrance)
|
||||
|
||||
connect_regions(world, player, "Menu", "Second Floor", lambda state: state.has("Second Floor Key", player) or state.has("Progressive Key", player, 2))
|
||||
connect_regions(multiworld, player, "Menu", "Second Floor", lambda state: state.has("Second Floor Key", player) or state.has("Progressive Key", player, 2))
|
||||
|
||||
connect_regions(world, player, "Second Floor", randomized_entrances_s["Snowman's Land"],
|
||||
connect_regions(multiworld, player, "Second Floor", randomized_entrances_s["Snowman's Land"],
|
||||
rf.build_rule("", painting_lvl_name="SL"))
|
||||
connect_regions(world, player, "Second Floor", randomized_entrances_s["Wet-Dry World"],
|
||||
connect_regions(multiworld, player, "Second Floor", randomized_entrances_s["Wet-Dry World"],
|
||||
rf.build_rule("", painting_lvl_name="WDW"))
|
||||
connect_regions(world, player, "Second Floor", randomized_entrances_s["Tall, Tall Mountain"],
|
||||
connect_regions(multiworld, player, "Second Floor", randomized_entrances_s["Tall, Tall Mountain"],
|
||||
rf.build_rule("", painting_lvl_name="TTM"))
|
||||
connect_regions(world, player, "Second Floor", randomized_entrances_s["Tiny-Huge Island (Tiny)"],
|
||||
connect_regions(multiworld, player, "Second Floor", randomized_entrances_s["Tiny-Huge Island (Tiny)"],
|
||||
rf.build_rule("", painting_lvl_name="THI"))
|
||||
connect_regions(world, player, "Second Floor", randomized_entrances_s["Tiny-Huge Island (Huge)"],
|
||||
connect_regions(multiworld, player, "Second Floor", randomized_entrances_s["Tiny-Huge Island (Huge)"],
|
||||
rf.build_rule("", painting_lvl_name="THI"))
|
||||
connect_regions(world, player, "Tiny-Huge Island (Tiny)", "Tiny-Huge Island")
|
||||
connect_regions(world, player, "Tiny-Huge Island (Huge)", "Tiny-Huge Island")
|
||||
connect_regions(multiworld, player, "Tiny-Huge Island (Tiny)", "Tiny-Huge Island")
|
||||
connect_regions(multiworld, player, "Tiny-Huge Island (Huge)", "Tiny-Huge Island")
|
||||
|
||||
connect_regions(world, player, "Second Floor", "Third Floor", lambda state: state.has("Power Star", player, star_costs["SecondFloorDoorCost"]))
|
||||
connect_regions(multiworld, player, "Second Floor", "Third Floor", lambda state: state.has("Power Star", player, star_costs["SecondFloorDoorCost"]))
|
||||
|
||||
connect_regions(world, player, "Third Floor", randomized_entrances_s["Tick Tock Clock"],
|
||||
connect_regions(multiworld, player, "Third Floor", randomized_entrances_s["Tick Tock Clock"],
|
||||
rf.build_rule("LG/TJ/SF/BF/WK", painting_lvl_name="TTC"))
|
||||
connect_regions(world, player, "Third Floor", randomized_entrances_s["Rainbow Ride"], rf.build_rule("TJ/SF/BF"))
|
||||
connect_regions(world, player, "Third Floor", randomized_entrances_s["Wing Mario over the Rainbow"], rf.build_rule("TJ/SF/BF"))
|
||||
connect_regions(world, player, "Third Floor", "Bowser in the Sky", lambda state: state.has("Power Star", player, star_costs["StarsToFinish"]))
|
||||
connect_regions(multiworld, player, "Third Floor", randomized_entrances_s["Rainbow Ride"], rf.build_rule("TJ/SF/BF"))
|
||||
connect_regions(multiworld, player, "Third Floor", randomized_entrances_s["Wing Mario over the Rainbow"], rf.build_rule("TJ/SF/BF"))
|
||||
connect_regions(multiworld, player, "Third Floor", "Bowser in the Sky", lambda state: state.has("Power Star", player, star_costs["StarsToFinish"]))
|
||||
|
||||
# Course Rules
|
||||
# Bob-omb Battlefield
|
||||
@@ -229,30 +229,30 @@ def set_rules(world, options: SM64Options, player: int, area_connections: dict,
|
||||
rf.assign_rule("THI: 100 Coins", "GP")
|
||||
rf.assign_rule("RR: 100 Coins", "GP & WK")
|
||||
# Castle Stars
|
||||
add_rule(world.get_location("Toad (Basement)", player), lambda state: state.can_reach("Basement", 'Region', player) and state.has("Power Star", player, 12))
|
||||
add_rule(world.get_location("Toad (Second Floor)", player), lambda state: state.can_reach("Second Floor", 'Region', player) and state.has("Power Star", player, 25))
|
||||
add_rule(world.get_location("Toad (Third Floor)", player), lambda state: state.can_reach("Third Floor", 'Region', player) and state.has("Power Star", player, 35))
|
||||
add_rule(multiworld.get_location("Toad (Basement)", player), lambda state: state.can_reach("Basement", 'Region', player) and state.has("Power Star", player, 12))
|
||||
add_rule(multiworld.get_location("Toad (Second Floor)", player), lambda state: state.can_reach("Second Floor", 'Region', player) and state.has("Power Star", player, 25))
|
||||
add_rule(multiworld.get_location("Toad (Third Floor)", player), lambda state: state.can_reach("Third Floor", 'Region', player) and state.has("Power Star", player, 35))
|
||||
|
||||
if star_costs["MIPS1Cost"] > star_costs["MIPS2Cost"]:
|
||||
(star_costs["MIPS2Cost"], star_costs["MIPS1Cost"]) = (star_costs["MIPS1Cost"], star_costs["MIPS2Cost"])
|
||||
rf.assign_rule("MIPS 1", "DV | MOVELESS")
|
||||
rf.assign_rule("MIPS 2", "DV | MOVELESS")
|
||||
add_rule(world.get_location("MIPS 1", player), lambda state: state.can_reach("Basement", 'Region', player) and state.has("Power Star", player, star_costs["MIPS1Cost"]))
|
||||
add_rule(world.get_location("MIPS 2", player), lambda state: state.can_reach("Basement", 'Region', player) and state.has("Power Star", player, star_costs["MIPS2Cost"]))
|
||||
add_rule(multiworld.get_location("MIPS 1", player), lambda state: state.can_reach("Basement", 'Region', player) and state.has("Power Star", player, star_costs["MIPS1Cost"]))
|
||||
add_rule(multiworld.get_location("MIPS 2", player), lambda state: state.can_reach("Basement", 'Region', player) and state.has("Power Star", player, star_costs["MIPS2Cost"]))
|
||||
|
||||
world.completion_condition[player] = lambda state: state.can_reach("BitS: Top", 'Region', player)
|
||||
multiworld.completion_condition[player] = lambda state: state.can_reach("BitS: Top", 'Region', player)
|
||||
|
||||
if options.completion_type == "last_bowser_stage":
|
||||
world.completion_condition[player] = lambda state: state.can_reach("BitS: Top", 'Region', player)
|
||||
multiworld.completion_condition[player] = lambda state: state.can_reach("BitS: Top", 'Region', player)
|
||||
elif options.completion_type == "all_bowser_stages":
|
||||
world.completion_condition[player] = lambda state: state.can_reach("Bowser in the Dark World", 'Region', player) and \
|
||||
multiworld.completion_condition[player] = lambda state: state.can_reach("Bowser in the Dark World", 'Region', player) and \
|
||||
state.can_reach("BitFS: Upper", 'Region', player) and \
|
||||
state.can_reach("BitS: Top", 'Region', player)
|
||||
|
||||
|
||||
class RuleFactory:
|
||||
|
||||
world: MultiWorld
|
||||
multiworld: MultiWorld
|
||||
player: int
|
||||
move_rando_bitvec: bool
|
||||
area_randomizer: bool
|
||||
@@ -280,8 +280,8 @@ class RuleFactory:
|
||||
class SM64LogicException(Exception):
|
||||
pass
|
||||
|
||||
def __init__(self, world, options: SM64Options, player: int, move_rando_bitvec: int):
|
||||
self.world = world
|
||||
def __init__(self, multiworld, options: SM64Options, player: int, move_rando_bitvec: int):
|
||||
self.multiworld = multiworld
|
||||
self.player = player
|
||||
self.move_rando_bitvec = move_rando_bitvec
|
||||
self.area_randomizer = options.area_rando > 0
|
||||
@@ -291,7 +291,7 @@ class RuleFactory:
|
||||
self.moveless = not options.strict_move_requirements
|
||||
|
||||
def assign_rule(self, target_name: str, rule_expr: str):
|
||||
target = self.world.get_location(target_name, self.player) if target_name in location_table else self.world.get_entrance(target_name, self.player)
|
||||
target = self.multiworld.get_location(target_name, self.player) if target_name in location_table else self.multiworld.get_entrance(target_name, self.player)
|
||||
cannon_name = "Cannon Unlock " + target_name.split(':')[0]
|
||||
try:
|
||||
rule = self.build_rule(rule_expr, cannon_name)
|
||||
|
||||
@@ -83,7 +83,7 @@ class SMZ3World(World):
|
||||
# optimized message queues for 0.4.4
|
||||
required_client_version = (0, 4, 4)
|
||||
|
||||
def __init__(self, world: MultiWorld, player: int):
|
||||
def __init__(self, multiworld: MultiWorld, player: int):
|
||||
self.rom_name_available_event = threading.Event()
|
||||
self.locations: Dict[str, Location] = {}
|
||||
self.unreachable = []
|
||||
@@ -101,7 +101,7 @@ class SMZ3World(World):
|
||||
ItemType.Super,
|
||||
ItemType.PowerBomb
|
||||
]]
|
||||
super().__init__(world, player)
|
||||
super().__init__(multiworld, player)
|
||||
|
||||
@classmethod
|
||||
def isProgression(cls, itemType):
|
||||
@@ -672,8 +672,8 @@ class SMZ3World(World):
|
||||
self.locations[name] = newLoc
|
||||
self.smz3World.locationLookup[name].APLocation = newLoc
|
||||
|
||||
def create_region(self, world: MultiWorld, player: int, name: str, locations=None, exits=None):
|
||||
ret = Region(name, player, world)
|
||||
def create_region(self, multiworld: MultiWorld, player: int, name: str, locations=None, exits=None):
|
||||
ret = Region(name, player, multiworld)
|
||||
if locations:
|
||||
for loc in locations:
|
||||
location = self.locations[loc]
|
||||
|
||||
@@ -589,8 +589,8 @@ id,name,classification,groups,content_packs
|
||||
666,Maru Portrait,filler,"ENDGAME_LOCATION_ITEMS,MAXIMUM_ONE,FILLER_DECORATION,REQUIRES_FRIENDSANITY_MARRIAGE",
|
||||
667,Penny Portrait,filler,"ENDGAME_LOCATION_ITEMS,MAXIMUM_ONE,FILLER_DECORATION,REQUIRES_FRIENDSANITY_MARRIAGE",
|
||||
668,Sam Portrait,filler,"ENDGAME_LOCATION_ITEMS,MAXIMUM_ONE,FILLER_DECORATION,REQUIRES_FRIENDSANITY_MARRIAGE",
|
||||
669,Sebastian Portrait,filler,"FILLER_DECORATION",
|
||||
670,Shane Portrait,filler,"FILLER_DECORATION",
|
||||
669,Sebastian Portrait,filler,"ENDGAME_LOCATION_ITEMS,MAXIMUM_ONE,FILLER_DECORATION,REQUIRES_FRIENDSANITY_MARRIAGE",
|
||||
670,Shane Portrait,filler,"ENDGAME_LOCATION_ITEMS,MAXIMUM_ONE,FILLER_DECORATION,REQUIRES_FRIENDSANITY_MARRIAGE",
|
||||
671,Trash Bear Arrival,progression,"TRASH_BEAR,COMMUNITY_REWARD",
|
||||
672,Trash Bear Cleanup,filler,"TRASH_BEAR,COMMUNITY_REWARD",
|
||||
673,Progressive Bookseller Days,progression,"BOOKSELLER",
|
||||
|
||||
|
@@ -6,60 +6,6 @@ from . import options
|
||||
from .jojapocalypse_options import Jojapocalypse, JojaStartPrice, JojaEndPrice, JojaPricingPattern, JojaPurchasesForMembership, JojaAreYouSure
|
||||
from ..strings.ap_names.ap_option_names import EatsanityOptionName, ChefsanityOptionName, HatsanityOptionName
|
||||
|
||||
all_random_settings = {
|
||||
"progression_balancing": "random",
|
||||
"accessibility": "random",
|
||||
options.Goal.internal_name: "random",
|
||||
options.FarmType.internal_name: "random",
|
||||
options.StartingMoney.internal_name: "random",
|
||||
options.ProfitMargin.internal_name: "random",
|
||||
options.BundleRandomization.internal_name: "random",
|
||||
options.BundlePrice.internal_name: "random",
|
||||
options.BundlePerRoom.internal_name: "random",
|
||||
options.EntranceRandomization.internal_name: "random",
|
||||
options.SeasonRandomization.internal_name: "random",
|
||||
options.Cropsanity.internal_name: "random",
|
||||
options.BackpackProgression.internal_name: "random",
|
||||
options.BackpackSize.internal_name: "random",
|
||||
options.ToolProgression.internal_name: "random",
|
||||
options.ElevatorProgression.internal_name: "random",
|
||||
options.SkillProgression.internal_name: "random",
|
||||
options.BuildingProgression.internal_name: "random",
|
||||
options.FestivalLocations.internal_name: "random",
|
||||
options.ArcadeMachineLocations.internal_name: "random",
|
||||
options.SpecialOrderLocations.internal_name: "random",
|
||||
options.QuestLocations.internal_name: "random",
|
||||
options.Fishsanity.internal_name: "random",
|
||||
options.Museumsanity.internal_name: "random",
|
||||
options.Monstersanity.internal_name: "random",
|
||||
options.Shipsanity.internal_name: "random",
|
||||
options.Cooksanity.internal_name: "random",
|
||||
options.Craftsanity.internal_name: "random",
|
||||
options.Friendsanity.internal_name: "random",
|
||||
options.FriendsanityHeartSize.internal_name: "random",
|
||||
options.Booksanity.internal_name: "random",
|
||||
options.Moviesanity.internal_name: "random",
|
||||
options.IncludeEndgameLocations.internal_name: "random",
|
||||
options.NumberOfMovementBuffs.internal_name: "random",
|
||||
options.ExcludeGingerIsland.internal_name: "random",
|
||||
options.TrapDifficulty.internal_name: "random",
|
||||
options.MultipleDaySleepEnabled.internal_name: "random",
|
||||
options.MultipleDaySleepCost.internal_name: "random",
|
||||
options.ExperienceMultiplier.internal_name: "random",
|
||||
options.FriendshipMultiplier.internal_name: "random",
|
||||
options.DebrisMultiplier.internal_name: "random",
|
||||
options.QuickStart.internal_name: "random",
|
||||
options.Gifting.internal_name: "random",
|
||||
"death_link": "random",
|
||||
|
||||
options.Jojapocalypse.internal_name: Jojapocalypse.option_disabled,
|
||||
options.JojaStartPrice.internal_name: JojaStartPrice.default,
|
||||
options.JojaEndPrice.internal_name: JojaEndPrice.default,
|
||||
options.JojaPricingPattern.internal_name: JojaPricingPattern.default,
|
||||
options.JojaPurchasesForMembership.internal_name: JojaPurchasesForMembership.default,
|
||||
options.JojaAreYouSure.internal_name: JojaAreYouSure.option_false,
|
||||
}
|
||||
|
||||
easy_settings = {
|
||||
options.Goal.internal_name: options.Goal.option_community_center,
|
||||
options.FarmType.internal_name: "random",
|
||||
@@ -414,9 +360,9 @@ minsanity_settings = {
|
||||
options.JojaAreYouSure.internal_name: JojaAreYouSure.option_false,
|
||||
}
|
||||
|
||||
allsanity_settings = {
|
||||
maxsanity_settings = {
|
||||
options.Goal.internal_name: options.Goal.default,
|
||||
options.FarmType.internal_name: "random",
|
||||
options.FarmType.internal_name: options.FarmType.option_beach,
|
||||
options.StartingMoney.internal_name: options.StartingMoney.default,
|
||||
options.ProfitMargin.internal_name: options.ProfitMargin.default,
|
||||
options.BundleRandomization.internal_name: options.BundleRandomization.default,
|
||||
@@ -476,12 +422,11 @@ allsanity_settings = {
|
||||
|
||||
|
||||
sv_options_presets: Dict[str, Dict[str, Any]] = {
|
||||
"All random": all_random_settings,
|
||||
"Easy": easy_settings,
|
||||
"Medium": medium_settings,
|
||||
"Hard": hard_settings,
|
||||
"Nightmare": nightmare_settings,
|
||||
"Short": short_settings,
|
||||
"Minsanity": minsanity_settings,
|
||||
"Allsanity": allsanity_settings,
|
||||
"Maxsanity": maxsanity_settings,
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ class TestItemLinksEverythingIncluded(SVTestBase):
|
||||
}
|
||||
|
||||
def test_filler_of_all_types_generated(self):
|
||||
max_number_filler = 199
|
||||
max_number_filler = 197
|
||||
filler_generated = []
|
||||
at_least_one_trap = False
|
||||
at_least_one_island = False
|
||||
@@ -41,7 +41,7 @@ class TestItemLinksNoIsland(SVTestBase):
|
||||
}
|
||||
|
||||
def test_filler_has_no_island_but_has_traps(self):
|
||||
max_number_filler = 192
|
||||
max_number_filler = 190
|
||||
filler_generated = []
|
||||
at_least_one_trap = False
|
||||
for i in range(0, max_iterations):
|
||||
@@ -67,7 +67,7 @@ class TestItemLinksNoTraps(SVTestBase):
|
||||
}
|
||||
|
||||
def test_filler_has_no_traps_but_has_island(self):
|
||||
max_number_filler = 176
|
||||
max_number_filler = 174
|
||||
filler_generated = []
|
||||
at_least_one_island = False
|
||||
for i in range(0, max_iterations):
|
||||
@@ -93,7 +93,7 @@ class TestItemLinksNoTrapsAndIsland(SVTestBase):
|
||||
}
|
||||
|
||||
def test_filler_generated_without_island_or_traps(self):
|
||||
max_number_filler = 169
|
||||
max_number_filler = 167
|
||||
filler_generated = []
|
||||
for i in range(0, max_iterations):
|
||||
filler = self.multiworld.worlds[1].get_filler_item_name()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from BaseClasses import MultiWorld, get_seed, ItemClassification
|
||||
from .bases import SVTestCase, solo_multiworld, setup_solo_multiworld
|
||||
from .options.presets import get_minsanity_options, allsanity_no_mods_7_x_x
|
||||
from .options.presets import get_minsanity_options, maxsanity_no_mods_7_x_x
|
||||
from .. import StardewValleyWorld
|
||||
from ..items import Group, item_table
|
||||
from ..options import Friendsanity, SeasonRandomization, Museumsanity, Shipsanity, Goal
|
||||
@@ -44,14 +44,14 @@ class TestItems(SVTestCase):
|
||||
self.assertEqual(len(baby_permutations), 4)
|
||||
|
||||
def test_correct_number_of_stardrops(self):
|
||||
allsanity_options = allsanity_no_mods_7_x_x()
|
||||
with solo_multiworld(allsanity_options) as (multiworld, _):
|
||||
maxsanity_options = maxsanity_no_mods_7_x_x()
|
||||
with solo_multiworld(maxsanity_options) as (multiworld, _):
|
||||
stardrop_items = [item for item in multiworld.get_items() if item.name == "Stardrop"]
|
||||
self.assertEqual(len(stardrop_items), 7)
|
||||
|
||||
def test_no_duplicate_rings(self):
|
||||
allsanity_options = allsanity_no_mods_7_x_x()
|
||||
with solo_multiworld(allsanity_options) as (multiworld, _):
|
||||
maxsanity_options = maxsanity_no_mods_7_x_x()
|
||||
with solo_multiworld(maxsanity_options) as (multiworld, _):
|
||||
ring_items = [item.name for item in multiworld.get_items() if Group.FILLER_RING in item_table[item.name].groups]
|
||||
self.assertEqual(len(ring_items), len(set(ring_items)))
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ from unittest import TestCase, SkipTest
|
||||
from BaseClasses import MultiWorld
|
||||
from .assertion import RuleAssertMixin
|
||||
from .bases import setup_solo_multiworld, skip_long_tests
|
||||
from .options.presets import minimal_locations_maximal_items, allsanity_mods_7_x_x
|
||||
from .options.presets import minimal_locations_maximal_items, maxsanity_mods_7_x_x
|
||||
from .. import StardewValleyWorld
|
||||
from ..data.bundles_data.bundle_data import all_bundle_items_except_money
|
||||
from ..logic.logic import StardewLogic
|
||||
@@ -101,7 +101,7 @@ class LogicTestBase(RuleAssertMixin, TestCase):
|
||||
|
||||
|
||||
class TestAllSanityLogic(LogicTestBase):
|
||||
options = allsanity_mods_7_x_x()
|
||||
options = maxsanity_mods_7_x_x()
|
||||
|
||||
|
||||
@unittest.skip("This test does not pass because some content is still not in content packs.")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from BaseClasses import ItemClassification
|
||||
from .bases import SVTestBase
|
||||
from .options.presets import default_7_x_x, allsanity_no_mods_7_x_x, get_minsanity_options, \
|
||||
minimal_locations_maximal_items, minimal_locations_maximal_items_with_island, allsanity_mods_7_x_x_exclude_disabled
|
||||
from .options.presets import default_7_x_x, maxsanity_no_mods_7_x_x, get_minsanity_options, \
|
||||
minimal_locations_maximal_items, minimal_locations_maximal_items_with_island, maxsanity_mods_7_x_x_exclude_disabled
|
||||
from .. import location_table
|
||||
from ..items import Group, item_table
|
||||
from ..items.item_data import FILLER_GROUPS
|
||||
@@ -63,7 +63,7 @@ class TestDefaultSettingsHasAllExpectedLocations(SVTestBase):
|
||||
options = default_7_x_x()
|
||||
|
||||
def test_default_settings_has_exactly_locations(self):
|
||||
expected_locations = 475
|
||||
expected_locations = 471
|
||||
real_locations = self.get_real_locations()
|
||||
number_locations = len(real_locations)
|
||||
print(f"Stardew Valley - Default options locations: {number_locations}")
|
||||
@@ -75,33 +75,33 @@ class TestDefaultSettingsHasAllExpectedLocations(SVTestBase):
|
||||
|
||||
|
||||
class TestAllSanitySettingsHasAllExpectedLocations(SVTestBase):
|
||||
options = allsanity_no_mods_7_x_x()
|
||||
options = maxsanity_no_mods_7_x_x()
|
||||
|
||||
def test_allsanity_without_mods_has_at_least_locations(self):
|
||||
def test_maxsanity_without_mods_has_at_least_locations(self):
|
||||
expected_locations = 2812
|
||||
real_locations = self.get_real_locations()
|
||||
number_locations = len(real_locations)
|
||||
print(f"Stardew Valley - Allsanity Locations without mods: {number_locations}")
|
||||
print(f"Stardew Valley - Maxsanity Locations without mods: {number_locations}")
|
||||
self.assertGreaterEqual(number_locations, expected_locations)
|
||||
if number_locations != expected_locations:
|
||||
print(f"\tNew locations detected!"
|
||||
f"\n\tPlease update test_allsanity_without_mods_has_at_least_locations"
|
||||
f"\n\tPlease update test_maxsanity_without_mods_has_at_least_locations"
|
||||
f"\n\t\tExpected: {expected_locations}"
|
||||
f"\n\t\tActual: {number_locations}")
|
||||
|
||||
|
||||
class TestAllSanityWithModsSettingsHasAllExpectedLocations(SVTestBase):
|
||||
options = allsanity_mods_7_x_x_exclude_disabled()
|
||||
options = maxsanity_mods_7_x_x_exclude_disabled()
|
||||
|
||||
def test_allsanity_with_mods_has_at_least_locations(self):
|
||||
def test_maxsanity_with_mods_has_at_least_locations(self):
|
||||
expected_locations = 3180 # It was 3473 before disabling SVE
|
||||
real_locations = self.get_real_locations()
|
||||
number_locations = len(real_locations)
|
||||
print(f"Stardew Valley - Allsanity Locations with all mods: {number_locations}")
|
||||
print(f"Stardew Valley - Maxsanity Locations with all mods: {number_locations}")
|
||||
self.assertGreaterEqual(number_locations, expected_locations)
|
||||
if number_locations != expected_locations:
|
||||
print(f"\tNew locations detected!"
|
||||
f"\n\tPlease update test_allsanity_with_mods_has_at_least_locations"
|
||||
f"\n\tPlease update test_maxsanity_with_mods_has_at_least_locations"
|
||||
f"\n\t\tExpected: {expected_locations}"
|
||||
f"\n\t\tActual: {number_locations}")
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import unittest
|
||||
from BaseClasses import ItemClassification
|
||||
from ..assertion import get_all_location_names
|
||||
from ..bases import skip_long_tests, SVTestCase, solo_multiworld
|
||||
from ..options.presets import setting_mins_and_maxes, allsanity_no_mods_7_x_x, get_minsanity_options, default_7_x_x
|
||||
from ..options.presets import setting_mins_and_maxes, maxsanity_no_mods_7_x_x, get_minsanity_options, default_7_x_x
|
||||
from ...items import Group, item_table
|
||||
from ...items.item_data import FILLER_GROUPS
|
||||
|
||||
@@ -30,7 +30,7 @@ class TestCountsPerSetting(SVTestCase):
|
||||
with self.subTest(f"{name}"):
|
||||
highest_variance_items = -1
|
||||
highest_variance_locations = -1
|
||||
for preset in [allsanity_no_mods_7_x_x, default_7_x_x, get_minsanity_options]:
|
||||
for preset in [maxsanity_no_mods_7_x_x, default_7_x_x, get_minsanity_options]:
|
||||
lowest_items = 9999
|
||||
lowest_locations = 9999
|
||||
highest_items = -1
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
from ..TestGeneration import get_all_permanent_progression_items
|
||||
from ..assertion import ModAssertMixin, WorldAssertMixin
|
||||
from ..bases import SVTestCase, SVTestBase, solo_multiworld
|
||||
from ..options.presets import allsanity_mods_7_x_x
|
||||
from ..options.presets import maxsanity_mods_7_x_x
|
||||
from ... import options
|
||||
from ...items import Group
|
||||
from ...mods.mod_data import invalid_mod_combinations
|
||||
from ...options.options import all_mods
|
||||
|
||||
|
||||
class TestCanGenerateAllsanityWithMods(WorldAssertMixin, ModAssertMixin, SVTestCase):
|
||||
class TestCanGenerateMaxsanityWithMods(WorldAssertMixin, ModAssertMixin, SVTestCase):
|
||||
|
||||
def test_allsanity_all_mods_when_generate_then_basic_checks(self):
|
||||
with solo_multiworld(allsanity_mods_7_x_x()) as (multi_world, _):
|
||||
def test_maxsanity_all_mods_when_generate_then_basic_checks(self):
|
||||
with solo_multiworld(maxsanity_mods_7_x_x()) as (multi_world, _):
|
||||
self.assert_basic_checks(multi_world)
|
||||
|
||||
def test_allsanity_all_mods_exclude_island_when_generate_then_basic_checks(self):
|
||||
world_options = allsanity_mods_7_x_x()
|
||||
def test_maxsanity_all_mods_exclude_island_when_generate_then_basic_checks(self):
|
||||
world_options = maxsanity_mods_7_x_x()
|
||||
world_options.update({options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true})
|
||||
with solo_multiworld(world_options) as (multi_world, _):
|
||||
self.assert_basic_checks(multi_world)
|
||||
@@ -106,7 +106,7 @@ class TestVanillaLogicAlternativeWhenQuestsAreNotRandomized(WorldAssertMixin, SV
|
||||
"""We often forget to add an alternative rule that works when quests are not randomized. When this happens, some
|
||||
Location are not reachable because they depend on items that are only added to the pool when quests are randomized.
|
||||
"""
|
||||
options = allsanity_mods_7_x_x() | {
|
||||
options = maxsanity_mods_7_x_x() | {
|
||||
options.QuestLocations.internal_name: options.QuestLocations.special_range_names["none"],
|
||||
options.Goal.internal_name: options.Goal.option_perfection,
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ def default_6_x_x():
|
||||
}
|
||||
|
||||
|
||||
def allsanity_no_mods_6_x_x():
|
||||
def maxsanity_no_mods_6_x_x():
|
||||
return {
|
||||
options.ArcadeMachineLocations.internal_name: options.ArcadeMachineLocations.option_full_shuffling,
|
||||
options.BackpackProgression.internal_name: options.BackpackProgression.option_progressive,
|
||||
@@ -88,16 +88,16 @@ def allsanity_no_mods_6_x_x():
|
||||
}
|
||||
|
||||
|
||||
def allsanity_mods_6_x_x_exclude_disabled():
|
||||
allsanity = allsanity_no_mods_6_x_x()
|
||||
allsanity.update({options.Mods.internal_name: frozenset(options.enabled_mods_except_invalid_combinations)})
|
||||
return allsanity
|
||||
def maxsanity_mods_6_x_x_exclude_disabled():
|
||||
maxsanity = maxsanity_no_mods_6_x_x()
|
||||
maxsanity.update({options.Mods.internal_name: frozenset(options.enabled_mods_except_invalid_combinations)})
|
||||
return maxsanity
|
||||
|
||||
|
||||
def allsanity_mods_6_x_x():
|
||||
allsanity = allsanity_no_mods_6_x_x()
|
||||
allsanity.update({options.Mods.internal_name: frozenset(options.all_mods_except_invalid_combinations)})
|
||||
return allsanity
|
||||
def maxsanity_mods_6_x_x():
|
||||
maxsanity = maxsanity_no_mods_6_x_x()
|
||||
maxsanity.update({options.Mods.internal_name: frozenset(options.all_mods_except_invalid_combinations)})
|
||||
return maxsanity
|
||||
|
||||
|
||||
def default_7_x_x():
|
||||
@@ -143,7 +143,7 @@ def default_7_x_x():
|
||||
}
|
||||
|
||||
|
||||
def allsanity_no_mods_7_x_x():
|
||||
def maxsanity_no_mods_7_x_x():
|
||||
return {
|
||||
options.ArcadeMachineLocations.internal_name: options.ArcadeMachineLocations.option_full_shuffling,
|
||||
options.BackpackProgression.internal_name: options.BackpackProgression.option_progressive,
|
||||
@@ -188,16 +188,16 @@ def allsanity_no_mods_7_x_x():
|
||||
}
|
||||
|
||||
|
||||
def allsanity_mods_7_x_x():
|
||||
allsanity = allsanity_no_mods_7_x_x()
|
||||
allsanity.update({options.Mods.internal_name: frozenset(options.all_mods_except_invalid_combinations)})
|
||||
return allsanity
|
||||
def maxsanity_mods_7_x_x():
|
||||
maxsanity = maxsanity_no_mods_7_x_x()
|
||||
maxsanity.update({options.Mods.internal_name: frozenset(options.all_mods_except_invalid_combinations)})
|
||||
return maxsanity
|
||||
|
||||
|
||||
def allsanity_mods_7_x_x_exclude_disabled():
|
||||
allsanity = allsanity_no_mods_7_x_x()
|
||||
allsanity.update({options.Mods.internal_name: frozenset(options.enabled_mods_except_invalid_combinations)})
|
||||
return allsanity
|
||||
def maxsanity_mods_7_x_x_exclude_disabled():
|
||||
maxsanity = maxsanity_no_mods_7_x_x()
|
||||
maxsanity.update({options.Mods.internal_name: frozenset(options.enabled_mods_except_invalid_combinations)})
|
||||
return maxsanity
|
||||
|
||||
|
||||
def get_minsanity_options():
|
||||
@@ -318,7 +318,7 @@ def setting_mins_and_maxes():
|
||||
options.Fishsanity.internal_name: [options.Fishsanity.option_none, options.Fishsanity.option_all],
|
||||
options.Friendsanity.internal_name: [options.Friendsanity.option_none, options.Friendsanity.option_all_with_marriage],
|
||||
options.FriendsanityHeartSize.internal_name: [1, 8],
|
||||
options.Goal.internal_name: options.Goal.option_allsanity,
|
||||
options.Goal.internal_name: options.Goal.option_maxsanity,
|
||||
options.IncludeEndgameLocations.internal_name: [options.IncludeEndgameLocations.option_false, options.IncludeEndgameLocations.option_true],
|
||||
options.Mods.internal_name: frozenset(),
|
||||
options.Monstersanity.internal_name: [options.Monstersanity.option_none, options.Monstersanity.option_one_per_monster],
|
||||
|
||||
@@ -9,7 +9,7 @@ from BaseClasses import get_seed
|
||||
from Fill import distribute_items_restrictive, balance_multiworld_progression
|
||||
from worlds import AutoWorld
|
||||
from ..bases import SVTestCase, setup_multiworld
|
||||
from ..options.presets import default_6_x_x, allsanity_no_mods_6_x_x, minimal_locations_maximal_items, allsanity_mods_7_x_x, allsanity_no_mods_7_x_x, \
|
||||
from ..options.presets import default_6_x_x, maxsanity_no_mods_6_x_x, minimal_locations_maximal_items, maxsanity_mods_7_x_x, maxsanity_no_mods_7_x_x, \
|
||||
default_7_x_x
|
||||
|
||||
default_number_generations = 25
|
||||
@@ -213,9 +213,9 @@ class TestMinLocationMaxItems(SVPerformanceTestCase):
|
||||
self.performance_test_multiworld(multiworld_options)
|
||||
|
||||
|
||||
class TestAllsanityWithoutMods6xx(SVPerformanceTestCase):
|
||||
class TestMaxsanityWithoutMods6xx(SVPerformanceTestCase):
|
||||
acceptable_time_per_player = 10
|
||||
options = allsanity_no_mods_6_x_x()
|
||||
options = maxsanity_no_mods_6_x_x()
|
||||
results = []
|
||||
|
||||
def test_solo(self):
|
||||
@@ -242,9 +242,9 @@ class TestAllsanityWithoutMods6xx(SVPerformanceTestCase):
|
||||
self.performance_test_multiworld(multiworld_options)
|
||||
|
||||
|
||||
class TestAllsanityWithoutMods7xx(SVPerformanceTestCase):
|
||||
class TestMaxsanityWithoutMods7xx(SVPerformanceTestCase):
|
||||
acceptable_time_per_player = 10
|
||||
options = allsanity_no_mods_7_x_x()
|
||||
options = maxsanity_no_mods_7_x_x()
|
||||
results = []
|
||||
|
||||
def test_solo(self):
|
||||
@@ -270,9 +270,9 @@ class TestAllsanityWithoutMods7xx(SVPerformanceTestCase):
|
||||
self.performance_test_multiworld(multiworld_options)
|
||||
|
||||
|
||||
class TestAllsanityWithMods7xx(SVPerformanceTestCase):
|
||||
class TestMaxsanityWithMods7xx(SVPerformanceTestCase):
|
||||
acceptable_time_per_player = 25
|
||||
options = allsanity_mods_7_x_x()
|
||||
options = maxsanity_mods_7_x_x()
|
||||
results = []
|
||||
|
||||
@unittest.skip
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from ..bases import SVTestBase
|
||||
from ..options.presets import allsanity_mods_7_x_x
|
||||
from ..options.presets import maxsanity_mods_7_x_x
|
||||
from ... import locations_by_tag
|
||||
from ...content.feature.hatsanity import to_location_name
|
||||
from ...data.hats_data import Hats
|
||||
@@ -75,7 +75,7 @@ class TestNoHatsLogic(SVTestBase):
|
||||
|
||||
|
||||
class TestHatLocations(SVTestBase):
|
||||
options = allsanity_mods_7_x_x()
|
||||
options = maxsanity_mods_7_x_x()
|
||||
|
||||
def test_all_hat_locations_are_added(self):
|
||||
location_names = [location.name for location in self.multiworld.get_locations()]
|
||||
|
||||
@@ -36,7 +36,7 @@ class DisabledMuseumRule(LiteralStardewRule):
|
||||
|
||||
class TestMuseumsanityDisabledExcludesMuseumDonationsFromOtherLocations(SVTestBase):
|
||||
options = {
|
||||
**presets.allsanity_mods_7_x_x(),
|
||||
**presets.maxsanity_mods_7_x_x(),
|
||||
options.Museumsanity.internal_name: options.Museumsanity.option_none
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
from ..bases import SVTestBase
|
||||
from ..options.presets import allsanity_mods_7_x_x
|
||||
from ..options.presets import maxsanity_mods_7_x_x
|
||||
from ...stardew_rule import HasProgressionPercent
|
||||
|
||||
|
||||
class TestHasProgressionPercentWithVictory(SVTestBase):
|
||||
options = allsanity_mods_7_x_x()
|
||||
options = maxsanity_mods_7_x_x()
|
||||
skip_default_tests = True
|
||||
|
||||
def test_has_100_progression_percent_is_false_while_items_are_missing(self):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import argparse
|
||||
import json
|
||||
|
||||
from worlds.stardew_valley.test.options.presets import allsanity_mods_7_x_x_exclude_disabled
|
||||
from worlds.stardew_valley.test.options.presets import maxsanity_mods_7_x_x_exclude_disabled
|
||||
from ..bases import setup_solo_multiworld
|
||||
from ...options import FarmType, EntranceRandomization
|
||||
|
||||
@@ -12,7 +12,7 @@ if __name__ == "__main__":
|
||||
args = parser.parse_args()
|
||||
seed = args.seed
|
||||
|
||||
options = allsanity_mods_7_x_x_exclude_disabled()
|
||||
options = maxsanity_mods_7_x_x_exclude_disabled()
|
||||
options[FarmType.internal_name] = FarmType.option_standard
|
||||
options[EntranceRandomization.internal_name] = EntranceRandomization.option_buildings
|
||||
multi_world = setup_solo_multiworld(options, seed=seed)
|
||||
|
||||
@@ -2,7 +2,7 @@ import unittest
|
||||
from unittest.mock import Mock
|
||||
|
||||
from ..bases import skip_long_tests, SVTestBase
|
||||
from ..options.presets import allsanity_mods_7_x_x
|
||||
from ..options.presets import maxsanity_mods_7_x_x
|
||||
from ..options.utils import fill_namespace_with_default
|
||||
from ... import STARDEW_VALLEY
|
||||
from ...options import FarmType, BundleRandomization, EntranceRandomization
|
||||
@@ -10,7 +10,7 @@ from ...options import FarmType, BundleRandomization, EntranceRandomization
|
||||
|
||||
@unittest.skipIf(skip_long_tests(), "Long tests disabled")
|
||||
class TestUniversalTrackerGenerationIsStable(SVTestBase):
|
||||
options = allsanity_mods_7_x_x()
|
||||
options = maxsanity_mods_7_x_x()
|
||||
options.update({
|
||||
EntranceRandomization.internal_name: EntranceRandomization.option_buildings,
|
||||
BundleRandomization.internal_name: BundleRandomization.option_shuffled,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
from ...items import items_by_group, Group
|
||||
from ...options import TrapDifficulty
|
||||
from ...test.bases import SVTestCase, solo_multiworld
|
||||
from ...test.options.presets import allsanity_mods_7_x_x, allsanity_no_mods_7_x_x
|
||||
from ...test.options.presets import maxsanity_mods_7_x_x, maxsanity_no_mods_7_x_x
|
||||
|
||||
|
||||
class TestTraps(SVTestCase):
|
||||
def test_given_no_traps_when_generate_then_no_trap_in_pool(self):
|
||||
world_options = allsanity_no_mods_7_x_x().copy()
|
||||
world_options = maxsanity_no_mods_7_x_x().copy()
|
||||
world_options[TrapDifficulty.internal_name] = TrapDifficulty.option_no_traps
|
||||
with solo_multiworld(world_options) as (multi_world, _):
|
||||
trap_items = [item_data.name for item_data in items_by_group[Group.TRAP]]
|
||||
@@ -18,7 +18,7 @@ class TestTraps(SVTestCase):
|
||||
|
||||
def test_given_traps_when_generate_then_all_traps_in_pool(self):
|
||||
trap_option = TrapDifficulty
|
||||
world_options = allsanity_mods_7_x_x()
|
||||
world_options = maxsanity_mods_7_x_x()
|
||||
world_options.update({TrapDifficulty.internal_name: trap_option.option_easy})
|
||||
with solo_multiworld(world_options) as (multi_world, _):
|
||||
trap_items = [item_data.name for item_data in items_by_group[Group.TRAP] if Group.DEPRECATED not in item_data.groups]
|
||||
|
||||
+188
-188
@@ -6,200 +6,200 @@ from .PreCalculatedWeights import PreCalculatedWeights
|
||||
from .LogicExtensions import TimespinnerLogic
|
||||
|
||||
|
||||
def create_regions_and_locations(world: MultiWorld, player: int, options: TimespinnerOptions,
|
||||
def create_regions_and_locations(multiworld: MultiWorld, player: int, options: TimespinnerOptions,
|
||||
precalculated_weights: PreCalculatedWeights):
|
||||
|
||||
locations_per_region: Dict[str, List[LocationData]] = split_location_datas_per_region(
|
||||
get_location_datas(player, options, precalculated_weights))
|
||||
|
||||
regions = [
|
||||
create_region(world, player, locations_per_region, 'Menu'),
|
||||
create_region(world, player, locations_per_region, 'Tutorial'),
|
||||
create_region(world, player, locations_per_region, 'Lake desolation'),
|
||||
create_region(world, player, locations_per_region, 'Upper lake desolation'),
|
||||
create_region(world, player, locations_per_region, 'Lower lake desolation'),
|
||||
create_region(world, player, locations_per_region, 'Eastern lake desolation'),
|
||||
create_region(world, player, locations_per_region, 'Library'),
|
||||
create_region(world, player, locations_per_region, 'Library top'),
|
||||
create_region(world, player, locations_per_region, 'Varndagroth tower left'),
|
||||
create_region(world, player, locations_per_region, 'Varndagroth tower right (upper)'),
|
||||
create_region(world, player, locations_per_region, 'Varndagroth tower right (lower)'),
|
||||
create_region(world, player, locations_per_region, 'Varndagroth tower right (elevator)'),
|
||||
create_region(world, player, locations_per_region, 'Sealed Caves (Sirens)'),
|
||||
create_region(world, player, locations_per_region, 'Military Fortress'),
|
||||
create_region(world, player, locations_per_region, 'Military Fortress (hangar)'),
|
||||
create_region(world, player, locations_per_region, 'Lab Entrance'),
|
||||
create_region(world, player, locations_per_region, 'Main Lab'),
|
||||
create_region(world, player, locations_per_region, 'Lab Research'),
|
||||
create_region(world, player, locations_per_region, 'The lab (upper)'),
|
||||
create_region(world, player, locations_per_region, 'Emperors tower (courtyard)'),
|
||||
create_region(world, player, locations_per_region, 'Emperors tower'),
|
||||
create_region(world, player, locations_per_region, 'Skeleton Shaft'),
|
||||
create_region(world, player, locations_per_region, 'Sealed Caves (Xarion)'),
|
||||
create_region(world, player, locations_per_region, 'Refugee Camp'),
|
||||
create_region(world, player, locations_per_region, 'Forest'),
|
||||
create_region(world, player, locations_per_region, 'Left Side forest Caves'),
|
||||
create_region(world, player, locations_per_region, 'Upper Lake Serene'),
|
||||
create_region(world, player, locations_per_region, 'Lower Lake Serene'),
|
||||
create_region(world, player, locations_per_region, 'Caves of Banishment (upper)'),
|
||||
create_region(world, player, locations_per_region, 'Caves of Banishment (Maw)'),
|
||||
create_region(world, player, locations_per_region, 'Caves of Banishment (Flooded)'),
|
||||
create_region(world, player, locations_per_region, 'Caves of Banishment (Sirens)'),
|
||||
create_region(world, player, locations_per_region, 'Castle Ramparts'),
|
||||
create_region(world, player, locations_per_region, 'Castle Keep'),
|
||||
create_region(world, player, locations_per_region, 'Castle Basement'),
|
||||
create_region(world, player, locations_per_region, 'Royal towers (lower)'),
|
||||
create_region(world, player, locations_per_region, 'Royal towers'),
|
||||
create_region(world, player, locations_per_region, 'Royal towers (upper)'),
|
||||
create_region(world, player, locations_per_region, 'Temporal Gyre'),
|
||||
create_region(world, player, locations_per_region, 'Ancient Pyramid (entrance)'),
|
||||
create_region(world, player, locations_per_region, 'Ancient Pyramid (left)'),
|
||||
create_region(world, player, locations_per_region, 'Ancient Pyramid (right)'),
|
||||
create_region(world, player, locations_per_region, 'Space time continuum')
|
||||
create_region(multiworld, player, locations_per_region, 'Menu'),
|
||||
create_region(multiworld, player, locations_per_region, 'Tutorial'),
|
||||
create_region(multiworld, player, locations_per_region, 'Lake desolation'),
|
||||
create_region(multiworld, player, locations_per_region, 'Upper lake desolation'),
|
||||
create_region(multiworld, player, locations_per_region, 'Lower lake desolation'),
|
||||
create_region(multiworld, player, locations_per_region, 'Eastern lake desolation'),
|
||||
create_region(multiworld, player, locations_per_region, 'Library'),
|
||||
create_region(multiworld, player, locations_per_region, 'Library top'),
|
||||
create_region(multiworld, player, locations_per_region, 'Varndagroth tower left'),
|
||||
create_region(multiworld, player, locations_per_region, 'Varndagroth tower right (upper)'),
|
||||
create_region(multiworld, player, locations_per_region, 'Varndagroth tower right (lower)'),
|
||||
create_region(multiworld, player, locations_per_region, 'Varndagroth tower right (elevator)'),
|
||||
create_region(multiworld, player, locations_per_region, 'Sealed Caves (Sirens)'),
|
||||
create_region(multiworld, player, locations_per_region, 'Military Fortress'),
|
||||
create_region(multiworld, player, locations_per_region, 'Military Fortress (hangar)'),
|
||||
create_region(multiworld, player, locations_per_region, 'Lab Entrance'),
|
||||
create_region(multiworld, player, locations_per_region, 'Main Lab'),
|
||||
create_region(multiworld, player, locations_per_region, 'Lab Research'),
|
||||
create_region(multiworld, player, locations_per_region, 'The lab (upper)'),
|
||||
create_region(multiworld, player, locations_per_region, 'Emperors tower (courtyard)'),
|
||||
create_region(multiworld, player, locations_per_region, 'Emperors tower'),
|
||||
create_region(multiworld, player, locations_per_region, 'Skeleton Shaft'),
|
||||
create_region(multiworld, player, locations_per_region, 'Sealed Caves (Xarion)'),
|
||||
create_region(multiworld, player, locations_per_region, 'Refugee Camp'),
|
||||
create_region(multiworld, player, locations_per_region, 'Forest'),
|
||||
create_region(multiworld, player, locations_per_region, 'Left Side forest Caves'),
|
||||
create_region(multiworld, player, locations_per_region, 'Upper Lake Serene'),
|
||||
create_region(multiworld, player, locations_per_region, 'Lower Lake Serene'),
|
||||
create_region(multiworld, player, locations_per_region, 'Caves of Banishment (upper)'),
|
||||
create_region(multiworld, player, locations_per_region, 'Caves of Banishment (Maw)'),
|
||||
create_region(multiworld, player, locations_per_region, 'Caves of Banishment (Flooded)'),
|
||||
create_region(multiworld, player, locations_per_region, 'Caves of Banishment (Sirens)'),
|
||||
create_region(multiworld, player, locations_per_region, 'Castle Ramparts'),
|
||||
create_region(multiworld, player, locations_per_region, 'Castle Keep'),
|
||||
create_region(multiworld, player, locations_per_region, 'Castle Basement'),
|
||||
create_region(multiworld, player, locations_per_region, 'Royal towers (lower)'),
|
||||
create_region(multiworld, player, locations_per_region, 'Royal towers'),
|
||||
create_region(multiworld, player, locations_per_region, 'Royal towers (upper)'),
|
||||
create_region(multiworld, player, locations_per_region, 'Temporal Gyre'),
|
||||
create_region(multiworld, player, locations_per_region, 'Ancient Pyramid (entrance)'),
|
||||
create_region(multiworld, player, locations_per_region, 'Ancient Pyramid (left)'),
|
||||
create_region(multiworld, player, locations_per_region, 'Ancient Pyramid (right)'),
|
||||
create_region(multiworld, player, locations_per_region, 'Space time continuum')
|
||||
]
|
||||
|
||||
if options.gyre_archives:
|
||||
regions.extend([
|
||||
create_region(world, player, locations_per_region, 'Ravenlord\'s Lair'),
|
||||
create_region(world, player, locations_per_region, 'Ifrit\'s Lair'),
|
||||
create_region(multiworld, player, locations_per_region, 'Ravenlord\'s Lair'),
|
||||
create_region(multiworld, player, locations_per_region, 'Ifrit\'s Lair'),
|
||||
])
|
||||
|
||||
if __debug__:
|
||||
throwIfAnyLocationIsNotAssignedToARegion(regions, locations_per_region.keys())
|
||||
|
||||
world.regions += regions
|
||||
multiworld.regions += regions
|
||||
|
||||
connectStartingRegion(world, player, options)
|
||||
connectStartingRegion(multiworld, player, options)
|
||||
|
||||
flooded: PreCalculatedWeights = precalculated_weights
|
||||
logic = TimespinnerLogic(player, options, precalculated_weights)
|
||||
|
||||
connect(world, player, 'Lake desolation', 'Lower lake desolation', lambda state: flooded.flood_lake_desolation or logic.has_timestop(state) or state.has('Talaria Attachment', player))
|
||||
connect(world, player, 'Lake desolation', 'Upper lake desolation', lambda state: logic.has_fire(state) and state.can_reach('Upper Lake Serene', 'Region', player), "Upper Lake Serene")
|
||||
connect(world, player, 'Lake desolation', 'Skeleton Shaft', lambda state: flooded.flood_lake_desolation or logic.has_doublejump(state))
|
||||
connect(world, player, 'Lake desolation', 'Space time continuum', logic.has_teleport)
|
||||
connect(world, player, 'Upper lake desolation', 'Lake desolation')
|
||||
connect(world, player, 'Upper lake desolation', 'Eastern lake desolation')
|
||||
connect(world, player, 'Lower lake desolation', 'Lake desolation')
|
||||
connect(world, player, 'Lower lake desolation', 'Eastern lake desolation')
|
||||
connect(world, player, 'Eastern lake desolation', 'Space time continuum', logic.has_teleport)
|
||||
connect(world, player, 'Eastern lake desolation', 'Library')
|
||||
connect(world, player, 'Eastern lake desolation', 'Lower lake desolation')
|
||||
connect(world, player, 'Eastern lake desolation', 'Upper lake desolation', lambda state: logic.has_fire(state) and state.can_reach('Upper Lake Serene', 'Region', player), "Upper Lake Serene")
|
||||
connect(world, player, 'Library', 'Eastern lake desolation')
|
||||
connect(world, player, 'Library', 'Library top', lambda state: logic.has_doublejump(state) or state.has('Talaria Attachment', player))
|
||||
connect(world, player, 'Library', 'Varndagroth tower left', logic.has_keycard_D)
|
||||
connect(world, player, 'Library', 'Space time continuum', logic.has_teleport)
|
||||
connect(world, player, 'Library top', 'Library')
|
||||
connect(world, player, 'Varndagroth tower left', 'Library')
|
||||
connect(world, player, 'Varndagroth tower left', 'Varndagroth tower right (upper)', logic.has_keycard_C)
|
||||
connect(world, player, 'Varndagroth tower left', 'Varndagroth tower right (lower)', logic.has_keycard_B)
|
||||
connect(world, player, 'Varndagroth tower left', 'Sealed Caves (Sirens)', lambda state: logic.has_keycard_B(state) and state.has('Elevator Keycard', player))
|
||||
connect(world, player, 'Varndagroth tower left', 'Refugee Camp', lambda state: state.has('Timespinner Wheel', player) and state.has('Timespinner Spindle', player))
|
||||
connect(world, player, 'Varndagroth tower right (upper)', 'Varndagroth tower left')
|
||||
connect(world, player, 'Varndagroth tower right (upper)', 'Varndagroth tower right (elevator)', lambda state: state.has('Elevator Keycard', player))
|
||||
connect(world, player, 'Varndagroth tower right (elevator)', 'Varndagroth tower right (upper)')
|
||||
connect(world, player, 'Varndagroth tower right (elevator)', 'Varndagroth tower right (lower)')
|
||||
connect(world, player, 'Varndagroth tower right (lower)', 'Varndagroth tower left', logic.has_keycard_B)
|
||||
connect(world, player, 'Varndagroth tower right (lower)', 'Varndagroth tower right (elevator)', lambda state: state.has('Elevator Keycard', player))
|
||||
connect(world, player, 'Varndagroth tower right (lower)', 'Sealed Caves (Sirens)', lambda state: logic.has_keycard_B(state) and state.has('Elevator Keycard', player))
|
||||
connect(world, player, 'Varndagroth tower right (lower)', 'Military Fortress', logic.can_kill_all_3_bosses)
|
||||
connect(world, player, 'Varndagroth tower right (lower)', 'Space time continuum', logic.has_teleport)
|
||||
connect(world, player, 'Sealed Caves (Sirens)', 'Varndagroth tower left', lambda state: state.has('Elevator Keycard', player))
|
||||
connect(world, player, 'Sealed Caves (Sirens)', 'Varndagroth tower right (lower)', lambda state: state.has('Elevator Keycard', player))
|
||||
connect(world, player, 'Sealed Caves (Sirens)', 'Space time continuum', logic.has_teleport)
|
||||
connect(world, player, 'Military Fortress', 'Varndagroth tower right (lower)', logic.can_kill_all_3_bosses)
|
||||
connect(world, player, 'Military Fortress', 'Temporal Gyre', lambda state: state.has('Timespinner Wheel', player) and logic.can_kill_all_3_bosses(state))
|
||||
connect(world, player, 'Military Fortress', 'Military Fortress (hangar)', logic.has_doublejump)
|
||||
connect(world, player, 'Military Fortress (hangar)', 'Military Fortress')
|
||||
connect(world, player, 'Military Fortress (hangar)', 'Lab Entrance', lambda state: state.has('Water Mask', player) if flooded.flood_lab else logic.has_doublejump(state))
|
||||
connect(world, player, 'Lab Entrance', 'Main Lab', lambda state: logic.has_keycard_B(state))
|
||||
connect(world, player, 'Main Lab', 'Lab Entrance')
|
||||
connect(world, player, 'Lab Entrance', 'Military Fortress (hangar)')
|
||||
connect(world, player, 'Temporal Gyre', 'Military Fortress')
|
||||
connect(world, player, 'Main Lab', 'Lab Research', lambda state: state.has('Lab Access Research', player) if options.lock_key_amadeus else logic.has_doublejump_of_npc(state))
|
||||
connect(world, player, 'Main Lab', 'The lab (upper)', lambda state: logic.has_forwarddash_doublejump(state) and ((not options.lock_key_amadeus) or state.has('Lab Access Genza', player)))
|
||||
connect(world, player, 'The lab (upper)', 'Main Lab', lambda state: options.lock_key_amadeus and state.has('Lab Access Genza', player))
|
||||
connect(world, player, 'The lab (upper)', 'Emperors tower (courtyard)', logic.has_forwarddash_doublejump)
|
||||
connect(world, player, 'The lab (upper)', 'Ancient Pyramid (entrance)', lambda state: state.has_all({'Timespinner Wheel', 'Timespinner Spindle', 'Timespinner Gear 1', 'Timespinner Gear 2', 'Timespinner Gear 3'}, player))
|
||||
connect(world, player, 'Emperors tower (courtyard)', 'The lab (upper)')
|
||||
connect(world, player, 'Emperors tower (courtyard)', 'Emperors tower', logic.has_doublejump)
|
||||
connect(world, player, 'Emperors tower', 'Emperors tower (courtyard)')
|
||||
connect(world, player, 'Skeleton Shaft', 'Lake desolation')
|
||||
connect(world, player, 'Skeleton Shaft', 'Sealed Caves (Xarion)', logic.has_keycard_A)
|
||||
connect(world, player, 'Skeleton Shaft', 'Space time continuum', logic.has_teleport)
|
||||
connect(world, player, 'Sealed Caves (Xarion)', 'Skeleton Shaft')
|
||||
connect(world, player, 'Sealed Caves (Xarion)', 'Space time continuum', logic.has_teleport)
|
||||
connect(world, player, 'Refugee Camp', 'Forest')
|
||||
connect(world, player, 'Refugee Camp', 'Library', lambda state: (options.pyramid_start or options.inverted) and options.back_to_the_future and state.has_all({'Timespinner Wheel', 'Timespinner Spindle'}, player))
|
||||
connect(world, player, 'Refugee Camp', 'Space time continuum', logic.has_teleport)
|
||||
connect(world, player, 'Forest', 'Refugee Camp')
|
||||
connect(world, player, 'Forest', 'Left Side forest Caves', lambda state: flooded.flood_lake_serene_bridge or state.has('Talaria Attachment', player) or logic.has_timestop(state))
|
||||
connect(world, player, 'Forest', 'Caves of Banishment (Sirens)')
|
||||
connect(world, player, 'Forest', 'Castle Ramparts', lambda state: not options.gate_keep or state.has('Drawbridge Key', player) or logic.has_upwarddash(state))
|
||||
connect(world, player, 'Left Side forest Caves', 'Forest')
|
||||
connect(world, player, 'Left Side forest Caves', 'Upper Lake Serene', logic.has_timestop)
|
||||
connect(world, player, 'Left Side forest Caves', 'Lower Lake Serene', lambda state: not flooded.flood_lake_serene or state.has('Water Mask', player))
|
||||
connect(world, player, 'Left Side forest Caves', 'Space time continuum', logic.has_teleport)
|
||||
connect(world, player, 'Upper Lake Serene', 'Left Side forest Caves')
|
||||
connect(world, player, 'Upper Lake Serene', 'Lower Lake Serene', lambda state: not flooded.flood_lake_serene or state.has('Water Mask', player))
|
||||
connect(world, player, 'Lower Lake Serene', 'Upper Lake Serene')
|
||||
connect(world, player, 'Lower Lake Serene', 'Left Side forest Caves')
|
||||
connect(world, player, 'Lower Lake Serene', 'Caves of Banishment (upper)', lambda state: flooded.flood_lake_serene or logic.has_doublejump(state))
|
||||
connect(world, player, 'Caves of Banishment (upper)', 'Lower Lake Serene', lambda state: not flooded.flood_lake_serene or state.has('Water Mask', player))
|
||||
connect(world, player, 'Caves of Banishment (upper)', 'Caves of Banishment (Maw)', lambda state: not flooded.flood_maw or state.has('Water Mask', player))
|
||||
connect(world, player, 'Caves of Banishment (upper)', 'Space time continuum', logic.has_teleport)
|
||||
connect(world, player, 'Caves of Banishment (Maw)', 'Caves of Banishment (upper)', lambda state: logic.has_doublejump(state) if not flooded.flood_maw else state.has('Water Mask', player))
|
||||
connect(world, player, 'Caves of Banishment (Maw)', 'Caves of Banishment (Sirens)', lambda state: state.has_any({'Gas Mask', 'Talaria Attachment'}, player) )
|
||||
connect(world, player, 'Caves of Banishment (Maw)', 'Caves of Banishment (Flooded)', lambda state: flooded.flood_maw or state.has('Water Mask', player))
|
||||
connect(world, player, 'Caves of Banishment (Maw)', 'Space time continuum', logic.has_teleport)
|
||||
connect(world, player, 'Caves of Banishment (Sirens)', 'Forest')
|
||||
connect(world, player, 'Castle Ramparts', 'Forest')
|
||||
connect(world, player, 'Castle Ramparts', 'Castle Keep')
|
||||
connect(world, player, 'Castle Ramparts', 'Space time continuum', logic.has_teleport)
|
||||
connect(world, player, 'Castle Keep', 'Castle Ramparts')
|
||||
connect(world, player, 'Castle Keep', 'Castle Basement', lambda state: not flooded.flood_basement or state.has('Water Mask', player))
|
||||
connect(world, player, 'Castle Keep', 'Royal towers (lower)', lambda state: logic.has_doublejump(state) and (not options.royal_roadblock or logic.has_pink(state)))
|
||||
connect(world, player, 'Castle Keep', 'Space time continuum', logic.has_teleport)
|
||||
connect(world, player, 'Royal towers (lower)', 'Castle Keep')
|
||||
connect(world, player, 'Royal towers (lower)', 'Royal towers', lambda state: state.has('Timespinner Wheel', player) or logic.has_forwarddash_doublejump(state))
|
||||
connect(world, player, 'Royal towers (lower)', 'Space time continuum', logic.has_teleport)
|
||||
connect(world, player, 'Royal towers', 'Royal towers (lower)')
|
||||
connect(world, player, 'Royal towers', 'Royal towers (upper)', logic.has_doublejump)
|
||||
connect(world, player, 'Royal towers (upper)', 'Royal towers')
|
||||
#connect(world, player, 'Ancient Pyramid (entrance)', 'The lab (upper)', lambda state: not is_option_enabled(world, player, "EnterSandman"))
|
||||
connect(world, player, 'Ancient Pyramid (entrance)', 'Ancient Pyramid (left)', logic.has_doublejump)
|
||||
connect(world, player, 'Ancient Pyramid (entrance)', 'Space time continuum', logic.has_teleport)
|
||||
connect(world, player, 'Ancient Pyramid (left)', 'Ancient Pyramid (entrance)')
|
||||
connect(world, player, 'Ancient Pyramid (left)', 'Ancient Pyramid (right)', lambda state: flooded.flood_pyramid_shaft or logic.has_upwarddash(state))
|
||||
connect(world, player, 'Ancient Pyramid (left)', 'Space time continuum', logic.has_teleport)
|
||||
connect(world, player, 'Ancient Pyramid (right)', 'Ancient Pyramid (left)', lambda state: flooded.flood_pyramid_shaft or logic.has_upwarddash(state))
|
||||
connect(world, player, 'Ancient Pyramid (right)', 'Space time continuum', logic.has_teleport)
|
||||
connect(world, player, 'Space time continuum', 'Lake desolation', lambda state: logic.can_teleport_to(state, "Present", "GateLakeDesolation"))
|
||||
connect(world, player, 'Space time continuum', 'Lower lake desolation', lambda state: logic.can_teleport_to(state, "Present", "GateKittyBoss"))
|
||||
connect(world, player, 'Space time continuum', 'Library', lambda state: logic.can_teleport_to(state, "Present", "GateLeftLibrary"))
|
||||
connect(world, player, 'Space time continuum', 'Varndagroth tower right (lower)', lambda state: logic.can_teleport_to(state, "Present", "GateMilitaryGate"))
|
||||
connect(world, player, 'Space time continuum', 'Skeleton Shaft', lambda state: logic.can_teleport_to(state, "Present", "GateSealedCaves"))
|
||||
connect(world, player, 'Space time continuum', 'Sealed Caves (Sirens)', lambda state: logic.can_teleport_to(state, "Present", "GateSealedSirensCave"))
|
||||
connect(world, player, 'Space time continuum', 'Sealed Caves (Xarion)', lambda state: logic.can_teleport_to(state, "Present", "GateXarion"))
|
||||
connect(world, player, 'Space time continuum', 'Upper Lake Serene', lambda state: logic.can_teleport_to(state, "Past", "GateLakeSereneLeft"))
|
||||
connect(world, player, 'Space time continuum', 'Left Side forest Caves', lambda state: logic.can_teleport_to(state, "Past", "GateLakeSereneRight"))
|
||||
connect(world, player, 'Space time continuum', 'Refugee Camp', lambda state: logic.can_teleport_to(state, "Past", "GateAccessToPast"))
|
||||
connect(world, player, 'Space time continuum', 'Forest', lambda state: logic.can_teleport_to(state, "Past", "GateCastleRamparts"))
|
||||
connect(world, player, 'Space time continuum', 'Castle Keep', lambda state: logic.can_teleport_to(state, "Past", "GateCastleKeep"))
|
||||
connect(world, player, 'Space time continuum', 'Royal towers (lower)', lambda state: logic.can_teleport_to(state, "Past", "GateRoyalTowers"))
|
||||
connect(world, player, 'Space time continuum', 'Caves of Banishment (Maw)', lambda state: logic.can_teleport_to(state, "Past", "GateMaw"))
|
||||
connect(world, player, 'Space time continuum', 'Caves of Banishment (upper)', lambda state: logic.can_teleport_to(state, "Past", "GateCavesOfBanishment"))
|
||||
connect(world, player, 'Space time continuum', 'Military Fortress (hangar)', lambda state: logic.can_teleport_to(state, "Present", "GateLabEntrance"))
|
||||
connect(world, player, 'Space time continuum', 'The lab (upper)', lambda state: logic.can_teleport_to(state, "Present", "GateDadsTower"))
|
||||
connect(world, player, 'Space time continuum', 'Ancient Pyramid (entrance)', lambda state: logic.can_teleport_to(state, "Time", "GateGyre") or logic.can_teleport_to(state, "Time", "GateLeftPyramid") or (not options.unchained_keys and options.enter_sandman))
|
||||
connect(world, player, 'Space time continuum', 'Ancient Pyramid (right)', lambda state: logic.can_teleport_to(state, "Time", "GateRightPyramid"))
|
||||
connect(multiworld, player, 'Lake desolation', 'Lower lake desolation', lambda state: flooded.flood_lake_desolation or logic.has_timestop(state) or state.has('Talaria Attachment', player))
|
||||
connect(multiworld, player, 'Lake desolation', 'Upper lake desolation', lambda state: logic.has_fire(state) and state.can_reach('Upper Lake Serene', 'Region', player), "Upper Lake Serene")
|
||||
connect(multiworld, player, 'Lake desolation', 'Skeleton Shaft', lambda state: flooded.flood_lake_desolation or logic.has_doublejump(state))
|
||||
connect(multiworld, player, 'Lake desolation', 'Space time continuum', logic.has_teleport)
|
||||
connect(multiworld, player, 'Upper lake desolation', 'Lake desolation')
|
||||
connect(multiworld, player, 'Upper lake desolation', 'Eastern lake desolation')
|
||||
connect(multiworld, player, 'Lower lake desolation', 'Lake desolation')
|
||||
connect(multiworld, player, 'Lower lake desolation', 'Eastern lake desolation')
|
||||
connect(multiworld, player, 'Eastern lake desolation', 'Space time continuum', logic.has_teleport)
|
||||
connect(multiworld, player, 'Eastern lake desolation', 'Library')
|
||||
connect(multiworld, player, 'Eastern lake desolation', 'Lower lake desolation')
|
||||
connect(multiworld, player, 'Eastern lake desolation', 'Upper lake desolation', lambda state: logic.has_fire(state) and state.can_reach('Upper Lake Serene', 'Region', player), "Upper Lake Serene")
|
||||
connect(multiworld, player, 'Library', 'Eastern lake desolation')
|
||||
connect(multiworld, player, 'Library', 'Library top', lambda state: logic.has_doublejump(state) or state.has('Talaria Attachment', player))
|
||||
connect(multiworld, player, 'Library', 'Varndagroth tower left', logic.has_keycard_D)
|
||||
connect(multiworld, player, 'Library', 'Space time continuum', logic.has_teleport)
|
||||
connect(multiworld, player, 'Library top', 'Library')
|
||||
connect(multiworld, player, 'Varndagroth tower left', 'Library')
|
||||
connect(multiworld, player, 'Varndagroth tower left', 'Varndagroth tower right (upper)', logic.has_keycard_C)
|
||||
connect(multiworld, player, 'Varndagroth tower left', 'Varndagroth tower right (lower)', logic.has_keycard_B)
|
||||
connect(multiworld, player, 'Varndagroth tower left', 'Sealed Caves (Sirens)', lambda state: logic.has_keycard_B(state) and state.has('Elevator Keycard', player))
|
||||
connect(multiworld, player, 'Varndagroth tower left', 'Refugee Camp', lambda state: state.has('Timespinner Wheel', player) and state.has('Timespinner Spindle', player))
|
||||
connect(multiworld, player, 'Varndagroth tower right (upper)', 'Varndagroth tower left')
|
||||
connect(multiworld, player, 'Varndagroth tower right (upper)', 'Varndagroth tower right (elevator)', lambda state: state.has('Elevator Keycard', player))
|
||||
connect(multiworld, player, 'Varndagroth tower right (elevator)', 'Varndagroth tower right (upper)')
|
||||
connect(multiworld, player, 'Varndagroth tower right (elevator)', 'Varndagroth tower right (lower)')
|
||||
connect(multiworld, player, 'Varndagroth tower right (lower)', 'Varndagroth tower left', logic.has_keycard_B)
|
||||
connect(multiworld, player, 'Varndagroth tower right (lower)', 'Varndagroth tower right (elevator)', lambda state: state.has('Elevator Keycard', player))
|
||||
connect(multiworld, player, 'Varndagroth tower right (lower)', 'Sealed Caves (Sirens)', lambda state: logic.has_keycard_B(state) and state.has('Elevator Keycard', player))
|
||||
connect(multiworld, player, 'Varndagroth tower right (lower)', 'Military Fortress', logic.can_kill_all_3_bosses)
|
||||
connect(multiworld, player, 'Varndagroth tower right (lower)', 'Space time continuum', logic.has_teleport)
|
||||
connect(multiworld, player, 'Sealed Caves (Sirens)', 'Varndagroth tower left', lambda state: state.has('Elevator Keycard', player))
|
||||
connect(multiworld, player, 'Sealed Caves (Sirens)', 'Varndagroth tower right (lower)', lambda state: state.has('Elevator Keycard', player))
|
||||
connect(multiworld, player, 'Sealed Caves (Sirens)', 'Space time continuum', logic.has_teleport)
|
||||
connect(multiworld, player, 'Military Fortress', 'Varndagroth tower right (lower)', logic.can_kill_all_3_bosses)
|
||||
connect(multiworld, player, 'Military Fortress', 'Temporal Gyre', lambda state: state.has('Timespinner Wheel', player) and logic.can_kill_all_3_bosses(state))
|
||||
connect(multiworld, player, 'Military Fortress', 'Military Fortress (hangar)', logic.has_doublejump)
|
||||
connect(multiworld, player, 'Military Fortress (hangar)', 'Military Fortress')
|
||||
connect(multiworld, player, 'Military Fortress (hangar)', 'Lab Entrance', lambda state: state.has('Water Mask', player) if flooded.flood_lab else logic.has_doublejump(state))
|
||||
connect(multiworld, player, 'Lab Entrance', 'Main Lab', lambda state: logic.has_keycard_B(state))
|
||||
connect(multiworld, player, 'Main Lab', 'Lab Entrance')
|
||||
connect(multiworld, player, 'Lab Entrance', 'Military Fortress (hangar)')
|
||||
connect(multiworld, player, 'Temporal Gyre', 'Military Fortress')
|
||||
connect(multiworld, player, 'Main Lab', 'Lab Research', lambda state: state.has('Lab Access Research', player) if options.lock_key_amadeus else logic.has_doublejump_of_npc(state))
|
||||
connect(multiworld, player, 'Main Lab', 'The lab (upper)', lambda state: logic.has_forwarddash_doublejump(state) and ((not options.lock_key_amadeus) or state.has('Lab Access Genza', player)))
|
||||
connect(multiworld, player, 'The lab (upper)', 'Main Lab', lambda state: options.lock_key_amadeus and state.has('Lab Access Genza', player))
|
||||
connect(multiworld, player, 'The lab (upper)', 'Emperors tower (courtyard)', logic.has_forwarddash_doublejump)
|
||||
connect(multiworld, player, 'The lab (upper)', 'Ancient Pyramid (entrance)', lambda state: state.has_all({'Timespinner Wheel', 'Timespinner Spindle', 'Timespinner Gear 1', 'Timespinner Gear 2', 'Timespinner Gear 3'}, player))
|
||||
connect(multiworld, player, 'Emperors tower (courtyard)', 'The lab (upper)')
|
||||
connect(multiworld, player, 'Emperors tower (courtyard)', 'Emperors tower', logic.has_doublejump)
|
||||
connect(multiworld, player, 'Emperors tower', 'Emperors tower (courtyard)')
|
||||
connect(multiworld, player, 'Skeleton Shaft', 'Lake desolation')
|
||||
connect(multiworld, player, 'Skeleton Shaft', 'Sealed Caves (Xarion)', logic.has_keycard_A)
|
||||
connect(multiworld, player, 'Skeleton Shaft', 'Space time continuum', logic.has_teleport)
|
||||
connect(multiworld, player, 'Sealed Caves (Xarion)', 'Skeleton Shaft')
|
||||
connect(multiworld, player, 'Sealed Caves (Xarion)', 'Space time continuum', logic.has_teleport)
|
||||
connect(multiworld, player, 'Refugee Camp', 'Forest')
|
||||
connect(multiworld, player, 'Refugee Camp', 'Library', lambda state: (options.pyramid_start or options.inverted) and options.back_to_the_future and state.has_all({'Timespinner Wheel', 'Timespinner Spindle'}, player))
|
||||
connect(multiworld, player, 'Refugee Camp', 'Space time continuum', logic.has_teleport)
|
||||
connect(multiworld, player, 'Forest', 'Refugee Camp')
|
||||
connect(multiworld, player, 'Forest', 'Left Side forest Caves', lambda state: flooded.flood_lake_serene_bridge or state.has('Talaria Attachment', player) or logic.has_timestop(state))
|
||||
connect(multiworld, player, 'Forest', 'Caves of Banishment (Sirens)')
|
||||
connect(multiworld, player, 'Forest', 'Castle Ramparts', lambda state: not options.gate_keep or state.has('Drawbridge Key', player) or logic.has_upwarddash(state))
|
||||
connect(multiworld, player, 'Left Side forest Caves', 'Forest')
|
||||
connect(multiworld, player, 'Left Side forest Caves', 'Upper Lake Serene', logic.has_timestop)
|
||||
connect(multiworld, player, 'Left Side forest Caves', 'Lower Lake Serene', lambda state: not flooded.flood_lake_serene or state.has('Water Mask', player))
|
||||
connect(multiworld, player, 'Left Side forest Caves', 'Space time continuum', logic.has_teleport)
|
||||
connect(multiworld, player, 'Upper Lake Serene', 'Left Side forest Caves')
|
||||
connect(multiworld, player, 'Upper Lake Serene', 'Lower Lake Serene', lambda state: not flooded.flood_lake_serene or state.has('Water Mask', player))
|
||||
connect(multiworld, player, 'Lower Lake Serene', 'Upper Lake Serene')
|
||||
connect(multiworld, player, 'Lower Lake Serene', 'Left Side forest Caves')
|
||||
connect(multiworld, player, 'Lower Lake Serene', 'Caves of Banishment (upper)', lambda state: flooded.flood_lake_serene or logic.has_doublejump(state))
|
||||
connect(multiworld, player, 'Caves of Banishment (upper)', 'Lower Lake Serene', lambda state: not flooded.flood_lake_serene or state.has('Water Mask', player))
|
||||
connect(multiworld, player, 'Caves of Banishment (upper)', 'Caves of Banishment (Maw)', lambda state: not flooded.flood_maw or state.has('Water Mask', player))
|
||||
connect(multiworld, player, 'Caves of Banishment (upper)', 'Space time continuum', logic.has_teleport)
|
||||
connect(multiworld, player, 'Caves of Banishment (Maw)', 'Caves of Banishment (upper)', lambda state: logic.has_doublejump(state) if not flooded.flood_maw else state.has('Water Mask', player))
|
||||
connect(multiworld, player, 'Caves of Banishment (Maw)', 'Caves of Banishment (Sirens)', lambda state: state.has_any({'Gas Mask', 'Talaria Attachment'}, player) )
|
||||
connect(multiworld, player, 'Caves of Banishment (Maw)', 'Caves of Banishment (Flooded)', lambda state: flooded.flood_maw or state.has('Water Mask', player))
|
||||
connect(multiworld, player, 'Caves of Banishment (Maw)', 'Space time continuum', logic.has_teleport)
|
||||
connect(multiworld, player, 'Caves of Banishment (Sirens)', 'Forest')
|
||||
connect(multiworld, player, 'Castle Ramparts', 'Forest')
|
||||
connect(multiworld, player, 'Castle Ramparts', 'Castle Keep')
|
||||
connect(multiworld, player, 'Castle Ramparts', 'Space time continuum', logic.has_teleport)
|
||||
connect(multiworld, player, 'Castle Keep', 'Castle Ramparts')
|
||||
connect(multiworld, player, 'Castle Keep', 'Castle Basement', lambda state: not flooded.flood_basement or state.has('Water Mask', player))
|
||||
connect(multiworld, player, 'Castle Keep', 'Royal towers (lower)', lambda state: logic.has_doublejump(state) and (not options.royal_roadblock or logic.has_pink(state)))
|
||||
connect(multiworld, player, 'Castle Keep', 'Space time continuum', logic.has_teleport)
|
||||
connect(multiworld, player, 'Royal towers (lower)', 'Castle Keep')
|
||||
connect(multiworld, player, 'Royal towers (lower)', 'Royal towers', lambda state: state.has('Timespinner Wheel', player) or logic.has_forwarddash_doublejump(state))
|
||||
connect(multiworld, player, 'Royal towers (lower)', 'Space time continuum', logic.has_teleport)
|
||||
connect(multiworld, player, 'Royal towers', 'Royal towers (lower)')
|
||||
connect(multiworld, player, 'Royal towers', 'Royal towers (upper)', logic.has_doublejump)
|
||||
connect(multiworld, player, 'Royal towers (upper)', 'Royal towers')
|
||||
#connect(multiworld, player, 'Ancient Pyramid (entrance)', 'The lab (upper)', lambda state: not is_option_enabled(multiworld, player, "EnterSandman"))
|
||||
connect(multiworld, player, 'Ancient Pyramid (entrance)', 'Ancient Pyramid (left)', logic.has_doublejump)
|
||||
connect(multiworld, player, 'Ancient Pyramid (entrance)', 'Space time continuum', logic.has_teleport)
|
||||
connect(multiworld, player, 'Ancient Pyramid (left)', 'Ancient Pyramid (entrance)')
|
||||
connect(multiworld, player, 'Ancient Pyramid (left)', 'Ancient Pyramid (right)', lambda state: flooded.flood_pyramid_shaft or logic.has_upwarddash(state))
|
||||
connect(multiworld, player, 'Ancient Pyramid (left)', 'Space time continuum', logic.has_teleport)
|
||||
connect(multiworld, player, 'Ancient Pyramid (right)', 'Ancient Pyramid (left)', lambda state: flooded.flood_pyramid_shaft or logic.has_upwarddash(state))
|
||||
connect(multiworld, player, 'Ancient Pyramid (right)', 'Space time continuum', logic.has_teleport)
|
||||
connect(multiworld, player, 'Space time continuum', 'Lake desolation', lambda state: logic.can_teleport_to(state, "Present", "GateLakeDesolation"))
|
||||
connect(multiworld, player, 'Space time continuum', 'Lower lake desolation', lambda state: logic.can_teleport_to(state, "Present", "GateKittyBoss"))
|
||||
connect(multiworld, player, 'Space time continuum', 'Library', lambda state: logic.can_teleport_to(state, "Present", "GateLeftLibrary"))
|
||||
connect(multiworld, player, 'Space time continuum', 'Varndagroth tower right (lower)', lambda state: logic.can_teleport_to(state, "Present", "GateMilitaryGate"))
|
||||
connect(multiworld, player, 'Space time continuum', 'Skeleton Shaft', lambda state: logic.can_teleport_to(state, "Present", "GateSealedCaves"))
|
||||
connect(multiworld, player, 'Space time continuum', 'Sealed Caves (Sirens)', lambda state: logic.can_teleport_to(state, "Present", "GateSealedSirensCave"))
|
||||
connect(multiworld, player, 'Space time continuum', 'Sealed Caves (Xarion)', lambda state: logic.can_teleport_to(state, "Present", "GateXarion"))
|
||||
connect(multiworld, player, 'Space time continuum', 'Upper Lake Serene', lambda state: logic.can_teleport_to(state, "Past", "GateLakeSereneLeft"))
|
||||
connect(multiworld, player, 'Space time continuum', 'Left Side forest Caves', lambda state: logic.can_teleport_to(state, "Past", "GateLakeSereneRight"))
|
||||
connect(multiworld, player, 'Space time continuum', 'Refugee Camp', lambda state: logic.can_teleport_to(state, "Past", "GateAccessToPast"))
|
||||
connect(multiworld, player, 'Space time continuum', 'Forest', lambda state: logic.can_teleport_to(state, "Past", "GateCastleRamparts"))
|
||||
connect(multiworld, player, 'Space time continuum', 'Castle Keep', lambda state: logic.can_teleport_to(state, "Past", "GateCastleKeep"))
|
||||
connect(multiworld, player, 'Space time continuum', 'Royal towers (lower)', lambda state: logic.can_teleport_to(state, "Past", "GateRoyalTowers"))
|
||||
connect(multiworld, player, 'Space time continuum', 'Caves of Banishment (Maw)', lambda state: logic.can_teleport_to(state, "Past", "GateMaw"))
|
||||
connect(multiworld, player, 'Space time continuum', 'Caves of Banishment (upper)', lambda state: logic.can_teleport_to(state, "Past", "GateCavesOfBanishment"))
|
||||
connect(multiworld, player, 'Space time continuum', 'Military Fortress (hangar)', lambda state: logic.can_teleport_to(state, "Present", "GateLabEntrance"))
|
||||
connect(multiworld, player, 'Space time continuum', 'The lab (upper)', lambda state: logic.can_teleport_to(state, "Present", "GateDadsTower"))
|
||||
connect(multiworld, player, 'Space time continuum', 'Ancient Pyramid (entrance)', lambda state: logic.can_teleport_to(state, "Time", "GateGyre") or logic.can_teleport_to(state, "Time", "GateLeftPyramid") or (not options.unchained_keys and options.enter_sandman))
|
||||
connect(multiworld, player, 'Space time continuum', 'Ancient Pyramid (right)', lambda state: logic.can_teleport_to(state, "Time", "GateRightPyramid"))
|
||||
|
||||
if options.gyre_archives:
|
||||
connect(world, player, 'The lab (upper)', 'Ravenlord\'s Lair', lambda state: state.has('Merchant Crow', player))
|
||||
connect(world, player, 'Ravenlord\'s Lair', 'The lab (upper)')
|
||||
connect(world, player, 'Library top', 'Ifrit\'s Lair', lambda state: state.has('Kobo', player) and state.can_reach('Refugee Camp', 'Region', player), "Refugee Camp")
|
||||
connect(world, player, 'Ifrit\'s Lair', 'Library top')
|
||||
connect(multiworld, player, 'The lab (upper)', 'Ravenlord\'s Lair', lambda state: state.has('Merchant Crow', player))
|
||||
connect(multiworld, player, 'Ravenlord\'s Lair', 'The lab (upper)')
|
||||
connect(multiworld, player, 'Library top', 'Ifrit\'s Lair', lambda state: state.has('Kobo', player) and state.can_reach('Refugee Camp', 'Region', player), "Refugee Camp")
|
||||
connect(multiworld, player, 'Ifrit\'s Lair', 'Library top')
|
||||
|
||||
|
||||
def throwIfAnyLocationIsNotAssignedToARegion(regions: List[Region], regionNames: Set[str]):
|
||||
@@ -223,8 +223,8 @@ def create_location(player: int, location_data: LocationData, region: Region) ->
|
||||
return location
|
||||
|
||||
|
||||
def create_region(world: MultiWorld, player: int, locations_per_region: Dict[str, List[LocationData]], name: str) -> Region:
|
||||
region = Region(name, player, world)
|
||||
def create_region(multiworld: MultiWorld, player: int, locations_per_region: Dict[str, List[LocationData]], name: str) -> Region:
|
||||
region = Region(name, player, multiworld)
|
||||
|
||||
if name in locations_per_region:
|
||||
for location_data in locations_per_region[name]:
|
||||
@@ -233,17 +233,17 @@ def create_region(world: MultiWorld, player: int, locations_per_region: Dict[str
|
||||
return region
|
||||
|
||||
|
||||
def connectStartingRegion(world: MultiWorld, player: int, options: TimespinnerOptions):
|
||||
menu = world.get_region('Menu', player)
|
||||
tutorial = world.get_region('Tutorial', player)
|
||||
space_time_continuum = world.get_region('Space time continuum', player)
|
||||
def connectStartingRegion(multiworld: MultiWorld, player: int, options: TimespinnerOptions):
|
||||
menu = multiworld.get_region('Menu', player)
|
||||
tutorial = multiworld.get_region('Tutorial', player)
|
||||
space_time_continuum = multiworld.get_region('Space time continuum', player)
|
||||
|
||||
if options.pyramid_start:
|
||||
starting_region = world.get_region('Ancient Pyramid (entrance)', player)
|
||||
starting_region = multiworld.get_region('Ancient Pyramid (entrance)', player)
|
||||
elif options.inverted:
|
||||
starting_region = world.get_region('Refugee Camp', player)
|
||||
starting_region = multiworld.get_region('Refugee Camp', player)
|
||||
else:
|
||||
starting_region = world.get_region('Lake desolation', player)
|
||||
starting_region = multiworld.get_region('Lake desolation', player)
|
||||
|
||||
menu_to_tutorial = Entrance(player, 'Tutorial', menu)
|
||||
menu_to_tutorial.connect(tutorial)
|
||||
@@ -256,20 +256,20 @@ def connectStartingRegion(world: MultiWorld, player: int, options: TimespinnerOp
|
||||
space_time_continuum.exits.append(teleport_back_to_start)
|
||||
|
||||
|
||||
def connect(world: MultiWorld, player: int, source: str, target: str,
|
||||
def connect(multiworld: MultiWorld, player: int, source: str, target: str,
|
||||
rule: Optional[Callable[[CollectionState], bool]] = None,
|
||||
indirect: str = ""):
|
||||
|
||||
sourceRegion = world.get_region(source, player)
|
||||
targetRegion = world.get_region(target, player)
|
||||
sourceRegion = multiworld.get_region(source, player)
|
||||
targetRegion = multiworld.get_region(target, player)
|
||||
entrance = sourceRegion.connect(targetRegion, rule=rule)
|
||||
|
||||
if indirect:
|
||||
indirectRegion = world.get_region(indirect, player)
|
||||
if indirectRegion in world.indirect_connections:
|
||||
world.indirect_connections[indirectRegion].add(entrance)
|
||||
indirectRegion = multiworld.get_region(indirect, player)
|
||||
if indirectRegion in multiworld.indirect_connections:
|
||||
multiworld.indirect_connections[indirectRegion].add(entrance)
|
||||
else:
|
||||
world.indirect_connections[indirectRegion] = {entrance}
|
||||
multiworld.indirect_connections[indirectRegion] = {entrance}
|
||||
|
||||
|
||||
def split_location_datas_per_region(locations: List[LocationData]) -> Dict[str, List[LocationData]]:
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from BaseClasses import MultiWorld
|
||||
|
||||
|
||||
def link_undertale_areas(world: MultiWorld, player: int):
|
||||
def link_undertale_areas(multiworld: MultiWorld, player: int):
|
||||
for (exit, region) in mandatory_connections:
|
||||
world.get_entrance(exit, player).connect(world.get_region(region, player))
|
||||
multiworld.get_entrance(exit, player).connect(multiworld.get_region(region, player))
|
||||
|
||||
|
||||
# (Region name, list of exits)
|
||||
|
||||
+11
-11
@@ -5,29 +5,29 @@ from .Locations import V6Location, location_table
|
||||
v6areas = ["Laboratory", "The Tower", "Space Station 2", "Warp Zone"]
|
||||
|
||||
|
||||
def create_regions(world: MultiWorld, player: int):
|
||||
regOvr = Region("Menu", player, world, "Dimension VVVVVV")
|
||||
def create_regions(multiworld: MultiWorld, player: int):
|
||||
regOvr = Region("Menu", player, multiworld, "Dimension VVVVVV")
|
||||
locOvr_names = ["Overworld (Pipe-shaped Segment)", "Overworld (Left of Ship)", "Overworld (Square Room)", "Overworld (Sad Elephant)",
|
||||
"It's a Secret to Nobody", "Trench Warfare", "NPC Trinket", "V"]
|
||||
regOvr.locations += [V6Location(player, loc_name, location_table[loc_name], regOvr) for loc_name in locOvr_names]
|
||||
world.regions.append(regOvr)
|
||||
multiworld.regions.append(regOvr)
|
||||
|
||||
regLab = Region("Laboratory", player, world)
|
||||
regLab = Region("Laboratory", player, multiworld)
|
||||
locLab_names = ["Young Man, It's Worth the Challenge", "Overworld (Outside Entanglement Generator)", "The Tantalizing Trinket", "Purest Unobtainium"]
|
||||
regLab.locations += [V6Location(player, loc_name, location_table[loc_name], regLab) for loc_name in locLab_names]
|
||||
world.regions.append(regLab)
|
||||
multiworld.regions.append(regLab)
|
||||
|
||||
regTow = Region("The Tower", player, world)
|
||||
regTow = Region("The Tower", player, multiworld)
|
||||
locTow_names = ["The Tower 1", "The Tower 2"]
|
||||
regTow.locations += [V6Location(player, loc_name, location_table[loc_name], regTow) for loc_name in locTow_names]
|
||||
world.regions.append(regTow)
|
||||
multiworld.regions.append(regTow)
|
||||
|
||||
regSp2 = Region("Space Station 2", player, world)
|
||||
regSp2 = Region("Space Station 2", player, multiworld)
|
||||
locSp2_names = ["One Way Room", "You Just Keep Coming Back", "Clarion Call", "Prize for the Reckless", "Doing things the hard way"]
|
||||
regSp2.locations += [V6Location(player, loc_name, location_table[loc_name], regSp2) for loc_name in locSp2_names]
|
||||
world.regions.append(regSp2)
|
||||
multiworld.regions.append(regSp2)
|
||||
|
||||
regWrp = Region("Warp Zone", player, world)
|
||||
regWrp = Region("Warp Zone", player, multiworld)
|
||||
locWrp_names = ["Edge Games"]
|
||||
regWrp.locations += [V6Location(player, loc_name, location_table[loc_name], regWrp) for loc_name in locWrp_names]
|
||||
world.regions.append(regWrp)
|
||||
multiworld.regions.append(regWrp)
|
||||
|
||||
+65
-65
@@ -16,139 +16,139 @@ class WargrooveLogic(LogicMixin):
|
||||
return self.can_reach(region, 'Region', player) and self.has(item, player)
|
||||
|
||||
|
||||
def set_rules(world: MultiWorld, player: int):
|
||||
def set_rules(multiworld: MultiWorld, player: int):
|
||||
# Final Level
|
||||
set_rule(world.get_location('Wargroove Finale: Victory', player),
|
||||
set_rule(multiworld.get_location('Wargroove Finale: Victory', player),
|
||||
lambda state: state._wargroove_has_item(player, "Final Bridges") and
|
||||
state._wargroove_has_item(player, "Final Walls") and
|
||||
state._wargroove_has_item(player, "Final Sickle"))
|
||||
# Level 1
|
||||
set_rule(world.get_location('Humble Beginnings: Caesar', player), lambda state: True)
|
||||
set_rule(world.get_location('Humble Beginnings: Chest 1', player), lambda state: True)
|
||||
set_rule(world.get_location('Humble Beginnings: Chest 2', player), lambda state: True)
|
||||
set_rule(world.get_location('Humble Beginnings: Victory', player), lambda state: True)
|
||||
set_region_exit_rules(world.get_region('Humble Beginnings', player),
|
||||
[world.get_location('Humble Beginnings: Victory', player)])
|
||||
set_rule(multiworld.get_location('Humble Beginnings: Caesar', player), lambda state: True)
|
||||
set_rule(multiworld.get_location('Humble Beginnings: Chest 1', player), lambda state: True)
|
||||
set_rule(multiworld.get_location('Humble Beginnings: Chest 2', player), lambda state: True)
|
||||
set_rule(multiworld.get_location('Humble Beginnings: Victory', player), lambda state: True)
|
||||
set_region_exit_rules(multiworld.get_region('Humble Beginnings', player),
|
||||
[multiworld.get_location('Humble Beginnings: Victory', player)])
|
||||
|
||||
# Levels 2A-2C
|
||||
set_rule(world.get_location('Best Friendssss: Find Sedge', player), lambda state: True)
|
||||
set_rule(world.get_location('Best Friendssss: Victory', player), lambda state: True)
|
||||
set_region_exit_rules(world.get_region('Best Friendssss', player),
|
||||
[world.get_location('Best Friendssss: Victory', player)])
|
||||
set_rule(multiworld.get_location('Best Friendssss: Find Sedge', player), lambda state: True)
|
||||
set_rule(multiworld.get_location('Best Friendssss: Victory', player), lambda state: True)
|
||||
set_region_exit_rules(multiworld.get_region('Best Friendssss', player),
|
||||
[multiworld.get_location('Best Friendssss: Victory', player)])
|
||||
|
||||
set_rule(world.get_location('A Knight\'s Folly: Caesar', player), lambda state: True)
|
||||
set_rule(world.get_location('A Knight\'s Folly: Victory', player), lambda state: True)
|
||||
set_region_exit_rules(world.get_region('A Knight\'s Folly', player),
|
||||
[world.get_location('A Knight\'s Folly: Victory', player)])
|
||||
set_rule(multiworld.get_location('A Knight\'s Folly: Caesar', player), lambda state: True)
|
||||
set_rule(multiworld.get_location('A Knight\'s Folly: Victory', player), lambda state: True)
|
||||
set_region_exit_rules(multiworld.get_region('A Knight\'s Folly', player),
|
||||
[multiworld.get_location('A Knight\'s Folly: Victory', player)])
|
||||
|
||||
set_rule(world.get_location('Denrunaway: Chest', player), lambda state: True)
|
||||
set_rule(world.get_location('Denrunaway: Victory', player), lambda state: True)
|
||||
set_region_exit_rules(world.get_region('Denrunaway', player), [world.get_location('Denrunaway: Victory', player)])
|
||||
set_rule(multiworld.get_location('Denrunaway: Chest', player), lambda state: True)
|
||||
set_rule(multiworld.get_location('Denrunaway: Victory', player), lambda state: True)
|
||||
set_region_exit_rules(multiworld.get_region('Denrunaway', player), [multiworld.get_location('Denrunaway: Victory', player)])
|
||||
|
||||
# Levels 3AA-3AC
|
||||
set_rule(world.get_location('Dragon Freeway: Victory', player),
|
||||
set_rule(multiworld.get_location('Dragon Freeway: Victory', player),
|
||||
lambda state: state._wargroove_has_item(player, 'Mage'))
|
||||
set_region_exit_rules(world.get_region('Dragon Freeway', player),
|
||||
[world.get_location('Dragon Freeway: Victory', player)])
|
||||
set_region_exit_rules(multiworld.get_region('Dragon Freeway', player),
|
||||
[multiworld.get_location('Dragon Freeway: Victory', player)])
|
||||
|
||||
set_rule(world.get_location('Deep Thicket: Find Sedge', player),
|
||||
set_rule(multiworld.get_location('Deep Thicket: Find Sedge', player),
|
||||
lambda state: state._wargroove_has_item(player, 'Mage'))
|
||||
set_rule(world.get_location('Deep Thicket: Victory', player),
|
||||
set_rule(multiworld.get_location('Deep Thicket: Victory', player),
|
||||
lambda state: state._wargroove_has_item(player, 'Mage'))
|
||||
set_region_exit_rules(world.get_region('Deep Thicket', player),
|
||||
[world.get_location('Deep Thicket: Victory', player)])
|
||||
set_region_exit_rules(multiworld.get_region('Deep Thicket', player),
|
||||
[multiworld.get_location('Deep Thicket: Victory', player)])
|
||||
|
||||
set_rule(world.get_location('Corrupted Inlet: Victory', player),
|
||||
set_rule(multiworld.get_location('Corrupted Inlet: Victory', player),
|
||||
lambda state: state._wargroove_has_item(player, 'Barge') or
|
||||
state._wargroove_has_item(player, 'Merfolk') or
|
||||
state._wargroove_has_item(player, 'Warship'))
|
||||
set_region_exit_rules(world.get_region('Corrupted Inlet', player),
|
||||
[world.get_location('Corrupted Inlet: Victory', player)])
|
||||
set_region_exit_rules(multiworld.get_region('Corrupted Inlet', player),
|
||||
[multiworld.get_location('Corrupted Inlet: Victory', player)])
|
||||
|
||||
# Levels 3BA-3BC
|
||||
set_rule(world.get_location('Mage Mayhem: Caesar', player),
|
||||
set_rule(multiworld.get_location('Mage Mayhem: Caesar', player),
|
||||
lambda state: state._wargroove_has_item(player, 'Harpy') or state._wargroove_has_item(player, 'Dragon'))
|
||||
set_rule(world.get_location('Mage Mayhem: Victory', player),
|
||||
set_rule(multiworld.get_location('Mage Mayhem: Victory', player),
|
||||
lambda state: state._wargroove_has_item(player, 'Harpy') or state._wargroove_has_item(player, 'Dragon'))
|
||||
set_region_exit_rules(world.get_region('Mage Mayhem', player), [world.get_location('Mage Mayhem: Victory', player)])
|
||||
set_region_exit_rules(multiworld.get_region('Mage Mayhem', player), [multiworld.get_location('Mage Mayhem: Victory', player)])
|
||||
|
||||
set_rule(world.get_location('Endless Knight: Victory', player),
|
||||
set_rule(multiworld.get_location('Endless Knight: Victory', player),
|
||||
lambda state: state._wargroove_has_item(player, 'Eastern Bridges') and (
|
||||
state._wargroove_has_item(player, 'Spearman') or
|
||||
state._wargroove_has_item(player, 'Harpy') or
|
||||
state._wargroove_has_item(player, 'Dragon')))
|
||||
set_region_exit_rules(world.get_region('Endless Knight', player),
|
||||
[world.get_location('Endless Knight: Victory', player)])
|
||||
set_region_exit_rules(multiworld.get_region('Endless Knight', player),
|
||||
[multiworld.get_location('Endless Knight: Victory', player)])
|
||||
|
||||
set_rule(world.get_location('Ambushed in the Middle: Victory (Blue)', player),
|
||||
set_rule(multiworld.get_location('Ambushed in the Middle: Victory (Blue)', player),
|
||||
lambda state: state._wargroove_has_item(player, 'Spearman'))
|
||||
set_rule(world.get_location('Ambushed in the Middle: Victory (Green)', player),
|
||||
set_rule(multiworld.get_location('Ambushed in the Middle: Victory (Green)', player),
|
||||
lambda state: state._wargroove_has_item(player, 'Spearman'))
|
||||
set_region_exit_rules(world.get_region('Ambushed in the Middle', player),
|
||||
[world.get_location('Ambushed in the Middle: Victory (Blue)', player),
|
||||
world.get_location('Ambushed in the Middle: Victory (Green)', player)])
|
||||
set_region_exit_rules(multiworld.get_region('Ambushed in the Middle', player),
|
||||
[multiworld.get_location('Ambushed in the Middle: Victory (Blue)', player),
|
||||
multiworld.get_location('Ambushed in the Middle: Victory (Green)', player)])
|
||||
|
||||
# Levels 3CA-3CC
|
||||
set_rule(world.get_location('The Churning Sea: Victory', player),
|
||||
set_rule(multiworld.get_location('The Churning Sea: Victory', player),
|
||||
lambda state: (state._wargroove_has_item(player, 'Merfolk') or state._wargroove_has_item(player, 'Turtle'))
|
||||
and state._wargroove_has_item(player, 'Harpoon Ship'))
|
||||
set_region_exit_rules(world.get_region('The Churning Sea', player),
|
||||
[world.get_location('The Churning Sea: Victory', player)])
|
||||
set_region_exit_rules(multiworld.get_region('The Churning Sea', player),
|
||||
[multiworld.get_location('The Churning Sea: Victory', player)])
|
||||
|
||||
set_rule(world.get_location('Frigid Archery: Light the Torch', player),
|
||||
set_rule(multiworld.get_location('Frigid Archery: Light the Torch', player),
|
||||
lambda state: state._wargroove_has_item(player, 'Archer') and
|
||||
state._wargroove_has_item(player, 'Southern Walls'))
|
||||
set_rule(world.get_location('Frigid Archery: Victory', player),
|
||||
set_rule(multiworld.get_location('Frigid Archery: Victory', player),
|
||||
lambda state: state._wargroove_has_item(player, 'Archer'))
|
||||
set_region_exit_rules(world.get_region('Frigid Archery', player),
|
||||
[world.get_location('Frigid Archery: Victory', player)])
|
||||
set_region_exit_rules(multiworld.get_region('Frigid Archery', player),
|
||||
[multiworld.get_location('Frigid Archery: Victory', player)])
|
||||
|
||||
set_rule(world.get_location('Archery Lessons: Chest', player),
|
||||
set_rule(multiworld.get_location('Archery Lessons: Chest', player),
|
||||
lambda state: state._wargroove_has_item(player, 'Knight') and
|
||||
state._wargroove_has_item(player, 'Southern Walls'))
|
||||
set_rule(world.get_location('Archery Lessons: Victory', player),
|
||||
set_rule(multiworld.get_location('Archery Lessons: Victory', player),
|
||||
lambda state: state._wargroove_has_item(player, 'Knight') and
|
||||
state._wargroove_has_item(player, 'Southern Walls'))
|
||||
set_region_exit_rules(world.get_region('Archery Lessons', player),
|
||||
[world.get_location('Archery Lessons: Victory', player)])
|
||||
set_region_exit_rules(multiworld.get_region('Archery Lessons', player),
|
||||
[multiworld.get_location('Archery Lessons: Victory', player)])
|
||||
|
||||
# Levels 4AA-4AC
|
||||
set_rule(world.get_location('Surrounded: Caesar', player),
|
||||
set_rule(multiworld.get_location('Surrounded: Caesar', player),
|
||||
lambda state: state._wargroove_has_item_and_region(player, 'Knight', 'Surrounded'))
|
||||
set_rule(world.get_location('Surrounded: Victory', player),
|
||||
set_rule(multiworld.get_location('Surrounded: Victory', player),
|
||||
lambda state: state._wargroove_has_item_and_region(player, 'Knight', 'Surrounded'))
|
||||
set_rule(world.get_location('Darkest Knight: Victory', player),
|
||||
set_rule(multiworld.get_location('Darkest Knight: Victory', player),
|
||||
lambda state: state._wargroove_has_item_and_region(player, 'Spearman', 'Darkest Knight'))
|
||||
set_rule(world.get_location('Robbed: Victory', player),
|
||||
set_rule(multiworld.get_location('Robbed: Victory', player),
|
||||
lambda state: state._wargroove_has_item_and_region(player, 'Thief', 'Robbed') and
|
||||
state._wargroove_has_item(player, 'Rifleman'))
|
||||
|
||||
# Levels 4BA-4BC
|
||||
set_rule(world.get_location('Open Season: Caesar', player),
|
||||
set_rule(multiworld.get_location('Open Season: Caesar', player),
|
||||
lambda state: state._wargroove_has_item_and_region(player, 'Mage', 'Open Season') and
|
||||
state._wargroove_has_item(player, 'Knight'))
|
||||
set_rule(world.get_location('Open Season: Victory', player),
|
||||
set_rule(multiworld.get_location('Open Season: Victory', player),
|
||||
lambda state: state._wargroove_has_item_and_region(player, 'Mage', 'Open Season') and
|
||||
state._wargroove_has_item(player, 'Knight'))
|
||||
set_rule(world.get_location('Doggo Mountain: Find all the Dogs', player),
|
||||
set_rule(multiworld.get_location('Doggo Mountain: Find all the Dogs', player),
|
||||
lambda state: state._wargroove_has_item_and_region(player, 'Knight', 'Doggo Mountain'))
|
||||
set_rule(world.get_location('Doggo Mountain: Victory', player),
|
||||
set_rule(multiworld.get_location('Doggo Mountain: Victory', player),
|
||||
lambda state: state._wargroove_has_item_and_region(player, 'Knight', 'Doggo Mountain'))
|
||||
set_rule(world.get_location('Tenri\'s Fall: Victory', player),
|
||||
set_rule(multiworld.get_location('Tenri\'s Fall: Victory', player),
|
||||
lambda state: state._wargroove_has_item_and_region(player, 'Mage', 'Tenri\'s Fall') and
|
||||
state._wargroove_has_item(player, 'Thief'))
|
||||
set_rule(world.get_location('Foolish Canal: Victory', player),
|
||||
set_rule(multiworld.get_location('Foolish Canal: Victory', player),
|
||||
lambda state: state._wargroove_has_item_and_region(player, 'Mage', 'Foolish Canal') and
|
||||
state._wargroove_has_item(player, 'Spearman'))
|
||||
|
||||
# Levels 4CA-4CC
|
||||
set_rule(world.get_location('Master of the Lake: Victory', player),
|
||||
set_rule(multiworld.get_location('Master of the Lake: Victory', player),
|
||||
lambda state: state._wargroove_has_item_and_region(player, 'Warship', 'Master of the Lake'))
|
||||
set_rule(world.get_location('A Ballista\'s Revenge: Victory', player),
|
||||
set_rule(multiworld.get_location('A Ballista\'s Revenge: Victory', player),
|
||||
lambda state: state._wargroove_has_item_and_region(player, 'Ballista', 'A Ballista\'s Revenge'))
|
||||
set_rule(world.get_location('Rebel Village: Victory (Pink)', player),
|
||||
set_rule(multiworld.get_location('Rebel Village: Victory (Pink)', player),
|
||||
lambda state: state._wargroove_has_item_and_region(player, 'Spearman', 'Rebel Village'))
|
||||
set_rule(world.get_location('Rebel Village: Victory (Red)', player),
|
||||
set_rule(multiworld.get_location('Rebel Village: Victory (Red)', player),
|
||||
lambda state: state._wargroove_has_item_and_region(player, 'Spearman', 'Rebel Village'))
|
||||
|
||||
|
||||
|
||||
@@ -143,8 +143,8 @@ class WargrooveWorld(World):
|
||||
return self.multiworld.random.choice(["Commander Defense Boost", "Income Boost"])
|
||||
|
||||
|
||||
def create_region(world: MultiWorld, player: int, name: str, locations=None, exits=None):
|
||||
ret = Region(name, player, world)
|
||||
def create_region(multiworld: MultiWorld, player: int, name: str, locations=None, exits=None):
|
||||
ret = Region(name, player, multiworld)
|
||||
if locations:
|
||||
for location in locations:
|
||||
loc_id = location_table.get(location, 0)
|
||||
|
||||
@@ -218,12 +218,12 @@ def dice_simulation_state_change(state, player, frags_per_dice, frags_per_roll,
|
||||
return state.prog_items[player]["maximum_achievable_score"]
|
||||
|
||||
|
||||
def set_yacht_rules(world: MultiWorld, player: int, frags_per_dice, frags_per_roll, allowed_categories, difficulty):
|
||||
def set_yacht_rules(multiworld: MultiWorld, player: int, frags_per_dice, frags_per_roll, allowed_categories, difficulty):
|
||||
"""
|
||||
Sets rules on reaching scores
|
||||
"""
|
||||
|
||||
for location in world.get_locations(player):
|
||||
for location in multiworld.get_locations(player):
|
||||
set_rule(
|
||||
location,
|
||||
lambda state, curscore=location.yacht_dice_score, player=player: dice_simulation_state_change(
|
||||
@@ -233,8 +233,8 @@ def set_yacht_rules(world: MultiWorld, player: int, frags_per_dice, frags_per_ro
|
||||
)
|
||||
|
||||
|
||||
def set_yacht_completion_rules(world: MultiWorld, player: int):
|
||||
def set_yacht_completion_rules(multiworld: MultiWorld, player: int):
|
||||
"""
|
||||
Sets rules on completion condition
|
||||
"""
|
||||
world.completion_condition[player] = lambda state: state.has("Victory", player)
|
||||
multiworld.completion_condition[player] = lambda state: state.has("Victory", player)
|
||||
|
||||
@@ -341,7 +341,6 @@ class YoshisIslandWorld(World):
|
||||
def generate_output(self, output_directory: str) -> None:
|
||||
rompath = "" # if variable is not declared finally clause may fail
|
||||
try:
|
||||
world = self.multiworld
|
||||
player = self.player
|
||||
rom = LocalRom(get_base_rom_path())
|
||||
patch_rom(self, rom, self.player)
|
||||
@@ -351,7 +350,7 @@ class YoshisIslandWorld(World):
|
||||
self.rom_name = rom.name
|
||||
|
||||
patch = YoshisIslandDeltaPatch(os.path.splitext(rompath)[0] + YoshisIslandDeltaPatch.patch_file_ending,
|
||||
player=player, player_name=world.player_name[player], patched_path=rompath)
|
||||
player=player, player_name=self.player_name, patched_path=rompath)
|
||||
patch.write()
|
||||
finally:
|
||||
self.rom_name_available_event.set()
|
||||
|
||||
@@ -130,8 +130,8 @@ class Yugioh06World(World):
|
||||
campaign_opponents: List[OpponentData]
|
||||
is_draft_mode: bool
|
||||
|
||||
def __init__(self, world: MultiWorld, player: int):
|
||||
super().__init__(world, player)
|
||||
def __init__(self, multiworld: MultiWorld, player: int):
|
||||
super().__init__(multiworld, player)
|
||||
|
||||
def generate_early(self):
|
||||
self.starting_opponent = ""
|
||||
|
||||
@@ -128,8 +128,8 @@ class ZillionWorld(World):
|
||||
"""
|
||||
logic_cache: ZillionLogicCache | None = None
|
||||
|
||||
def __init__(self, world: MultiWorld, player: int) -> None:
|
||||
super().__init__(world, player)
|
||||
def __init__(self, multiworld: MultiWorld, player: int) -> None:
|
||||
super().__init__(multiworld, player)
|
||||
self.logger = logging.getLogger("Zillion")
|
||||
self.lsi = ZillionWorld.LogStreamInterface(self.logger)
|
||||
self.zz_system = System()
|
||||
|
||||
Reference in New Issue
Block a user