extends Node
var SCRIPT_doorControl
var SCRIPT_effects
var SCRIPT_location
var SCRIPT_multiplayer
var SCRIPT_mypainting
var SCRIPT_notifier
var SCRIPT_panel
var SCRIPT_pilgrimage_terminator
var SCRIPT_textclient
var SCRIPT_uuid
var ap_server = ""
var ap_user = ""
var ap_pass = ""
var confusify_world = false
var enable_multiplayer = false
var track_player = false
var connection_history = []
const my_version = "4.2.0"
const ap_version = {"major": 0, "minor": 5, "build": 0, "class": "Version"}
const color_items = [
"White", "Black", "Red", "Blue", "Green", "Brown", "Gray", "Orange", "Purple", "Yellow"
]
const progressive_items = {
"Progressive Orange Tower":
["Second Floor", "Third Floor", "Fourth Floor", "Fifth Floor", "Sixth Floor", "Seventh Floor"],
"Progressive Art Gallery":
["Second Floor", "Third Floor", "Fourth Floor", "Fifth Floor", "Exit"],
"Progressive Hallway Room": ["First Door", "Second Door", "Third Door", "Fourth Door"],
"Progressive Fearless": ["Second Floor", "Third Floor"],
"Progressive Colorful":
["White", "Black", "Red", "Yellow", "Blue", "Purple", "Orange", "Green", "Brown", "Gray"],
"Progressive Pilgrimage":
["1 Sunwarp", "2 Sunwarp", "3 Sunwarp", "4 Sunwarp", "5 Sunwarp", "6 Sunwarp"]
}
const kTHE_END = 0
const kTHE_MASTER = 1
const kLEVEL_2 = 2
const kPILGRIMAGE = 3
const kNO_PANEL_SHUFFLE = 0
const kREARRANGE_PANELS = 1
const kCLASSIFICATION_LOCAL_NORMAL = 1
const kCLASSIFICATION_LOCAL_REDUCED = 2
const kCLASSIFICATION_LOCAL_INSANITY = 4
const kCLASSIFICATION_LOCAL_SMALL_SPHERE_ONE = 8
const kCLASSIFICATION_REMOTE_NORMAL = 0
const kCLASSIFICATION_REMOTE_REDUCED = 1
const kCLASSIFICATION_REMOTE_INSANITY = 2
const kSUNWARP_ACCESS_NORMAL = 0
const kSUNWARP_ACCESS_DISABLED = 1
const kSUNWARP_ACCESS_UNLOCK = 2
const kSUNWARP_ACCESS_INDIVIDUAL = 3
const kSUNWARP_ACCESS_PROGRESSIVE = 4
var _client = WebSocketClient.new()
var _should_process = false
var _initiated_disconnect = false
var _try_wss = false
var _datapackages = {}
var _pending_packages = []
var _item_id_to_name = {} # All games
var _location_id_to_name = {} # All games
var _item_name_to_id = {} # LINGO only
var _location_name_to_id = {} # LINGO only
var _remote_version = {"major": 0, "minor": 0, "build": 0}
var _gen_version = {"major": 0, "minor": 0, "build": 0}
# TODO: caching per MW/slot, reset between connections
var _authenticated = false
var _seed = ""
var _team = 0
var _slot = 0
var _players = []
var _player_name_by_slot = {}
var _game_by_player = {}
var _checked_locations = []
var _slot_data = {}
var _paintings_mapping = {}
var _localdata_file = ""
var _death_link = false
var _victory_condition = 0 # THE END, THE MASTER, LEVEL 2
var _door_shuffle = false
var _color_shuffle = false
var _panel_shuffle = 0 # none, rearrange
var _painting_shuffle = false
var _sunwarp_access = 0 # normal, disabled, unlock, progressive
var _mastery_achievements = 21
var _level_2_requirement = 223
var _location_classification_bit = 0
var _early_color_hallways = false
var _pilgrimage_compatibility = false # set to true for pre-0.4.6
var _pilgrimage_enabled = false
var _pilgrimage_allows_roof_access = false
var _pilgrimage_allows_paintings = false
var _sunwarp_shuffle = false
var _sunwarp_mapping = []
var _speed_boost_mode = false
var _slot_seed = 0
var _map_loaded = false
var _held_items = []
var _held_locations = []
var _last_new_item = -1
var _progressive_progress = {}
var _has_colors = ["white"]
var _received_indexes = []
var _puzzle_skips = 0
var _cached_slowness = 0
var _cached_iceland = 0
var _cached_atbash = 0
var _cached_speed_boosts = 0
var _geronimo_skip = false
var _checked_paintings = []
signal could_not_connect
signal connect_status
signal client_connected
signal evaluate_solvability
func _init():
global._print("Instantiated APClient")
# Read AP settings from file, if there are any
var file = File.new()
if file.file_exists("user://settings/archipelago"):
file.open("user://settings/archipelago", File.READ)
var data = file.get_var(true)
file.close()
if typeof(data) != TYPE_ARRAY:
global._print("AP settings file is corrupted")
data = []
if data.size() > 0:
ap_server = data[0]
if data.size() > 1:
ap_user = data[1]
if data.size() > 2:
ap_pass = data[2]
if data.size() > 3:
_datapackages = data[3]
if data.size() > 4:
confusify_world = data[4]
if data.size() > 5:
enable_multiplayer = data[5]
if data.size() > 6:
track_player = data[6]
if data.size() > 7:
connection_history = data[7]
processDatapackages()
func _ready():
_client.connect("connection_closed", self, "_closed")
_client.connect("connection_failed", self, "_closed")
_client.connect("server_disconnected", self, "_closed")
_client.connect("connection_error", self, "_errored")
_client.connect("connection_established", self, "_connected")
_client.connect("data_received", self, "_on_data")
func _reset_state():
_should_process = false
_authenticated = false
_map_loaded = false
_try_wss = false
func _errored():
if _try_wss:
global._print("Could not connect to AP with ws://, now trying wss://")
connectToServer()
else:
global._print("AP connection failed")
_reset_state()
emit_signal(
"could_not_connect",
"Could not connect to Archipelago. Check that your server and port are correct. See the error log for more information."
)
func _closed(_was_clean = true):
global._print("Connection closed")
_reset_state()
if not _initiated_disconnect:
emit_signal("could_not_connect", "Disconnected from Archipelago")
_initiated_disconnect = false
func _connected(_proto = ""):
global._print("Connected!")
_try_wss = false
func disconnect_from_ap():
_initiated_disconnect = true
_client.disconnect_from_host()
func _on_data():
var packet = _client.get_peer(1).get_packet()
global._print("Got data from server: " + packet.get_string_from_utf8())
var data = JSON.parse(packet.get_string_from_utf8())
if data.error != OK:
global._print("Error parsing packet from AP: " + data.error_string)
return
for message in data.result:
var cmd = message["cmd"]
global._print("Received command: " + cmd)
if cmd == "RoomInfo":
_seed = message["seed_name"]
_remote_version = message["version"]
_gen_version = message["generator_version"]
var needed_games = []
for game in message["datapackage_checksums"].keys():
if (
!_datapackages.has(game)
or _datapackages[game]["checksum"] != message["datapackage_checksums"][game]
):
needed_games.append(game)
if !needed_games.empty():
_pending_packages = needed_games
var cur_needed = _pending_packages.pop_front()
requestDatapackages([cur_needed])
else:
connectToRoom()
elif cmd == "DataPackage":
for game in message["data"]["games"].keys():
_datapackages[game] = message["data"]["games"][game]
saveSettings()
if !_pending_packages.empty():
var cur_needed = _pending_packages.pop_front()
requestDatapackages([cur_needed])
else:
processDatapackages()
connectToRoom()
elif cmd == "Connected":
_authenticated = true
_team = message["team"]
_slot = message["slot"]
_players = message["players"]
_checked_locations = message["checked_locations"]
_slot_data = message["slot_data"]
for player in _players:
_player_name_by_slot[player["slot"]] = player["alias"]
_game_by_player[player["slot"]] = message["slot_info"][str(player["slot"])]["game"]
_death_link = _slot_data.has("death_link") and _slot_data["death_link"]
if _death_link:
sendConnectUpdate(["DeathLink"])
if _slot_data.has("victory_condition"):
_victory_condition = _slot_data["victory_condition"]
if _slot_data.has("shuffle_colors"):
_color_shuffle = _slot_data["shuffle_colors"]
if _slot_data.has("shuffle_doors"):
_door_shuffle = (_slot_data["shuffle_doors"] > 0)
else:
_door_shuffle = false
if _slot_data.has("shuffle_paintings"):
_painting_shuffle = _slot_data["shuffle_paintings"]
if _slot_data.has("shuffle_panels"):
_panel_shuffle = _slot_data["shuffle_panels"]
if _slot_data.has("sunwarp_access"):
_sunwarp_access = _slot_data["sunwarp_access"]
else:
_sunwarp_access = kSUNWARP_ACCESS_NORMAL
if _slot_data.has("seed"):
_slot_seed = _slot_data["seed"]
if _slot_data.has("painting_entrance_to_exit"):
_paintings_mapping = _slot_data["painting_entrance_to_exit"]
if _slot_data.has("mastery_achievements"):
_mastery_achievements = _slot_data["mastery_achievements"]
if _slot_data.has("level_2_requirement"):
_level_2_requirement = _slot_data["level_2_requirement"]
if _slot_data.has("location_checks"):
if _slot_data["location_checks"] == kCLASSIFICATION_REMOTE_NORMAL:
_location_classification_bit = kCLASSIFICATION_LOCAL_NORMAL
elif _slot_data["location_checks"] == kCLASSIFICATION_REMOTE_REDUCED:
_location_classification_bit = kCLASSIFICATION_LOCAL_REDUCED
elif _slot_data["location_checks"] == kCLASSIFICATION_REMOTE_INSANITY:
_location_classification_bit = kCLASSIFICATION_LOCAL_INSANITY
else:
_location_classification_bit = kCLASSIFICATION_LOCAL_NORMAL
if _slot_data.has("early_color_hallways"):
_early_color_hallways = _slot_data["early_color_hallways"]
else:
_early_color_hallways = false
if _slot_data.has("enable_pilgrimage"):
_pilgrimage_enabled = _slot_data["enable_pilgrimage"]
else:
_pilgrimage_compatibility = true
_pilgrimage_enabled = true
if _slot_data.has("pilgrimage_allows_roof_access"):
_pilgrimage_allows_roof_access = _slot_data["pilgrimage_allows_roof_access"]
else:
_pilgrimage_allows_roof_access = true
if _slot_data.has("pilgrimage_allows_paintings"):
_pilgrimage_allows_paintings = _slot_data["pilgrimage_allows_paintings"]
else:
_pilgrimage_allows_paintings = true
if _slot_data.has("shuffle_sunwarps"):
_sunwarp_shuffle = _slot_data["shuffle_sunwarps"]
else:
_sunwarp_shuffle = false
if _slot_data.has("sunwarp_permutation"):
_sunwarp_mapping = _slot_data["sunwarp_permutation"]
if _slot_data.has("speed_boost_mode"):
_speed_boost_mode = _slot_data["speed_boost_mode"]
else:
_speed_boost_mode = false
if (
_location_classification_bit != kCLASSIFICATION_LOCAL_INSANITY
and _door_shuffle
and not _early_color_hallways
):
_location_classification_bit += kCLASSIFICATION_LOCAL_SMALL_SPHERE_ONE
if track_player:
setValue("PlayerPos", {"x": 0, "z": 0})
else:
setValue("PlayerPos", null)
_puzzle_skips = 0
_last_new_item = -1
_cached_slowness = 0
_cached_iceland = 0
_cached_atbash = 0
_cached_speed_boosts = 0
_geronimo_skip = false
_localdata_file = "user://archipelago_data/%s_%d" % [_seed, _slot]
var ap_file = File.new()
if ap_file.file_exists(_localdata_file):
ap_file.open(_localdata_file, File.READ)
var localdata = ap_file.get_var(true)
ap_file.close()
if typeof(localdata) != TYPE_ARRAY:
global._print("AP localdata file is corrupted")
localdata = []
if localdata.size() > 0:
_last_new_item = localdata[0]
if localdata.size() > 1:
_puzzle_skips = localdata[1]
if localdata.size() > 2:
_cached_slowness = localdata[2]
if localdata.size() > 3:
_cached_iceland = localdata[3]
if localdata.size() > 4:
_cached_atbash = localdata[4]
if localdata.size() > 5:
_geronimo_skip = localdata[5]
if localdata.size() > 6:
_cached_speed_boosts = localdata[6]
requestSync()
sendMessage(
[
{
"cmd": "Set",
"key": "Lingo_%d_Paintings" % [_slot],
"default": [],
"want_reply": true,
"operations": [{"operation": "default", "value": []}]
}
]
)
emit_signal("client_connected")
elif cmd == "ConnectionRefused":
var error_message = ""
for error in message["errors"]:
var submsg = ""
if error == "InvalidSlot":
submsg = "Invalid player name."
elif error == "InvalidGame":
submsg = "The specified player is not playing Lingo."
elif error == "IncompatibleVersion":
submsg = (
"The Archipelago server is not the correct version for this client. Expected v%d.%d.%d. Found v%d.%d.%d."
% [
ap_version["major"],
ap_version["minor"],
ap_version["build"],
_remote_version["major"],
_remote_version["minor"],
_remote_version["build"]
]
)
elif error == "InvalidPassword":
submsg = "Incorrect password."
elif error == "InvalidItemsHandling":
submsg = "Invalid item handling flag. This is a bug with the client. Please report it to the lingo-archipelago GitHub."
if submsg != "":
if error_message != "":
error_message += " "
error_message += submsg
if error_message == "":
error_message = "Unknown error."
_initiated_disconnect = true
_client.disconnect_from_host()
emit_signal("could_not_connect", error_message)
global._print("Connection to AP refused")
global._print(message)
elif cmd == "ReceivedItems":
var i = 0
for item in message["items"]:
if _map_loaded:
processItem(item["item"], message["index"] + i, item["player"], item["flags"])
else:
_held_items.append(
{
"item": item["item"],
"index": message["index"] + i,
"from": item["player"],
"flags": item["flags"]
}
)
i += 1
elif cmd == "PrintJSON":
parse_printjson(message)
if (
!message.has("receiving")
or !message.has("item")
or message["item"]["player"] != _slot
):
continue
var item_name = "Unknown"
var item_player_game = _game_by_player[message["receiving"]]
if _item_id_to_name[item_player_game].has(message["item"]["item"]):
item_name = _item_id_to_name[item_player_game][message["item"]["item"]]
var location_name = "Unknown"
var location_player_game = _game_by_player[message["item"]["player"]]
if _location_id_to_name[location_player_game].has(message["item"]["location"]):
location_name = _location_id_to_name[location_player_game][message["item"]["location"]]
var player_name = "Unknown"
if _player_name_by_slot.has(message["receiving"]):
player_name = _player_name_by_slot[message["receiving"]]
var item_color = colorForItemType(message["item"]["flags"])
if message["type"] == "Hint":
var is_for = ""
if message["receiving"] != _slot:
is_for = " for %s" % player_name
if !message.has("found") || !message["found"]:
messages.showMessage(
(
"Hint: [color=%s]%s[/color]%s is on %s"
% [item_color, item_name, is_for, location_name]
)
)
else:
if message["receiving"] != _slot:
messages.showMessage(
"Sent [color=%s]%s[/color] to %s" % [item_color, item_name, player_name]
)
elif cmd == "Bounced":
if (
_death_link
and message.has("tags")
and message.has("data")
and message["tags"].has("DeathLink")
):
var first_sentence = "Received Death"
var second_sentence = ""
if message["data"].has("source"):
first_sentence = "Received Death from %s" % message["data"]["source"]
if message["data"].has("cause") and message["data"]["cause"] != "":
second_sentence = ". Reason: %s" % message["data"]["cause"]
messages.showMessage(first_sentence + second_sentence)
# Return the player home.
get_tree().get_root().get_node("Spatial/player/pause_menu")._reload()
elif cmd == "SetReply":
if message.has("key") and message["key"] == ("Lingo_%d_Paintings" % _slot):
_checked_paintings = message["value"]
func _process(_delta):
if _should_process:
_client.poll()
func saveSettings():
# Save the AP settings to disk.
var dir = Directory.new()
var path = "user://settings"
if dir.dir_exists(path):
pass
else:
dir.make_dir(path)
var file = File.new()
file.open("user://settings/archipelago", File.WRITE)
var data = [
ap_server,
ap_user,
ap_pass,
_datapackages,
confusify_world,
enable_multiplayer,
track_player,
connection_history
]
file.store_var(data, true)
file.close()
func saveLocaldata():
# Save the MW/slot specific settings to disk.
var dir = Directory.new()
var path = "user://archipelago_data"
if dir.dir_exists(path):
pass
else:
dir.make_dir(path)
var file = File.new()
file.open(_localdata_file, File.WRITE)
var effects_node = get_tree().get_root().get_node("Spatial/AP_Effects")
var data = [
_last_new_item,
_puzzle_skips,
effects_node.slowness_remaining,
effects_node.iceland_remaining,
effects_node.atbash_remaining,
_geronimo_skip,
effects_node.speed_boosts_remaining,
]
file.store_var(data, true)
file.close()
func getSaveFileName():
return "zzAP_%s_%d" % [_seed, _slot]
func connectToServer():
_initiated_disconnect = false
var url = ""
if ap_server.begins_with("ws://") or ap_server.begins_with("wss://"):
url = ap_server
_try_wss = false
elif _try_wss:
url = "wss://" + ap_server
_try_wss = false
else:
url = "ws://" + ap_server
_try_wss = true
var err = _client.connect_to_url(url)
if err != OK:
emit_signal(
"could_not_connect",
(
"Could not connect to Archipelago. Check that your server and port are correct. See the error log for more information. Error code: %d."
% err
)
)
global._print("Could not connect to AP: " + err)
return
_should_process = true
emit_signal("connect_status", "Connecting...")
func sendMessage(msg):
var payload = JSON.print(msg)
_client.get_peer(1).set_write_mode(WebSocketPeer.WRITE_MODE_TEXT)
_client.get_peer(1).put_packet(payload.to_utf8())
func requestDatapackages(games):
emit_signal("connect_status", "Downloading %s data package..." % games[0])
sendMessage([{"cmd": "GetDataPackage", "games": games}])
func processDatapackages():
_item_id_to_name = {}
_location_id_to_name = {}
for game in _datapackages.keys():
var package = _datapackages[game]
_item_id_to_name[game] = {}
for name in package["item_name_to_id"].keys():
_item_id_to_name[game][package["item_name_to_id"][name]] = name
_location_id_to_name[game] = {}
for name in package["location_name_to_id"].keys():
_location_id_to_name[game][package["location_name_to_id"][name]] = name
if _datapackages.has("Lingo"):
_item_name_to_id = _datapackages["Lingo"]["item_name_to_id"]
_location_name_to_id = _datapackages["Lingo"]["location_name_to_id"]
func connectToRoom():
emit_signal("connect_status", "Authenticating...")
sendMessage(
[
{
"cmd": "Connect",
"password": ap_pass,
"game": "Lingo",
"name": ap_user,
"uuid": SCRIPT_uuid.v4(),
"version": ap_version,
"items_handling": 0b111, # always receive our items
"tags": [],
"slot_data": true
}
]
)
func sendConnectUpdate(tags):
sendMessage([{"cmd": "ConnectUpdate", "tags": tags}])
func requestSync():
sendMessage([{"cmd": "Sync"}])
func sendLocation(loc_id):
if _map_loaded:
sendMessage([{"cmd": "LocationChecks", "locations": [loc_id]}])
else:
_held_locations.append(loc_id)
func setValue(key, value, operation = "replace"):
sendMessage(
[
{
"cmd": "Set",
"key": "Lingo_%d_%s" % [_slot, key],
"want_reply": false,
"operations": [{"operation": operation, "value": value}]
}
]
)
func say(textdata):
sendMessage([{"cmd": "Say", "text": textdata}])
func completedGoal():
sendMessage([{"cmd": "StatusUpdate", "status": 30}]) # CLIENT_GOAL
messages.showMessage("You have completed your goal!")
func mapFinishedLoading():
if !_map_loaded:
_received_indexes.clear()
_progressive_progress.clear()
_has_colors = ["white"]
emit_signal("evaluate_solvability")
for item in _held_items:
processItem(item["item"], item["index"], item["from"], item["flags"])
sendMessage([{"cmd": "LocationChecks", "locations": _held_locations}])
_map_loaded = true
_held_items = []
_held_locations = []
func processItem(item, index, from, flags):
if index != null:
if _received_indexes.has(index):
# Do not re-process items.
return
_received_indexes.append(index)
global._print(item)
var gamedata = $Gamedata
var item_name = "Unknown"
if _item_id_to_name["Lingo"].has(item):
item_name = _item_id_to_name["Lingo"][item]
if gamedata.door_ids_by_item_id.has(int(item)):
var doorsNode = get_tree().get_root().get_node("Spatial/Doors")
for door_id in gamedata.door_ids_by_item_id[int(item)]:
doorsNode.get_node(door_id).openDoor()
if gamedata.painting_ids_by_item_id.has(int(item)):
var real_parent_node = get_tree().get_root().get_node("Spatial/Decorations/Paintings")
var fake_parent_node = get_tree().get_root().get_node_or_null("Spatial/AP_Paintings")
for painting_id in gamedata.painting_ids_by_item_id[int(item)]:
var painting_node = real_parent_node.get_node_or_null(painting_id)
if painting_node != null:
painting_node.movePainting()
if _painting_shuffle:
painting_node = fake_parent_node.get_node_or_null(painting_id)
if painting_node != null:
painting_node.get_node("Script").movePainting()
if gamedata.warp_ids_by_item_id.has(int(item)):
var warpsNode = get_tree().get_root().get_node("Spatial/Warps")
for warp_id in gamedata.warp_ids_by_item_id[int(item)]:
warpsNode.get_node(warp_id).unlock_warp()
# Handle progressive items.
if int(item) in gamedata.items_by_progressive_id.keys():
if not int(item) in _progressive_progress:
_progressive_progress[int(item)] = 0
if _progressive_progress[int(item)] < gamedata.items_by_progressive_id[int(item)].size():
var subitems = gamedata.items_by_progressive_id[int(item)]
var subitem_id = subitems[_progressive_progress[int(item)]]
global._print("Subitem: %d" % subitem_id)
processItem(subitem_id, null, null, null)
_progressive_progress[int(item)] += 1
if _color_shuffle and color_items.has(_item_id_to_name["Lingo"][item]):
var lcol = _item_id_to_name["Lingo"][item].to_lower()
if not _has_colors.has(lcol):
_has_colors.append(lcol)
emit_signal("evaluate_solvability")
# Show a message about the item if it's new. Also apply effects here.
if index != null and index > _last_new_item:
_last_new_item = index
saveLocaldata()
if item_name in progressive_items:
var subitem = progressive_items[item_name][_progressive_progress[int(item)] - 1]
item_name += " (%s)" % subitem
var player_name = "Unknown"
if _player_name_by_slot.has(from):
player_name = _player_name_by_slot[from]
var item_color = colorForItemType(flags)
if from == _slot:
messages.showMessage("Found [color=%s]%s[/color]" % [item_color, item_name])
else:
messages.showMessage(
"Received [color=%s]%s[/color] from %s" % [item_color, item_name, player_name]
)
var effects_node = get_tree().get_root().get_node("Spatial/AP_Effects")
if item_name == "Slowness Trap":
effects_node.trigger_slowness_trap()
if item_name == "Iceland Trap":
effects_node.trigger_iceland_trap()
if item_name == "Atbash Trap":
effects_node.trigger_atbash_trap()
if item_name == "Speed Boost":
effects_node.trigger_speed_boost()
if item_name == "Puzzle Skip":
_puzzle_skips += 1
saveLocaldata()
func doorIsVanilla(door):
return !$Gamedata.mentioned_doors.has(door)
func paintingIsVanilla(painting):
return !$Gamedata.mentioned_paintings.has(painting)
func warpIsVanilla(warp):
return !$Gamedata.mentioned_warps.has(warp)
func evaluateSolvability():
emit_signal("evaluate_solvability")
func getAvailablePuzzleSkips():
return _puzzle_skips
func usePuzzleSkip():
_puzzle_skips -= 1
saveLocaldata()
func geronimo():
if !_geronimo_skip:
messages.showMessage("Geronimo! You found a puzzle skip.")
_puzzle_skips += 1
_geronimo_skip = true
saveLocaldata()
func checkPainting(painting_id):
if _checked_paintings.has(painting_id):
return
_checked_paintings.append(painting_id)
setValue("Paintings", [painting_id], "add")
func colorForItemType(flags):
var int_flags = int(flags)
if int_flags & 1: # progression
return "#bc51e0"
elif int_flags & 2: # useful
return "#2b67ff"
elif int_flags & 4: # trap
return "#d63a22"
else: # filler
return "#14de9e"
func parse_printjson(message):
var parts = []
for message_part in message["data"]:
if !message_part.has("type") and message_part.has("text"):
parts.append(message_part["text"])
elif message_part["type"] == "player_id":
if int(message_part["text"]) == _slot:
parts.append("[color=#ee00ee]%s[/color]" % _player_name_by_slot[_slot])
else:
var from = float(message_part["text"])
parts.append("[color=#fafad2]%s[/color]" % _player_name_by_slot[from])
elif message_part["type"] == "item_id":
var item_name = "Unknown"
var item_player_game = _game_by_player[message_part["player"]]
if _item_id_to_name[item_player_game].has(float(message_part["text"])):
item_name = _item_id_to_name[item_player_game][float(message_part["text"])]
parts.append(
"[color=%s]%s[/color]" % [colorForItemType(message_part["flags"]), item_name]
)
elif message_part["type"] == "location_id":
var location_name = "Unknown"
var location_player_game = _game_by_player[message_part["player"]]
if _location_id_to_name[location_player_game].has(float(message_part["text"])):
location_name = _location_id_to_name[location_player_game][float(
message_part["text"]
)]
parts.append("[color=#00ff7f]%s[/color]" % location_name)
elif message_part.has("text"):
parts.append(message_part["text"])
var textclient_node = get_tree().get_root().get_node_or_null("Spatial/AP_TextClient")
if textclient_node != null:
textclient_node.parse_printjson("".join(parts))
func get_player_name():
return _player_name_by_slot[_slot]
func compareVersion(lhs, rhs):
if lhs["major"] == rhs["major"]:
if lhs["minor"] == rhs["minor"]:
return lhs["build"] < rhs["build"]
else:
return lhs["minor"] < rhs["minor"]
else:
return lhs["major"] < rhs["major"]
func wasGeneratedBeforeVersion(major, minor, build):
return compareVersion(_gen_version, {"major": major, "minor": minor, "build": build})