diff options
-rw-r--r-- | Archipelago/client.gd | 260 | ||||
-rw-r--r-- | Archipelago/extradata.gd | 99 | ||||
-rw-r--r-- | Archipelago/load.gd | 43 | ||||
-rw-r--r-- | Archipelago/multiplayer.gd | 2 | ||||
-rw-r--r-- | Archipelago/notifier.gd | 14 | ||||
-rw-r--r-- | Archipelago/painting.gd | 32 | ||||
-rw-r--r-- | Archipelago/panel.gd | 17 | ||||
-rw-r--r-- | Archipelago/player.gd | 29 | ||||
-rw-r--r-- | Archipelago/settings_screen.gd | 2 | ||||
-rw-r--r-- | Archipelago/textclient.gd | 3 | ||||
-rw-r--r-- | Archipelago/tracker.gd | 89 | ||||
-rw-r--r-- | CHANGELOG.md | 137 | ||||
-rw-r--r-- | README.md | 10 | ||||
-rw-r--r-- | util/generate_gamedata.rb | 96 |
14 files changed, 741 insertions, 92 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 | |||
5 | var SCRIPT_location | 5 | var SCRIPT_location |
6 | var SCRIPT_multiplayer | 6 | var SCRIPT_multiplayer |
7 | var SCRIPT_mypainting | 7 | var SCRIPT_mypainting |
8 | var SCRIPT_notifier | ||
9 | var SCRIPT_panel | 8 | var SCRIPT_panel |
10 | var SCRIPT_pilgrimage_terminator | 9 | var SCRIPT_pilgrimage_terminator |
11 | var SCRIPT_textclient | 10 | var SCRIPT_textclient |
11 | var SCRIPT_tracker | ||
12 | var SCRIPT_uuid | 12 | var SCRIPT_uuid |
13 | 13 | ||
14 | var ap_server = "" | 14 | var ap_server = "" |
@@ -19,12 +19,12 @@ var enable_multiplayer = false | |||
19 | var track_player = false | 19 | var track_player = false |
20 | var connection_history = [] | 20 | var connection_history = [] |
21 | 21 | ||
22 | const my_version = "4.2.0" | 22 | const my_version = "5.4.0" |
23 | const ap_version = {"major": 0, "minor": 5, "build": 0, "class": "Version"} | 23 | const ap_version = {"major": 0, "minor": 5, "build": 1, "class": "Version"} |
24 | const color_items = [ | 24 | const 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 | ] |
27 | const progressive_items = { | 27 | const 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 | } |
39 | const 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 | ||
40 | const kTHE_END = 0 | 49 | const kTHE_END = 0 |
41 | const kTHE_MASTER = 1 | 50 | const kTHE_MASTER = 1 |
@@ -90,6 +99,7 @@ var _localdata_file = "" | |||
90 | var _death_link = false | 99 | var _death_link = false |
91 | var _victory_condition = 0 # THE END, THE MASTER, LEVEL 2 | 100 | var _victory_condition = 0 # THE END, THE MASTER, LEVEL 2 |
92 | var _door_shuffle = false | 101 | var _door_shuffle = false |
102 | var _panel_door_shuffle = false | ||
93 | var _color_shuffle = false | 103 | var _color_shuffle = false |
94 | var _panel_shuffle = 0 # none, rearrange | 104 | var _panel_shuffle = 0 # none, rearrange |
95 | var _painting_shuffle = false | 105 | var _painting_shuffle = false |
@@ -121,6 +131,17 @@ var _cached_atbash = 0 | |||
121 | var _cached_speed_boosts = 0 | 131 | var _cached_speed_boosts = 0 |
122 | var _geronimo_skip = false | 132 | var _geronimo_skip = false |
123 | var _checked_paintings = [] | 133 | var _checked_paintings = [] |
134 | var _hints_key = "" | ||
135 | var _hinted_locations = [] | ||
136 | var _batch_messages = false | ||
137 | var _held_messages = {} | ||
138 | var _held_panels = [] | ||
139 | var _held_synced_panels = [] | ||
140 | var _solved_panels = [] | ||
141 | |||
142 | var _panelsBySolveIndex = {} | ||
143 | const kPANEL_BITFIELDS = 17 # 800 / 48 | ||
144 | const kPANEL_BITFIELD_LENGTH = 48 | ||
124 | 145 | ||
125 | signal could_not_connect | 146 | signal could_not_connect |
126 | signal connect_status | 147 | signal 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 | ||
181 | func _errored(): | 204 | func _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 | ||
530 | func _process(_delta): | 592 | func _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 | ||
728 | func processItem(item, index, from, flags): | 829 | func 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 | ||
959 | func 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 | |||
822 | func doorIsVanilla(door): | 977 | func 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 | ||
1021 | func 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 | |||
1035 | func 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 | |||
866 | func colorForItemType(flags): | 1043 | func 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 | ||
929 | func wasGeneratedBeforeVersion(major, minor, build): | 1109 | func 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 | |||
1113 | func 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 | |||
97 | var 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 | |||
164 | var 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 | |||
181 | var 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 | ||
49 | func say(text): | 49 | func 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 @@ | |||
1 | extends Node | ||
2 | |||
3 | var key | ||
4 | |||
5 | |||
6 | func _ready(): | ||
7 | self.get_parent().get_node("Viewport/GUI/Panel/TextEdit").connect( | ||
8 | "answer_correct", self, "handle_correct" | ||
9 | ) | ||
10 | |||
11 | |||
12 | func 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 @@ | |||
1 | extends "res://scripts/painting.gd" | 1 | extends "res://scripts/painting.gd" |
2 | 2 | ||
3 | func _looked_at(var body, var painting): | 3 | var breaks_pilgrimage = false |
4 | ._looked_at(body, painting) | 4 | |
5 | 5 | ||
6 | if body.is_in_group("player") && (painting.get_name() == self.get_name()): | 6 | func _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 | |||
17 | func _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 = "" | |||
5 | var atbash_text = "" | 5 | var atbash_text = "" |
6 | var orig_color = Color(0, 0, 0, 0) | 6 | var orig_color = Color(0, 0, 0, 0) |
7 | var solvable = true | 7 | var solvable = true |
8 | var locked = false | ||
9 | var solve_index = null | ||
10 | var solved_remotely = false | ||
8 | 11 | ||
9 | const kAtbashPre = "abcdefghijklmnopqrstuvwxyz1234567890+-" | 12 | const kAtbashPre = "abcdefghijklmnopqrstuvwxyz1234567890+-" |
10 | const kAtbashPost = "zyxwvutsrqponmlkjihgfedcba0987654321-+" | 13 | const 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 | ||
35 | func evaluate_solvability(): | 42 | func 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 | ||
4 | var _oldpos = Vector3(0, -200, 0) | 4 | var _oldpos = Vector3(0, -200, 0) |
5 | var _oldpos_fine = Vector3(0, -200, 0) | ||
5 | 6 | ||
6 | 7 | ||
7 | func _ready(): | 8 | func _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 | ||
21 | func _tick_tracking(): | 32 | func _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 | ||
47 | func _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 | |||
32 | func _solving(): | 61 | func _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 | ||
52 | func _input(event): | 53 | func _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 @@ | |||
1 | extends Node | ||
2 | |||
3 | var autotracker_port = 41253 | ||
4 | |||
5 | var _server = WebSocketServer.new() | ||
6 | var _peers = [] | ||
7 | |||
8 | |||
9 | func _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 | |||
17 | func _process(_delta): | ||
18 | _server.poll() | ||
19 | |||
20 | |||
21 | func _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 | |||
37 | func _connection_dropped(id, _was_clean_close): | ||
38 | _peers.erase(id) | ||
39 | |||
40 | |||
41 | func _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 | |||
68 | func _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 | |||
84 | func has_connection(): | ||
85 | return _peers.size() > 0 | ||
86 | |||
87 | |||
88 | func update_position(x, z): | ||
89 | _broadcast({"cmd": "UpdatePosition", "position": {"x": x, "z": z}}) | ||
diff --git a/CHANGELOG.md b/CHANGELOG.md index d00999c..6e02284 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md | |||
@@ -1,5 +1,142 @@ | |||
1 | # lingo-archipelago Releases | 1 | # lingo-archipelago Releases |
2 | 2 | ||
3 | ## v5.4.0 - 2025-05-17 | ||
4 | |||
5 | - ProgUseful items (items marked both Progression and Useful) are now colored | ||
6 | gold in the text client and the message popups. | ||
7 | - Fixed an issue where two copies of THE MASTER could appear on top of one | ||
8 | another. | ||
9 | - This update adds a workaround for | ||
10 | [a logic error in Archipelago 0.6.1 and earlier](https://github.com/ArchipelagoMW/Archipelago/pull/5005). | ||
11 | - This bug causes the paintings in The Bearer to be considered logically | ||
12 | usable for the pilgrimage even when the "Allow Paintings For Pilgrimage" | ||
13 | option is disabled, despite the paintings not being usable in-game. This | ||
14 | can, on rare occasion, cause the game to become unbeatable. | ||
15 | - If you are playing in a slot affected by this issue (generated using | ||
16 | Archipelago 0.6.1 or earlier, with pilgrimage enabled and paintings during | ||
17 | pilgrimage disabled), the mod will work around the issue by allowing you to | ||
18 | use the paintings in The Bearer without breaking your pilgrimage. | ||
19 | - This can lead to non-intuitive gameplay, as one would not expect the | ||
20 | paintings to be usable in this situation. You can use the Lingo AP Tracker | ||
21 | to figure out whether or not you are expected to be able to perform a | ||
22 | pilgrimage, as it currently uses the same broken logic as the generator. | ||
23 | - There is already a fix for the logic error, and it will likely be included | ||
24 | as part of the next major Archipelago release. I apologize for the | ||
25 | inconvenience. | ||
26 | |||
27 | Download: | ||
28 | [lingo-archipelago-v5.4.0.zip](https://files.fourisland.com/releases/lingo-archipelago/lingo-archipelago-v5.4.0.zip)<br/> | ||
29 | Source: [v5.4.0](https://code.fourisland.com/lingo-archipelago/tag/?h=v5.4.0) | ||
30 | |||
31 | ## v5.3.1 - 2025-03-22 | ||
32 | |||
33 | - Fixed a bug with panel syncing that would cause the client to crash on | ||
34 | startup. | ||
35 | |||
36 | Download: | ||
37 | [lingo-archipelago-v5.3.1.zip](https://files.fourisland.com/releases/lingo-archipelago/lingo-archipelago-v5.3.1.zip)<br/> | ||
38 | Source: [v5.3.1](https://code.fourisland.com/lingo-archipelago/tag/?h=v5.3.1) | ||
39 | |||
40 | ## v5.3.0 - 2025-03-21 | ||
41 | |||
42 | - Panel solves are now saved in the multiworld state. | ||
43 | - This means you no longer have to copy your save file if you want to play on | ||
44 | a second computer. Connecting to the slot will automatically download all of | ||
45 | your solved panels. | ||
46 | - It also makes slot co-op easy and seamless. Panels solved by other players | ||
47 | connected to the same slot as you will automatically solve for you, and any | ||
48 | doors connected to them will open. | ||
49 | - In multiplayer mode, players' Steam names will now appear over their heads, so | ||
50 | that multiple players connected to the same slot can be distinguished. | ||
51 | |||
52 | Download: | ||
53 | [lingo-archipelago-v5.3.0.zip](https://files.fourisland.com/releases/lingo-archipelago/lingo-archipelago-v5.3.0.zip)<br/> | ||
54 | Source: [v5.3.0](https://code.fourisland.com/lingo-archipelago/tag/?h=v5.3.0) | ||
55 | |||
56 | ## v5.2.0 - 2025-02-10 | ||
57 | |||
58 | - When displaying newly received items at connection time, multiple instances of | ||
59 | the same received item will be consolidated to save space. | ||
60 | |||
61 | Download: | ||
62 | [lingo-archipelago-v5.2.0.zip](https://files.fourisland.com/releases/lingo-archipelago/lingo-archipelago-v5.2.0.zip)<br/> | ||
63 | Source: [v5.2.0](https://code.fourisland.com/lingo-archipelago/tag/?h=v5.2.0) | ||
64 | |||
65 | ## v5.1.0 - 2024-12-20 | ||
66 | |||
67 | - The tracker can now connect to Lingo when it is running the Archipelago mod, | ||
68 | which allows it to display the player's position and solved panels. This | ||
69 | requires v0.12.0 of the tracker. | ||
70 | |||
71 | Download: | ||
72 | [lingo-archipelago-v5.1.0.zip](https://files.fourisland.com/releases/lingo-archipelago/lingo-archipelago-v5.1.0.zip)<br/> | ||
73 | Source: [v5.1.0](https://code.fourisland.com/lingo-archipelago/tag/?h=v5.1.0) | ||
74 | |||
75 | ## v5.0.1 - 2024-12-08 | ||
76 | |||
77 | - This update adds a workaround for | ||
78 | [a logic error in Archipelago 0.5.1](https://github.com/ArchipelagoMW/Archipelago/pull/4342). | ||
79 | If your slot is affected by this bug (if you are playing panels mode door | ||
80 | shuffle in a multiworld generated on Archipelago 0.5.1), the following changes | ||
81 | will occur: | ||
82 | - The broken panels (listed at the above link) will now unlock at one | ||
83 | Progressive Number Hunt earlier than would be expected. | ||
84 | - The doors covering the broken panels will now open when all of the numbers | ||
85 | in the previous set have been solved, instead of when the number in the | ||
86 | number hunt hallway is solved. | ||
87 | - This can lead to some non-intuitive gameplay, because the panels no longer | ||
88 | unlock the way they do in the base game. To help with this, v0.11.5 of the | ||
89 | tracker now uses the 0.5.1 broken logic, so that you can always tell what is | ||
90 | expected of you. | ||
91 | - There is already a fix for the logic error, and it will likely be included as | ||
92 | part of the next major Archipelago release. I apologize for the inconvenience. | ||
93 | |||
94 | Download: | ||
95 | [lingo-archipelago-v5.0.1.zip](https://files.fourisland.com/releases/lingo-archipelago/lingo-archipelago-v5.0.1.zip)<br/> | ||
96 | Source: [v5.0.1](https://code.fourisland.com/lingo-archipelago/tag/?h=v5.0.1) | ||
97 | |||
98 | ## v5.0.0 - 2024-11-26 | ||
99 | |||
100 | - [Archipelago 0.5.1](https://github.com/ArchipelagoMW/Archipelago/releases/tag/0.5.1) | ||
101 | has been released! this release includes a couple of major new features for | ||
102 | Lingo: | ||
103 | - There is a new type of door shuffle called "panels mode". In panels mode, | ||
104 | the doors open when their vanilla panels are solved, but the panels | ||
105 | themselves are locked behind items. This provides a vanilla-like progression | ||
106 | route through the game, while maintaining a door shuffle amount of | ||
107 | progression gating. | ||
108 | - By default, checks that are behind your victory condition are now removed | ||
109 | from your world. | ||
110 | - There are also a number of minor tweaks and bug fixes, which you can see in | ||
111 | the above changelog. | ||
112 | - This update should retain compatibility with Archipelago 0.5.0 worlds. | ||
113 | - The messages in the bottom left corner now lets you know if an item you sent | ||
114 | out was hinted. | ||
115 | - The text in the text client is now selectable. | ||
116 | |||
117 | Download: | ||
118 | [lingo-archipelago-v5.0.0.zip](https://files.fourisland.com/releases/lingo-archipelago/lingo-archipelago-v5.0.0.zip)<br/> | ||
119 | Source: [v5.0.0](https://code.fourisland.com/lingo-archipelago/tag/?h=v5.0.0) | ||
120 | |||
121 | ## v4.2.1 - 2024-09-21 | ||
122 | |||
123 | - The text client will no longer open if SHIFT is being held, to prevent | ||
124 | conflicts with the Steam Overlay. | ||
125 | |||
126 | Download: | ||
127 | [lingo-archipelago-v4.2.1.zip](https://files.fourisland.com/releases/lingo-archipelago/lingo-archipelago-v4.2.1.zip)<br/> | ||
128 | Source: [v4.2.1](https://code.fourisland.com/lingo-archipelago/tag/?h=v4.2.1) | ||
129 | |||
130 | ## v4.2.0 - 2024-09-20 | ||
131 | |||
132 | - Added a proximity chat feature. You can use the command "/say" followed by a | ||
133 | message in the text client, and it will broadcast the message only to other | ||
134 | nearby Lingo players. | ||
135 | |||
136 | Download: | ||
137 | [lingo-archipelago-v4.2.0.zip](https://files.fourisland.com/releases/lingo-archipelago/lingo-archipelago-v4.2.0.zip)<br/> | ||
138 | Source: [v4.2.0](https://code.fourisland.com/lingo-archipelago/tag/?h=v4.2.0) | ||
139 | |||
3 | ## v4.1.0 - 2024-09-02 | 140 | ## v4.1.0 - 2024-09-02 |
4 | 141 | ||
5 | - Added an in-game text client, which can be used to talk to other players and | 142 | - Added an in-game text client, which can be used to talk to other players and |
diff --git a/README.md b/README.md index dcdc9cd..cfded75 100644 --- a/README.md +++ b/README.md | |||
@@ -195,3 +195,13 @@ This is no longer relevant, because all possible pilgrimage paths are now in | |||
195 | logic, but you can still see the old route | 195 | logic, but you can still see the old route |
196 | [starting at 2:47 in this video](https://youtu.be/8GfuDRRswdA?t=167) for | 196 | [starting at 2:47 in this video](https://youtu.be/8GfuDRRswdA?t=167) for |
197 | reference. | 197 | reference. |
198 | |||
199 | ### The mod won't load! It just shows the settings screen instead. | ||
200 | |||
201 | This is typically caused by playing on a severely outdated or pirated version of | ||
202 | Lingo. If your copy of Lingo doesn't contain Level 2, it will not be able to run | ||
203 | the Archipelago mod. It is recommended that you keep Lingo up-to-date, as the | ||
204 | mod is only intended to support the latest version of the game. For instance, | ||
205 | even if you are able to get the mod to run on an older version of the game, you | ||
206 | may be expected to do things that aren't possible, like use passages that don't | ||
207 | exist yet. | ||
diff --git a/util/generate_gamedata.rb b/util/generate_gamedata.rb index ce8df43..7db06ca 100644 --- a/util/generate_gamedata.rb +++ b/util/generate_gamedata.rb | |||
@@ -12,24 +12,43 @@ CLASSIFICATION_SMALL_SPHERE_ONE = 8 | |||
12 | 12 | ||
13 | panel_to_id = {} | 13 | panel_to_id = {} |
14 | door_groups = {} | 14 | door_groups = {} |
15 | panel_groups = {} | ||
15 | warp_groups = {} | 16 | warp_groups = {} |
16 | 17 | ||
17 | panel_output = [] | 18 | panel_output = [] |
18 | door_ids_by_item_id = {} | 19 | door_ids_by_item_id = {} |
19 | painting_ids_by_item_id = {} | 20 | painting_ids_by_item_id = {} |
21 | panel_ids_by_item_id = {} | ||
20 | warp_ids_by_item_id = {} | 22 | warp_ids_by_item_id = {} |
21 | panel_ids_by_location_id = {} | 23 | panel_ids_by_location_id = {} |
22 | classification_by_location_id = {} | 24 | classification_by_location_id = {} |
23 | sunwarps = Array.new(12) {Hash.new} | 25 | sunwarps = Array.new(12) {Hash.new} |
24 | mentioned_doors = Set[] | 26 | mentioned_doors = Set[] |
25 | mentioned_paintings = Set[] | 27 | mentioned_paintings = Set[] |
28 | mentioned_panels = Set[] | ||
26 | mentioned_warps = Set[] | 29 | mentioned_warps = Set[] |
27 | painting_output = {} | 30 | painting_output = {} |
28 | items_by_progressive_id = {} | 31 | door_items_by_progressive_id = {} |
32 | panel_items_by_progressive_id = {} | ||
33 | panel_location_ids = [] | ||
34 | solve_index_by_location = {} | ||
29 | 35 | ||
30 | ids_config = YAML.load_file(idspath) | 36 | ids_config = YAML.load_file(idspath) |
31 | |||
32 | config = YAML.load_file(configpath) | 37 | config = YAML.load_file(configpath) |
38 | |||
39 | config.each do |room_name, room_data| | ||
40 | if room_data.include? "panels" | ||
41 | room_data["panels"].each do |panel_name, panel| | ||
42 | location_id = ids_config["panels"][room_name][panel_name] | ||
43 | panel_location_ids << location_id | ||
44 | end | ||
45 | end | ||
46 | end | ||
47 | |||
48 | panel_location_ids.sort.each_with_index do |location_id, index| | ||
49 | solve_index_by_location[location_id] = index | ||
50 | end | ||
51 | |||
33 | config.each do |room_name, room_data| | 52 | config.each do |room_name, room_data| |
34 | if room_data.include? "panels" | 53 | if room_data.include? "panels" |
35 | room_data["panels"].each do |panel_name, panel| | 54 | room_data["panels"].each do |panel_name, panel| |
@@ -41,6 +60,7 @@ config.each do |room_name, room_data| | |||
41 | ret = {} | 60 | ret = {} |
42 | ret["id"] = "\"#{panel["id"]}\"" | 61 | ret["id"] = "\"#{panel["id"]}\"" |
43 | ret["loc"] = location_id | 62 | ret["loc"] = location_id |
63 | ret["solve_index"] = solve_index_by_location[location_id] | ||
44 | if panel.include? "colors" | 64 | if panel.include? "colors" |
45 | if panel["colors"].kind_of? String | 65 | if panel["colors"].kind_of? String |
46 | ret["color"] = "[\"#{panel["colors"]}\"]" | 66 | ret["color"] = "[\"#{panel["colors"]}\"]" |
@@ -69,9 +89,6 @@ config.each do |room_name, room_data| | |||
69 | if panel.include? "achievement" | 89 | if panel.include? "achievement" |
70 | ret["achievement"] = "\"#{panel["achievement"]}\"" | 90 | ret["achievement"] = "\"#{panel["achievement"]}\"" |
71 | end | 91 | end |
72 | if panel.include? "hunt" and panel["hunt"] | ||
73 | ret["hunt"] = "true" | ||
74 | end | ||
75 | panel_output << ret | 92 | panel_output << ret |
76 | 93 | ||
77 | panel_ids_by_location_id[location_id] = [panel["id"]] | 94 | panel_ids_by_location_id[location_id] = [panel["id"]] |
@@ -110,15 +127,29 @@ config.each do |room_name, room_data| | |||
110 | end | 127 | end |
111 | 128 | ||
112 | if room_data.include? "progression" | 129 | if room_data.include? "progression" |
113 | room_data["progression"].each do |progressive_item_name, progression| | 130 | room_data["progression"].each do |progressive_item_name, pdata| |
114 | progressive_id = ids_config["progression"][progressive_item_name] | 131 | progressive_id = ids_config["progression"][progressive_item_name] |
115 | items_by_progressive_id[progressive_id] = [] | ||
116 | 132 | ||
117 | progression.each do |item| | 133 | if pdata.include? "doors" |
118 | item_room_name = (item.kind_of? Hash) ? item["room"] : room_name | 134 | door_items_by_progressive_id[progressive_id] = [] |
119 | item_item_name = (item.kind_of? Hash) ? item["door"] : item | 135 | |
136 | pdata["doors"].each do |item| | ||
137 | item_room_name = (item.kind_of? Hash) ? item["room"] : room_name | ||
138 | item_item_name = (item.kind_of? Hash) ? item["door"] : item | ||
139 | |||
140 | door_items_by_progressive_id[progressive_id] << ids_config["doors"][item_room_name][item_item_name]["item"] | ||
141 | end | ||
142 | end | ||
143 | |||
144 | if pdata.include? "panel_doors" | ||
145 | panel_items_by_progressive_id[progressive_id] = [] | ||
120 | 146 | ||
121 | items_by_progressive_id[progressive_id] << ids_config["doors"][item_room_name][item_item_name]["item"] | 147 | pdata["panel_doors"].each do |item| |
148 | item_room_name = (item.kind_of? Hash) ? item["room"] : room_name | ||
149 | item_item_name = (item.kind_of? Hash) ? item["panel_door"] : item | ||
150 | |||
151 | panel_items_by_progressive_id[progressive_id] << ids_config["panel_doors"][item_room_name][item_item_name] | ||
152 | end | ||
122 | end | 153 | end |
123 | end | 154 | end |
124 | end | 155 | end |
@@ -206,6 +237,26 @@ config.each do |room_name, room_data| | |||
206 | end | 237 | end |
207 | end | 238 | end |
208 | end | 239 | end |
240 | |||
241 | if room_data.include? "panel_doors" | ||
242 | room_data["panel_doors"].each do |panel_door_name, panel_door| | ||
243 | item_id = ids_config["panel_doors"][room_name][panel_door_name] | ||
244 | |||
245 | panel_ids_by_item_id[item_id] = panel_door["panels"].map do |panel_identifier| | ||
246 | other_room_name = (panel_identifier.kind_of? String) ? room_name : panel_identifier["room"] | ||
247 | other_panel_name = (panel_identifier.kind_of? String) ? panel_identifier : panel_identifier["panel"] | ||
248 | |||
249 | config[other_room_name]["panels"][other_panel_name]["id"] | ||
250 | end | ||
251 | |||
252 | mentioned_panels.merge(panel_ids_by_item_id[item_id]) | ||
253 | |||
254 | if panel_door.include? "panel_group" | ||
255 | panel_groups[panel_door["panel_group"]] ||= Set[] | ||
256 | panel_groups[panel_door["panel_group"]].merge(panel_ids_by_item_id[item_id]) | ||
257 | end | ||
258 | end | ||
259 | end | ||
209 | end | 260 | end |
210 | 261 | ||
211 | door_groups.each do |group_name, door_ids| | 262 | door_groups.each do |group_name, door_ids| |
@@ -213,6 +264,11 @@ door_groups.each do |group_name, door_ids| | |||
213 | door_ids_by_item_id[item_id] = door_ids.to_a | 264 | door_ids_by_item_id[item_id] = door_ids.to_a |
214 | end | 265 | end |
215 | 266 | ||
267 | panel_groups.each do |group_name, panel_ids| | ||
268 | item_id = ids_config["panel_groups"][group_name] | ||
269 | panel_ids_by_item_id[item_id] = panel_ids.to_a | ||
270 | end | ||
271 | |||
216 | warp_groups.each do |group_name, warp_ids| | 272 | warp_groups.each do |group_name, warp_ids| |
217 | item_id = ids_config["door_groups"][group_name] | 273 | item_id = ids_config["door_groups"][group_name] |
218 | warp_ids_by_item_id[item_id] = warp_ids.to_a | 274 | warp_ids_by_item_id[item_id] = warp_ids.to_a |
@@ -231,6 +287,12 @@ File.open(outputpath, "w") do |f| | |||
231 | "\"#{door_id}\"" | 287 | "\"#{door_id}\"" |
232 | end.join(",") + "]" | 288 | end.join(",") + "]" |
233 | end.join(",")) | 289 | end.join(",")) |
290 | f.write "}\nvar panel_ids_by_item_id = {" | ||
291 | f.write(panel_ids_by_item_id.map do |item_id, panel_ids| | ||
292 | "#{item_id}:[" + panel_ids.map do |panel_id| | ||
293 | "\"#{panel_id}\"" | ||
294 | end.join(",") + "]" | ||
295 | end.join(",")) | ||
234 | f.write "}\nvar painting_ids_by_item_id = {" | 296 | f.write "}\nvar painting_ids_by_item_id = {" |
235 | f.write(painting_ids_by_item_id.map do |item_id, painting_ids| | 297 | f.write(painting_ids_by_item_id.map do |item_id, painting_ids| |
236 | "#{item_id}:[" + painting_ids.map do |painting_id| | 298 | "#{item_id}:[" + painting_ids.map do |painting_id| |
@@ -257,6 +319,10 @@ File.open(outputpath, "w") do |f| | |||
257 | f.write(mentioned_paintings.map do |painting_id| | 319 | f.write(mentioned_paintings.map do |painting_id| |
258 | "\"#{painting_id}\"" | 320 | "\"#{painting_id}\"" |
259 | end.join(",")) | 321 | end.join(",")) |
322 | f.write "]\nvar mentioned_panels = [" | ||
323 | f.write(mentioned_panels.map do |panel_id| | ||
324 | "\"#{panel_id}\"" | ||
325 | end.join(",")) | ||
260 | f.write "]\nvar mentioned_warps = [" | 326 | f.write "]\nvar mentioned_warps = [" |
261 | f.write(mentioned_warps.map do |warp_id| | 327 | f.write(mentioned_warps.map do |warp_id| |
262 | "\"#{warp_id}\"" | 328 | "\"#{warp_id}\"" |
@@ -273,8 +339,12 @@ File.open(outputpath, "w") do |f| | |||
273 | f.write(sunwarps.map do |sunwarp| | 339 | f.write(sunwarps.map do |sunwarp| |
274 | "{\"orientation\":\"#{sunwarp["orientation"]}\",\"entrance_indicator_pos\":#{sunwarp["entrance_indicator_pos"].to_s}}" | 340 | "{\"orientation\":\"#{sunwarp["orientation"]}\",\"entrance_indicator_pos\":#{sunwarp["entrance_indicator_pos"].to_s}}" |
275 | end.join(",")) | 341 | end.join(",")) |
276 | f.write "]\nvar items_by_progressive_id = {" | 342 | f.write "]\nvar door_items_by_progressive_id = {" |
277 | f.write(items_by_progressive_id.map do |item_id, progression_ids| | 343 | f.write(door_items_by_progressive_id.map do |item_id, progression_ids| |
344 | "#{item_id}:[" + progression_ids.map(&:to_s).join(",") + "]" | ||
345 | end.join(",")) | ||
346 | f.write "}\nvar panel_items_by_progressive_id = {" | ||
347 | f.write(panel_items_by_progressive_id.map do |item_id, progression_ids| | ||
278 | "#{item_id}:[" + progression_ids.map(&:to_s).join(",") + "]" | 348 | "#{item_id}:[" + progression_ids.map(&:to_s).join(",") + "]" |
279 | end.join(",")) | 349 | end.join(",")) |
280 | f.write "}" | 350 | f.write "}" |