Compare commits

..

No commits in common. "04efdf11d70dc7a016815b57e28f8b7ee0ef490f" and "0d9fce29c69caf0eb8e4f4eab1f1961a550c6d0c" have entirely different histories.

22 changed files with 75 additions and 162 deletions

View File

@ -80,7 +80,7 @@ class AdventureContext(CommonContext):
self.local_item_locations = {} self.local_item_locations = {}
self.dragon_speed_info = {} self.dragon_speed_info = {}
options = Utils.get_settings() options = Utils.get_options()
self.display_msgs = options["adventure_options"]["display_msgs"] self.display_msgs = options["adventure_options"]["display_msgs"]
async def server_auth(self, password_requested: bool = False): async def server_auth(self, password_requested: bool = False):
@ -102,7 +102,7 @@ class AdventureContext(CommonContext):
def on_package(self, cmd: str, args: dict): def on_package(self, cmd: str, args: dict):
if cmd == 'Connected': if cmd == 'Connected':
self.locations_array = None self.locations_array = None
if Utils.get_settings()["adventure_options"].get("death_link", False): if Utils.get_options()["adventure_options"].get("death_link", False):
self.set_deathlink = True self.set_deathlink = True
async_start(self.get_freeincarnates_used()) async_start(self.get_freeincarnates_used())
elif cmd == "RoomInfo": elif cmd == "RoomInfo":
@ -415,8 +415,8 @@ async def atari_sync_task(ctx: AdventureContext):
async def run_game(romfile): async def run_game(romfile):
auto_start = Utils.get_settings()["adventure_options"].get("rom_start", True) auto_start = Utils.get_options()["adventure_options"].get("rom_start", True)
rom_args = Utils.get_settings()["adventure_options"].get("rom_args") rom_args = Utils.get_options()["adventure_options"].get("rom_args")
if auto_start is True: if auto_start is True:
import webbrowser import webbrowser
webbrowser.open(romfile) webbrowser.open(romfile)

View File

@ -493,11 +493,6 @@ class CommonContext:
"""Gets called before sending a Say to the server from the user. """Gets called before sending a Say to the server from the user.
Returned text is sent, or sending is aborted if None is returned.""" Returned text is sent, or sending is aborted if None is returned."""
return text return text
def on_ui_command(self, text: str) -> None:
"""Gets called by kivy when the user executes a command starting with `/` or `!`.
The command processor is still called; this is just intended for command echoing."""
self.ui.print_json([{"text": text, "type": "color", "color": "orange"}])
def update_permissions(self, permissions: typing.Dict[str, int]): def update_permissions(self, permissions: typing.Dict[str, int]):
for permission_name, permission_flag in permissions.items(): for permission_name, permission_flag in permissions.items():

View File

@ -1,12 +1,10 @@
from __future__ import annotations from __future__ import annotations
import argparse import argparse
import copy
import logging import logging
import os import os
import random import random
import string import string
import sys
import urllib.parse import urllib.parse
import urllib.request import urllib.request
from collections import Counter from collections import Counter
@ -17,16 +15,21 @@ import ModuleUpdate
ModuleUpdate.update() ModuleUpdate.update()
import copy
import Utils import Utils
import Options import Options
from BaseClasses import seeddigits, get_seed, PlandoOptions from BaseClasses import seeddigits, get_seed, PlandoOptions
from Main import main as ERmain
from settings import get_settings
from Utils import parse_yamls, version_tuple, __version__, tuplize_version from Utils import parse_yamls, version_tuple, __version__, tuplize_version
from worlds.alttp.EntranceRandomizer import parse_arguments
from worlds.AutoWorld import AutoWorldRegister
from worlds import failed_world_loads
def mystery_argparse(): def mystery_argparse():
from settings import get_settings options = get_settings()
settings = get_settings() defaults = options.generator
defaults = settings.generator
parser = argparse.ArgumentParser(description="CMD Generation Interface, defaults come from host.yaml.") parser = argparse.ArgumentParser(description="CMD Generation Interface, defaults come from host.yaml.")
parser.add_argument('--weights_file_path', default=defaults.weights_file_path, parser.add_argument('--weights_file_path', default=defaults.weights_file_path,
@ -38,7 +41,7 @@ def mystery_argparse():
parser.add_argument('--seed', help='Define seed number to generate.', type=int) parser.add_argument('--seed', help='Define seed number to generate.', type=int)
parser.add_argument('--multi', default=defaults.players, type=lambda value: max(int(value), 1)) parser.add_argument('--multi', default=defaults.players, type=lambda value: max(int(value), 1))
parser.add_argument('--spoiler', type=int, default=defaults.spoiler) parser.add_argument('--spoiler', type=int, default=defaults.spoiler)
parser.add_argument('--outputpath', default=settings.general_options.output_path, parser.add_argument('--outputpath', default=options.general_options.output_path,
help="Path to output folder. Absolute or relative to cwd.") # absolute or relative to cwd help="Path to output folder. Absolute or relative to cwd.") # absolute or relative to cwd
parser.add_argument('--race', action='store_true', default=defaults.race) parser.add_argument('--race', action='store_true', default=defaults.race)
parser.add_argument('--meta_file_path', default=defaults.meta_file_path) parser.add_argument('--meta_file_path', default=defaults.meta_file_path)
@ -58,21 +61,20 @@ def mystery_argparse():
if not os.path.isabs(args.meta_file_path): if not os.path.isabs(args.meta_file_path):
args.meta_file_path = os.path.join(args.player_files_path, args.meta_file_path) args.meta_file_path = os.path.join(args.player_files_path, args.meta_file_path)
args.plando: PlandoOptions = PlandoOptions.from_option_string(args.plando) args.plando: PlandoOptions = PlandoOptions.from_option_string(args.plando)
return args return args, options
def get_seed_name(random_source) -> str: def get_seed_name(random_source) -> str:
return f"{random_source.randint(0, pow(10, seeddigits) - 1)}".zfill(seeddigits) return f"{random_source.randint(0, pow(10, seeddigits) - 1)}".zfill(seeddigits)
def main(args=None): def main(args=None, callback=ERmain):
if not args: if not args:
args = mystery_argparse() args, options = mystery_argparse()
else:
options = get_settings()
seed = get_seed(args.seed) seed = get_seed(args.seed)
# __name__ == "__main__" check so unittests that already imported worlds don't trip this.
if __name__ == "__main__" and "worlds" in sys.modules:
raise Exception("Worlds system should not be loaded before logging init.")
Utils.init_logging(f"Generate_{seed}", loglevel=args.log_level) Utils.init_logging(f"Generate_{seed}", loglevel=args.log_level)
random.seed(seed) random.seed(seed)
seed_name = get_seed_name(random) seed_name = get_seed_name(random)
@ -141,9 +143,6 @@ def main(args=None):
raise Exception(f"No weights found. " raise Exception(f"No weights found. "
f"Provide a general weights file ({args.weights_file_path}) or individual player files. " f"Provide a general weights file ({args.weights_file_path}) or individual player files. "
f"A mix is also permitted.") f"A mix is also permitted.")
from worlds.AutoWorld import AutoWorldRegister
from worlds.alttp.EntranceRandomizer import parse_arguments
erargs = parse_arguments(['--multi', str(args.multi)]) erargs = parse_arguments(['--multi', str(args.multi)])
erargs.seed = seed erargs.seed = seed
erargs.plando_options = args.plando erargs.plando_options = args.plando
@ -235,8 +234,7 @@ def main(args=None):
with open(os.path.join(args.outputpath if args.outputpath else ".", f"generate_{seed_name}.yaml"), "wt") as f: with open(os.path.join(args.outputpath if args.outputpath else ".", f"generate_{seed_name}.yaml"), "wt") as f:
yaml.dump(important, f) yaml.dump(important, f)
from Main import main as ERmain return callback(erargs, seed)
return ERmain(erargs, seed)
def read_weights_yamls(path) -> Tuple[Any, ...]: def read_weights_yamls(path) -> Tuple[Any, ...]:
@ -361,8 +359,6 @@ def update_weights(weights: dict, new_weights: dict, update_type: str, name: str
def roll_meta_option(option_key, game: str, category_dict: Dict) -> Any: def roll_meta_option(option_key, game: str, category_dict: Dict) -> Any:
from worlds import AutoWorldRegister
if not game: if not game:
return get_choice(option_key, category_dict) return get_choice(option_key, category_dict)
if game in AutoWorldRegister.world_types: if game in AutoWorldRegister.world_types:
@ -440,13 +436,10 @@ def handle_option(ret: argparse.Namespace, game_weights: dict, option_key: str,
except Exception as e: except Exception as e:
raise Options.OptionError(f"Error generating option {option_key} in {ret.game}") from e raise Options.OptionError(f"Error generating option {option_key} in {ret.game}") from e
else: else:
from worlds import AutoWorldRegister
player_option.verify(AutoWorldRegister.world_types[ret.game], ret.name, plando_options) player_option.verify(AutoWorldRegister.world_types[ret.game], ret.name, plando_options)
def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.bosses): def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.bosses):
from worlds import AutoWorldRegister
if "linked_options" in weights: if "linked_options" in weights:
weights = roll_linked_options(weights) weights = roll_linked_options(weights)
@ -473,7 +466,6 @@ def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.b
ret.game = get_choice("game", weights) ret.game = get_choice("game", weights)
if ret.game not in AutoWorldRegister.world_types: if ret.game not in AutoWorldRegister.world_types:
from worlds import failed_world_loads
picks = Utils.get_fuzzy_results(ret.game, list(AutoWorldRegister.world_types) + failed_world_loads, limit=1)[0] picks = Utils.get_fuzzy_results(ret.game, list(AutoWorldRegister.world_types) + failed_world_loads, limit=1)[0]
if picks[0] in failed_world_loads: if picks[0] in failed_world_loads:
raise Exception(f"No functional world found to handle game {ret.game}. " raise Exception(f"No functional world found to handle game {ret.game}. "

View File

@ -198,8 +198,7 @@ class JSONtoTextParser(metaclass=HandlerMeta):
"slateblue": "6D8BE8", "slateblue": "6D8BE8",
"plum": "AF99EF", "plum": "AF99EF",
"salmon": "FA8072", "salmon": "FA8072",
"white": "FFFFFF", "white": "FFFFFF"
"orange": "FF7700",
} }
def __init__(self, ctx): def __init__(self, ctx):

View File

@ -553,7 +553,6 @@ def init_logging(name: str, loglevel: typing.Union[str, int] = logging.INFO, wri
f"Archipelago ({__version__}) logging initialized" f"Archipelago ({__version__}) logging initialized"
f" on {platform.platform()}" f" on {platform.platform()}"
f" running Python {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}" f" running Python {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
f"{' (frozen)' if is_frozen() else ''}"
) )

2
WebHost.py Executable file → Normal file
View File

@ -1,5 +1,3 @@
#!/usr/bin/env python3
import os import os
import multiprocessing import multiprocessing
import logging import logging

View File

@ -13,7 +13,6 @@
plum: "AF99EF" # typically progression item plum: "AF99EF" # typically progression item
salmon: "FA8072" # typically trap item salmon: "FA8072" # typically trap item
white: "FFFFFF" # not used, if you want to change the generic text color change color in Label white: "FFFFFF" # not used, if you want to change the generic text color change color in Label
orange: "FF7700" # Used for command echo
<Label>: <Label>:
color: "FFFFFF" color: "FFFFFF"
<TabbedPanel>: <TabbedPanel>:

View File

@ -89,9 +89,6 @@ Type: files; Name: "{app}\ArchipelagoPokemonClient.exe"
Type: files; Name: "{app}\data\lua\connector_pkmn_rb.lua" Type: files; Name: "{app}\data\lua\connector_pkmn_rb.lua"
Type: filesandordirs; Name: "{app}\lib\worlds\rogue-legacy" Type: filesandordirs; Name: "{app}\lib\worlds\rogue-legacy"
Type: dirifempty; Name: "{app}\lib\worlds\rogue-legacy" Type: dirifempty; Name: "{app}\lib\worlds\rogue-legacy"
Type: files; Name: "{app}\lib\worlds\sc2wol.apworld"
Type: filesandordirs; Name: "{app}\lib\worlds\sc2wol"
Type: dirifempty; Name: "{app}\lib\worlds\sc2wol"
Type: filesandordirs; Name: "{app}\lib\worlds\bk_sudoku" Type: filesandordirs; Name: "{app}\lib\worlds\bk_sudoku"
Type: dirifempty; Name: "{app}\lib\worlds\bk_sudoku" Type: dirifempty; Name: "{app}\lib\worlds\bk_sudoku"
Type: files; Name: "{app}\ArchipelagoLauncher(DEBUG).exe" Type: files; Name: "{app}\ArchipelagoLauncher(DEBUG).exe"

62
kvui.py
View File

@ -3,7 +3,6 @@ import logging
import sys import sys
import typing import typing
import re import re
from collections import deque
if sys.platform == "win32": if sys.platform == "win32":
import ctypes import ctypes
@ -381,57 +380,6 @@ class ConnectBarTextInput(TextInput):
return super(ConnectBarTextInput, self).insert_text(s, from_undo=from_undo) return super(ConnectBarTextInput, self).insert_text(s, from_undo=from_undo)
def is_command_input(string: str) -> bool:
return len(string) > 0 and string[0] in "/!"
class CommandPromptTextInput(TextInput):
MAXIMUM_HISTORY_MESSAGES = 50
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
self._command_history_index = -1
self._command_history: typing.Deque[str] = deque(maxlen=CommandPromptTextInput.MAXIMUM_HISTORY_MESSAGES)
def update_history(self, new_entry: str) -> None:
self._command_history_index = -1
if is_command_input(new_entry):
self._command_history.appendleft(new_entry)
def keyboard_on_key_down(
self,
window,
keycode: typing.Tuple[int, str],
text: typing.Optional[str],
modifiers: typing.List[str]
) -> bool:
"""
:param window: The kivy window object
:param keycode: A tuple of (keycode, keyname). Keynames are always lowercase
:param text: The text printed by this key, not accounting for modifiers, or `None` if no text.
Seems to pretty naively interpret the keycode as unicode, so numlock can return odd characters.
:param modifiers: A list of string modifiers, like `ctrl` or `numlock`
"""
if keycode[1] == 'up':
self._change_to_history_text_if_available(self._command_history_index + 1)
return True
if keycode[1] == 'down':
self._change_to_history_text_if_available(self._command_history_index - 1)
return True
return super().keyboard_on_key_down(window, keycode, text, modifiers)
def _change_to_history_text_if_available(self, new_index: int) -> None:
if new_index < -1:
return
if new_index >= len(self._command_history):
return
self._command_history_index = new_index
if new_index == -1:
self.text = ""
return
self.text = self._command_history[self._command_history_index]
class MessageBox(Popup): class MessageBox(Popup):
class MessageBoxLabel(Label): class MessageBoxLabel(Label):
def __init__(self, **kwargs): def __init__(self, **kwargs):
@ -467,7 +415,7 @@ class GameManager(App):
self.commandprocessor = ctx.command_processor(ctx) self.commandprocessor = ctx.command_processor(ctx)
self.icon = r"data/icon.png" self.icon = r"data/icon.png"
self.json_to_kivy_parser = KivyJSONtoTextParser(ctx) self.json_to_kivy_parser = KivyJSONtoTextParser(ctx)
self.log_panels: typing.Dict[str, Widget] = {} self.log_panels = {}
# keep track of last used command to autofill on click # keep track of last used command to autofill on click
self.last_autofillable_command = "hint" self.last_autofillable_command = "hint"
@ -551,7 +499,7 @@ class GameManager(App):
info_button = Button(size=(dp(100), dp(30)), text="Command:", size_hint_x=None) info_button = Button(size=(dp(100), dp(30)), text="Command:", size_hint_x=None)
info_button.bind(on_release=self.command_button_action) info_button.bind(on_release=self.command_button_action)
bottom_layout.add_widget(info_button) bottom_layout.add_widget(info_button)
self.textinput = CommandPromptTextInput(size_hint_y=None, height=dp(30), multiline=False, write_tab=False) self.textinput = TextInput(size_hint_y=None, height=dp(30), multiline=False, write_tab=False)
self.textinput.bind(on_text_validate=self.on_message) self.textinput.bind(on_text_validate=self.on_message)
self.textinput.text_validate_unfocus = False self.textinput.text_validate_unfocus = False
bottom_layout.add_widget(self.textinput) bottom_layout.add_widget(self.textinput)
@ -609,18 +557,14 @@ class GameManager(App):
self.ctx.exit_event.set() self.ctx.exit_event.set()
def on_message(self, textinput: CommandPromptTextInput): def on_message(self, textinput: TextInput):
try: try:
input_text = textinput.text.strip() input_text = textinput.text.strip()
textinput.text = "" textinput.text = ""
textinput.update_history(input_text)
if self.ctx.input_requests > 0: if self.ctx.input_requests > 0:
self.ctx.input_requests -= 1 self.ctx.input_requests -= 1
self.ctx.input_queue.put_nowait(input_text) self.ctx.input_queue.put_nowait(input_text)
elif is_command_input(input_text):
self.ctx.on_ui_command(input_text)
self.commandprocessor(input_text)
elif input_text: elif input_text:
self.commandprocessor(input_text) self.commandprocessor(input_text)

View File

@ -2,7 +2,6 @@ from argparse import Namespace
from typing import List, Optional, Tuple, Type, Union from typing import List, Optional, Tuple, Type, Union
from BaseClasses import CollectionState, Item, ItemClassification, Location, MultiWorld, Region from BaseClasses import CollectionState, Item, ItemClassification, Location, MultiWorld, Region
from worlds import network_data_package
from worlds.AutoWorld import World, call_all from worlds.AutoWorld import World, call_all
gen_steps = ("generate_early", "create_regions", "create_items", "set_rules", "generate_basic", "pre_fill") gen_steps = ("generate_early", "create_regions", "create_items", "set_rules", "generate_basic", "pre_fill")
@ -61,10 +60,6 @@ class TestWorld(World):
hidden = True hidden = True
# add our test world to the data package, so we can test it later
network_data_package["games"][TestWorld.game] = TestWorld.get_data_package_data()
def generate_test_multiworld(players: int = 1) -> MultiWorld: def generate_test_multiworld(players: int = 1) -> MultiWorld:
""" """
Generates a multiworld using a special Test Case World class, and seed of 0. Generates a multiworld using a special Test Case World class, and seed of 0.

View File

@ -1,7 +1,6 @@
import unittest import unittest
from Fill import distribute_items_restrictive from Fill import distribute_items_restrictive
from worlds import network_data_package
from worlds.AutoWorld import AutoWorldRegister, call_all from worlds.AutoWorld import AutoWorldRegister, call_all
from . import setup_solo_multiworld from . import setup_solo_multiworld
@ -85,4 +84,3 @@ class TestIDs(unittest.TestCase):
f"{loc_name} is not a valid item name for location_name_to_id") f"{loc_name} is not a valid item name for location_name_to_id")
self.assertIsInstance(loc_id, int, self.assertIsInstance(loc_id, int,
f"{loc_id} for {loc_name} should be an int") f"{loc_id} for {loc_name} should be an int")
self.assertEqual(datapackage["checksum"], network_data_package["games"][gamename]["checksum"])

View File

@ -1,5 +1,4 @@
import importlib import importlib
import importlib.util
import logging import logging
import os import os
import sys import sys

View File

@ -2,8 +2,7 @@ from __future__ import annotations
from typing import Dict from typing import Dict
from dataclasses import dataclass from Options import Choice, Option, DefaultOnToggle, DeathLink, Range, Toggle
from Options import Choice, Option, DefaultOnToggle, DeathLink, Range, Toggle, PerGameCommonOptions
class FreeincarnateMax(Range): class FreeincarnateMax(Range):
@ -224,22 +223,22 @@ class StartCastle(Choice):
option_white = 2 option_white = 2
default = option_yellow default = option_yellow
@dataclass
class AdventureOptions(PerGameCommonOptions):
dragon_slay_check: DragonSlayCheck
death_link: DeathLink
bat_logic: BatLogic
freeincarnate_max: FreeincarnateMax
dragon_rando_type: DragonRandoType
connector_multi_slot: ConnectorMultiSlot
yorgle_speed: YorgleStartingSpeed
yorgle_min_speed: YorgleMinimumSpeed
grundle_speed: GrundleStartingSpeed
grundle_min_speed: GrundleMinimumSpeed
rhindle_speed: RhindleStartingSpeed
rhindle_min_speed: RhindleMinimumSpeed
difficulty_switch_a: DifficultySwitchA
difficulty_switch_b: DifficultySwitchB
start_castle: StartCastle
adventure_option_definitions: Dict[str, type(Option)] = {
"dragon_slay_check": DragonSlayCheck,
"death_link": DeathLink,
"bat_logic": BatLogic,
"freeincarnate_max": FreeincarnateMax,
"dragon_rando_type": DragonRandoType,
"connector_multi_slot": ConnectorMultiSlot,
"yorgle_speed": YorgleStartingSpeed,
"yorgle_min_speed": YorgleMinimumSpeed,
"grundle_speed": GrundleStartingSpeed,
"grundle_min_speed": GrundleMinimumSpeed,
"rhindle_speed": RhindleStartingSpeed,
"rhindle_min_speed": RhindleMinimumSpeed,
"difficulty_switch_a": DifficultySwitchA,
"difficulty_switch_b": DifficultySwitchB,
"start_castle": StartCastle,
}

View File

@ -1,5 +1,4 @@
from BaseClasses import MultiWorld, Region, Entrance, LocationProgressType from BaseClasses import MultiWorld, Region, Entrance, LocationProgressType
from Options import PerGameCommonOptions
from .Locations import location_table, LocationData, AdventureLocation, dragon_room_to_region from .Locations import location_table, LocationData, AdventureLocation, dragon_room_to_region
@ -25,7 +24,7 @@ def connect(world: MultiWorld, player: int, source: str, target: str, rule: call
connect(world, player, target, source, rule, True) connect(world, player, target, source, rule, True)
def create_regions(options: PerGameCommonOptions, multiworld: MultiWorld, player: int, dragon_rooms: []) -> None: def create_regions(multiworld: MultiWorld, player: int, dragon_rooms: []) -> None:
menu = Region("Menu", player, multiworld) menu = Region("Menu", player, multiworld)
@ -75,7 +74,7 @@ def create_regions(options: PerGameCommonOptions, multiworld: MultiWorld, player
credits_room_far_side.exits.append(Entrance(player, "CreditsFromFarSide", credits_room_far_side)) credits_room_far_side.exits.append(Entrance(player, "CreditsFromFarSide", credits_room_far_side))
multiworld.regions.append(credits_room_far_side) multiworld.regions.append(credits_room_far_side)
dragon_slay_check = options.dragon_slay_check.value dragon_slay_check = multiworld.dragon_slay_check[player].value
priority_locations = determine_priority_locations(multiworld, dragon_slay_check) priority_locations = determine_priority_locations(multiworld, dragon_slay_check)
for name, location_data in location_table.items(): for name, location_data in location_table.items():

View File

@ -6,7 +6,7 @@ from BaseClasses import LocationProgressType
def set_rules(self) -> None: def set_rules(self) -> None:
world = self.multiworld world = self.multiworld
use_bat_logic = self.options.bat_logic.value == BatLogic.option_use_logic use_bat_logic = world.bat_logic[self.player].value == BatLogic.option_use_logic
set_rule(world.get_entrance("YellowCastlePort", self.player), set_rule(world.get_entrance("YellowCastlePort", self.player),
lambda state: state.has("Yellow Key", self.player)) lambda state: state.has("Yellow Key", self.player))
@ -28,7 +28,7 @@ def set_rules(self) -> None:
lambda state: state.has("Bridge", self.player) or lambda state: state.has("Bridge", self.player) or
state.has("Magnet", self.player)) state.has("Magnet", self.player))
dragon_slay_check = self.options.dragon_slay_check.value dragon_slay_check = world.dragon_slay_check[self.player].value
if dragon_slay_check: if dragon_slay_check:
if self.difficulty_switch_b == DifficultySwitchB.option_hard_with_unlock_item: if self.difficulty_switch_b == DifficultySwitchB.option_hard_with_unlock_item:
set_rule(world.get_location("Slay Yorgle", self.player), set_rule(world.get_location("Slay Yorgle", self.player),

View File

@ -15,8 +15,7 @@ from Options import AssembleOptions
from worlds.AutoWorld import WebWorld, World from worlds.AutoWorld import WebWorld, World
from Fill import fill_restrictive from Fill import fill_restrictive
from worlds.generic.Rules import add_rule, set_rule from worlds.generic.Rules import add_rule, set_rule
from .Options import DragonRandoType, DifficultySwitchA, DifficultySwitchB, \ from .Options import adventure_option_definitions, DragonRandoType, DifficultySwitchA, DifficultySwitchB
AdventureOptions
from .Rom import get_base_rom_bytes, get_base_rom_path, AdventureDeltaPatch, apply_basepatch, \ from .Rom import get_base_rom_bytes, get_base_rom_path, AdventureDeltaPatch, apply_basepatch, \
AdventureAutoCollectLocation AdventureAutoCollectLocation
from .Items import item_table, ItemData, nothing_item_id, event_table, AdventureItem, standard_item_max from .Items import item_table, ItemData, nothing_item_id, event_table, AdventureItem, standard_item_max
@ -110,7 +109,7 @@ class AdventureWorld(World):
game: ClassVar[str] = "Adventure" game: ClassVar[str] = "Adventure"
web: ClassVar[WebWorld] = AdventureWeb() web: ClassVar[WebWorld] = AdventureWeb()
options_dataclass = AdventureOptions option_definitions: ClassVar[Dict[str, AssembleOptions]] = adventure_option_definitions
settings: ClassVar[AdventureSettings] settings: ClassVar[AdventureSettings]
item_name_to_id: ClassVar[Dict[str, int]] = {name: data.id for name, data in item_table.items()} item_name_to_id: ClassVar[Dict[str, int]] = {name: data.id for name, data in item_table.items()}
location_name_to_id: ClassVar[Dict[str, int]] = {name: data.location_id for name, data in location_table.items()} location_name_to_id: ClassVar[Dict[str, int]] = {name: data.location_id for name, data in location_table.items()}
@ -150,18 +149,18 @@ class AdventureWorld(World):
bytearray(f"ADVENTURE{__version__.replace('.', '')[:3]}_{self.player}_{self.multiworld.seed}", "utf8")[:21] bytearray(f"ADVENTURE{__version__.replace('.', '')[:3]}_{self.player}_{self.multiworld.seed}", "utf8")[:21]
self.rom_name.extend([0] * (21 - len(self.rom_name))) self.rom_name.extend([0] * (21 - len(self.rom_name)))
self.dragon_rando_type = self.options.dragon_rando_type.value self.dragon_rando_type = self.multiworld.dragon_rando_type[self.player].value
self.dragon_slay_check = self.options.dragon_slay_check.value self.dragon_slay_check = self.multiworld.dragon_slay_check[self.player].value
self.connector_multi_slot = self.options.connector_multi_slot.value self.connector_multi_slot = self.multiworld.connector_multi_slot[self.player].value
self.yorgle_speed = self.options.yorgle_speed.value self.yorgle_speed = self.multiworld.yorgle_speed[self.player].value
self.yorgle_min_speed = self.options.yorgle_min_speed.value self.yorgle_min_speed = self.multiworld.yorgle_min_speed[self.player].value
self.grundle_speed = self.options.grundle_speed.value self.grundle_speed = self.multiworld.grundle_speed[self.player].value
self.grundle_min_speed = self.options.grundle_min_speed.value self.grundle_min_speed = self.multiworld.grundle_min_speed[self.player].value
self.rhindle_speed = self.options.rhindle_speed.value self.rhindle_speed = self.multiworld.rhindle_speed[self.player].value
self.rhindle_min_speed = self.options.rhindle_min_speed.value self.rhindle_min_speed = self.multiworld.rhindle_min_speed[self.player].value
self.difficulty_switch_a = self.options.difficulty_switch_a.value self.difficulty_switch_a = self.multiworld.difficulty_switch_a[self.player].value
self.difficulty_switch_b = self.options.difficulty_switch_b.value self.difficulty_switch_b = self.multiworld.difficulty_switch_b[self.player].value
self.start_castle = self.options.start_castle.value self.start_castle = self.multiworld.start_castle[self.player].value
self.created_items = 0 self.created_items = 0
if self.dragon_slay_check == 0: if self.dragon_slay_check == 0:
@ -228,7 +227,7 @@ class AdventureWorld(World):
extra_filler_count = num_locations - self.created_items extra_filler_count = num_locations - self.created_items
# traps would probably go here, if enabled # traps would probably go here, if enabled
freeincarnate_max = self.options.freeincarnate_max.value freeincarnate_max = self.multiworld.freeincarnate_max[self.player].value
actual_freeincarnates = min(extra_filler_count, freeincarnate_max) actual_freeincarnates = min(extra_filler_count, freeincarnate_max)
self.multiworld.itempool += [self.create_item("Freeincarnate") for _ in range(actual_freeincarnates)] self.multiworld.itempool += [self.create_item("Freeincarnate") for _ in range(actual_freeincarnates)]
self.created_items += actual_freeincarnates self.created_items += actual_freeincarnates
@ -248,7 +247,7 @@ class AdventureWorld(World):
self.created_items += 1 self.created_items += 1
def create_regions(self) -> None: def create_regions(self) -> None:
create_regions(self.options, self.multiworld, self.player, self.dragon_rooms) create_regions(self.multiworld, self.player, self.dragon_rooms)
set_rules = set_rules set_rules = set_rules
@ -355,7 +354,7 @@ class AdventureWorld(World):
auto_collect_locations: [AdventureAutoCollectLocation] = [] auto_collect_locations: [AdventureAutoCollectLocation] = []
local_item_to_location: {int, int} = {} local_item_to_location: {int, int} = {}
bat_no_touch_locs: [LocationData] = [] bat_no_touch_locs: [LocationData] = []
bat_logic: int = self.options.bat_logic.value bat_logic: int = self.multiworld.bat_logic[self.player].value
try: try:
rom_deltas: { int, int } = {} rom_deltas: { int, int } = {}
self.place_dragons(rom_deltas) self.place_dragons(rom_deltas)
@ -422,7 +421,7 @@ class AdventureWorld(World):
item_position_data_start = get_item_position_data_start(unplaced_item.table_index) item_position_data_start = get_item_position_data_start(unplaced_item.table_index)
rom_deltas[item_position_data_start] = 0xff rom_deltas[item_position_data_start] = 0xff
if self.options.connector_multi_slot.value: if self.multiworld.connector_multi_slot[self.player].value:
rom_deltas[connector_port_offset] = (self.player & 0xff) rom_deltas[connector_port_offset] = (self.player & 0xff)
else: else:
rom_deltas[connector_port_offset] = 0 rom_deltas[connector_port_offset] = 0

View File

@ -5,7 +5,7 @@ from schema import And, Optional, Or, Schema
from Options import Accessibility, Choice, DeathLinkMixin, DefaultOnToggle, OptionDict, PerGameCommonOptions, \ from Options import Accessibility, Choice, DeathLinkMixin, DefaultOnToggle, OptionDict, PerGameCommonOptions, \
PlandoConnections, Range, StartInventoryPool, Toggle, Visibility PlandoConnections, Range, StartInventoryPool, Toggle, Visibility
from .portals import CHECKPOINTS, PORTALS, SHOP_POINTS from worlds.messenger.portals import CHECKPOINTS, PORTALS, SHOP_POINTS
class MessengerAccessibility(Accessibility): class MessengerAccessibility(Accessibility):

View File

@ -306,7 +306,8 @@ def write_tokens(world: "MLSSWorld", patch: MLSSProcedurePatch) -> None:
if world.options.scale_stats: if world.options.scale_stats:
patch.write_token(APTokenTypes.WRITE, 0xD00002, bytes([0x1])) patch.write_token(APTokenTypes.WRITE, 0xD00002, bytes([0x1]))
patch.write_token(APTokenTypes.WRITE, 0xD00003, bytes([world.options.xp_multiplier.value])) if world.options.xp_multiplier:
patch.write_token(APTokenTypes.WRITE, 0xD00003, bytes([world.options.xp_multiplier.value]))
if world.options.tattle_hp: if world.options.tattle_hp:
patch.write_token(APTokenTypes.WRITE, 0xD00000, bytes([0x1])) patch.write_token(APTokenTypes.WRITE, 0xD00000, bytes([0x1]))

View File

@ -107,10 +107,10 @@ class ColouredMessage:
def coloured(self, text: str, colour: str) -> 'ColouredMessage': def coloured(self, text: str, colour: str) -> 'ColouredMessage':
add_json_text(self.parts, text, type="color", color=colour) add_json_text(self.parts, text, type="color", color=colour)
return self return self
def location(self, location_id: int, player_id: int) -> 'ColouredMessage': def location(self, location_id: int, player_id: int = 0) -> 'ColouredMessage':
add_json_location(self.parts, location_id, player_id) add_json_location(self.parts, location_id, player_id)
return self return self
def item(self, item_id: int, player_id: int, flags: int = 0) -> 'ColouredMessage': def item(self, item_id: int, player_id: int = 0, flags: int = 0) -> 'ColouredMessage':
add_json_item(self.parts, item_id, player_id, flags) add_json_item(self.parts, item_id, player_id, flags)
return self return self
def player(self, player_id: int) -> 'ColouredMessage': def player(self, player_id: int) -> 'ColouredMessage':
@ -122,6 +122,7 @@ class ColouredMessage:
class StarcraftClientProcessor(ClientCommandProcessor): class StarcraftClientProcessor(ClientCommandProcessor):
ctx: SC2Context ctx: SC2Context
echo_commands = True
def formatted_print(self, text: str) -> None: def formatted_print(self, text: str) -> None:
"""Prints with kivy formatting to the GUI, and also prints to command-line and to all logs""" """Prints with kivy formatting to the GUI, and also prints to command-line and to all logs"""
@ -256,7 +257,7 @@ class StarcraftClientProcessor(ClientCommandProcessor):
for item in received_items_of_this_type: for item in received_items_of_this_type:
print_faction_title() print_faction_title()
has_printed_faction_title = True has_printed_faction_title = True
(ColouredMessage('* ').item(item.item, self.ctx.slot, flags=item.flags) (ColouredMessage('* ').item(item.item, flags=item.flags)
(" from ").location(item.location, self.ctx.slot) (" from ").location(item.location, self.ctx.slot)
(" by ").player(item.player) (" by ").player(item.player)
).send(self.ctx) ).send(self.ctx)
@ -277,7 +278,7 @@ class StarcraftClientProcessor(ClientCommandProcessor):
received_items_of_this_type = items_received.get(child_item, []) received_items_of_this_type = items_received.get(child_item, [])
for item in received_items_of_this_type: for item in received_items_of_this_type:
filter_match_count += len(received_items_of_this_type) filter_match_count += len(received_items_of_this_type)
(ColouredMessage(' * ').item(item.item, self.ctx.slot, flags=item.flags) (ColouredMessage(' * ').item(item.item, flags=item.flags)
(" from ").location(item.location, self.ctx.slot) (" from ").location(item.location, self.ctx.slot)
(" by ").player(item.player) (" by ").player(item.player)
).send(self.ctx) ).send(self.ctx)

View File

@ -1,6 +1,5 @@
from worlds.generic.Rules import forbid_items_for_player, add_rule from worlds.generic.Rules import forbid_items_for_player, add_rule
from .Options import Goal, GoldenFeatherProgression, MinShopCheckLogic, ShopCheckLogic from worlds.shorthike.Options import Goal, GoldenFeatherProgression, MinShopCheckLogic, ShopCheckLogic
def create_rules(self, location_table): def create_rules(self, location_table):
multiworld = self.multiworld multiworld = self.multiworld

View File

@ -5,7 +5,7 @@ from NetUtils import ClientStatus, NetworkItem
import worlds._bizhawk as bizhawk import worlds._bizhawk as bizhawk
from worlds._bizhawk.client import BizHawkClient from worlds._bizhawk.client import BizHawkClient
from . import item_to_index from worlds.yugioh06 import item_to_index
if TYPE_CHECKING: if TYPE_CHECKING:
from worlds._bizhawk.context import BizHawkClientContext from worlds._bizhawk.context import BizHawkClientContext

View File

@ -3,8 +3,8 @@ from typing import Dict, List, NamedTuple, Optional, Union
from BaseClasses import MultiWorld from BaseClasses import MultiWorld
from worlds.generic.Rules import CollectionRule from worlds.generic.Rules import CollectionRule
from . import item_to_index, tier_1_opponents, yugioh06_difficulty from worlds.yugioh06 import item_to_index, tier_1_opponents, yugioh06_difficulty
from .locations import special from worlds.yugioh06.locations import special
class OpponentData(NamedTuple): class OpponentData(NamedTuple):