about summary refs log tree commit diff stats
path: root/Archipelago
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2024-12-09 12:50:37 -0500
committerStar Rauchenberger <fefferburbia@gmail.com>2024-12-09 12:50:37 -0500
commit880e4b5069c4dfbf1ed532fc117697cde83b5566 (patch)
tree233bcbd82ff1ea8b2237232d430c665168ba009f /Archipelago
parentf834267a75c873d143e1f7f56f73faaa5e15cf2f (diff)
parent45fa76505dd00bdd6665bae476277371fb1252a2 (diff)
downloadlingo-archipelago-880e4b5069c4dfbf1ed532fc117697cde83b5566.tar.gz
lingo-archipelago-880e4b5069c4dfbf1ed532fc117697cde83b5566.tar.bz2
lingo-archipelago-880e4b5069c4dfbf1ed532fc117697cde83b5566.zip
Merge branch 'main' into experimental-panels
Diffstat (limited to 'Archipelago')
-rw-r--r--Archipelago/client.gd171
-rw-r--r--Archipelago/effects.gd66
-rw-r--r--Archipelago/extradata.gd84
-rw-r--r--Archipelago/load.gd23
-rw-r--r--Archipelago/multiplayer.gd55
-rw-r--r--Archipelago/panel.gd11
-rw-r--r--Archipelago/pause_menu.gd5
-rw-r--r--Archipelago/settings_screen.gd1
-rw-r--r--Archipelago/textclient.gd100
9 files changed, 489 insertions, 27 deletions
diff --git a/Archipelago/client.gd b/Archipelago/client.gd index 78058ca..390b14d 100644 --- a/Archipelago/client.gd +++ b/Archipelago/client.gd
@@ -9,6 +9,7 @@ var SCRIPT_mypainting
9var SCRIPT_notifier 9var SCRIPT_notifier
10var SCRIPT_panel 10var SCRIPT_panel
11var SCRIPT_pilgrimage_terminator 11var SCRIPT_pilgrimage_terminator
12var SCRIPT_textclient
12var SCRIPT_uuid 13var SCRIPT_uuid
13 14
14var ap_server = "" 15var ap_server = ""
@@ -19,12 +20,12 @@ var enable_multiplayer = false
19var track_player = false 20var track_player = false
20var connection_history = [] 21var connection_history = []
21 22
22const my_version = "4.0.2" 23const my_version = "5.0.1"
23const ap_version = {"major": 0, "minor": 5, "build": 0, "class": "Version"} 24const ap_version = {"major": 0, "minor": 5, "build": 1, "class": "Version"}
24const color_items = [ 25const color_items = [
25 "White", "Black", "Red", "Blue", "Green", "Brown", "Gray", "Orange", "Purple", "Yellow" 26 "White", "Black", "Red", "Blue", "Green", "Brown", "Gray", "Orange", "Purple", "Yellow"
26] 27]
27const progressive_items = { 28const door_progressive_items = {
28 "Progressive Orange Tower": 29 "Progressive Orange Tower":
29 ["Second Floor", "Third Floor", "Fourth Floor", "Fifth Floor", "Sixth Floor", "Seventh Floor"], 30 ["Second Floor", "Third Floor", "Fourth Floor", "Fifth Floor", "Sixth Floor", "Seventh Floor"],
30 "Progressive Art Gallery": 31 "Progressive Art Gallery":
@@ -36,6 +37,15 @@ const progressive_items = {
36 "Progressive Pilgrimage": 37 "Progressive Pilgrimage":
37 ["1 Sunwarp", "2 Sunwarp", "3 Sunwarp", "4 Sunwarp", "5 Sunwarp", "6 Sunwarp"] 38 ["1 Sunwarp", "2 Sunwarp", "3 Sunwarp", "4 Sunwarp", "5 Sunwarp", "6 Sunwarp"]
38} 39}
40const panel_progressive_items = {
41 "Progressive Hallway Room": ["First Door", "Second Door", "Third Door", "Fourth Door"],
42 "Progressive Colorful":
43 ["White", "Black", "Red", "Yellow", "Blue", "Purple", "Orange", "Green", "Brown", "Gray"],
44 "Progressive Number Hunt":
45 ["Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Zero"],
46 "Progressive Symmetry Room": ["Near Far", "Warts Straw", "Leaf Feel"],
47 "Progressive Suits Area": ["Words Sword", "Lost", "Amen Name"]
48}
39 49
40const kTHE_END = 0 50const kTHE_END = 0
41const kTHE_MASTER = 1 51const kTHE_MASTER = 1
@@ -91,6 +101,7 @@ var _localdata_file = ""
91var _death_link = false 101var _death_link = false
92var _victory_condition = 0 # THE END, THE MASTER, LEVEL 2 102var _victory_condition = 0 # THE END, THE MASTER, LEVEL 2
93var _door_shuffle = false 103var _door_shuffle = false
104var _panel_door_shuffle = false
94var _color_shuffle = false 105var _color_shuffle = false
95var _panel_shuffle = 0 # none, rearrange 106var _panel_shuffle = 0 # none, rearrange
96var _painting_shuffle = false 107var _painting_shuffle = false
@@ -105,6 +116,7 @@ var _pilgrimage_allows_roof_access = false
105var _pilgrimage_allows_paintings = false 116var _pilgrimage_allows_paintings = false
106var _sunwarp_shuffle = false 117var _sunwarp_shuffle = false
107var _sunwarp_mapping = [] 118var _sunwarp_mapping = []
119var _speed_boost_mode = false
108var _slot_seed = 0 120var _slot_seed = 0
109 121
110var _map_loaded = false 122var _map_loaded = false
@@ -118,8 +130,11 @@ var _puzzle_skips = 0
118var _cached_slowness = 0 130var _cached_slowness = 0
119var _cached_iceland = 0 131var _cached_iceland = 0
120var _cached_atbash = 0 132var _cached_atbash = 0
133var _cached_speed_boosts = 0
121var _geronimo_skip = false 134var _geronimo_skip = false
122var _checked_paintings = [] 135var _checked_paintings = []
136var _hints_key = ""
137var _hinted_locations = []
123 138
124signal could_not_connect 139signal could_not_connect
125signal connect_status 140signal connect_status
@@ -277,9 +292,15 @@ func _on_data():
277 _color_shuffle = _slot_data["shuffle_colors"] 292 _color_shuffle = _slot_data["shuffle_colors"]
278 293
279 if _slot_data.has("shuffle_doors"): 294 if _slot_data.has("shuffle_doors"):
280 _door_shuffle = (_slot_data["shuffle_doors"] > 0) 295 if _slot_data.has("group_doors"):
296 _door_shuffle = (_slot_data["shuffle_doors"] == 2)
297 _panel_door_shuffle = (_slot_data["shuffle_doors"] == 1)
298 else:
299 _door_shuffle = (_slot_data["shuffle_doors"] > 0)
300 _panel_door_shuffle = false
281 else: 301 else:
282 _door_shuffle = false 302 _door_shuffle = false
303 _panel_door_shuffle = false
283 304
284 if _slot_data.has("shuffle_paintings"): 305 if _slot_data.has("shuffle_paintings"):
285 _painting_shuffle = _slot_data["shuffle_paintings"] 306 _painting_shuffle = _slot_data["shuffle_paintings"]
@@ -331,6 +352,10 @@ func _on_data():
331 _sunwarp_shuffle = false 352 _sunwarp_shuffle = false
332 if _slot_data.has("sunwarp_permutation"): 353 if _slot_data.has("sunwarp_permutation"):
333 _sunwarp_mapping = _slot_data["sunwarp_permutation"] 354 _sunwarp_mapping = _slot_data["sunwarp_permutation"]
355 if _slot_data.has("speed_boost_mode"):
356 _speed_boost_mode = _slot_data["speed_boost_mode"]
357 else:
358 _speed_boost_mode = false
334 359
335 if ( 360 if (
336 _location_classification_bit != kCLASSIFICATION_LOCAL_INSANITY 361 _location_classification_bit != kCLASSIFICATION_LOCAL_INSANITY
@@ -349,6 +374,7 @@ func _on_data():
349 _cached_slowness = 0 374 _cached_slowness = 0
350 _cached_iceland = 0 375 _cached_iceland = 0
351 _cached_atbash = 0 376 _cached_atbash = 0
377 _cached_speed_boosts = 0
352 _geronimo_skip = false 378 _geronimo_skip = false
353 379
354 _localdata_file = "user://archipelago_data/%s_%d" % [_seed, _slot] 380 _localdata_file = "user://archipelago_data/%s_%d" % [_seed, _slot]
@@ -380,6 +406,9 @@ func _on_data():
380 if localdata.size() > 5: 406 if localdata.size() > 5:
381 _geronimo_skip = localdata[5] 407 _geronimo_skip = localdata[5]
382 408
409 if localdata.size() > 6:
410 _cached_speed_boosts = localdata[6]
411
383 requestSync() 412 requestSync()
384 413
385 sendMessage( 414 sendMessage(
@@ -394,6 +423,11 @@ func _on_data():
394 ] 423 ]
395 ) 424 )
396 425
426 _hints_key = "_read_hints_%d_%d" % [_team, _slot]
427 sendMessage(
428 [{"cmd": "SetNotify", "keys": [_hints_key]}, {"cmd": "Get", "keys": [_hints_key]}]
429 )
430
397 emit_signal("client_connected") 431 emit_signal("client_connected")
398 432
399 elif cmd == "ConnectionRefused": 433 elif cmd == "ConnectionRefused":
@@ -453,6 +487,8 @@ func _on_data():
453 i += 1 487 i += 1
454 488
455 elif cmd == "PrintJSON": 489 elif cmd == "PrintJSON":
490 parse_printjson(message)
491
456 if ( 492 if (
457 !message.has("receiving") 493 !message.has("receiving")
458 or !message.has("item") 494 or !message.has("item")
@@ -489,9 +525,12 @@ func _on_data():
489 ) 525 )
490 else: 526 else:
491 if message["receiving"] != _slot: 527 if message["receiving"] != _slot:
492 messages.showMessage( 528 var sentMsg = (
493 "Sent [color=%s]%s[/color] to %s" % [item_color, item_name, player_name] 529 "Sent [color=%s]%s[/color] to %s" % [item_color, item_name, player_name]
494 ) 530 )
531 if _hinted_locations.has(message["item"]["location"]):
532 sentMsg += " ([color=#fafad2]Hinted![/color])"
533 messages.showMessage(sentMsg)
495 534
496 elif cmd == "Bounced": 535 elif cmd == "Bounced":
497 if ( 536 if (
@@ -512,8 +551,15 @@ func _on_data():
512 get_tree().get_root().get_node("Spatial/player/pause_menu")._reload() 551 get_tree().get_root().get_node("Spatial/player/pause_menu")._reload()
513 552
514 elif cmd == "SetReply": 553 elif cmd == "SetReply":
515 if message.has("key") and message["key"] == ("Lingo_%d_Paintings" % _slot): 554 if message.has("key"):
516 _checked_paintings = message["value"] 555 if message["key"] == ("Lingo_%d_Paintings" % _slot):
556 _checked_paintings = message["value"]
557 elif message["key"] == _hints_key:
558 parseHints(message["value"])
559
560 elif cmd == "Retrieved":
561 if message.has("keys") and message["keys"].has(_hints_key):
562 parseHints(message["keys"][_hints_key])
517 563
518 564
519func _process(_delta): 565func _process(_delta):
@@ -567,7 +613,8 @@ func saveLocaldata():
567 effects_node.slowness_remaining, 613 effects_node.slowness_remaining,
568 effects_node.iceland_remaining, 614 effects_node.iceland_remaining,
569 effects_node.atbash_remaining, 615 effects_node.atbash_remaining,
570 _geronimo_skip 616 _geronimo_skip,
617 effects_node.speed_boosts_remaining,
571 ] 618 ]
572 file.store_var(data, true) 619 file.store_var(data, true)
573 file.close() 620 file.close()
@@ -686,6 +733,10 @@ func setValue(key, value, operation = "replace"):
686 ) 733 )
687 734
688 735
736func say(textdata):
737 sendMessage([{"cmd": "Say", "text": textdata}])
738
739
689func completedGoal(): 740func completedGoal():
690 sendMessage([{"cmd": "StatusUpdate", "status": 30}]) # CLIENT_GOAL 741 sendMessage([{"cmd": "StatusUpdate", "status": 30}]) # CLIENT_GOAL
691 742
@@ -729,6 +780,18 @@ func processItem(item, index, from, flags):
729 for door_id in gamedata.door_ids_by_item_id[int(item)]: 780 for door_id in gamedata.door_ids_by_item_id[int(item)]:
730 doorsNode.get_node(door_id).openDoor() 781 doorsNode.get_node(door_id).openDoor()
731 782
783 if gamedata.panel_ids_by_item_id.has(int(item)):
784 var panel_ids = gamedata.panel_ids_by_item_id[int(item)]
785 if wasGeneratedOnVersion(0, 5, 1):
786 var extradata = get_node("Extradata")
787 if extradata.panels_mode_051_panel_fixes.has(int(item)):
788 panel_ids = extradata.panels_mode_051_panel_fixes[int(item)]
789
790 var panelsNode = get_tree().get_root().get_node("Spatial/Panels")
791 for panel_id in panel_ids:
792 panelsNode.get_node(panel_id).get_node("AP_Panel").locked = false
793 emit_signal("evaluate_solvability")
794
732 if gamedata.painting_ids_by_item_id.has(int(item)): 795 if gamedata.painting_ids_by_item_id.has(int(item)):
733 var real_parent_node = get_tree().get_root().get_node("Spatial/Decorations/Paintings") 796 var real_parent_node = get_tree().get_root().get_node("Spatial/Decorations/Paintings")
734 var fake_parent_node = get_tree().get_root().get_node_or_null("Spatial/AP_Paintings") 797 var fake_parent_node = get_tree().get_root().get_node_or_null("Spatial/AP_Paintings")
@@ -749,15 +812,34 @@ func processItem(item, index, from, flags):
749 warpsNode.get_node(warp_id).unlock_warp() 812 warpsNode.get_node(warp_id).unlock_warp()
750 813
751 # Handle progressive items. 814 # Handle progressive items.
752 if int(item) in gamedata.items_by_progressive_id.keys(): 815 var is_progressive_door = int(item) in gamedata.door_items_by_progressive_id
816 var is_progressive_panel = int(item) in gamedata.panel_items_by_progressive_id
817 var progitems = null
818 var prognames = null
819
820 if is_progressive_door and is_progressive_panel:
821 if _door_shuffle:
822 progitems = gamedata.door_items_by_progressive_id[int(item)]
823 prognames = door_progressive_items
824 else:
825 progitems = gamedata.panel_items_by_progressive_id[int(item)]
826 prognames = panel_progressive_items
827 elif is_progressive_door:
828 progitems = gamedata.door_items_by_progressive_id[int(item)]
829 prognames = door_progressive_items
830 elif is_progressive_panel:
831 progitems = gamedata.panel_items_by_progressive_id[int(item)]
832 prognames = panel_progressive_items
833
834 if progitems != null:
753 if not int(item) in _progressive_progress: 835 if not int(item) in _progressive_progress:
754 _progressive_progress[int(item)] = 0 836 _progressive_progress[int(item)] = 0
755 837
756 if _progressive_progress[int(item)] < gamedata.items_by_progressive_id[int(item)].size(): 838 if _progressive_progress[int(item)] < progitems.size():
757 var subitems = gamedata.items_by_progressive_id[int(item)] 839 var subitem_id = progitems[_progressive_progress[int(item)]]
758 var subitem_id = subitems[_progressive_progress[int(item)]]
759 global._print("Subitem: %d" % subitem_id) 840 global._print("Subitem: %d" % subitem_id)
760 processItem(subitem_id, null, null, null) 841 processItem(subitem_id, null, null, null)
842 item_name += " (%s)" % prognames[item_name][_progressive_progress[int(item)]]
761 _progressive_progress[int(item)] += 1 843 _progressive_progress[int(item)] += 1
762 844
763 if _color_shuffle and color_items.has(_item_id_to_name["Lingo"][item]): 845 if _color_shuffle and color_items.has(_item_id_to_name["Lingo"][item]):
@@ -771,10 +853,6 @@ func processItem(item, index, from, flags):
771 _last_new_item = index 853 _last_new_item = index
772 saveLocaldata() 854 saveLocaldata()
773 855
774 if item_name in progressive_items:
775 var subitem = progressive_items[item_name][_progressive_progress[int(item)] - 1]
776 item_name += " (%s)" % subitem
777
778 var player_name = "Unknown" 856 var player_name = "Unknown"
779 if _player_name_by_slot.has(from): 857 if _player_name_by_slot.has(from):
780 player_name = _player_name_by_slot[from] 858 player_name = _player_name_by_slot[from]
@@ -789,12 +867,14 @@ func processItem(item, index, from, flags):
789 ) 867 )
790 868
791 var effects_node = get_tree().get_root().get_node("Spatial/AP_Effects") 869 var effects_node = get_tree().get_root().get_node("Spatial/AP_Effects")
792 if item_name == "Slowness Trap": 870 if item_name == "Slowness Trap" and !_speed_boost_mode:
793 effects_node.trigger_slowness_trap() 871 effects_node.trigger_slowness_trap()
794 if item_name == "Iceland Trap": 872 if item_name == "Iceland Trap":
795 effects_node.trigger_iceland_trap() 873 effects_node.trigger_iceland_trap()
796 if item_name == "Atbash Trap": 874 if item_name == "Atbash Trap":
797 effects_node.trigger_atbash_trap() 875 effects_node.trigger_atbash_trap()
876 if item_name == "Speed Boost" and _speed_boost_mode:
877 effects_node.trigger_speed_boost()
798 if item_name == "Puzzle Skip": 878 if item_name == "Puzzle Skip":
799 _puzzle_skips += 1 879 _puzzle_skips += 1
800 880
@@ -845,6 +925,14 @@ func checkPainting(painting_id):
845 setValue("Paintings", [painting_id], "add") 925 setValue("Paintings", [painting_id], "add")
846 926
847 927
928func parseHints(hints):
929 _hinted_locations.clear()
930
931 for hint in hints:
932 if hint["finding_player"] == int(_slot):
933 _hinted_locations.append(hint["location"])
934
935
848func colorForItemType(flags): 936func colorForItemType(flags):
849 var int_flags = int(flags) 937 var int_flags = int(flags)
850 if int_flags & 1: # progression 938 if int_flags & 1: # progression
@@ -857,6 +945,47 @@ func colorForItemType(flags):
857 return "#14de9e" 945 return "#14de9e"
858 946
859 947
948func parse_printjson(message):
949 var parts = []
950 for message_part in message["data"]:
951 if !message_part.has("type") and message_part.has("text"):
952 parts.append(message_part["text"])
953 elif message_part["type"] == "player_id":
954 if int(message_part["text"]) == _slot:
955 parts.append("[color=#ee00ee]%s[/color]" % _player_name_by_slot[_slot])
956 else:
957 var from = float(message_part["text"])
958 parts.append("[color=#fafad2]%s[/color]" % _player_name_by_slot[from])
959 elif message_part["type"] == "item_id":
960 var item_name = "Unknown"
961 var item_player_game = _game_by_player[message_part["player"]]
962 if _item_id_to_name[item_player_game].has(float(message_part["text"])):
963 item_name = _item_id_to_name[item_player_game][float(message_part["text"])]
964
965 parts.append(
966 "[color=%s]%s[/color]" % [colorForItemType(message_part["flags"]), item_name]
967 )
968 elif message_part["type"] == "location_id":
969 var location_name = "Unknown"
970 var location_player_game = _game_by_player[message_part["player"]]
971 if _location_id_to_name[location_player_game].has(float(message_part["text"])):
972 location_name = _location_id_to_name[location_player_game][float(
973 message_part["text"]
974 )]
975
976 parts.append("[color=#00ff7f]%s[/color]" % location_name)
977 elif message_part.has("text"):
978 parts.append(message_part["text"])
979
980 var textclient_node = get_tree().get_root().get_node_or_null("Spatial/AP_TextClient")
981 if textclient_node != null:
982 textclient_node.parse_printjson("".join(parts))
983
984
985func get_player_name():
986 return _player_name_by_slot[_slot]
987
988
860func compareVersion(lhs, rhs): 989func compareVersion(lhs, rhs):
861 if lhs["major"] == rhs["major"]: 990 if lhs["major"] == rhs["major"]:
862 if lhs["minor"] == rhs["minor"]: 991 if lhs["minor"] == rhs["minor"]:
@@ -869,3 +998,11 @@ func compareVersion(lhs, rhs):
869 998
870func wasGeneratedBeforeVersion(major, minor, build): 999func wasGeneratedBeforeVersion(major, minor, build):
871 return compareVersion(_gen_version, {"major": major, "minor": minor, "build": build}) 1000 return compareVersion(_gen_version, {"major": major, "minor": minor, "build": build})
1001
1002
1003func wasGeneratedOnVersion(major, minor, build):
1004 return (
1005 _gen_version["major"] == major
1006 and _gen_version["minor"] == minor
1007 and _gen_version["build"] == build
1008 )
diff --git a/Archipelago/effects.gd b/Archipelago/effects.gd index 1e2e311..341a783 100644 --- a/Archipelago/effects.gd +++ b/Archipelago/effects.gd
@@ -5,6 +5,7 @@ var effect_running = false
5var slowness_remaining = 0 5var slowness_remaining = 0
6var iceland_remaining = 0 6var iceland_remaining = 0
7var atbash_remaining = 0 7var atbash_remaining = 0
8var speed_boosts_remaining = 0
8var queued_iceland = 0 9var queued_iceland = 0
9var skip_available = false 10var skip_available = false
10var puzzle_focused = false 11var puzzle_focused = false
@@ -48,6 +49,12 @@ func _ready():
48 add_child(slowness_timer) 49 add_child(slowness_timer)
49 slowness_timer.connect("timeout", self, "_tick_slowness") 50 slowness_timer.connect("timeout", self, "_tick_slowness")
50 51
52 var speed_boost_timer = Timer.new()
53 speed_boost_timer.name = "SpeedBoostTimer"
54 speed_boost_timer.wait_time = 1.0
55 add_child(speed_boost_timer)
56 speed_boost_timer.connect("timeout", self, "_tick_speed_boost")
57
51 var iceland_timer = Timer.new() 58 var iceland_timer = Timer.new()
52 iceland_timer.name = "IcelandTimer" 59 iceland_timer.name = "IcelandTimer"
53 iceland_timer.wait_time = 1.0 60 iceland_timer.wait_time = 1.0
@@ -63,6 +70,12 @@ func activate():
63 70
64 queued_iceland = 0 71 queued_iceland = 0
65 72
73 var apclient = global.get_node("Archipelago")
74 if apclient._speed_boost_mode:
75 var player = get_tree().get_root().get_node("Spatial/player")
76 player.walk_speed = orig_walk / 2.0
77 player.run_speed = orig_run / 2.0
78
66 79
67func trigger_slowness_trap(length = 30): 80func trigger_slowness_trap(length = 30):
68 if slowness_remaining == 0: 81 if slowness_remaining == 0:
@@ -79,6 +92,21 @@ func trigger_slowness_trap(length = 30):
79 apclient.saveLocaldata() 92 apclient.saveLocaldata()
80 93
81 94
95func trigger_speed_boost(length = 20):
96 if speed_boosts_remaining == 0:
97 var player = get_tree().get_root().get_node("Spatial/player")
98 player.walk_speed = orig_walk
99 player.run_speed = orig_run
100
101 $SpeedBoostTimer.start()
102
103 speed_boosts_remaining += length
104 text_dirty = true
105
106 var apclient = global.get_node("Archipelago")
107 apclient.saveLocaldata()
108
109
82func trigger_iceland_trap(length = 60): 110func trigger_iceland_trap(length = 60):
83 if not activated: 111 if not activated:
84 queued_iceland += length 112 queued_iceland += length
@@ -99,7 +127,7 @@ func trigger_iceland_trap(length = 60):
99 127
100 128
101func trigger_atbash_trap(): 129func trigger_atbash_trap():
102 var newly_atbash = (atbash_remaining == 0) 130 var newly_atbash = atbash_remaining == 0
103 atbash_remaining += 1 131 atbash_remaining += 1
104 132
105 if newly_atbash: 133 if newly_atbash:
@@ -121,7 +149,7 @@ func deactivate_atbash_trap():
121 apclient.evaluateSolvability() 149 apclient.evaluateSolvability()
122 150
123 text_dirty = true 151 text_dirty = true
124 152
125 var apclient = global.get_node("Archipelago") 153 var apclient = global.get_node("Archipelago")
126 apclient.saveLocaldata() 154 apclient.saveLocaldata()
127 155
@@ -192,23 +220,37 @@ func _tick_slowness():
192 player.run_speed = orig_run 220 player.run_speed = orig_run
193 221
194 $SlownessTimer.stop() 222 $SlownessTimer.stop()
195 223
196 if slowness_remaining % 5 == 0: 224 if slowness_remaining % 5 == 0:
197 var apclient = global.get_node("Archipelago") 225 var apclient = global.get_node("Archipelago")
198 apclient.saveLocaldata() 226 apclient.saveLocaldata()
199 227
200 228
229func _tick_speed_boost():
230 speed_boosts_remaining -= 1
231 text_dirty = true
232
233 if speed_boosts_remaining == 0:
234 var player = get_tree().get_root().get_node("Spatial/player")
235 player.walk_speed = orig_walk / 2.0
236 player.run_speed = orig_run / 2.0
237
238 $SpeedBoostTimer.stop()
239
240 if speed_boosts_remaining % 5 == 0:
241 var apclient = global.get_node("Archipelago")
242 apclient.saveLocaldata()
243
244
201func _tick_iceland(): 245func _tick_iceland():
202 iceland_remaining -= 1 246 iceland_remaining -= 1
203 text_dirty = true 247 text_dirty = true
204 248
205 if iceland_remaining == 0: 249 if iceland_remaining == 0:
206 get_tree().get_root().get_node("Spatial/player/pivot/camera").set_environment( 250 get_tree().get_root().get_node("Spatial/player/pivot/camera").set_environment(orig_env)
207 orig_env
208 )
209 251
210 $IcelandTimer.stop() 252 $IcelandTimer.stop()
211 253
212 if iceland_remaining % 5 == 0: 254 if iceland_remaining % 5 == 0:
213 var apclient = global.get_node("Archipelago") 255 var apclient = global.get_node("Archipelago")
214 apclient.saveLocaldata() 256 apclient.saveLocaldata()
@@ -220,9 +262,11 @@ func _process(_delta):
220 if wallcast.is_colliding(): 262 if wallcast.is_colliding():
221 var player = get_tree().get_root().get_node("Spatial/player") 263 var player = get_tree().get_root().get_node("Spatial/player")
222 var puzzlecast = player.get_node("pivot/camera/RayCast_sight") 264 var puzzlecast = player.get_node("pivot/camera/RayCast_sight")
223 var distance = puzzlecast.get_collision_point().distance_to(wallcast.get_collision_point()) 265 var distance = puzzlecast.get_collision_point().distance_to(
266 wallcast.get_collision_point()
267 )
224 should_nbw = (distance < 0.05) 268 should_nbw = (distance < 0.05)
225 269
226 if should_nbw != not_behind_wall: 270 if should_nbw != not_behind_wall:
227 not_behind_wall = should_nbw 271 not_behind_wall = should_nbw
228 text_dirty = true 272 text_dirty = true
@@ -239,6 +283,10 @@ func _process(_delta):
239 if not text.empty(): 283 if not text.empty():
240 text += "\n" 284 text += "\n"
241 text += "Slowness: %d seconds" % slowness_remaining 285 text += "Slowness: %d seconds" % slowness_remaining
286 if speed_boosts_remaining > 0:
287 if not text.empty():
288 text += "\n"
289 text += "Speed Boost: %d seconds" % speed_boosts_remaining
242 if iceland_remaining > 0: 290 if iceland_remaining > 0:
243 if not text.empty(): 291 if not text.empty():
244 text += "\n" 292 text += "\n"
diff --git a/Archipelago/extradata.gd b/Archipelago/extradata.gd index 89c41d2..2e26eb2 100644 --- a/Archipelago/extradata.gd +++ b/Archipelago/extradata.gd
@@ -93,3 +93,87 @@ 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}
diff --git a/Archipelago/load.gd b/Archipelago/load.gd index be209c3..8559b10 100644 --- a/Archipelago/load.gd +++ b/Archipelago/load.gd
@@ -554,6 +554,20 @@ func _load():
554 proxynode.exact_proxy = true 554 proxynode.exact_proxy = true
555 proxynode.request_ready() 555 proxynode.request_ready()
556 oldparent.add_child(proxynode) 556 oldparent.add_child(proxynode)
557
558 # If the world was generated on 0.5.1, apply the hotfix for the number hunt doors.
559 if apclient._panel_door_shuffle && apclient.wasGeneratedOnVersion(0, 5, 1):
560 var number_hunt_parent = get_node("Doors/Count Up Room Area Doors")
561 var extradata_051_fix = apclient.get_node("Extradata").panels_mode_051_door_fixes
562 for template_door_path in extradata_051_fix:
563 var template_door = number_hunt_parent.get_node(template_door_path)
564 var impacted_doors = extradata_051_fix[template_door_path]
565 for impacted_door_path in impacted_doors:
566 var impacted_door = number_hunt_parent.get_node(impacted_door_path)
567 var copied_door = impacted_door.duplicate()
568 copied_door.panels = template_door.panels
569 number_hunt_parent.add_child(copied_door)
570 impacted_door.queue_free()
557 571
558 # Attach a script to every panel so that we can do things like conditionally 572 # Attach a script to every panel so that we can do things like conditionally
559 # disable them. 573 # disable them.
@@ -567,6 +581,8 @@ func _load():
567 var script_instance = panel_script.new() 581 var script_instance = panel_script.new()
568 script_instance.name = "AP_Panel" 582 script_instance.name = "AP_Panel"
569 script_instance.data = panel 583 script_instance.data = panel
584 if apclient._panel_door_shuffle and gamedata.mentioned_panels.has(panel["id"]):
585 script_instance.locked = true
570 panel_node.add_child(script_instance) 586 panel_node.add_child(script_instance)
571 apclient.connect("evaluate_solvability", script_instance, "evaluate_solvability") 587 apclient.connect("evaluate_solvability", script_instance, "evaluate_solvability")
572 588
@@ -666,9 +682,16 @@ func _load():
666 effects.set_name("AP_Effects") 682 effects.set_name("AP_Effects")
667 self.add_child(effects) 683 self.add_child(effects)
668 684
685 # Create the textclient node.
686 var textclient_script = apclient.SCRIPT_textclient
687 var textclient = textclient_script.new()
688 textclient.set_name("AP_TextClient")
689 self.add_child(textclient)
690
669 # Create the multiplayer node, if needed. 691 # Create the multiplayer node, if needed.
670 if apclient.enable_multiplayer: 692 if apclient.enable_multiplayer:
671 var multiplayer_node = apclient.SCRIPT_multiplayer.new() 693 var multiplayer_node = apclient.SCRIPT_multiplayer.new()
694 multiplayer_node.name = "Multiplayer"
672 multiplayer_node.ghost_mode = true 695 multiplayer_node.ghost_mode = true
673 add_child(multiplayer_node) 696 add_child(multiplayer_node)
674 697
diff --git a/Archipelago/multiplayer.gd b/Archipelago/multiplayer.gd index 0bc2241..c2d9875 100644 --- a/Archipelago/multiplayer.gd +++ b/Archipelago/multiplayer.gd
@@ -1,5 +1,8 @@
1extends "res://scripts/multiplayer.gd" 1extends "res://scripts/multiplayer.gd"
2 2
3var queued_messages = []
4var queued_messages_mutex = Mutex.new()
5
3 6
4func _request_lobby_list(): 7func _request_lobby_list():
5 var apclient = global.get_node("Archipelago") 8 var apclient = global.get_node("Archipelago")
@@ -41,3 +44,55 @@ func _update_lobby_members():
41 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:
42 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")
43 active_lobby_members[member_id].steam_name = slot_name 46 active_lobby_members[member_id].steam_name = slot_name
47
48
49func say(text):
50 queued_messages_mutex.lock()
51 queued_messages.append(text)
52 queued_messages_mutex.unlock()
53
54
55func _physics_process(_delta):
56 if queued_messages_mutex.try_lock() == OK:
57 if queued_messages.empty():
58 queued_messages_mutex.unlock()
59 else:
60 var messages = queued_messages.duplicate()
61 queued_messages = []
62 queued_messages_mutex.unlock()
63
64 var player = get_tree().get_root().get_node("Spatial/player")
65 var space_state = get_tree().get_root().get_world().direct_space_state
66 var nearby_members = []
67 for member_id in active_lobby_members.keys():
68 var other_member = active_lobby_members[member_id]
69 var ray = space_state.intersect_ray(
70 player.global_translation, other_member.global_translation, [player], 0b0101
71 )
72 if !("collider" in ray) or ray["collider"] == other_member:
73 # Visible!
74 nearby_members.append(member_id)
75
76 var apclient = global.get_node("Archipelago")
77 var player_name = apclient.get_player_name()
78 for member_id in nearby_members:
79 for msg in messages:
80 _send_p2p_packet(
81 {"solves": [{"say": msg, "from": player_name}]},
82 member_id,
83 Steam.P2P_SEND_RELIABLE,
84 true
85 )
86
87
88# I'm completely hijacking this callback, since we're in ghost mode and it won't be called normally.
89func _receive_solve(data):
90 if "say" in data:
91 get_tree().get_root().get_node("Spatial/AP_TextClient").parse_printjson(
92 "[LOCAL] [color=#fafad2]%s[/color]: %s" % [data["from"], data["say"]]
93 )
94 messages.showMessage("[color=#fafad2]%s[/color]: %s" % [data["from"], data["say"]])
95
96
97func _send_hi(_discard):
98 pass
diff --git a/Archipelago/panel.gd b/Archipelago/panel.gd index fc5963a..ce632c5 100644 --- a/Archipelago/panel.gd +++ b/Archipelago/panel.gd
@@ -5,6 +5,7 @@ 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
8 9
9const kAtbashPre = "abcdefghijklmnopqrstuvwxyz1234567890+-" 10const kAtbashPre = "abcdefghijklmnopqrstuvwxyz1234567890+-"
10const kAtbashPost = "zyxwvutsrqponmlkjihgfedcba0987654321-+" 11const kAtbashPost = "zyxwvutsrqponmlkjihgfedcba0987654321-+"
@@ -39,7 +40,9 @@ func evaluate_solvability():
39 solvable = true 40 solvable = true
40 var missing = [] 41 var missing = []
41 42
42 if apclient._color_shuffle: 43 if locked:
44 solvable = false
45 elif apclient._color_shuffle:
43 for color in data["color"]: 46 for color in data["color"]:
44 if not apclient._has_colors.has(color): 47 if not apclient._has_colors.has(color):
45 missing.append(color) 48 missing.append(color)
@@ -52,6 +55,12 @@ func evaluate_solvability():
52 self.get_parent().get_node("Viewport/GUI/Panel/Label").text = orig_text 55 self.get_parent().get_node("Viewport/GUI/Panel/Label").text = orig_text
53 self.get_parent().get_node("Viewport/GUI/Panel/TextEdit").editable = true 56 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 57 self.get_parent().get_node("Quad").get_surface_material(0).albedo_color = orig_color
58 elif locked:
59 self.get_parent().get_node("Viewport/GUI/Panel/Label").text = "Locked"
60 self.get_parent().get_node("Viewport/GUI/Panel/TextEdit").editable = false
61 self.get_parent().get_node("Quad").get_surface_material(0).albedo_color = Color(
62 0.2, 0.7, 0.7
63 )
55 else: 64 else:
56 var missing_text = "Missing: " 65 var missing_text = "Missing: "
57 for thing in missing: 66 for thing in missing:
diff --git a/Archipelago/pause_menu.gd b/Archipelago/pause_menu.gd index 40994d9..62ba6c3 100644 --- a/Archipelago/pause_menu.gd +++ b/Archipelago/pause_menu.gd
@@ -6,3 +6,8 @@ func _main_menu():
6 apclient.disconnect_from_ap() 6 apclient.disconnect_from_ap()
7 7
8 ._main_menu() 8 ._main_menu()
9
10
11func _pause_game():
12 get_tree().get_root().get_node("Spatial/AP_TextClient").dismiss()
13 ._pause_game()
diff --git a/Archipelago/settings_screen.gd b/Archipelago/settings_screen.gd index 956d966..ec3b5f1 100644 --- a/Archipelago/settings_screen.gd +++ b/Archipelago/settings_screen.gd
@@ -38,6 +38,7 @@ func _ready():
38 apclient_instance.SCRIPT_panel = load("user://maps/Archipelago/panel.gd") 38 apclient_instance.SCRIPT_panel = load("user://maps/Archipelago/panel.gd")
39 var pilg_term = load("user://maps/Archipelago/pilgrimage_terminator.gd") 39 var pilg_term = load("user://maps/Archipelago/pilgrimage_terminator.gd")
40 apclient_instance.SCRIPT_pilgrimage_terminator = pilg_term 40 apclient_instance.SCRIPT_pilgrimage_terminator = pilg_term
41 apclient_instance.SCRIPT_textclient = load("user://maps/Archipelago/textclient.gd")
41 apclient_instance.SCRIPT_uuid = load("user://maps/Archipelago/vendor/uuid.gd") 42 apclient_instance.SCRIPT_uuid = load("user://maps/Archipelago/vendor/uuid.gd")
42 43
43 var apdata = ResourceLoader.load("user://maps/Archipelago/gamedata.gd") 44 var apdata = ResourceLoader.load("user://maps/Archipelago/gamedata.gd")
diff --git a/Archipelago/textclient.gd b/Archipelago/textclient.gd new file mode 100644 index 0000000..3abd9e0 --- /dev/null +++ b/Archipelago/textclient.gd
@@ -0,0 +1,100 @@
1extends Node
2
3var panel
4var label
5var entry
6var is_open = false
7
8
9func _ready():
10 pause_mode = PAUSE_MODE_PROCESS
11
12 panel = Panel.new()
13 panel.set_name("Panel")
14 panel.margin_left = 100
15 panel.margin_right = 1820
16 panel.margin_top = 100
17 panel.margin_bottom = 980
18 panel.visible = false
19 add_child(panel)
20
21 label = RichTextLabel.new()
22 label.set_name("Label")
23 label.margin_left = 80
24 label.margin_right = 1640
25 label.margin_top = 80
26 label.margin_bottom = 720
27 label.scroll_following = true
28 label.selection_enabled = true
29 panel.add_child(label)
30
31 var dynamic_font = DynamicFont.new()
32 dynamic_font.font_data = load("res://fonts/Lingo.ttf")
33 dynamic_font.size = 36
34 label.push_font(dynamic_font)
35
36 var entry_style = StyleBoxFlat.new()
37 entry_style.bg_color = Color(0.9, 0.9, 0.9, 1)
38
39 entry = LineEdit.new()
40 entry.set_name("Entry")
41 entry.margin_left = 80
42 entry.margin_right = 1640
43 entry.margin_top = 760
44 entry.margin_bottom = 840
45 entry.add_font_override("font", dynamic_font)
46 entry.add_color_override("font_color", Color(0, 0, 0, 1))
47 entry.add_color_override("cursor_color", Color(0, 0, 0, 1))
48 entry.add_stylebox_override("focus", entry_style)
49 panel.add_child(entry)
50 entry.connect("text_entered", self, "text_entered")
51
52
53func _input(event):
54 if event is InputEventKey and event.pressed:
55 if event.scancode == KEY_TAB and !Input.is_key_pressed(KEY_SHIFT):
56 if !get_tree().paused:
57 is_open = true
58 get_tree().paused = true
59 Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
60 panel.visible = true
61 entry.grab_focus()
62 get_tree().set_input_as_handled()
63 else:
64 dismiss()
65 elif event.scancode == KEY_ESCAPE:
66 if is_open:
67 dismiss()
68 get_tree().set_input_as_handled()
69
70
71func dismiss():
72 if is_open:
73 get_tree().paused = false
74 Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
75 panel.visible = false
76 is_open = false
77
78
79func parse_printjson(text):
80 if !label.text.empty():
81 label.append_bbcode("\n")
82
83 label.append_bbcode(text)
84
85
86func text_entered(text):
87 var apclient = global.get_node("Archipelago")
88 var cmd = text.trim_suffix("\n")
89 if cmd.begins_with("/say "):
90 if apclient.enable_multiplayer:
91 var msg = cmd.trim_prefix("/say ")
92 parse_printjson(
93 "[LOCAL] [color=#ee00ee]%s[/color]: %s" % [apclient.get_player_name(), msg]
94 )
95 get_tree().get_root().get_node("Spatial/Multiplayer").say(msg)
96 else:
97 parse_printjson("Multiplayer must be enabled to use /say")
98 else:
99 apclient.say(cmd)
100 entry.text = ""