mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-27 09:33:22 -07:00
Fix client and leftover old options api
This commit is contained in:
240
AHITClient.py
240
AHITClient.py
@@ -1,236 +1,8 @@
|
||||
import asyncio
|
||||
from worlds.ahit.Client import launch
|
||||
import Utils
|
||||
import websockets
|
||||
import functools
|
||||
from copy import deepcopy
|
||||
from typing import List, Any, Iterable
|
||||
from NetUtils import decode, encode, JSONtoTextParser, JSONMessagePart, NetworkItem
|
||||
from MultiServer import Endpoint
|
||||
from CommonClient import CommonContext, gui_enabled, ClientCommandProcessor, logger, get_base_parser
|
||||
import ModuleUpdate
|
||||
ModuleUpdate.update()
|
||||
|
||||
DEBUG = False
|
||||
|
||||
|
||||
class AHITJSONToTextParser(JSONtoTextParser):
|
||||
def _handle_color(self, node: JSONMessagePart):
|
||||
return self._handle_text(node) # No colors for the in-game text
|
||||
|
||||
|
||||
class AHITCommandProcessor(ClientCommandProcessor):
|
||||
def __init__(self, ctx: CommonContext):
|
||||
super().__init__(ctx)
|
||||
|
||||
def _cmd_ahit(self):
|
||||
"""Check AHIT Connection State"""
|
||||
if isinstance(self.ctx, AHITContext):
|
||||
logger.info(f"AHIT Status: {self.ctx.get_ahit_status()}")
|
||||
|
||||
|
||||
class AHITContext(CommonContext):
|
||||
command_processor = AHITCommandProcessor
|
||||
game = "A Hat in Time"
|
||||
|
||||
def __init__(self, server_address, password):
|
||||
super().__init__(server_address, password)
|
||||
self.proxy = None
|
||||
self.proxy_task = None
|
||||
self.gamejsontotext = AHITJSONToTextParser(self)
|
||||
self.autoreconnect_task = None
|
||||
self.endpoint = None
|
||||
self.items_handling = 0b111
|
||||
self.room_info = None
|
||||
self.connected_msg = None
|
||||
self.game_connected = False
|
||||
self.awaiting_info = False
|
||||
self.full_inventory: List[Any] = []
|
||||
self.server_msgs: List[Any] = []
|
||||
|
||||
async def server_auth(self, password_requested: bool = False):
|
||||
if password_requested and not self.password:
|
||||
await super(AHITContext, self).server_auth(password_requested)
|
||||
|
||||
await self.get_username()
|
||||
await self.send_connect()
|
||||
|
||||
def get_ahit_status(self) -> str:
|
||||
if not self.is_proxy_connected():
|
||||
return "Not connected to A Hat in Time"
|
||||
|
||||
return "Connected to A Hat in Time"
|
||||
|
||||
async def send_msgs_proxy(self, msgs: Iterable[dict]) -> bool:
|
||||
""" `msgs` JSON serializable """
|
||||
if not self.endpoint or not self.endpoint.socket.open or self.endpoint.socket.closed:
|
||||
return False
|
||||
|
||||
if DEBUG:
|
||||
logger.info(f"Outgoing message: {msgs}")
|
||||
|
||||
await self.endpoint.socket.send(msgs)
|
||||
return True
|
||||
|
||||
async def disconnect(self, allow_autoreconnect: bool = False):
|
||||
await super().disconnect(allow_autoreconnect)
|
||||
|
||||
async def disconnect_proxy(self):
|
||||
if self.endpoint and not self.endpoint.socket.closed:
|
||||
await self.endpoint.socket.close()
|
||||
if self.proxy_task is not None:
|
||||
await self.proxy_task
|
||||
|
||||
def is_connected(self) -> bool:
|
||||
return self.server and self.server.socket.open
|
||||
|
||||
def is_proxy_connected(self) -> bool:
|
||||
return self.endpoint and self.endpoint.socket.open
|
||||
|
||||
def on_print_json(self, args: dict):
|
||||
text = self.gamejsontotext(deepcopy(args["data"]))
|
||||
msg = {"cmd": "PrintJSON", "data": [{"text": text}], "type": "Chat"}
|
||||
self.server_msgs.append(encode([msg]))
|
||||
|
||||
if self.ui:
|
||||
self.ui.print_json(args["data"])
|
||||
else:
|
||||
text = self.jsontotextparser(args["data"])
|
||||
logger.info(text)
|
||||
|
||||
def update_items(self):
|
||||
# just to be safe - we might still have an inventory from a different room
|
||||
if not self.is_connected():
|
||||
return
|
||||
|
||||
self.server_msgs.append(encode([{"cmd": "ReceivedItems", "index": 0, "items": self.full_inventory}]))
|
||||
|
||||
def on_package(self, cmd: str, args: dict):
|
||||
if cmd == "Connected":
|
||||
self.connected_msg = encode([args])
|
||||
if self.awaiting_info:
|
||||
self.server_msgs.append(self.room_info)
|
||||
self.update_items()
|
||||
self.awaiting_info = False
|
||||
|
||||
elif cmd == "ReceivedItems":
|
||||
if args["index"] == 0:
|
||||
self.full_inventory.clear()
|
||||
|
||||
for item in args["items"]:
|
||||
self.full_inventory.append(NetworkItem(*item))
|
||||
|
||||
self.server_msgs.append(encode([args]))
|
||||
|
||||
elif cmd == "RoomInfo":
|
||||
self.seed_name = args["seed_name"]
|
||||
self.room_info = encode([args])
|
||||
|
||||
else:
|
||||
if cmd != "PrintJSON":
|
||||
self.server_msgs.append(encode([args]))
|
||||
|
||||
def run_gui(self):
|
||||
from kvui import GameManager
|
||||
|
||||
class AHITManager(GameManager):
|
||||
logging_pairs = [
|
||||
("Client", "Archipelago")
|
||||
]
|
||||
base_title = "Archipelago A Hat in Time Client"
|
||||
|
||||
self.ui = AHITManager(self)
|
||||
self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI")
|
||||
|
||||
|
||||
async def proxy(websocket, path: str = "/", ctx: AHITContext = None):
|
||||
ctx.endpoint = Endpoint(websocket)
|
||||
try:
|
||||
await on_client_connected(ctx)
|
||||
|
||||
if ctx.is_proxy_connected():
|
||||
async for data in websocket:
|
||||
if DEBUG:
|
||||
logger.info(f"Incoming message: {data}")
|
||||
|
||||
for msg in decode(data):
|
||||
if msg["cmd"] == "Connect":
|
||||
# Proxy is connecting, make sure it is valid
|
||||
if msg["game"] != "A Hat in Time":
|
||||
logger.info("Aborting proxy connection: game is not A Hat in Time")
|
||||
await ctx.disconnect_proxy()
|
||||
break
|
||||
|
||||
if ctx.seed_name:
|
||||
seed_name = msg.get("seed_name", "")
|
||||
if seed_name != "" and seed_name != ctx.seed_name:
|
||||
logger.info("Aborting proxy connection: seed mismatch from save file")
|
||||
logger.info(f"Expected: {ctx.seed_name}, got: {seed_name}")
|
||||
text = encode([{"cmd": "PrintJSON",
|
||||
"data": [{"text": "Connection aborted - save file to seed mismatch"}]}])
|
||||
await ctx.send_msgs_proxy(text)
|
||||
await ctx.disconnect_proxy()
|
||||
break
|
||||
|
||||
if ctx.connected_msg and ctx.is_connected():
|
||||
await ctx.send_msgs_proxy(ctx.connected_msg)
|
||||
ctx.update_items()
|
||||
continue
|
||||
|
||||
if not ctx.is_proxy_connected():
|
||||
break
|
||||
|
||||
await ctx.send_msgs([msg])
|
||||
|
||||
except Exception as e:
|
||||
if not isinstance(e, websockets.WebSocketException):
|
||||
logger.exception(e)
|
||||
finally:
|
||||
await ctx.disconnect_proxy()
|
||||
|
||||
|
||||
async def on_client_connected(ctx: AHITContext):
|
||||
if ctx.room_info and ctx.is_connected():
|
||||
await ctx.send_msgs_proxy(ctx.room_info)
|
||||
else:
|
||||
ctx.awaiting_info = True
|
||||
|
||||
|
||||
async def main():
|
||||
parser = get_base_parser()
|
||||
args = parser.parse_args()
|
||||
|
||||
ctx = AHITContext(args.connect, args.password)
|
||||
logger.info("Starting A Hat in Time proxy server")
|
||||
ctx.proxy = websockets.serve(functools.partial(proxy, ctx=ctx),
|
||||
host="localhost", port=11311, ping_timeout=999999, ping_interval=999999)
|
||||
ctx.proxy_task = asyncio.create_task(proxy_loop(ctx), name="ProxyLoop")
|
||||
|
||||
if gui_enabled:
|
||||
ctx.run_gui()
|
||||
ctx.run_cli()
|
||||
|
||||
await ctx.proxy
|
||||
await ctx.proxy_task
|
||||
await ctx.exit_event.wait()
|
||||
|
||||
|
||||
async def proxy_loop(ctx: AHITContext):
|
||||
try:
|
||||
while not ctx.exit_event.is_set():
|
||||
if len(ctx.server_msgs) > 0:
|
||||
for msg in ctx.server_msgs:
|
||||
await ctx.send_msgs_proxy(msg)
|
||||
|
||||
ctx.server_msgs.clear()
|
||||
await asyncio.sleep(0.1)
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
logger.info("Aborting AHIT Proxy Client due to errors")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
Utils.init_logging("AHITClient")
|
||||
options = Utils.get_options()
|
||||
|
||||
import colorama
|
||||
colorama.init()
|
||||
asyncio.run(main())
|
||||
colorama.deinit()
|
||||
if __name__ == "__main__":
|
||||
Utils.init_logging("AHITClient", exception_logger="Client")
|
||||
launch()
|
||||
|
||||
235
worlds/ahit/Client.py
Normal file
235
worlds/ahit/Client.py
Normal file
@@ -0,0 +1,235 @@
|
||||
import asyncio
|
||||
import Utils
|
||||
import websockets
|
||||
import functools
|
||||
from copy import deepcopy
|
||||
from typing import List, Any, Iterable
|
||||
from NetUtils import decode, encode, JSONtoTextParser, JSONMessagePart, NetworkItem
|
||||
from MultiServer import Endpoint
|
||||
from CommonClient import CommonContext, gui_enabled, ClientCommandProcessor, logger, get_base_parser
|
||||
|
||||
DEBUG = False
|
||||
|
||||
|
||||
class AHITJSONToTextParser(JSONtoTextParser):
|
||||
def _handle_color(self, node: JSONMessagePart):
|
||||
return self._handle_text(node) # No colors for the in-game text
|
||||
|
||||
|
||||
class AHITCommandProcessor(ClientCommandProcessor):
|
||||
def __init__(self, ctx: CommonContext):
|
||||
super().__init__(ctx)
|
||||
|
||||
def _cmd_ahit(self):
|
||||
"""Check AHIT Connection State"""
|
||||
if isinstance(self.ctx, AHITContext):
|
||||
logger.info(f"AHIT Status: {self.ctx.get_ahit_status()}")
|
||||
|
||||
|
||||
class AHITContext(CommonContext):
|
||||
command_processor = AHITCommandProcessor
|
||||
game = "A Hat in Time"
|
||||
|
||||
def __init__(self, server_address, password):
|
||||
super().__init__(server_address, password)
|
||||
self.proxy = None
|
||||
self.proxy_task = None
|
||||
self.gamejsontotext = AHITJSONToTextParser(self)
|
||||
self.autoreconnect_task = None
|
||||
self.endpoint = None
|
||||
self.items_handling = 0b111
|
||||
self.room_info = None
|
||||
self.connected_msg = None
|
||||
self.game_connected = False
|
||||
self.awaiting_info = False
|
||||
self.full_inventory: List[Any] = []
|
||||
self.server_msgs: List[Any] = []
|
||||
|
||||
async def server_auth(self, password_requested: bool = False):
|
||||
if password_requested and not self.password:
|
||||
await super(AHITContext, self).server_auth(password_requested)
|
||||
|
||||
await self.get_username()
|
||||
await self.send_connect()
|
||||
|
||||
def get_ahit_status(self) -> str:
|
||||
if not self.is_proxy_connected():
|
||||
return "Not connected to A Hat in Time"
|
||||
|
||||
return "Connected to A Hat in Time"
|
||||
|
||||
async def send_msgs_proxy(self, msgs: Iterable[dict]) -> bool:
|
||||
""" `msgs` JSON serializable """
|
||||
if not self.endpoint or not self.endpoint.socket.open or self.endpoint.socket.closed:
|
||||
return False
|
||||
|
||||
if DEBUG:
|
||||
logger.info(f"Outgoing message: {msgs}")
|
||||
|
||||
await self.endpoint.socket.send(msgs)
|
||||
return True
|
||||
|
||||
async def disconnect(self, allow_autoreconnect: bool = False):
|
||||
await super().disconnect(allow_autoreconnect)
|
||||
|
||||
async def disconnect_proxy(self):
|
||||
if self.endpoint and not self.endpoint.socket.closed:
|
||||
await self.endpoint.socket.close()
|
||||
if self.proxy_task is not None:
|
||||
await self.proxy_task
|
||||
|
||||
def is_connected(self) -> bool:
|
||||
return self.server and self.server.socket.open
|
||||
|
||||
def is_proxy_connected(self) -> bool:
|
||||
return self.endpoint and self.endpoint.socket.open
|
||||
|
||||
def on_print_json(self, args: dict):
|
||||
text = self.gamejsontotext(deepcopy(args["data"]))
|
||||
msg = {"cmd": "PrintJSON", "data": [{"text": text}], "type": "Chat"}
|
||||
self.server_msgs.append(encode([msg]))
|
||||
|
||||
if self.ui:
|
||||
self.ui.print_json(args["data"])
|
||||
else:
|
||||
text = self.jsontotextparser(args["data"])
|
||||
logger.info(text)
|
||||
|
||||
def update_items(self):
|
||||
# just to be safe - we might still have an inventory from a different room
|
||||
if not self.is_connected():
|
||||
return
|
||||
|
||||
self.server_msgs.append(encode([{"cmd": "ReceivedItems", "index": 0, "items": self.full_inventory}]))
|
||||
|
||||
def on_package(self, cmd: str, args: dict):
|
||||
if cmd == "Connected":
|
||||
self.connected_msg = encode([args])
|
||||
if self.awaiting_info:
|
||||
self.server_msgs.append(self.room_info)
|
||||
self.update_items()
|
||||
self.awaiting_info = False
|
||||
|
||||
elif cmd == "ReceivedItems":
|
||||
if args["index"] == 0:
|
||||
self.full_inventory.clear()
|
||||
|
||||
for item in args["items"]:
|
||||
self.full_inventory.append(NetworkItem(*item))
|
||||
|
||||
self.server_msgs.append(encode([args]))
|
||||
|
||||
elif cmd == "RoomInfo":
|
||||
self.seed_name = args["seed_name"]
|
||||
self.room_info = encode([args])
|
||||
|
||||
else:
|
||||
if cmd != "PrintJSON":
|
||||
self.server_msgs.append(encode([args]))
|
||||
|
||||
def run_gui(self):
|
||||
from kvui import GameManager
|
||||
|
||||
class AHITManager(GameManager):
|
||||
logging_pairs = [
|
||||
("Client", "Archipelago")
|
||||
]
|
||||
base_title = "Archipelago A Hat in Time Client"
|
||||
|
||||
self.ui = AHITManager(self)
|
||||
self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI")
|
||||
|
||||
|
||||
async def proxy(websocket, path: str = "/", ctx: AHITContext = None):
|
||||
ctx.endpoint = Endpoint(websocket)
|
||||
try:
|
||||
await on_client_connected(ctx)
|
||||
|
||||
if ctx.is_proxy_connected():
|
||||
async for data in websocket:
|
||||
if DEBUG:
|
||||
logger.info(f"Incoming message: {data}")
|
||||
|
||||
for msg in decode(data):
|
||||
if msg["cmd"] == "Connect":
|
||||
# Proxy is connecting, make sure it is valid
|
||||
if msg["game"] != "A Hat in Time":
|
||||
logger.info("Aborting proxy connection: game is not A Hat in Time")
|
||||
await ctx.disconnect_proxy()
|
||||
break
|
||||
|
||||
if ctx.seed_name:
|
||||
seed_name = msg.get("seed_name", "")
|
||||
if seed_name != "" and seed_name != ctx.seed_name:
|
||||
logger.info("Aborting proxy connection: seed mismatch from save file")
|
||||
logger.info(f"Expected: {ctx.seed_name}, got: {seed_name}")
|
||||
text = encode([{"cmd": "PrintJSON",
|
||||
"data": [{"text": "Connection aborted - save file to seed mismatch"}]}])
|
||||
await ctx.send_msgs_proxy(text)
|
||||
await ctx.disconnect_proxy()
|
||||
break
|
||||
|
||||
if ctx.connected_msg and ctx.is_connected():
|
||||
await ctx.send_msgs_proxy(ctx.connected_msg)
|
||||
ctx.update_items()
|
||||
continue
|
||||
|
||||
if not ctx.is_proxy_connected():
|
||||
break
|
||||
|
||||
await ctx.send_msgs([msg])
|
||||
|
||||
except Exception as e:
|
||||
if not isinstance(e, websockets.WebSocketException):
|
||||
logger.exception(e)
|
||||
finally:
|
||||
await ctx.disconnect_proxy()
|
||||
|
||||
|
||||
async def on_client_connected(ctx: AHITContext):
|
||||
if ctx.room_info and ctx.is_connected():
|
||||
await ctx.send_msgs_proxy(ctx.room_info)
|
||||
else:
|
||||
ctx.awaiting_info = True
|
||||
|
||||
|
||||
async def proxy_loop(ctx: AHITContext):
|
||||
try:
|
||||
while not ctx.exit_event.is_set():
|
||||
if len(ctx.server_msgs) > 0:
|
||||
for msg in ctx.server_msgs:
|
||||
await ctx.send_msgs_proxy(msg)
|
||||
|
||||
ctx.server_msgs.clear()
|
||||
await asyncio.sleep(0.1)
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
logger.info("Aborting AHIT Proxy Client due to errors")
|
||||
|
||||
|
||||
def launch():
|
||||
async def main():
|
||||
parser = get_base_parser()
|
||||
args = parser.parse_args()
|
||||
|
||||
ctx = AHITContext(args.connect, args.password)
|
||||
logger.info("Starting A Hat in Time proxy server")
|
||||
ctx.proxy = websockets.serve(functools.partial(proxy, ctx=ctx),
|
||||
host="localhost", port=11311, ping_timeout=999999, ping_interval=999999)
|
||||
ctx.proxy_task = asyncio.create_task(proxy_loop(ctx), name="ProxyLoop")
|
||||
|
||||
if gui_enabled:
|
||||
ctx.run_gui()
|
||||
ctx.run_cli()
|
||||
|
||||
await ctx.proxy
|
||||
await ctx.proxy_task
|
||||
await ctx.exit_event.wait()
|
||||
|
||||
Utils.init_logging("AHITClient")
|
||||
# options = Utils.get_options()
|
||||
|
||||
import colorama
|
||||
colorama.init()
|
||||
asyncio.run(main())
|
||||
colorama.deinit()
|
||||
@@ -286,7 +286,6 @@ def get_total_dw_stamps(state: CollectionState, world: World) -> int:
|
||||
if state.has(f"2 Stamps - {name}", world.player):
|
||||
count += 2
|
||||
elif name not in dw_candles:
|
||||
# most non-candle bonus requirements allow the player to get the other stamp (like not having One Hit Hero)
|
||||
count += 1
|
||||
|
||||
return count
|
||||
|
||||
@@ -89,7 +89,6 @@ def create_itempool(world: World) -> List[Item]:
|
||||
|
||||
def calculate_yarn_costs(world: World):
|
||||
mw = world.multiworld
|
||||
p = world.player
|
||||
min_yarn_cost = int(min(world.options.YarnCostMin.value, world.options.YarnCostMax.value))
|
||||
max_yarn_cost = int(max(world.options.YarnCostMin.value, world.options.YarnCostMax.value))
|
||||
|
||||
|
||||
@@ -439,7 +439,7 @@ def create_rift_connections(world: World, region: Region):
|
||||
def create_tasksanity_locations(world: World):
|
||||
ship_shape: Region = world.multiworld.get_region("Ship Shape", world.player)
|
||||
id_start: int = TASKSANITY_START_ID
|
||||
for i in range(world.multiworld.TasksanityCheckCount[world.player].value):
|
||||
for i in range(world.options.TasksanityCheckCount.value):
|
||||
location = HatInTimeLocation(world.player, f"Tasksanity Check {i+1}", id_start+i, ship_shape)
|
||||
ship_shape.locations.append(location)
|
||||
|
||||
|
||||
@@ -322,7 +322,7 @@ def set_rules(world: World):
|
||||
and can_use_hookshot(state, world)
|
||||
and can_hit(state, world, True))
|
||||
|
||||
difficulty: Difficulty = Difficulty(world.multiworld.LogicDifficulty[world.player].value)
|
||||
difficulty: Difficulty = Difficulty(world.options.LogicDifficulty.value)
|
||||
if difficulty >= Difficulty.MODERATE:
|
||||
add_rule(loc, lambda state: state.has("TIHS Access", world.player)
|
||||
and can_use_hat(state, world, HatType.SPRINT), "or")
|
||||
@@ -534,7 +534,7 @@ def set_hard_rules(world: World):
|
||||
lambda state: can_use_hat(state, world, HatType.ICE))
|
||||
|
||||
# Hard: clear Rush Hour with Brewing Hat only
|
||||
if world.multiworld.NoTicketSkips[world.player].value != 1:
|
||||
if world.options.NoTicketSkips.value != 1:
|
||||
set_rule(world.multiworld.get_location("Act Completion (Rush Hour)", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.BREWING))
|
||||
else:
|
||||
@@ -610,7 +610,7 @@ def set_expert_rules(world: World):
|
||||
|
||||
if world.is_dlc2():
|
||||
# Expert: clear Rush Hour with nothing
|
||||
if world.multiworld.NoTicketSkips[world.player].value == 0:
|
||||
if world.options.NoTicketSkips.value == 0:
|
||||
set_rule(world.multiworld.get_location("Act Completion (Rush Hour)", world.player), lambda state: True)
|
||||
else:
|
||||
set_rule(world.multiworld.get_location("Act Completion (Rush Hour)", world.player),
|
||||
|
||||
@@ -10,9 +10,20 @@ from .DeathWishLocations import create_dw_regions, dw_classes, death_wishes
|
||||
from .DeathWishRules import set_dw_rules, create_enemy_events
|
||||
from worlds.AutoWorld import World, WebWorld
|
||||
from typing import List, Dict, TextIO
|
||||
from worlds.LauncherComponents import Component, components, icon_paths
|
||||
from worlds.LauncherComponents import Component, components, icon_paths, launch_subprocess, Type
|
||||
from Utils import local_path
|
||||
|
||||
|
||||
def launch_client():
|
||||
from .Client import launch
|
||||
launch_subprocess(launch, name="AHITClient")
|
||||
|
||||
|
||||
components.append(Component("A Hat in Time Client", "AHITClient", func=launch_client,
|
||||
component_type=Type.CLIENT, icon='yatta'))
|
||||
|
||||
icon_paths['yatta'] = local_path('data', 'yatta.png')
|
||||
|
||||
hat_craft_order: Dict[int, List[HatType]] = {}
|
||||
hat_yarn_costs: Dict[int, Dict[HatType, int]] = {}
|
||||
chapter_timepiece_costs: Dict[int, Dict[ChapterIndex, int]] = {}
|
||||
@@ -22,9 +33,6 @@ dw_shuffle: Dict[int, List[str]] = {}
|
||||
nyakuza_thug_items: Dict[int, Dict[str, int]] = {}
|
||||
badge_seller_count: Dict[int, int] = {}
|
||||
|
||||
components.append(Component("A Hat in Time Client", "AHITClient", icon='yatta'))
|
||||
icon_paths['yatta'] = local_path('data', 'yatta.png')
|
||||
|
||||
|
||||
class AWebInTime(WebWorld):
|
||||
theme = "partyTime"
|
||||
@@ -85,7 +93,8 @@ class HatInTimeWorld(World):
|
||||
nyakuza_thug_items[self.player] = {}
|
||||
badge_seller_count[self.player] = 0
|
||||
self.shop_locs = []
|
||||
self.topology_present = self.options.ActRandomizer.value
|
||||
# noinspection PyClassVar
|
||||
self.topology_present = bool(self.options.ActRandomizer.value)
|
||||
|
||||
create_regions(self)
|
||||
if self.options.EnableDeathWish.value > 0:
|
||||
@@ -231,7 +240,9 @@ class HatInTimeWorld(World):
|
||||
return
|
||||
|
||||
new_hint_data = {}
|
||||
alpine_regions = ["The Birdhouse", "The Lava Cake", "The Windmill", "The Twilight Bell", "Alpine Skyline Area"]
|
||||
alpine_regions = ["The Birdhouse", "The Lava Cake", "The Windmill",
|
||||
"The Twilight Bell", "Alpine Skyline Area", "Alpine Skyline Area (TIHS)"]
|
||||
|
||||
metro_regions = ["Yellow Overpass Station", "Green Clean Station", "Bluefin Tunnel", "Pink Paw Station"]
|
||||
|
||||
for key, data in location_table.items():
|
||||
@@ -245,6 +256,8 @@ class HatInTimeWorld(World):
|
||||
region_name = "Alpine Free Roam"
|
||||
elif data.region in metro_regions:
|
||||
region_name = "Nyakuza Free Roam"
|
||||
elif "Dead Bird Studio - " in data.region:
|
||||
region_name = "Dead Bird Studio"
|
||||
elif data.region in chapter_act_info.keys():
|
||||
region_name = location.parent_region.name
|
||||
else:
|
||||
@@ -303,19 +316,19 @@ class HatInTimeWorld(World):
|
||||
def is_dw_excluded(self, name: str) -> bool:
|
||||
# don't exclude Seal the Deal if it's our goal
|
||||
if self.options.EndGoal.value == 3 and name == "Seal the Deal" \
|
||||
and f"{name} - Main Objective" not in self.multiworld.exclude_locations[self.player]:
|
||||
and f"{name} - Main Objective" not in self.options.exclude_locations:
|
||||
return False
|
||||
|
||||
if name in excluded_dws[self.player]:
|
||||
return True
|
||||
|
||||
return f"{name} - Main Objective" in self.multiworld.exclude_locations[self.player]
|
||||
return f"{name} - Main Objective" in self.options.exclude_locations
|
||||
|
||||
def is_bonus_excluded(self, name: str) -> bool:
|
||||
if self.is_dw_excluded(name) or name in excluded_bonuses[self.player]:
|
||||
return True
|
||||
|
||||
return f"{name} - All Clear" in self.multiworld.exclude_locations[self.player]
|
||||
return f"{name} - All Clear" in self.options.exclude_locations
|
||||
|
||||
def get_dw_shuffle(self):
|
||||
return dw_shuffle[self.player]
|
||||
|
||||
Reference in New Issue
Block a user