about summary refs log tree commit diff stats
path: root/Archipelago
diff options
context:
space:
mode:
Diffstat (limited to 'Archipelago')
-rw-r--r--Archipelago/client.gd260
-rw-r--r--Archipelago/extradata.gd99
-rw-r--r--Archipelago/load.gd43
-rw-r--r--Archipelago/multiplayer.gd2
-rw-r--r--Archipelago/notifier.gd14
-rw-r--r--Archipelago/painting.gd32
-rw-r--r--Archipelago/panel.gd17
-rw-r--r--Archipelago/player.gd29
-rw-r--r--Archipelago/settings_screen.gd2
-rw-r--r--Archipelago/textclient.gd3
-rw-r--r--Archipelago/tracker.gd89
11 files changed, 511 insertions, 79 deletions
diff --git a/Archipelago/client.gd b/Archipelago/client.gd index 350723e..fffd8c3 100644 --- a/Archipelago/client.gd +++ b/Archipelago/client.gd
@@ -5,10 +5,10 @@ var SCRIPT_effects
5var SCRIPT_location 5var SCRIPT_location
6var SCRIPT_multiplayer 6var SCRIPT_multiplayer
7var SCRIPT_mypainting 7var SCRIPT_mypainting
8var SCRIPT_notifier
9var SCRIPT_panel 8var SCRIPT_panel
10var SCRIPT_pilgrimage_terminator 9var SCRIPT_pilgrimage_terminator
11var SCRIPT_textclient 10var SCRIPT_textclient
11var SCRIPT_tracker
12var SCRIPT_uuid 12var SCRIPT_uuid
13 13
14var ap_server = "" 14var ap_server = ""
@@ -19,12 +19,12 @@ var enable_multiplayer = false
19var track_player = false 19var track_player = false
20var connection_history = [] 20var connection_history = []
21 21
22const my_version = "4.2.0" 22const my_version = "5.4.0"
23const ap_version = {"major": 0, "minor": 5, "build": 0, "class": "Version"} 23const ap_version = {"major": 0, "minor": 5, "build": 1, "class": "Version"}
24const color_items = [ 24const color_items = [
25 "White", "Black", "Red", "Blue", "Green", "Brown", "Gray", "Orange", "Purple", "Yellow" 25 "White", "Black", "Red", "Blue", "Green", "Brown", "Gray", "Orange", "Purple", "Yellow"
26] 26]
27const progressive_items = { 27const door_progressive_items = {
28 "Progressive Orange Tower": 28 "Progressive Orange Tower":
29 ["Second Floor", "Third Floor", "Fourth Floor", "Fifth Floor", "Sixth Floor", "Seventh Floor"], 29 ["Second Floor", "Third Floor", "Fourth Floor", "Fifth Floor", "Sixth Floor", "Seventh Floor"],
30 "Progressive Art Gallery": 30 "Progressive Art Gallery":
@@ -36,6 +36,15 @@ const progressive_items = {
36 "Progressive Pilgrimage": 36 "Progressive Pilgrimage":
37 ["1 Sunwarp", "2 Sunwarp", "3 Sunwarp", "4 Sunwarp", "5 Sunwarp", "6 Sunwarp"] 37 ["1 Sunwarp", "2 Sunwarp", "3 Sunwarp", "4 Sunwarp", "5 Sunwarp", "6 Sunwarp"]
38} 38}
39const panel_progressive_items = {
40 "Progressive Hallway Room": ["First Door", "Second Door", "Third Door", "Fourth Door"],
41 "Progressive Colorful":
42 ["White", "Black", "Red", "Yellow", "Blue", "Purple", "Orange", "Green", "Brown", "Gray"],
43 "Progressive Number Hunt":
44 ["Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Zero"],
45 "Progressive Symmetry Room": ["Near Far", "Warts Straw", "Leaf Feel"],
46 "Progressive Suits Area": ["Words Sword", "Lost", "Amen Name"]
47}
39 48
40const kTHE_END = 0 49const kTHE_END = 0
41const kTHE_MASTER = 1 50const kTHE_MASTER = 1
@@ -90,6 +99,7 @@ var _localdata_file = ""
90var _death_link = false 99var _death_link = false
91var _victory_condition = 0 # THE END, THE MASTER, LEVEL 2 100var _victory_condition = 0 # THE END, THE MASTER, LEVEL 2
92var _door_shuffle = false 101var _door_shuffle = false
102var _panel_door_shuffle = false
93var _color_shuffle = false 103var _color_shuffle = false
94var _panel_shuffle = 0 # none, rearrange 104var _panel_shuffle = 0 # none, rearrange
95var _painting_shuffle = false 105var _painting_shuffle = false
@@ -121,6 +131,17 @@ var _cached_atbash = 0
121var _cached_speed_boosts = 0 131var _cached_speed_boosts = 0
122var _geronimo_skip = false 132var _geronimo_skip = false
123var _checked_paintings = [] 133var _checked_paintings = []
134var _hints_key = ""
135var _hinted_locations = []
136var _batch_messages = false
137var _held_messages = {}
138var _held_panels = []
139var _held_synced_panels = []
140var _solved_panels = []
141
142var _panelsBySolveIndex = {}
143const kPANEL_BITFIELDS = 17 # 800 / 48
144const kPANEL_BITFIELD_LENGTH = 48
124 145
125signal could_not_connect 146signal could_not_connect
126signal connect_status 147signal connect_status
@@ -176,6 +197,8 @@ func _reset_state():
176 _authenticated = false 197 _authenticated = false
177 _map_loaded = false 198 _map_loaded = false
178 _try_wss = false 199 _try_wss = false
200 _panelsBySolveIndex = {}
201 _solved_panels = []
179 202
180 203
181func _errored(): 204func _errored():
@@ -278,9 +301,15 @@ func _on_data():
278 _color_shuffle = _slot_data["shuffle_colors"] 301 _color_shuffle = _slot_data["shuffle_colors"]
279 302
280 if _slot_data.has("shuffle_doors"): 303 if _slot_data.has("shuffle_doors"):
281 _door_shuffle = (_slot_data["shuffle_doors"] > 0) 304 if _slot_data.has("group_doors"):
305 _door_shuffle = (_slot_data["shuffle_doors"] == 2)
306 _panel_door_shuffle = (_slot_data["shuffle_doors"] == 1)
307 else:
308 _door_shuffle = (_slot_data["shuffle_doors"] > 0)
309 _panel_door_shuffle = false
282 else: 310 else:
283 _door_shuffle = false 311 _door_shuffle = false
312 _panel_door_shuffle = false
284 313
285 if _slot_data.has("shuffle_paintings"): 314 if _slot_data.has("shuffle_paintings"):
286 _painting_shuffle = _slot_data["shuffle_paintings"] 315 _painting_shuffle = _slot_data["shuffle_paintings"]
@@ -391,17 +420,33 @@ func _on_data():
391 420
392 requestSync() 421 requestSync()
393 422
394 sendMessage( 423 _hints_key = "_read_hints_%d_%d" % [_team, _slot]
395 [ 424
396 { 425 var cmds = [
397 "cmd": "Set", 426 {
398 "key": "Lingo_%d_Paintings" % [_slot], 427 "cmd": "Set",
399 "default": [], 428 "key": "Lingo_%d_Paintings" % [_slot],
400 "want_reply": true, 429 "default": [],
401 "operations": [{"operation": "default", "value": []}] 430 "want_reply": true,
402 } 431 "operations": [{"operation": "default", "value": []}]
403 ] 432 },
404 ) 433 {"cmd": "Get", "keys": [_hints_key]}
434 ]
435
436 var set_notifies = [_hints_key]
437 for k in range(0, kPANEL_BITFIELDS):
438 var panel_key = "Lingo_%d_Panels_%d" % [_slot, k]
439 set_notifies.append(panel_key)
440 cmds.append({
441 "cmd": "Set",
442 "key": panel_key,
443 "default": 0,
444 "operations": [{"operation": "default", "value": 0}]
445 })
446
447 cmds.append({"cmd": "SetNotify", "keys": set_notifies})
448
449 sendMessage(cmds)
405 450
406 emit_signal("client_connected") 451 emit_signal("client_connected")
407 452
@@ -500,9 +545,12 @@ func _on_data():
500 ) 545 )
501 else: 546 else:
502 if message["receiving"] != _slot: 547 if message["receiving"] != _slot:
503 messages.showMessage( 548 var sentMsg = (
504 "Sent [color=%s]%s[/color] to %s" % [item_color, item_name, player_name] 549 "Sent [color=%s]%s[/color] to %s" % [item_color, item_name, player_name]
505 ) 550 )
551 if _hinted_locations.has(message["item"]["location"]):
552 sentMsg += " ([color=#fafad2]Hinted![/color])"
553 messages.showMessage(sentMsg)
506 554
507 elif cmd == "Bounced": 555 elif cmd == "Bounced":
508 if ( 556 if (
@@ -523,8 +571,22 @@ func _on_data():
523 get_tree().get_root().get_node("Spatial/player/pause_menu")._reload() 571 get_tree().get_root().get_node("Spatial/player/pause_menu")._reload()
524 572
525 elif cmd == "SetReply": 573 elif cmd == "SetReply":
526 if message.has("key") and message["key"] == ("Lingo_%d_Paintings" % _slot): 574 if message.has("key"):
527 _checked_paintings = message["value"] 575 if message["key"] == ("Lingo_%d_Paintings" % _slot):
576 _checked_paintings = message["value"]
577 elif message["key"] == _hints_key:
578 parseHints(message["value"])
579 elif message["key"].begins_with("Lingo_%d_Panels_" % _slot):
580 var key_index = int(message["key"].substr(("Lingo_%d_Panels_" % _slot).length()))
581 var field_value = int(message["value"])
582 for k in range(0, kPANEL_BITFIELD_LENGTH):
583 if field_value & (1 << k) != 0:
584 var panel_index = key_index * kPANEL_BITFIELD_LENGTH + k
585 syncSolvedPanel(panel_index)
586
587 elif cmd == "Retrieved":
588 if message.has("keys") and message["keys"].has(_hints_key):
589 parseHints(message["keys"][_hints_key])
528 590
529 591
530func _process(_delta): 592func _process(_delta):
@@ -715,14 +777,53 @@ func mapFinishedLoading():
715 _has_colors = ["white"] 777 _has_colors = ["white"]
716 emit_signal("evaluate_solvability") 778 emit_signal("evaluate_solvability")
717 779
780 messages.showMessage("Press TAB to open the text client.")
781
782 _held_messages.clear()
783 _batch_messages = true
718 for item in _held_items: 784 for item in _held_items:
719 processItem(item["item"], item["index"], item["from"], item["flags"]) 785 processItem(item["item"], item["index"], item["from"], item["flags"])
786 _batch_messages = false
787
788 for item_name in _held_messages:
789 if _held_messages[item_name][1].size() > 1:
790 messages.showMessage(
791 (
792 "Received [color=%s]%s[/color] (x%d)"
793 % [
794 _held_messages[item_name][0],
795 item_name,
796 _held_messages[item_name][1].size()
797 ]
798 )
799 )
800 else:
801 messages.showMessage(_held_messages[item_name][1][0])
720 802
721 sendMessage([{"cmd": "LocationChecks", "locations": _held_locations}]) 803 sendMessage([{"cmd": "LocationChecks", "locations": _held_locations}])
722 804
805 var panel_data = []
806 for k in range(0, kPANEL_BITFIELDS):
807 panel_data.append(0)
808
809 for panel_index in _held_panels:
810 var key_index = panel_index / kPANEL_BITFIELD_LENGTH
811 var field_slot = panel_index % kPANEL_BITFIELD_LENGTH
812 panel_data[key_index] = panel_data[key_index] | (1 << field_slot)
813
814 for k in range(0, kPANEL_BITFIELDS):
815 if panel_data[k] != 0:
816 setValue("Panels_%d" % k, panel_data[k], "or")
817
723 _map_loaded = true 818 _map_loaded = true
819
820 for synced in _held_synced_panels:
821 syncSolvedPanel(synced)
822
724 _held_items = [] 823 _held_items = []
725 _held_locations = [] 824 _held_locations = []
825 _held_panels = []
826 _held_synced_panels = []
726 827
727 828
728func processItem(item, index, from, flags): 829func processItem(item, index, from, flags):
@@ -745,6 +846,18 @@ func processItem(item, index, from, flags):
745 for door_id in gamedata.door_ids_by_item_id[int(item)]: 846 for door_id in gamedata.door_ids_by_item_id[int(item)]:
746 doorsNode.get_node(door_id).openDoor() 847 doorsNode.get_node(door_id).openDoor()
747 848
849 if gamedata.panel_ids_by_item_id.has(int(item)):
850 var panel_ids = gamedata.panel_ids_by_item_id[int(item)]
851 if wasGeneratedOnVersion(0, 5, 1):
852 var extradata = get_node("Extradata")
853 if extradata.panels_mode_051_panel_fixes.has(int(item)):
854 panel_ids = extradata.panels_mode_051_panel_fixes[int(item)]
855
856 var panelsNode = get_tree().get_root().get_node("Spatial/Panels")
857 for panel_id in panel_ids:
858 panelsNode.get_node(panel_id).get_node("AP_Panel").locked = false
859 emit_signal("evaluate_solvability")
860
748 if gamedata.painting_ids_by_item_id.has(int(item)): 861 if gamedata.painting_ids_by_item_id.has(int(item)):
749 var real_parent_node = get_tree().get_root().get_node("Spatial/Decorations/Paintings") 862 var real_parent_node = get_tree().get_root().get_node("Spatial/Decorations/Paintings")
750 var fake_parent_node = get_tree().get_root().get_node_or_null("Spatial/AP_Paintings") 863 var fake_parent_node = get_tree().get_root().get_node_or_null("Spatial/AP_Paintings")
@@ -765,19 +878,38 @@ func processItem(item, index, from, flags):
765 warpsNode.get_node(warp_id).unlock_warp() 878 warpsNode.get_node(warp_id).unlock_warp()
766 879
767 # Handle progressive items. 880 # Handle progressive items.
768 if int(item) in gamedata.items_by_progressive_id.keys(): 881 var is_progressive_door = int(item) in gamedata.door_items_by_progressive_id
882 var is_progressive_panel = int(item) in gamedata.panel_items_by_progressive_id
883 var progitems = null
884 var prognames = null
885
886 if is_progressive_door and is_progressive_panel:
887 if _door_shuffle:
888 progitems = gamedata.door_items_by_progressive_id[int(item)]
889 prognames = door_progressive_items
890 else:
891 progitems = gamedata.panel_items_by_progressive_id[int(item)]
892 prognames = panel_progressive_items
893 elif is_progressive_door:
894 progitems = gamedata.door_items_by_progressive_id[int(item)]
895 prognames = door_progressive_items
896 elif is_progressive_panel:
897 progitems = gamedata.panel_items_by_progressive_id[int(item)]
898 prognames = panel_progressive_items
899
900 if progitems != null:
769 if not int(item) in _progressive_progress: 901 if not int(item) in _progressive_progress:
770 _progressive_progress[int(item)] = 0 902 _progressive_progress[int(item)] = 0
771 903
772 if _progressive_progress[int(item)] < gamedata.items_by_progressive_id[int(item)].size(): 904 if _progressive_progress[int(item)] < progitems.size():
773 var subitems = gamedata.items_by_progressive_id[int(item)] 905 var subitem_id = progitems[_progressive_progress[int(item)]]
774 var subitem_id = subitems[_progressive_progress[int(item)]]
775 global._print("Subitem: %d" % subitem_id) 906 global._print("Subitem: %d" % subitem_id)
776 processItem(subitem_id, null, null, null) 907 processItem(subitem_id, null, null, null)
908 item_name += " (%s)" % prognames[item_name][_progressive_progress[int(item)]]
777 _progressive_progress[int(item)] += 1 909 _progressive_progress[int(item)] += 1
778 910
779 if _color_shuffle and color_items.has(_item_id_to_name["Lingo"][item]): 911 if _color_shuffle and color_items.has(_item_id_to_name["Lingo"][float(item)]):
780 var lcol = _item_id_to_name["Lingo"][item].to_lower() 912 var lcol = _item_id_to_name["Lingo"][float(item)].to_lower()
781 if not _has_colors.has(lcol): 913 if not _has_colors.has(lcol):
782 _has_colors.append(lcol) 914 _has_colors.append(lcol)
783 emit_signal("evaluate_solvability") 915 emit_signal("evaluate_solvability")
@@ -787,31 +919,36 @@ func processItem(item, index, from, flags):
787 _last_new_item = index 919 _last_new_item = index
788 saveLocaldata() 920 saveLocaldata()
789 921
790 if item_name in progressive_items:
791 var subitem = progressive_items[item_name][_progressive_progress[int(item)] - 1]
792 item_name += " (%s)" % subitem
793
794 var player_name = "Unknown" 922 var player_name = "Unknown"
795 if _player_name_by_slot.has(from): 923 if _player_name_by_slot.has(from):
796 player_name = _player_name_by_slot[from] 924 player_name = _player_name_by_slot[from]
797 925
798 var item_color = colorForItemType(flags) 926 var item_color = colorForItemType(flags)
799 927
928 var message
800 if from == _slot: 929 if from == _slot:
801 messages.showMessage("Found [color=%s]%s[/color]" % [item_color, item_name]) 930 message = "Found [color=%s]%s[/color]" % [item_color, item_name]
802 else: 931 else:
803 messages.showMessage( 932 message = "Received [color=%s]%s[/color] from %s" % [item_color, item_name, player_name]
804 "Received [color=%s]%s[/color] from %s" % [item_color, item_name, player_name] 933
805 ) 934 global._print(message)
935
936 if _batch_messages:
937 if _held_messages.has(item_name):
938 _held_messages[item_name][1].append(message)
939 else:
940 _held_messages[item_name] = [item_color, [message]]
941 else:
942 messages.showMessage(message)
806 943
807 var effects_node = get_tree().get_root().get_node("Spatial/AP_Effects") 944 var effects_node = get_tree().get_root().get_node("Spatial/AP_Effects")
808 if item_name == "Slowness Trap": 945 if item_name == "Slowness Trap" and !_speed_boost_mode:
809 effects_node.trigger_slowness_trap() 946 effects_node.trigger_slowness_trap()
810 if item_name == "Iceland Trap": 947 if item_name == "Iceland Trap":
811 effects_node.trigger_iceland_trap() 948 effects_node.trigger_iceland_trap()
812 if item_name == "Atbash Trap": 949 if item_name == "Atbash Trap":
813 effects_node.trigger_atbash_trap() 950 effects_node.trigger_atbash_trap()
814 if item_name == "Speed Boost": 951 if item_name == "Speed Boost" and _speed_boost_mode:
815 effects_node.trigger_speed_boost() 952 effects_node.trigger_speed_boost()
816 if item_name == "Puzzle Skip": 953 if item_name == "Puzzle Skip":
817 _puzzle_skips += 1 954 _puzzle_skips += 1
@@ -819,6 +956,24 @@ func processItem(item, index, from, flags):
819 saveLocaldata() 956 saveLocaldata()
820 957
821 958
959func syncSolvedPanel(panel_index):
960 if _solved_panels.has(panel_index):
961 return
962
963 if _map_loaded:
964 var panel_name = _panelsBySolveIndex[panel_index]
965 global._print("Synced solved panel %d: %s" % [panel_index, panel_name])
966
967 if !panel_name.begins_with("EndPanel"):
968 var the_panel = get_tree().get_root().get_node("Spatial/Panels").get_node(panel_name)
969
970 if !the_panel.is_complete:
971 the_panel.get_node("AP_Panel").solved_remotely = true
972 the_panel.get_node("Viewport/GUI/Panel/TextEdit").complete()
973 else:
974 _held_synced_panels.append(panel_index)
975
976
822func doorIsVanilla(door): 977func doorIsVanilla(door):
823 return !$Gamedata.mentioned_doors.has(door) 978 return !$Gamedata.mentioned_doors.has(door)
824 979
@@ -863,10 +1018,35 @@ func checkPainting(painting_id):
863 setValue("Paintings", [painting_id], "add") 1018 setValue("Paintings", [painting_id], "add")
864 1019
865 1020
1021func solvePanel(panel_index, solved_remotely=false):
1022 _solved_panels.append(panel_index)
1023
1024 if solved_remotely:
1025 return
1026
1027 if _map_loaded:
1028 var key_index = panel_index / kPANEL_BITFIELD_LENGTH
1029 var field_slot = panel_index % kPANEL_BITFIELD_LENGTH
1030 setValue("Panels_%d" % key_index, 1 << field_slot, "or")
1031 else:
1032 _held_panels.append(panel_index)
1033
1034
1035func parseHints(hints):
1036 _hinted_locations.clear()
1037
1038 for hint in hints:
1039 if hint["finding_player"] == int(_slot):
1040 _hinted_locations.append(hint["location"])
1041
1042
866func colorForItemType(flags): 1043func colorForItemType(flags):
867 var int_flags = int(flags) 1044 var int_flags = int(flags)
868 if int_flags & 1: # progression 1045 if int_flags & 1: # progression
869 return "#bc51e0" 1046 if int_flags & 2: # proguseful
1047 return "#f0d200"
1048 else:
1049 return "#bc51e0"
870 elif int_flags & 2: # useful 1050 elif int_flags & 2: # useful
871 return "#2b67ff" 1051 return "#2b67ff"
872 elif int_flags & 4: # trap 1052 elif int_flags & 4: # trap
@@ -928,3 +1108,11 @@ func compareVersion(lhs, rhs):
928 1108
929func wasGeneratedBeforeVersion(major, minor, build): 1109func wasGeneratedBeforeVersion(major, minor, build):
930 return compareVersion(_gen_version, {"major": major, "minor": minor, "build": build}) 1110 return compareVersion(_gen_version, {"major": major, "minor": minor, "build": build})
1111
1112
1113func wasGeneratedOnVersion(major, minor, build):
1114 return (
1115 _gen_version["major"] == major
1116 and _gen_version["minor"] == minor
1117 and _gen_version["build"] == build
1118 )
diff --git a/Archipelago/extradata.gd b/Archipelago/extradata.gd index 89c41d2..c90433a 100644 --- a/Archipelago/extradata.gd +++ b/Archipelago/extradata.gd
@@ -93,3 +93,102 @@ var proxies = {
93 "Open Areas/Panel_rise_horizon": ["Open Areas/Panel_son_horizon"], 93 "Open Areas/Panel_rise_horizon": ["Open Areas/Panel_son_horizon"],
94 "Open Areas/Panel_son_sunrise": ["Open Areas/Panel_rise_sunrise"] 94 "Open Areas/Panel_son_sunrise": ["Open Areas/Panel_rise_sunrise"]
95} 95}
96
97var panels_mode_051_panel_fixes = {
98 444647:
99 [
100 "Backside Room/Panel_three_three",
101 "Backside Room/Panel_three_three_2",
102 "Backside Room/Panel_three_three_3",
103 "Backside Room/Panel_four_four_3",
104 "Backside Room/Panel_four_four_2",
105 "Backside Room/Panel_four_four_4"
106 ],
107 444648:
108 [
109 "Backside Room/Panel_four_four",
110 "Backside Room/Panel_five_five_5",
111 "Backside Room/Panel_five_five_4"
112 ],
113 444649:
114 [
115 "Backside Room/Panel_five_five",
116 "Backside Room/Panel_five_five_3",
117 "Backside Room/Panel_five_five_2",
118 "Backside Room/Panel_six_six_4"
119 ],
120 444650:
121 [
122 "Backside Room/Panel_six_six",
123 "Backside Room/Panel_six_six_3",
124 "Backside Room/Panel_six_six_2",
125 "Backside Room/Panel_six_six_5",
126 "Backside Room/Panel_six_six_6",
127 "Backside Room/Panel_seven_seven_5",
128 "Backside Room/Panel_seven_seven_6"
129 ],
130 444651:
131 [
132 "Backside Room/Panel_seven_seven",
133 "Backside Room/Panel_seven_seven_2",
134 "Backside Room/Panel_seven_seven_7",
135 "Backside Room/Panel_seven_seven_3",
136 "Backside Room/Panel_seven_seven_4",
137 "Backside Room/Panel_eight_eight_8",
138 "Backside Room/Panel_eight_eight_5",
139 "Backside Room/Panel_eight_eight_3",
140 "Backside Room/Panel_eight_eight_7"
141 ],
142 444652:
143 [
144 "Backside Room/Panel_eight_eight",
145 "Backside Room/Panel_eight_eight_2",
146 "Backside Room/Panel_eight_eight_4",
147 "Backside Room/Panel_eight_eight_6",
148 "Backside Room/Panel_nine_nine_3",
149 "Backside Room/Panel_nine_nine_8",
150 "Backside Room/Panel_nine_nine_4",
151 "Backside Room/Panel_nine_nine_5",
152 "Backside Room/Panel_nine_nine_2"
153 ],
154 444653:
155 [
156 "Backside Room/Panel_nine_nine",
157 "Backside Room/Panel_nine_nine_6",
158 "Backside Room/Panel_nine_nine_8",
159 "Backside Room/Panel_nine_nine_9",
160 "Backside Room/Panel_nine_nine_7"
161 ]
162}
163
164var panels_mode_051_door_fixes = {
165 "Door_four_hider": ["Door_four_hider_3", "Door_four_hider_4", "Door_four_hider_2"],
166 "Door_five_hider": ["Door_five_hider_4", "Door_five_hider_5"],
167 "Door_six_hider": ["Door_six_hider_4"],
168 "Door_seven_hider": ["Door_seven_hider_6", "Door_seven_hider_5"],
169 "Door_eight_hider":
170 ["Door_eight_hider_7", "Door_eight_hider_8", "Door_eight_hider_3", "Door_eight_hider_5"],
171 "Door_nine_hider":
172 [
173 "Door_nine_hider_3",
174 "Door_nine_hider_8",
175 "Door_nine_hider_4",
176 "Door_nine_hider_5",
177 "Door_nine_hider_2"
178 ]
179}
180
181var pilgrimage_061_painting_fixes = [
182 "outside2",
183 "outside_2",
184 "outside_3",
185 "outside_4",
186 "north2",
187 "south2",
188 "west2",
189 "east_enter",
190 "owl_painting_4",
191 "garden_painting",
192 "yinyang_painting",
193 "fruitbowl_painting2"
194]
diff --git a/Archipelago/load.gd b/Archipelago/load.gd index 09aaee2..b95e4c4 100644 --- a/Archipelago/load.gd +++ b/Archipelago/load.gd
@@ -120,6 +120,7 @@ func _load():
120 new_master_cdp.translation = old_master_cdp.translation 120 new_master_cdp.translation = old_master_cdp.translation
121 new_master_cdp.rotation = old_master_cdp.rotation 121 new_master_cdp.rotation = old_master_cdp.rotation
122 get_node("CountdownPanels").add_child(new_master_cdp) 122 get_node("CountdownPanels").add_child(new_master_cdp)
123 old_master_cdp.total = 5000
123 old_master_cdp.queue_free() 124 old_master_cdp.queue_free()
124 125
125 # Configure AN OTHER WAY. 126 # Configure AN OTHER WAY.
@@ -513,23 +514,6 @@ func _load():
513 fearless_door.name = "Door_hider_new1" 514 fearless_door.name = "Door_hider_new1"
514 fearless_door.translation.y = 5 515 fearless_door.translation.y = 5
515 get_node("Doors/Naps Room Doors").add_child(fearless_door) 516 get_node("Doors/Naps Room Doors").add_child(fearless_door)
516
517 # Set up notifiers for each achievement panel, for the tracker.
518 var notifier_script = apclient.SCRIPT_notifier
519 for panel in gamedata.panels:
520 if "achievement" in panel:
521 var panel_node = panels_parent.get_node(panel["id"])
522 var script_instance = notifier_script.new()
523 script_instance.name = "Achievement_Notifier"
524 script_instance.key = "Achievement|%s" % panel["achievement"]
525 panel_node.add_child(script_instance)
526
527 if "hunt" in panel and panel["hunt"] and not (gamedata.classification_by_location_id[panel["loc"]] & apclient._location_classification_bit):
528 var panel_node = panels_parent.get_node(panel["id"])
529 var script_instance = notifier_script.new()
530 script_instance.name = "Hunt_Notifier"
531 script_instance.key = "Hunt|%d" % panel["loc"]
532 panel_node.add_child(script_instance)
533 517
534 # Make stack/double puzzles into proxies, unless panelsanity is on. 518 # Make stack/double puzzles into proxies, unless panelsanity is on.
535 if apclient._location_classification_bit != apclient.kCLASSIFICATION_LOCAL_INSANITY: 519 if apclient._location_classification_bit != apclient.kCLASSIFICATION_LOCAL_INSANITY:
@@ -551,6 +535,20 @@ func _load():
551 proxynode.exact_proxy = true 535 proxynode.exact_proxy = true
552 proxynode.request_ready() 536 proxynode.request_ready()
553 oldparent.add_child(proxynode) 537 oldparent.add_child(proxynode)
538
539 # If the world was generated on 0.5.1, apply the hotfix for the number hunt doors.
540 if apclient._panel_door_shuffle && apclient.wasGeneratedOnVersion(0, 5, 1):
541 var number_hunt_parent = get_node("Doors/Count Up Room Area Doors")
542 var extradata_051_fix = apclient.get_node("Extradata").panels_mode_051_door_fixes
543 for template_door_path in extradata_051_fix:
544 var template_door = number_hunt_parent.get_node(template_door_path)
545 var impacted_doors = extradata_051_fix[template_door_path]
546 for impacted_door_path in impacted_doors:
547 var impacted_door = number_hunt_parent.get_node(impacted_door_path)
548 var copied_door = impacted_door.duplicate()
549 copied_door.panels = template_door.panels
550 number_hunt_parent.add_child(copied_door)
551 impacted_door.queue_free()
554 552
555 # Attach a script to every panel so that we can do things like conditionally 553 # Attach a script to every panel so that we can do things like conditionally
556 # disable them. 554 # disable them.
@@ -564,9 +562,14 @@ func _load():
564 var script_instance = panel_script.new() 562 var script_instance = panel_script.new()
565 script_instance.name = "AP_Panel" 563 script_instance.name = "AP_Panel"
566 script_instance.data = panel 564 script_instance.data = panel
565 script_instance.solve_index = panel["solve_index"]
566 if apclient._panel_door_shuffle and gamedata.mentioned_panels.has(panel["id"]):
567 script_instance.locked = true
567 panel_node.add_child(script_instance) 568 panel_node.add_child(script_instance)
568 apclient.connect("evaluate_solvability", script_instance, "evaluate_solvability") 569 apclient.connect("evaluate_solvability", script_instance, "evaluate_solvability")
569 570
571 apclient._panelsBySolveIndex[panel["solve_index"]] = panel["id"]
572
570 # Hook up the goal panel. 573 # Hook up the goal panel.
571 if apclient._victory_condition == apclient.kTHE_MASTER: 574 if apclient._victory_condition == apclient.kTHE_MASTER:
572 var the_master = self.get_node("Panels/Countdown Panels/Panel_master_master") 575 var the_master = self.get_node("Panels/Countdown Panels/Panel_master_master")
@@ -676,6 +679,12 @@ func _load():
676 multiplayer_node.ghost_mode = true 679 multiplayer_node.ghost_mode = true
677 add_child(multiplayer_node) 680 add_child(multiplayer_node)
678 681
682 # Create the autotracker node.
683 var autotracker_script = apclient.SCRIPT_tracker
684 var autotracker = autotracker_script.new()
685 autotracker.set_name("AP_Tracker")
686 self.add_child(autotracker)
687
679 # Hook up Geronimo handler. 688 # Hook up Geronimo handler.
680 $player.connect("player_jumped", apclient, "geronimo") 689 $player.connect("player_jumped", apclient, "geronimo")
681 690
diff --git a/Archipelago/multiplayer.gd b/Archipelago/multiplayer.gd index c2d9875..f2e4175 100644 --- a/Archipelago/multiplayer.gd +++ b/Archipelago/multiplayer.gd
@@ -43,7 +43,7 @@ func _update_lobby_members():
43 var member_id: int = Steam.getLobbyMemberByIndex(active_lobby_id, i) 43 var member_id: int = Steam.getLobbyMemberByIndex(active_lobby_id, i)
44 if member_id != player_steam_id and member_id in active_lobby_members: 44 if member_id != player_steam_id and member_id in active_lobby_members:
45 var slot_name = Steam.getLobbyMemberData(active_lobby_id, member_id, "slot_name") 45 var slot_name = Steam.getLobbyMemberData(active_lobby_id, member_id, "slot_name")
46 active_lobby_members[member_id].steam_name = slot_name 46 active_lobby_members[member_id].steam_name = "%s\n%s" % [slot_name, Steam.getFriendPersonaName(member_id)]
47 47
48 48
49func say(text): 49func say(text):
diff --git a/Archipelago/notifier.gd b/Archipelago/notifier.gd deleted file mode 100644 index 57d6564..0000000 --- a/Archipelago/notifier.gd +++ /dev/null
@@ -1,14 +0,0 @@
1extends Node
2
3var key
4
5
6func _ready():
7 self.get_parent().get_node("Viewport/GUI/Panel/TextEdit").connect(
8 "answer_correct", self, "handle_correct"
9 )
10
11
12func handle_correct():
13 var apclient = global.get_node("Archipelago")
14 apclient.setValue(key, true)
diff --git a/Archipelago/painting.gd b/Archipelago/painting.gd index adc8337..dc791ce 100644 --- a/Archipelago/painting.gd +++ b/Archipelago/painting.gd
@@ -1,10 +1,26 @@
1extends "res://scripts/painting.gd" 1extends "res://scripts/painting.gd"
2 2
3func _looked_at(var body, var painting): 3var breaks_pilgrimage = false
4 ._looked_at(body, painting) 4
5 5
6 if body.is_in_group("player") && (painting.get_name() == self.get_name()): 6func _ready():
7 var apclient = global.get_node("Archipelago") 7 var apclient = global.get_node("Archipelago")
8 if !apclient._pilgrimage_allows_paintings: 8 if !apclient._pilgrimage_allows_paintings:
9 global.sunwarp = 1 9 if apclient.wasGeneratedBeforeVersion(0, 6, 2):
10 body.get_node("pivot/camera/sunwarp_background").visible = false 10 var extradata = apclient.get_node("Extradata")
11 if not extradata.pilgrimage_061_painting_fixes.has(get_name()):
12 breaks_pilgrimage = true
13 else:
14 breaks_pilgrimage = true
15
16
17func _looked_at(body, painting):
18 ._looked_at(body, painting)
19
20 if (
21 breaks_pilgrimage
22 and body.is_in_group("player")
23 and (painting.get_name() == self.get_name())
24 ):
25 global.sunwarp = 1
26 body.get_node("pivot/camera/sunwarp_background").visible = false
diff --git a/Archipelago/panel.gd b/Archipelago/panel.gd index fc5963a..2224ffa 100644 --- a/Archipelago/panel.gd +++ b/Archipelago/panel.gd
@@ -5,6 +5,9 @@ var orig_text = ""
5var atbash_text = "" 5var atbash_text = ""
6var orig_color = Color(0, 0, 0, 0) 6var orig_color = Color(0, 0, 0, 0)
7var solvable = true 7var solvable = true
8var locked = false
9var solve_index = null
10var solved_remotely = false
8 11
9const kAtbashPre = "abcdefghijklmnopqrstuvwxyz1234567890+-" 12const kAtbashPre = "abcdefghijklmnopqrstuvwxyz1234567890+-"
10const kAtbashPost = "zyxwvutsrqponmlkjihgfedcba0987654321-+" 13const kAtbashPost = "zyxwvutsrqponmlkjihgfedcba0987654321-+"
@@ -31,6 +34,10 @@ func answer_correct():
31 var effects = get_tree().get_root().get_node("Spatial/AP_Effects") 34 var effects = get_tree().get_root().get_node("Spatial/AP_Effects")
32 effects.deactivate_atbash_trap() 35 effects.deactivate_atbash_trap()
33 36
37 if solve_index != null:
38 var apclient = global.get_node("Archipelago")
39 apclient.solvePanel(solve_index, solved_remotely)
40
34 41
35func evaluate_solvability(): 42func evaluate_solvability():
36 var apclient = global.get_node("Archipelago") 43 var apclient = global.get_node("Archipelago")
@@ -39,7 +46,9 @@ func evaluate_solvability():
39 solvable = true 46 solvable = true
40 var missing = [] 47 var missing = []
41 48
42 if apclient._color_shuffle: 49 if locked:
50 solvable = false
51 elif apclient._color_shuffle:
43 for color in data["color"]: 52 for color in data["color"]:
44 if not apclient._has_colors.has(color): 53 if not apclient._has_colors.has(color):
45 missing.append(color) 54 missing.append(color)
@@ -52,6 +61,12 @@ func evaluate_solvability():
52 self.get_parent().get_node("Viewport/GUI/Panel/Label").text = orig_text 61 self.get_parent().get_node("Viewport/GUI/Panel/Label").text = orig_text
53 self.get_parent().get_node("Viewport/GUI/Panel/TextEdit").editable = true 62 self.get_parent().get_node("Viewport/GUI/Panel/TextEdit").editable = true
54 self.get_parent().get_node("Quad").get_surface_material(0).albedo_color = orig_color 63 self.get_parent().get_node("Quad").get_surface_material(0).albedo_color = orig_color
64 elif locked:
65 self.get_parent().get_node("Viewport/GUI/Panel/Label").text = "Locked"
66 self.get_parent().get_node("Viewport/GUI/Panel/TextEdit").editable = false
67 self.get_parent().get_node("Quad").get_surface_material(0).albedo_color = Color(
68 0.2, 0.7, 0.7
69 )
55 else: 70 else:
56 var missing_text = "Missing: " 71 var missing_text = "Missing: "
57 for thing in missing: 72 for thing in missing:
diff --git a/Archipelago/player.gd b/Archipelago/player.gd index 52d743a..6638329 100644 --- a/Archipelago/player.gd +++ b/Archipelago/player.gd
@@ -2,12 +2,16 @@ extends "res://scripts/player.gd"
2 2
3 3
4var _oldpos = Vector3(0, -200, 0) 4var _oldpos = Vector3(0, -200, 0)
5var _oldpos_fine = Vector3(0, -200, 0)
5 6
6 7
7func _ready(): 8func _ready():
8 _oldpos = translation 9 _oldpos = translation
9 _oldpos.y = 0 10 _oldpos.y = 0
10 11
12 _oldpos_fine = translation
13 _oldpos_fine.y = 0
14
11 var apclient = global.get_node("Archipelago") 15 var apclient = global.get_node("Archipelago")
12 if apclient.track_player: 16 if apclient.track_player:
13 var tracking_timer = Timer.new() 17 var tracking_timer = Timer.new()
@@ -17,8 +21,19 @@ func _ready():
17 tracking_timer.connect("timeout", self, "_tick_tracking") 21 tracking_timer.connect("timeout", self, "_tick_tracking")
18 tracking_timer.start() 22 tracking_timer.start()
19 23
24 var tracking_timer_fine = Timer.new()
25 tracking_timer_fine.name = "TrackingTimerFine"
26 tracking_timer_fine.wait_time = 0.5
27 add_child(tracking_timer_fine)
28 tracking_timer_fine.connect("timeout", self, "_tick_tracking_fine")
29 tracking_timer_fine.start()
30
20 31
21func _tick_tracking(): 32func _tick_tracking():
33 var tracker = get_tree().get_root().get_node("Spatial/AP_Tracker")
34 if tracker.has_connection():
35 return
36
22 var newpos = translation 37 var newpos = translation
23 newpos.y = 0 38 newpos.y = 0
24 39
@@ -29,6 +44,20 @@ func _tick_tracking():
29 apclient.setValue("PlayerPos", {"x": int(_oldpos.x), "z": int(_oldpos.z)}) 44 apclient.setValue("PlayerPos", {"x": int(_oldpos.x), "z": int(_oldpos.z)})
30 45
31 46
47func _tick_tracking_fine():
48 var tracker = get_tree().get_root().get_node("Spatial/AP_Tracker")
49 if !tracker.has_connection():
50 return
51
52 var newpos = translation
53 newpos.y = 0
54
55 if newpos != _oldpos_fine && newpos.distance_to(_oldpos_fine) > 0.5:
56 _oldpos_fine = newpos
57
58 tracker.update_position(int(_oldpos_fine.x), int(_oldpos_fine.z))
59
60
32func _solving(): 61func _solving():
33 ._solving() 62 ._solving()
34 63
diff --git a/Archipelago/settings_screen.gd b/Archipelago/settings_screen.gd index 2ed8594..f390eed 100644 --- a/Archipelago/settings_screen.gd +++ b/Archipelago/settings_screen.gd
@@ -28,11 +28,11 @@ func _ready():
28 apclient_instance.SCRIPT_location = load("user://maps/Archipelago/location.gd") 28 apclient_instance.SCRIPT_location = load("user://maps/Archipelago/location.gd")
29 apclient_instance.SCRIPT_multiplayer = load("user://maps/Archipelago/multiplayer.gd") 29 apclient_instance.SCRIPT_multiplayer = load("user://maps/Archipelago/multiplayer.gd")
30 apclient_instance.SCRIPT_mypainting = load("user://maps/Archipelago/mypainting.gd") 30 apclient_instance.SCRIPT_mypainting = load("user://maps/Archipelago/mypainting.gd")
31 apclient_instance.SCRIPT_notifier = load("user://maps/Archipelago/notifier.gd")
32 apclient_instance.SCRIPT_panel = load("user://maps/Archipelago/panel.gd") 31 apclient_instance.SCRIPT_panel = load("user://maps/Archipelago/panel.gd")
33 var pilg_term = load("user://maps/Archipelago/pilgrimage_terminator.gd") 32 var pilg_term = load("user://maps/Archipelago/pilgrimage_terminator.gd")
34 apclient_instance.SCRIPT_pilgrimage_terminator = pilg_term 33 apclient_instance.SCRIPT_pilgrimage_terminator = pilg_term
35 apclient_instance.SCRIPT_textclient = load("user://maps/Archipelago/textclient.gd") 34 apclient_instance.SCRIPT_textclient = load("user://maps/Archipelago/textclient.gd")
35 apclient_instance.SCRIPT_tracker = load("user://maps/Archipelago/tracker.gd")
36 apclient_instance.SCRIPT_uuid = load("user://maps/Archipelago/vendor/uuid.gd") 36 apclient_instance.SCRIPT_uuid = load("user://maps/Archipelago/vendor/uuid.gd")
37 37
38 var apdata = ResourceLoader.load("user://maps/Archipelago/gamedata.gd") 38 var apdata = ResourceLoader.load("user://maps/Archipelago/gamedata.gd")
diff --git a/Archipelago/textclient.gd b/Archipelago/textclient.gd index f100776..3abd9e0 100644 --- a/Archipelago/textclient.gd +++ b/Archipelago/textclient.gd
@@ -25,6 +25,7 @@ func _ready():
25 label.margin_top = 80 25 label.margin_top = 80
26 label.margin_bottom = 720 26 label.margin_bottom = 720
27 label.scroll_following = true 27 label.scroll_following = true
28 label.selection_enabled = true
28 panel.add_child(label) 29 panel.add_child(label)
29 30
30 var dynamic_font = DynamicFont.new() 31 var dynamic_font = DynamicFont.new()
@@ -51,7 +52,7 @@ func _ready():
51 52
52func _input(event): 53func _input(event):
53 if event is InputEventKey and event.pressed: 54 if event is InputEventKey and event.pressed:
54 if event.scancode == KEY_TAB: 55 if event.scancode == KEY_TAB and !Input.is_key_pressed(KEY_SHIFT):
55 if !get_tree().paused: 56 if !get_tree().paused:
56 is_open = true 57 is_open = true
57 get_tree().paused = true 58 get_tree().paused = true
diff --git a/Archipelago/tracker.gd b/Archipelago/tracker.gd new file mode 100644 index 0000000..9def744 --- /dev/null +++ b/Archipelago/tracker.gd
@@ -0,0 +1,89 @@
1extends Node
2
3var autotracker_port = 41253
4
5var _server = WebSocketServer.new()
6var _peers = []
7
8
9func _ready():
10 _server.bind_ip = "127.0.0.1"
11 _server.connect("client_connected", self, "_connection_established")
12 _server.connect("client_disconnected", self, "_connection_dropped")
13 _server.connect("data_received", self, "_data_received")
14 _server.listen(autotracker_port)
15
16
17func _process(_delta):
18 _server.poll()
19
20
21func _connection_established(id, _protocol):
22 _peers.append(id)
23
24 var apclient = global.get_node("Archipelago")
25
26 var msg = {
27 "cmd": "Connect",
28 "slot":
29 {"server": apclient.ap_server, "player": apclient.ap_user, "password": apclient.ap_pass}
30 }
31
32 var peer = _server.get_peer(id)
33 peer.set_write_mode(WebSocketPeer.WRITE_MODE_TEXT)
34 peer.put_packet(JSON.print(msg).to_utf8())
35
36
37func _connection_dropped(id, _was_clean_close):
38 _peers.erase(id)
39
40
41func _data_received(id):
42 var peer = _server.get_peer(id)
43 peer.set_write_mode(WebSocketPeer.WRITE_MODE_TEXT)
44
45 var packet_text = peer.get_packet().get_string_from_utf8()
46 global._print("Got data from tracker: " + packet_text)
47 var data = JSON.parse(packet_text)
48 if data.error != OK:
49 global._print("Error parsing packet from Tracker: " + data.error_string)
50 return
51
52 var apclient = global.get_node("Archipelago")
53 var msg = data.result
54
55 if msg["cmd"] == "Sync":
56 var resp = {}
57
58 if apclient.track_player:
59 var player = get_tree().get_root().get_node("Spatial/player")
60 resp = {
61 "cmd": "UpdatePosition",
62 "position": {"x": int(player._oldpos_fine.x), "z": int(player._oldpos_fine.z)}
63 }
64
65 peer.put_packet(JSON.print(resp).to_utf8())
66
67
68func _broadcast(msg):
69 var to_remove = []
70 var serialized = JSON.print(msg).to_utf8()
71
72 for peer_id in _peers:
73 if _server.has_peer(peer_id):
74 var peer = _server.get_peer(peer_id)
75 peer.set_write_mode(WebSocketPeer.WRITE_MODE_TEXT)
76 peer.put_packet(serialized)
77 else:
78 to_remove.append(peer_id)
79
80 for peer_id in to_remove:
81 _peers.erase(peer_id)
82
83
84func has_connection():
85 return _peers.size() > 0
86
87
88func update_position(x, z):
89 _broadcast({"cmd": "UpdatePosition", "position": {"x": x, "z": z}})