about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--apworld/client/assets/goal.pngbin0 -> 215 bytes
-rw-r--r--apworld/client/client.gd4
-rw-r--r--apworld/client/gamedata.gd5
-rw-r--r--apworld/client/manager.gd16
-rw-r--r--apworld/client/player.gd22
-rw-r--r--apworld/client/textclient.gd15
-rw-r--r--apworld/context.py23
-rw-r--r--apworld/locations.py1
-rw-r--r--apworld/player_logic.py9
-rw-r--r--apworld/regions.py3
-rw-r--r--apworld/tracker.py6
-rw-r--r--data/maps/daedalus/doors.txtpb1
12 files changed, 77 insertions, 28 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 = {}
24var _slot_data = {} 24var _slot_data = {}
25var _accessible_locations = [] 25var _accessible_locations = []
26var _accessible_worldports = [] 26var _accessible_worldports = []
27var _goal_accessible = false
27 28
28signal could_not_connect 29signal could_not_connect
29signal connect_status 30signal 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
66func disconnect_from_ap(): 68func 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 = {}
14var symbol_item_ids = [] 14var symbol_item_ids = []
15var anti_trap_ids = {} 15var anti_trap_ids = {}
16var location_name_by_id = {} 16var location_name_by_id = {}
17var ending_display_name_by_name = {}
17 18
18var kSYMBOL_ITEMS 19var 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
45const kCYAN_DOOR_BEHAVIOR_DOUBLE_LETTER = 1 45const kCYAN_DOOR_BEHAVIOR_DOUBLE_LETTER = 1
46const kCYAN_DOOR_BEHAVIOR_ITEM = 2 46const kCYAN_DOOR_BEHAVIOR_ITEM = 2
47 47
48const 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
48var apworld_version = [0, 0] 64var apworld_version = [0, 0]
49var cyan_door_behavior = kCYAN_DOOR_BEHAVIOR_H2 65var cyan_door_behavior = kCYAN_DOOR_BEHAVIOR_H2
50var daedalus_roof_access = false 66var 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 @@
1extends "res://scripts/nodes/player.gd" 1extends "res://scripts/nodes/player.gd"
2 2
3const 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
19signal evaluate_solvability 3signal evaluate_solvability
20 4
21var compass 5var 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
10var locations_overlay 10var locations_overlay
11var location_texture 11var location_texture
12var worldport_texture 12var worldport_texture
13var goal_texture
13 14
14var worldports_tab 15var worldports_tab
15var worldports_tree 16var 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
120func _input(event): 125func _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
10import settings 10import settings
11from BaseClasses import ItemClassification 11from BaseClasses import ItemClassification
12from CommonClient import CommonContext, server_loop, gui_enabled, logger, get_base_parser, handle_url_arg 12from CommonClient import CommonContext, server_loop, gui_enabled, logger, get_base_parser, handle_url_arg
13from NetUtils import Endpoint, decode, encode 13from NetUtils import Endpoint, decode, encode, ClientStatus
14from Utils import async_start 14from Utils import async_start
15from . import Lingo2World 15from . import Lingo2World
16from .tracker import Tracker 16from .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
449async def pipe_loop(manager: Lingo2Manager): 468async 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/player_logic.py b/apworld/player_logic.py index 8f2bd59..5be066d 100644 --- a/apworld/player_logic.py +++ b/apworld/player_logic.py
@@ -316,12 +316,9 @@ class Lingo2PlayerLogic:
316 AccessRequirements())) 316 AccessRequirements()))
317 317
318 for ending in world.static_logic.objects.endings: 318 for ending in world.static_logic.objects.endings:
319 # Don't ever create a location for White Ending. Don't even make an event for it if it's not the victory 319 # Don't create a location for your selected ending, and never create a location for White Ending.
320 # condition, since it is necessarily going to be in the postgame. 320 if world.options.victory_condition.current_key.removesuffix("_ending").upper() != ending.name\
321 if ending.name == "WHITE": 321 and ending.name != "WHITE":
322 if self.world.options.victory_condition != VictoryCondition.option_white_ending:
323 continue
324 else:
325 self.locations_by_room.setdefault(ending.room_id, []).append(PlayerLocation(ending.ap_id, 322 self.locations_by_room.setdefault(ending.room_id, []).append(PlayerLocation(ending.ap_id,
326 AccessRequirements())) 323 AccessRequirements()))
327 324
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
diff --git a/data/maps/daedalus/doors.txtpb b/data/maps/daedalus/doors.txtpb index 95a3537..6097e57 100644 --- a/data/maps/daedalus/doors.txtpb +++ b/data/maps/daedalus/doors.txtpb
@@ -1579,6 +1579,7 @@ doors {
1579 panels { room: "Salt Room" name: "SEASONING" } 1579 panels { room: "Salt Room" name: "SEASONING" }
1580 panels { room: "Pepper Room" name: "SEASONING" } 1580 panels { room: "Pepper Room" name: "SEASONING" }
1581 location_room: "Pepper Room" 1581 location_room: "Pepper Room"
1582 location_name: "Seasonings"
1582} 1583}
1583doors { 1584doors {
1584 name: "Bow Side" 1585 name: "Bow Side"