diff options
Diffstat (limited to 'apworld')
| -rw-r--r-- | apworld/client/assets/goal.png | bin | 0 -> 215 bytes | |||
| -rw-r--r-- | apworld/client/client.gd | 4 | ||||
| -rw-r--r-- | apworld/client/gamedata.gd | 5 | ||||
| -rw-r--r-- | apworld/client/manager.gd | 16 | ||||
| -rw-r--r-- | apworld/client/player.gd | 22 | ||||
| -rw-r--r-- | apworld/client/textclient.gd | 15 | ||||
| -rw-r--r-- | apworld/context.py | 23 | ||||
| -rw-r--r-- | apworld/locations.py | 1 | ||||
| -rw-r--r-- | apworld/regions.py | 3 | ||||
| -rw-r--r-- | apworld/tracker.py | 6 |
10 files changed, 73 insertions, 22 deletions
| diff --git a/apworld/client/assets/goal.png b/apworld/client/assets/goal.png new file mode 100644 index 0000000..bd1650d --- /dev/null +++ b/apworld/client/assets/goal.png | |||
| Binary files differ | |||
| diff --git a/apworld/client/client.gd b/apworld/client/client.gd index a23e85a..62d7fd8 100644 --- a/apworld/client/client.gd +++ b/apworld/client/client.gd | |||
| @@ -24,6 +24,7 @@ var _received_items = {} | |||
| 24 | var _slot_data = {} | 24 | var _slot_data = {} |
| 25 | var _accessible_locations = [] | 25 | var _accessible_locations = [] |
| 26 | var _accessible_worldports = [] | 26 | var _accessible_worldports = [] |
| 27 | var _goal_accessible = false | ||
| 27 | 28 | ||
| 28 | signal could_not_connect | 29 | signal could_not_connect |
| 29 | signal connect_status | 30 | signal connect_status |
| @@ -61,6 +62,7 @@ func _reset_state(): | |||
| 61 | _checked_worldports = [] | 62 | _checked_worldports = [] |
| 62 | _accessible_locations = [] | 63 | _accessible_locations = [] |
| 63 | _accessible_worldports = [] | 64 | _accessible_worldports = [] |
| 65 | _goal_accessible = false | ||
| 64 | 66 | ||
| 65 | 67 | ||
| 66 | func disconnect_from_ap(): | 68 | func disconnect_from_ap(): |
| @@ -174,6 +176,8 @@ func _on_web_socket_server_message_received(_peer_id: int, packet: String) -> vo | |||
| 174 | for port_id in message["worldports"]: | 176 | for port_id in message["worldports"]: |
| 175 | _accessible_worldports.append(int(port_id)) | 177 | _accessible_worldports.append(int(port_id)) |
| 176 | 178 | ||
| 179 | _goal_accessible = bool(message.get("goal", false)) | ||
| 180 | |||
| 177 | accessible_locations_updated.emit() | 181 | accessible_locations_updated.emit() |
| 178 | 182 | ||
| 179 | elif cmd == "UpdateKeyboard": | 183 | elif cmd == "UpdateKeyboard": |
| diff --git a/apworld/client/gamedata.gd b/apworld/client/gamedata.gd index 1424721..334d42a 100644 --- a/apworld/client/gamedata.gd +++ b/apworld/client/gamedata.gd | |||
| @@ -14,6 +14,7 @@ var letter_id_by_ap_id = {} | |||
| 14 | var symbol_item_ids = [] | 14 | var symbol_item_ids = [] |
| 15 | var anti_trap_ids = {} | 15 | var anti_trap_ids = {} |
| 16 | var location_name_by_id = {} | 16 | var location_name_by_id = {} |
| 17 | var ending_display_name_by_name = {} | ||
| 17 | 18 | ||
| 18 | var kSYMBOL_ITEMS | 19 | var kSYMBOL_ITEMS |
| 19 | 20 | ||
| @@ -103,7 +104,9 @@ func load(data_bytes): | |||
| 103 | location_name_by_id[mastery.get_ap_id()] = _get_mastery_location_name(mastery) | 104 | location_name_by_id[mastery.get_ap_id()] = _get_mastery_location_name(mastery) |
| 104 | 105 | ||
| 105 | for ending in objects.get_endings(): | 106 | for ending in objects.get_endings(): |
| 106 | location_name_by_id[ending.get_ap_id()] = _get_ending_location_name(ending) | 107 | var location_name = _get_ending_location_name(ending) |
| 108 | location_name_by_id[ending.get_ap_id()] = location_name | ||
| 109 | ending_display_name_by_name[ending.get_name()] = location_name | ||
| 107 | 110 | ||
| 108 | for keyholder in objects.get_keyholders(): | 111 | for keyholder in objects.get_keyholders(): |
| 109 | if keyholder.has_key(): | 112 | if keyholder.has_key(): |
| diff --git a/apworld/client/manager.gd b/apworld/client/manager.gd index 5b731d2..b4fef1c 100644 --- a/apworld/client/manager.gd +++ b/apworld/client/manager.gd | |||
| @@ -45,6 +45,22 @@ const kCYAN_DOOR_BEHAVIOR_H2 = 0 | |||
| 45 | const kCYAN_DOOR_BEHAVIOR_DOUBLE_LETTER = 1 | 45 | const kCYAN_DOOR_BEHAVIOR_DOUBLE_LETTER = 1 |
| 46 | const kCYAN_DOOR_BEHAVIOR_ITEM = 2 | 46 | const kCYAN_DOOR_BEHAVIOR_ITEM = 2 |
| 47 | 47 | ||
| 48 | const kEndingNameByVictoryValue = { | ||
| 49 | 0: "GRAY", | ||
| 50 | 1: "PURPLE", | ||
| 51 | 2: "MINT", | ||
| 52 | 3: "BLACK", | ||
| 53 | 4: "BLUE", | ||
| 54 | 5: "CYAN", | ||
| 55 | 6: "RED", | ||
| 56 | 7: "PLUM", | ||
| 57 | 8: "ORANGE", | ||
| 58 | 9: "GOLD", | ||
| 59 | 10: "YELLOW", | ||
| 60 | 11: "GREEN", | ||
| 61 | 12: "WHITE", | ||
| 62 | } | ||
| 63 | |||
| 48 | var apworld_version = [0, 0] | 64 | var apworld_version = [0, 0] |
| 49 | var cyan_door_behavior = kCYAN_DOOR_BEHAVIOR_H2 | 65 | var cyan_door_behavior = kCYAN_DOOR_BEHAVIOR_H2 |
| 50 | var daedalus_roof_access = false | 66 | var daedalus_roof_access = false |
| diff --git a/apworld/client/player.gd b/apworld/client/player.gd index 366c3b0..5417a48 100644 --- a/apworld/client/player.gd +++ b/apworld/client/player.gd | |||
| @@ -1,21 +1,5 @@ | |||
| 1 | extends "res://scripts/nodes/player.gd" | 1 | extends "res://scripts/nodes/player.gd" |
| 2 | 2 | ||
| 3 | const kEndingNameByVictoryValue = { | ||
| 4 | 0: "GRAY", | ||
| 5 | 1: "PURPLE", | ||
| 6 | 2: "MINT", | ||
| 7 | 3: "BLACK", | ||
| 8 | 4: "BLUE", | ||
| 9 | 5: "CYAN", | ||
| 10 | 6: "RED", | ||
| 11 | 7: "PLUM", | ||
| 12 | 8: "ORANGE", | ||
| 13 | 9: "GOLD", | ||
| 14 | 10: "YELLOW", | ||
| 15 | 11: "GREEN", | ||
| 16 | 12: "WHITE", | ||
| 17 | } | ||
| 18 | |||
| 19 | signal evaluate_solvability | 3 | signal evaluate_solvability |
| 20 | 4 | ||
| 21 | var compass | 5 | var compass |
| @@ -138,7 +122,7 @@ func _ready(): | |||
| 138 | 122 | ||
| 139 | get_parent().add_child.call_deferred(locationListener) | 123 | get_parent().add_child.call_deferred(locationListener) |
| 140 | 124 | ||
| 141 | if kEndingNameByVictoryValue.get(ap.victory_condition, null) == ending.get_name(): | 125 | if ap.kEndingNameByVictoryValue.get(ap.victory_condition, null) == ending.get_name(): |
| 142 | var victoryListener = ap.SCRIPT_victoryListener.new() | 126 | var victoryListener = ap.SCRIPT_victoryListener.new() |
| 143 | victoryListener.name = "victoryListener" | 127 | victoryListener.name = "victoryListener" |
| 144 | victoryListener.senders.append(NodePath("/root/scene/" + ending.get_path())) | 128 | victoryListener.senders.append(NodePath("/root/scene/" + ending.get_path())) |
| @@ -216,9 +200,9 @@ func _ready(): | |||
| 216 | 200 | ||
| 217 | var sign2 = sign_prefab.instantiate() | 201 | var sign2 = sign_prefab.instantiate() |
| 218 | sign2.position = Vector3(-7, 4, -15.01) | 202 | sign2.position = Vector3(-7, 4, -15.01) |
| 219 | sign2.text = "%s ending" % kEndingNameByVictoryValue.get(ap.victory_condition, "?") | 203 | sign2.text = "%s ending" % ap.kEndingNameByVictoryValue.get(ap.victory_condition, "?") |
| 220 | 204 | ||
| 221 | var sign2_color = kEndingNameByVictoryValue.get(ap.victory_condition, "coral").to_lower() | 205 | var sign2_color = ap.kEndingNameByVictoryValue.get(ap.victory_condition, "coral").to_lower() |
| 222 | if sign2_color == "white": | 206 | if sign2_color == "white": |
| 223 | sign2_color = "silver" | 207 | sign2_color = "silver" |
| 224 | 208 | ||
| diff --git a/apworld/client/textclient.gd b/apworld/client/textclient.gd index 0c4e675..530eddb 100644 --- a/apworld/client/textclient.gd +++ b/apworld/client/textclient.gd | |||
| @@ -10,6 +10,7 @@ var is_open = false | |||
| 10 | var locations_overlay | 10 | var locations_overlay |
| 11 | var location_texture | 11 | var location_texture |
| 12 | var worldport_texture | 12 | var worldport_texture |
| 13 | var goal_texture | ||
| 13 | 14 | ||
| 14 | var worldports_tab | 15 | var worldports_tab |
| 15 | var worldports_tree | 16 | var worldports_tree |
| @@ -116,6 +117,10 @@ func _ready(): | |||
| 116 | worldport_image.load_png_from_buffer(runtime.read_path("assets/worldport.png")) | 117 | worldport_image.load_png_from_buffer(runtime.read_path("assets/worldport.png")) |
| 117 | worldport_texture = ImageTexture.create_from_image(worldport_image) | 118 | worldport_texture = ImageTexture.create_from_image(worldport_image) |
| 118 | 119 | ||
| 120 | var goal_image = Image.new() | ||
| 121 | goal_image.load_png_from_buffer(runtime.read_path("assets/goal.png")) | ||
| 122 | goal_texture = ImageTexture.create_from_image(goal_image) | ||
| 123 | |||
| 119 | 124 | ||
| 120 | func _input(event): | 125 | func _input(event): |
| 121 | if global.loaded and event is InputEventKey and event.pressed: | 126 | if global.loaded and event is InputEventKey and event.pressed: |
| @@ -179,6 +184,7 @@ func update_locations(): | |||
| 179 | 184 | ||
| 180 | const kLocation = 0 | 185 | const kLocation = 0 |
| 181 | const kWorldport = 1 | 186 | const kWorldport = 1 |
| 187 | const kGoal = 2 | ||
| 182 | 188 | ||
| 183 | var location_names = [] | 189 | var location_names = [] |
| 184 | var type_by_name = {} | 190 | var type_by_name = {} |
| @@ -196,6 +202,13 @@ func update_locations(): | |||
| 196 | 202 | ||
| 197 | location_names.sort() | 203 | location_names.sort() |
| 198 | 204 | ||
| 205 | if ap.client._goal_accessible: | ||
| 206 | var location_name = gamedata.ending_display_name_by_name[ap.kEndingNameByVictoryValue[ | ||
| 207 | ap.victory_condition | ||
| 208 | ]] | ||
| 209 | location_names.push_front(location_name) | ||
| 210 | type_by_name[location_name] = kGoal | ||
| 211 | |||
| 199 | var count = 0 | 212 | var count = 0 |
| 200 | for location_name in location_names: | 213 | for location_name in location_names: |
| 201 | tracker_label.append_text("[p]%s[/p]" % location_name) | 214 | tracker_label.append_text("[p]%s[/p]" % location_name) |
| @@ -207,6 +220,8 @@ func update_locations(): | |||
| 207 | locations_overlay.add_image(location_texture) | 220 | locations_overlay.add_image(location_texture) |
| 208 | elif type_by_name[location_name] == kWorldport: | 221 | elif type_by_name[location_name] == kWorldport: |
| 209 | locations_overlay.add_image(worldport_texture) | 222 | locations_overlay.add_image(worldport_texture) |
| 223 | elif type_by_name[location_name] == kGoal: | ||
| 224 | locations_overlay.add_image(goal_texture) | ||
| 210 | locations_overlay.pop() | 225 | locations_overlay.pop() |
| 211 | count += 1 | 226 | count += 1 |
| 212 | 227 | ||
| diff --git a/apworld/context.py b/apworld/context.py index 4b78517..0e1a125 100644 --- a/apworld/context.py +++ b/apworld/context.py | |||
| @@ -10,7 +10,7 @@ import Utils | |||
| 10 | import settings | 10 | import settings |
| 11 | from BaseClasses import ItemClassification | 11 | from BaseClasses import ItemClassification |
| 12 | from CommonClient import CommonContext, server_loop, gui_enabled, logger, get_base_parser, handle_url_arg | 12 | from CommonClient import CommonContext, server_loop, gui_enabled, logger, get_base_parser, handle_url_arg |
| 13 | from NetUtils import Endpoint, decode, encode | 13 | from NetUtils import Endpoint, decode, encode, ClientStatus |
| 14 | from Utils import async_start | 14 | from Utils import async_start |
| 15 | from . import Lingo2World | 15 | from . import Lingo2World |
| 16 | from .tracker import Tracker | 16 | from .tracker import Tracker |
| @@ -36,6 +36,7 @@ class Lingo2Manager: | |||
| 36 | 36 | ||
| 37 | keyboard: dict[str, int] | 37 | keyboard: dict[str, int] |
| 38 | worldports: set[int] | 38 | worldports: set[int] |
| 39 | goaled: bool | ||
| 39 | 40 | ||
| 40 | def __init__(self, game_ctx: "Lingo2GameContext", client_ctx: "Lingo2ClientContext"): | 41 | def __init__(self, game_ctx: "Lingo2GameContext", client_ctx: "Lingo2ClientContext"): |
| 41 | self.game_ctx = game_ctx | 42 | self.game_ctx = game_ctx |
| @@ -53,6 +54,7 @@ class Lingo2Manager: | |||
| 53 | self.keyboard[k] = 0 | 54 | self.keyboard[k] = 0 |
| 54 | 55 | ||
| 55 | self.worldports = set() | 56 | self.worldports = set() |
| 57 | self.goaled = False | ||
| 56 | 58 | ||
| 57 | def update_keyboard(self, new_keyboard: dict[str, int]) -> dict[str, int]: | 59 | def update_keyboard(self, new_keyboard: dict[str, int]) -> dict[str, int]: |
| 58 | ret: dict[str, int] = {} | 60 | ret: dict[str, int] = {} |
| @@ -177,6 +179,9 @@ class Lingo2GameContext: | |||
| 177 | if len(self.manager.tracker.accessible_worldports) > 0: | 179 | if len(self.manager.tracker.accessible_worldports) > 0: |
| 178 | msg["worldports"] = list(self.manager.tracker.accessible_worldports) | 180 | msg["worldports"] = list(self.manager.tracker.accessible_worldports) |
| 179 | 181 | ||
| 182 | if self.manager.tracker.goal_accessible and not self.manager.goaled: | ||
| 183 | msg["goal"] = True | ||
| 184 | |||
| 180 | async_start(self.send_msgs([msg]), name="accessible locations") | 185 | async_start(self.send_msgs([msg]), name="accessible locations") |
| 181 | 186 | ||
| 182 | def send_update_locations(self, locations): | 187 | def send_update_locations(self, locations): |
| @@ -226,6 +231,7 @@ class Lingo2ClientContext(CommonContext): | |||
| 226 | items_handling = 0b111 | 231 | items_handling = 0b111 |
| 227 | 232 | ||
| 228 | slot_data: dict[str, Any] | None | 233 | slot_data: dict[str, Any] | None |
| 234 | victory_data_storage_key: str | ||
| 229 | 235 | ||
| 230 | def __init__(self, server_address: str | None = None, password: str | None = None): | 236 | def __init__(self, server_address: str | None = None, password: str | None = None): |
| 231 | super().__init__(server_address, password) | 237 | super().__init__(server_address, password) |
| @@ -253,7 +259,10 @@ class Lingo2ClientContext(CommonContext): | |||
| 253 | self.manager.tracker.set_checked_locations(self.checked_locations) | 259 | self.manager.tracker.set_checked_locations(self.checked_locations) |
| 254 | self.manager.game_ctx.send_accessible_locations() | 260 | self.manager.game_ctx.send_accessible_locations() |
| 255 | 261 | ||
| 256 | self.set_notify(self.get_datastorage_key("keyboard1"), self.get_datastorage_key("keyboard2")) | 262 | self.victory_data_storage_key = f"_read_client_status_{self.team}_{self.slot}" |
| 263 | |||
| 264 | self.set_notify(self.get_datastorage_key("keyboard1"), self.get_datastorage_key("keyboard2"), | ||
| 265 | self.victory_data_storage_key) | ||
| 257 | msg_batch = [{ | 266 | msg_batch = [{ |
| 258 | "cmd": "Set", | 267 | "cmd": "Set", |
| 259 | "key": self.get_datastorage_key("keyboard1"), | 268 | "key": self.get_datastorage_key("keyboard1"), |
| @@ -360,6 +369,9 @@ class Lingo2ClientContext(CommonContext): | |||
| 360 | }) | 369 | }) |
| 361 | 370 | ||
| 362 | self.manager.game_ctx.send_location_info(locations) | 371 | self.manager.game_ctx.send_location_info(locations) |
| 372 | elif cmd == "Received": | ||
| 373 | if args["key"] == self.victory_data_storage_key: | ||
| 374 | self.handle_status_update(args["value"]) | ||
| 363 | elif cmd == "SetReply": | 375 | elif cmd == "SetReply": |
| 364 | if args["key"] == self.get_datastorage_key("keyboard1"): | 376 | if args["key"] == self.get_datastorage_key("keyboard1"): |
| 365 | self.handle_keyboard_update(1, args) | 377 | self.handle_keyboard_update(1, args) |
| @@ -369,6 +381,8 @@ class Lingo2ClientContext(CommonContext): | |||
| 369 | updates = self.manager.update_worldports(set(args["value"])) | 381 | updates = self.manager.update_worldports(set(args["value"])) |
| 370 | if len(updates) > 0: | 382 | if len(updates) > 0: |
| 371 | self.manager.game_ctx.send_update_worldports(updates) | 383 | self.manager.game_ctx.send_update_worldports(updates) |
| 384 | elif args["key"] == self.victory_data_storage_key: | ||
| 385 | self.handle_status_update(args["value"]) | ||
| 372 | 386 | ||
| 373 | def get_datastorage_key(self, name: str): | 387 | def get_datastorage_key(self, name: str): |
| 374 | return f"Lingo2_{self.slot}_{name}" | 388 | return f"Lingo2_{self.slot}_{name}" |
| @@ -445,6 +459,11 @@ class Lingo2ClientContext(CommonContext): | |||
| 445 | }] | 459 | }] |
| 446 | }]) | 460 | }]) |
| 447 | 461 | ||
| 462 | def handle_status_update(self, value: int): | ||
| 463 | self.manager.goaled = (value == ClientStatus.CLIENT_GOAL) | ||
| 464 | self.manager.tracker.refresh_state() | ||
| 465 | self.manager.game_ctx.send_accessible_locations() | ||
| 466 | |||
| 448 | 467 | ||
| 449 | async def pipe_loop(manager: Lingo2Manager): | 468 | async def pipe_loop(manager: Lingo2Manager): |
| 450 | while not manager.client_ctx.exit_event.is_set(): | 469 | while not manager.client_ctx.exit_event.is_set(): |
| diff --git a/apworld/locations.py b/apworld/locations.py index a502931..3d619dc 100644 --- a/apworld/locations.py +++ b/apworld/locations.py | |||
| @@ -5,3 +5,4 @@ class Lingo2Location(Location): | |||
| 5 | game: str = "Lingo 2" | 5 | game: str = "Lingo 2" |
| 6 | 6 | ||
| 7 | port_id: int | 7 | port_id: int |
| 8 | goal: bool | ||
| diff --git a/apworld/regions.py b/apworld/regions.py index 9f44682..64302f6 100644 --- a/apworld/regions.py +++ b/apworld/regions.py | |||
| @@ -28,6 +28,9 @@ def create_locations(room, new_region: Region, world: "Lingo2World", regions: di | |||
| 28 | 28 | ||
| 29 | for event_name, item_name in world.player_logic.event_loc_item_by_room.get(room.id, {}).items(): | 29 | for event_name, item_name in world.player_logic.event_loc_item_by_room.get(room.id, {}).items(): |
| 30 | new_location = Lingo2Location(world.player, event_name, None, new_region) | 30 | new_location = Lingo2Location(world.player, event_name, None, new_region) |
| 31 | if world.for_tracker and item_name == "Victory": | ||
| 32 | new_location.goal = True | ||
| 33 | |||
| 31 | event_item = Lingo2Item(item_name, ItemClassification.progression, None, world.player) | 34 | event_item = Lingo2Item(item_name, ItemClassification.progression, None, world.player) |
| 32 | new_location.place_locked_item(event_item) | 35 | new_location.place_locked_item(event_item) |
| 33 | new_region.locations.append(new_location) | 36 | new_region.locations.append(new_location) |
| diff --git a/apworld/tracker.py b/apworld/tracker.py index cf2dbe1..7239b65 100644 --- a/apworld/tracker.py +++ b/apworld/tracker.py | |||
| @@ -22,6 +22,7 @@ class Tracker: | |||
| 22 | checked_locations: set[int] | 22 | checked_locations: set[int] |
| 23 | accessible_locations: set[int] | 23 | accessible_locations: set[int] |
| 24 | accessible_worldports: set[int] | 24 | accessible_worldports: set[int] |
| 25 | goal_accessible: bool | ||
| 25 | 26 | ||
| 26 | state: CollectionState | 27 | state: CollectionState |
| 27 | 28 | ||
| @@ -31,6 +32,7 @@ class Tracker: | |||
| 31 | self.checked_locations = set() | 32 | self.checked_locations = set() |
| 32 | self.accessible_locations = set() | 33 | self.accessible_locations = set() |
| 33 | self.accessible_worldports = set() | 34 | self.accessible_worldports = set() |
| 35 | self.goal_accessible = False | ||
| 34 | 36 | ||
| 35 | def setup_slot(self, slot_data): | 37 | def setup_slot(self, slot_data): |
| 36 | Lingo2World.for_tracker = True | 38 | Lingo2World.for_tracker = True |
| @@ -94,6 +96,7 @@ class Tracker: | |||
| 94 | 96 | ||
| 95 | self.accessible_locations = set() | 97 | self.accessible_locations = set() |
| 96 | self.accessible_worldports = set() | 98 | self.accessible_worldports = set() |
| 99 | self.goal_accessible = False | ||
| 97 | 100 | ||
| 98 | for region in self.state.reachable_regions[PLAYER_NUM]: | 101 | for region in self.state.reachable_regions[PLAYER_NUM]: |
| 99 | for location in region.locations: | 102 | for location in region.locations: |
| @@ -104,3 +107,6 @@ class Tracker: | |||
| 104 | elif hasattr(location, "port_id"): | 107 | elif hasattr(location, "port_id"): |
| 105 | if location.port_id not in self.manager.worldports: | 108 | if location.port_id not in self.manager.worldports: |
| 106 | self.accessible_worldports.add(location.port_id) | 109 | self.accessible_worldports.add(location.port_id) |
| 110 | elif hasattr(location, "goal") and location.goal: | ||
| 111 | if not self.manager.goaled: | ||
| 112 | self.goal_accessible = True | ||
