style(client): gdformat all 52 GDScript files — zero format warnings

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-05 11:09:10 +02:00
co-authored by Claude Opus 4.6
parent 572e66f026
commit 88c7407cb6
52 changed files with 2323 additions and 1061 deletions
+12 -3
View File
@@ -86,15 +86,23 @@ func _try_extract_message() -> PackedByteArray:
if _pending_length < 0:
if _read_buffer.size() < 4:
return PackedByteArray()
_pending_length = (_read_buffer[0] << 24) | (_read_buffer[1] << 16) | \
(_read_buffer[2] << 8) | _read_buffer[3]
_pending_length = (
(_read_buffer[0] << 24)
| (_read_buffer[1] << 16)
| (_read_buffer[2] << 8)
| _read_buffer[3]
)
_read_buffer = _read_buffer.slice(4)
if _pending_length > MAX_MESSAGE_SIZE:
# Stream is corrupt — we can't find the next valid frame boundary.
# Disconnect rather than silently discarding valid buffered data.
push_error(
"LocalBridge: incoming message too large: %d bytes (max %d) — disconnecting" % [_pending_length, MAX_MESSAGE_SIZE])
(
"LocalBridge: incoming message too large: %d bytes (max %d) — disconnecting"
% [_pending_length, MAX_MESSAGE_SIZE]
)
)
_corrupt = true
_pending_length = -1
_read_buffer.clear()
@@ -129,6 +137,7 @@ func reset() -> void:
# These exist for unit tests that verify framing logic without a live TCP
# connection. Not used in production code paths.
## Encode a payload into a framed byte array: [4-byte BE length][payload].
static func frame_encode(payload: PackedByteArray) -> PackedByteArray:
var len := payload.size()
+187 -87
View File
@@ -14,9 +14,9 @@ extends Node
## v20: adds settings_response field to ObserverSnapshot (#627, D-138).
const PROTOCOL_VERSION: int = 20
# -- Decode: bytes from server → GDScript types --------------------------------
## Decode an ObserverSnapshot from MessagePack bytes.
## Returns decoded snapshot Dictionary or null on error.
## v2 fields (version, game_time, player_facing, visible_tiles) default to null/empty
@@ -36,7 +36,11 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant:
var version: Variant = raw.get("version")
if version != PROTOCOL_VERSION:
push_error(
"Protocol: version mismatch (got %s, expected %s). Server and client are out of sync." % [version, PROTOCOL_VERSION])
(
"Protocol: version mismatch (got %s, expected %s). Server and client are out of sync."
% [version, PROTOCOL_VERSION]
)
)
return null
var entities: Array[Dictionary] = []
@@ -51,7 +55,11 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant:
if dropped > 0:
push_error(
"Protocol: %d/%d entities failed to decode (D-010 information boundary violation)" % [dropped, raw_entities.size()])
(
"Protocol: %d/%d entities failed to decode (D-010 information boundary violation)"
% [dropped, raw_entities.size()]
)
)
# GDScript int is signed 64-bit. Rust tick is u64 but will not exceed 2^63
# in any realistic scenario (would require ~29 billion years at 10 ticks/game-minute per D-031).
@@ -71,7 +79,12 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant:
var raw_vtiles: Variant = raw.get("visible_tiles")
if raw_vtiles is Array:
for raw_tile in raw_vtiles:
if raw_tile is Dictionary and raw_tile.has("x") and raw_tile.has("y") and raw_tile.has("z"):
if (
raw_tile is Dictionary
and raw_tile.has("x")
and raw_tile.has("y")
and raw_tile.has("z")
):
var tile_entry := {
"x": int(raw_tile["x"]),
"y": int(raw_tile["y"]),
@@ -119,11 +132,16 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant:
if raw_inventory is Array:
for raw_item in raw_inventory:
if raw_item is Dictionary and raw_item.has("item_id") and raw_item.has("name"):
player_inventory.append({
"item_id": int(raw_item["item_id"]),
"name": str(raw_item["name"]),
"slot": int(raw_item.get("slot", 0)),
})
(
player_inventory
. append(
{
"item_id": int(raw_item["item_id"]),
"name": str(raw_item["name"]),
"slot": int(raw_item.get("slot", 0)),
}
)
)
# v7: pending_recognitions (#431, D-059/D-060) — cognitive delay fog entities
# Bounded: server sends at most ~50 pending recognitions per snapshot (practical limit
@@ -135,17 +153,32 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant:
var count := 0
for raw_pr in raw_recognitions:
if count >= MAX_PENDING_RECOGNITIONS:
push_warning("Protocol: pending_recognitions truncated at %d entries" % MAX_PENDING_RECOGNITIONS)
push_warning(
(
"Protocol: pending_recognitions truncated at %d entries"
% MAX_PENDING_RECOGNITIONS
)
)
break
if raw_pr is Dictionary and raw_pr.has("entity_id") and raw_pr.has("x") and raw_pr.has("y"):
pending_recognitions.append({
"entity_id": int(raw_pr["entity_id"]),
"x": float(raw_pr["x"]),
"y": float(raw_pr["y"]),
"z": int(raw_pr.get("z", 0)),
"remaining_ticks": int(raw_pr.get("remaining_ticks", 0)),
"total_delay_ticks": int(raw_pr.get("total_delay_ticks", 1)),
})
if (
raw_pr is Dictionary
and raw_pr.has("entity_id")
and raw_pr.has("x")
and raw_pr.has("y")
):
(
pending_recognitions
. append(
{
"entity_id": int(raw_pr["entity_id"]),
"x": float(raw_pr["x"]),
"y": float(raw_pr["y"]),
"z": int(raw_pr.get("z", 0)),
"remaining_ticks": int(raw_pr.get("remaining_ticks", 0)),
"total_delay_ticks": int(raw_pr.get("total_delay_ticks", 1)),
}
)
)
count += 1
# v7: current_dialogue (#435, D-061/D-062) — NPC speech + player response options
@@ -159,12 +192,17 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant:
if raw_options is Array:
for raw_opt in raw_options:
if raw_opt is Dictionary and raw_opt.has("text"):
dialogue_options.append({
"text": str(raw_opt["text"]),
"response_id": str(raw_opt.get("response_id", "")),
"priority": int(raw_opt.get("priority", 0)),
"confrontation": bool(raw_opt.get("confrontation", false)),
})
(
dialogue_options
. append(
{
"text": str(raw_opt["text"]),
"response_id": str(raw_opt.get("response_id", "")),
"priority": int(raw_opt.get("priority", 0)),
"confrontation": bool(raw_opt.get("confrontation", false)),
}
)
)
current_dialogue = {
"npc_name": str(raw_dialogue.get("npc_name", "")),
"npc_entity_id": int(raw_dialogue.get("npc_entity_id", -1)),
@@ -190,13 +228,18 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant:
if raw_conv_events is Array:
for raw_ce in raw_conv_events:
if raw_ce is Dictionary and raw_ce.has("occluded_line"):
conversation_events.append({
"speaker_id": int(raw_ce.get("speaker_id", 0)),
"target_id": int(raw_ce.get("target_id", 0)),
"speaker_name": str(raw_ce.get("speaker_name", "")),
"target_name": str(raw_ce.get("target_name", "")),
"occluded_line": str(raw_ce["occluded_line"]),
})
(
conversation_events
. append(
{
"speaker_id": int(raw_ce.get("speaker_id", 0)),
"target_id": int(raw_ce.get("target_id", 0)),
"speaker_name": str(raw_ce.get("speaker_name", "")),
"target_name": str(raw_ce.get("target_name", "")),
"occluded_line": str(raw_ce["occluded_line"]),
}
)
)
# v9: conversation_ended (#535, D-078) — pairs whose conversation ended this tick.
var conversation_ended: Array = []
@@ -204,10 +247,15 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant:
if raw_conv_ended is Array:
for raw_end in raw_conv_ended:
if raw_end is Dictionary:
conversation_ended.append({
"speaker_id": int(raw_end.get("speaker_id", 0)),
"target_id": int(raw_end.get("target_id", 0)),
})
(
conversation_ended
. append(
{
"speaker_id": int(raw_end.get("speaker_id", 0)),
"target_id": int(raw_end.get("target_id", 0)),
}
)
)
# v14: poi_list (#151) — discovered POIs for minimap rendering.
# Each entry: {poi_id, name, x, y, z, poi_category}. Positions in sim tile coords.
@@ -215,15 +263,26 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant:
var raw_pois: Variant = raw.get("poi_list")
if raw_pois is Array:
for raw_poi in raw_pois:
if raw_poi is Dictionary and raw_poi.has("poi_id") and raw_poi.has("x") and raw_poi.has("y"):
poi_list.append({
"poi_id": str(raw_poi["poi_id"]),
"name": str(raw_poi.get("name", "")),
"x": int(raw_poi["x"]),
"y": int(raw_poi["y"]),
"z": int(raw_poi.get("z", 0)),
"poi_category": str(raw_poi.get("poi_category", raw_poi.get("category", "Location"))),
})
if (
raw_poi is Dictionary
and raw_poi.has("poi_id")
and raw_poi.has("x")
and raw_poi.has("y")
):
(
poi_list
. append(
{
"poi_id": str(raw_poi["poi_id"]),
"name": str(raw_poi.get("name", "")),
"x": int(raw_poi["x"]),
"y": int(raw_poi["y"]),
"z": int(raw_poi.get("z", 0)),
"poi_category":
str(raw_poi.get("poi_category", raw_poi.get("category", "Location"))),
}
)
)
# v14: examine_result (#174, #242) — character-filtered observation text.
# {entity_id, text, confidence} or null. Auto-dismisses on client after 4-6 seconds.
@@ -268,9 +327,14 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant:
if raw_tce is Array:
for raw_ev in raw_tce:
if raw_ev is Dictionary and raw_ev.has("triangle_id"):
triangle_crisis_events.append({
"triangle_id": int(raw_ev["triangle_id"]),
})
(
triangle_crisis_events
. append(
{
"triangle_id": int(raw_ev["triangle_id"]),
}
)
)
# v20: settings_response (#627, D-138) — server ack after ChangeSettings / full settings dump
# after RequestAllSettings. kind = "full"|"ack". "full": settings array [{key, value}].
@@ -285,10 +349,15 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant:
if raw_sr_settings is Array:
for raw_s in raw_sr_settings:
if raw_s is Dictionary and raw_s.has("key"):
sr_settings.append({
"key": str(raw_s["key"]),
"value": raw_s.get("value"),
})
(
sr_settings
. append(
{
"key": str(raw_s["key"]),
"value": raw_s.get("value"),
}
)
)
settings_response = {"kind": "full", "settings": sr_settings}
elif sr_kind == "ack":
settings_response = {
@@ -338,27 +407,37 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant:
if raw_kg_entities is Array:
for raw_ke in raw_kg_entities:
if raw_ke is Dictionary and raw_ke.has("entity_id"):
kg_entities.append({
"entity_id": int(raw_ke["entity_id"]),
"name": str(raw_ke.get("name", "Unknown")),
"confidence": str(raw_ke.get("confidence", "Suspects")),
"source": str(raw_ke.get("source", "")),
"state": str(raw_ke.get("state", "Active")),
"relationship": str(raw_ke.get("relationship", "Unknown")),
"last_observed_tick": int(raw_ke.get("last_observed_tick", 0)),
})
(
kg_entities
. append(
{
"entity_id": int(raw_ke["entity_id"]),
"name": str(raw_ke.get("name", "Unknown")),
"confidence": str(raw_ke.get("confidence", "Suspects")),
"source": str(raw_ke.get("source", "")),
"state": str(raw_ke.get("state", "Active")),
"relationship": str(raw_ke.get("relationship", "Unknown")),
"last_observed_tick": int(raw_ke.get("last_observed_tick", 0)),
}
)
)
var kg_facts: Array = []
var raw_kg_facts: Variant = raw_pk.get("facts")
if raw_kg_facts is Array:
for raw_kf in raw_kg_facts:
if raw_kf is Dictionary and raw_kf.has("fact_id"):
kg_facts.append({
"fact_id": str(raw_kf["fact_id"]),
"confidence": str(raw_kf.get("confidence", "Suspects")),
"source": str(raw_kf.get("source", "")),
"state": str(raw_kf.get("state", "Active")),
"acquired_tick": int(raw_kf.get("acquired_tick", 0)),
})
(
kg_facts
. append(
{
"fact_id": str(raw_kf["fact_id"]),
"confidence": str(raw_kf.get("confidence", "Suspects")),
"source": str(raw_kf.get("source", "")),
"state": str(raw_kf.get("state", "Active")),
"acquired_tick": int(raw_kf.get("acquired_tick", 0)),
}
)
)
player_knowledge = {
"entities": kg_entities,
"facts": kg_facts,
@@ -396,8 +475,13 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant:
## Decode a single VisibleEntity from a raw msgpack map.
static func _decode_entity(raw: Dictionary) -> Variant:
if not raw.has("entity_id") or not raw.has("x") or not raw.has("y") \
or not raw.has("z") or not raw.has("kind"):
if (
not raw.has("entity_id")
or not raw.has("x")
or not raw.has("y")
or not raw.has("z")
or not raw.has("kind")
):
push_warning("Protocol: entity missing required fields: %s" % str(raw.keys()))
return null
@@ -485,23 +569,25 @@ static func _decode_verb_option(raw) -> Variant:
## Returns { "variant": String, "data": Variant } in both cases.
static func _decode_enum_variant(raw) -> Dictionary:
if raw is String:
return { "variant": raw, "data": null }
return {"variant": raw, "data": null}
if raw is Dictionary and raw.size() == 1:
var variant_name: String = raw.keys()[0]
return { "variant": variant_name, "data": raw[variant_name] }
return {"variant": variant_name, "data": raw[variant_name]}
push_warning("Protocol: unexpected enum encoding: %s" % str(raw))
return { "variant": "Unknown", "data": raw }
return {"variant": "Unknown", "data": raw}
# -- Encode: GDScript types → bytes to server ----------------------------------
## Encode a StartupMessage to MessagePack bytes (#175, #588, #718).
## Sent by the client immediately after handshake validation.
## Server reads this to initialize SimRng (D-010, D-029) and select monologue pool (D-032).
## character_archetype: "detective" → "Detective", "smuggler" → "Smuggler" (server enum variant).
## character_visual: optional CharacterVisualDescriptor — included as "character_visual_descriptor" dict.
static func encode_startup_message(
world_seed: int, character_archetype: String = "detective", character_visual: Variant = null) -> PackedByteArray:
world_seed: int, character_archetype: String = "detective", character_visual: Variant = null
) -> PackedByteArray:
# Map client lowercase archetype string to server PascalCase enum variant.
# Explicit match prevents unknown strings silently reaching the server as
# garbage enum values — fail loudly and fall back to "Detective".
@@ -512,7 +598,12 @@ static func encode_startup_message(
"smuggler":
archetype_variant = "Smuggler"
_:
push_error("Protocol: unknown character_archetype '%s' — defaulting to 'Detective'" % character_archetype)
push_error(
(
"Protocol: unknown character_archetype '%s' — defaulting to 'Detective'"
% character_archetype
)
)
archetype_variant = "Detective"
var msg := {
"world_seed": world_seed,
@@ -531,7 +622,9 @@ static func encode_startup_message(
## action_name: one of "MoveNorth", "MoveSouth", "MoveEast", "MoveWest",
## "Interact", "UsePerceptionMode", "Pause", "Unpause"
## action_data: null for unit variants, String for UsePerceptionMode
static func encode_player_input(tick: int, action_name: String, action_data: Variant = null) -> PackedByteArray:
static func encode_player_input(
tick: int, action_name: String, action_data: Variant = null
) -> PackedByteArray:
var action_value: Variant = _encode_action(action_name, action_data)
var input := {
@@ -555,10 +648,15 @@ static func encode_player_inputs(inputs: Array) -> PackedByteArray:
for input in inputs:
var action_name: String = input["action_name"]
var action_data: Variant = input.get("action_data")
wire_inputs.append({
"tick": input["tick"],
"action": _encode_action(action_name, action_data),
})
(
wire_inputs
. append(
{
"tick": input["tick"],
"action": _encode_action(action_name, action_data),
}
)
)
var result = Messagepack.encode(wire_inputs)
if result.status != null:
@@ -573,10 +671,10 @@ static func encode_player_inputs(inputs: Array) -> PackedByteArray:
## Unit variants (MoveNorth, Pause, etc.) encode as bare strings.
static func _encode_action(action_name: String, action_data: Variant) -> Variant:
if action_data != null:
return { action_name: action_data }
return {action_name: action_data}
# Interact is a struct variant — server expects named fields, not a bare string
if action_name == "Interact":
return { "Interact": { "target_entity_id": null, "verb": null } }
return {"Interact": {"target_entity_id": null, "verb": null}}
return action_name
@@ -586,11 +684,13 @@ static func _encode_action(action_name: String, action_data: Variant) -> Variant
## queuing via SimBridge._outbound_buffer.
## The server receives this as a PlayerAction::ChangeSettings variant.
static func encode_change_settings(enabled: bool) -> PackedByteArray:
var entries: Array = [{
"tick": 0,
"action_name": "ChangeSettings",
"action_data": {"ai_enhanced_dialogue": enabled},
}]
var entries: Array = [
{
"tick": 0,
"action_name": "ChangeSettings",
"action_data": {"ai_enhanced_dialogue": enabled},
}
]
var result = Messagepack.encode(entries)
if result.status != null:
push_error("Protocol: encode_change_settings failed: %s" % result.status)
+199 -84
View File
@@ -7,14 +7,34 @@ extends RefCounted
const _WALLS: Array = [
# Room walls (8x8 room from (7,7) to (14,14))
Vector2i(7,7), Vector2i(8,7), Vector2i(9,7), Vector2i(10,7),
Vector2i(11,7), Vector2i(12,7), Vector2i(13,7), Vector2i(14,7),
Vector2i(7,14), Vector2i(8,14), Vector2i(9,14), Vector2i(10,14),
Vector2i(11,14), Vector2i(12,14), Vector2i(13,14), Vector2i(14,14),
Vector2i(7,8), Vector2i(7,9), Vector2i(7,10), Vector2i(7,11),
Vector2i(7,12), Vector2i(7,13),
Vector2i(14,8), Vector2i(14,9), Vector2i(14,10), Vector2i(14,11),
Vector2i(14,12), Vector2i(14,13),
Vector2i(7, 7),
Vector2i(8, 7),
Vector2i(9, 7),
Vector2i(10, 7),
Vector2i(11, 7),
Vector2i(12, 7),
Vector2i(13, 7),
Vector2i(14, 7),
Vector2i(7, 14),
Vector2i(8, 14),
Vector2i(9, 14),
Vector2i(10, 14),
Vector2i(11, 14),
Vector2i(12, 14),
Vector2i(13, 14),
Vector2i(14, 14),
Vector2i(7, 8),
Vector2i(7, 9),
Vector2i(7, 10),
Vector2i(7, 11),
Vector2i(7, 12),
Vector2i(7, 13),
Vector2i(14, 8),
Vector2i(14, 9),
Vector2i(14, 10),
Vector2i(14, 11),
Vector2i(14, 12),
Vector2i(14, 13),
# Interior wall blocking NPC
Vector2i(12, 10),
]
@@ -48,6 +68,7 @@ func process_facing(new_facing: String) -> void:
# -- Snapshot generation -------------------------------------------------------
func snapshot() -> Dictionary:
tick += 1
@@ -76,42 +97,60 @@ func snapshot() -> Dictionary:
var py := player_pos.y
# Build entities — player always visible
var entities: Array = [{
"entity_id": 1,
"x": float(px),
"y": float(py),
"z": 0,
"kind": { "variant": "Player", "data": null },
"visibility": "Forward",
}]
var entities: Array = [
{
"entity_id": 1,
"x": float(px),
"y": float(py),
"z": 0,
"kind": {"variant": "Player", "data": null},
"visibility": "Forward",
}
]
# NPC at (12, 9) — visible if within range and not blocked by wall at (12, 10)
var npc_pos := Vector2i(12, 9)
var npc_dist := absi(px - npc_pos.x) + absi(py - npc_pos.y)
if npc_dist <= 4 and has_los(Vector2i(px, py), npc_pos):
var sector: String = "Forward" if npc_pos.y <= py else "Peripheral"
entities.append({
"entity_id": 2,
"x": float(npc_pos.x),
"y": float(npc_pos.y),
"z": 0,
"kind": { "variant": "Npc", "data": null },
"visibility": sector,
"relationship": npc_relationship,
})
(
entities
. append(
{
"entity_id": 2,
"x": float(npc_pos.x),
"y": float(npc_pos.y),
"z": 0,
"kind": {"variant": "Npc", "data": null},
"visibility": sector,
"relationship": npc_relationship,
}
)
)
# v4: nearby_interactions when NPC is nearby and visible (#404/#405)
var nearby: Array = []
if npc_dist <= 2 and has_los(Vector2i(px, py), npc_pos):
nearby.append({
"entity_id": 2,
"entity_type": "Npc",
"distance": npc_dist,
"verbs": [
{"kind": "Talk", "label": "Talk", "priority": 1, "available": true},
{"kind": "ExamineNpc", "label": "Observe", "priority": 2, "available": true},
],
})
(
nearby
. append(
{
"entity_id": 2,
"entity_type": "Npc",
"distance": npc_dist,
"verbs":
[
{"kind": "Talk", "label": "Talk", "priority": 1, "available": true},
{
"kind": "ExamineNpc",
"label": "Observe",
"priority": 2,
"available": true
},
],
}
)
)
# v5: monologue on first tick (#414)
var monologue: Variant = null
@@ -128,11 +167,28 @@ func snapshot() -> Dictionary:
dialogue = {
"npc_name": "Kael",
"npc_entity_id": 2,
"speech": "Haven't seen you around the transit hub before. You new to Sova, or just passing through?",
"options": [
{"text": "Just arrived. Still getting my bearings.", "response_id": "kael_greet_01", "priority": 1, "confrontation": false}, # gdlint:ignore = max-line-length
{"text": "Passing through. Know where I can find work?", "response_id": "kael_greet_02", "priority": 2, "confrontation": false}, # gdlint:ignore = max-line-length
{"text": "I saw you near the cargo bay last night.", "response_id": "kael_confront_01", "priority": 3, "confrontation": true}, # gdlint:ignore = max-line-length
"speech":
"Haven't seen you around the transit hub before. You new to Sova, or just passing through?",
"options":
[
{
"text": "Just arrived. Still getting my bearings.",
"response_id": "kael_greet_01",
"priority": 1,
"confrontation": false
}, # gdlint:ignore = max-line-length
{
"text": "Passing through. Know where I can find work?",
"response_id": "kael_greet_02",
"priority": 2,
"confrontation": false
}, # gdlint:ignore = max-line-length
{
"text": "I saw you near the cargo bay last night.",
"response_id": "kael_confront_01",
"priority": 3,
"confrontation": true
}, # gdlint:ignore = max-line-length
],
}
@@ -142,26 +198,55 @@ func snapshot() -> Dictionary:
if cycle_pos < 6:
var total_delay := 6
var remaining := total_delay - cycle_pos
pending_recs.append({
"entity_id": 100,
"x": 13.5,
"y": 12.5,
"z": 0,
"remaining_ticks": remaining,
"total_delay_ticks": total_delay,
})
(
pending_recs
. append(
{
"entity_id": 100,
"x": 13.5,
"y": 12.5,
"z": 0,
"remaining_ticks": remaining,
"total_delay_ticks": total_delay,
}
)
)
# #535: Mock overheard NPC-NPC conversation (D-078)
var conv_events: Array = []
var conv_ended: Array = []
var conv_start := 3
var conv_lines := [
{"speaker": "Mira", "target": "Soren", "line": "The cargo manifests don't add up. Three containers unaccounted for."},
{"speaker": "Soren", "target": "Mira", "line": "Could be a logging error. Happens every... cycle."},
{"speaker": "Mira", "target": "Soren", "line": "Not like this. Someone moved them after... check."},
{"speaker": "Soren", "target": "Mira", "line": "You're reading too much into it. The docks are... these days."},
{"speaker": "Mira", "target": "Soren", "line": "Then explain the weight discrepancy. Two hundred kilos... just gone."}, # gdlint:ignore = max-line-length
{"speaker": "Soren", "target": "Mira", "line": "Fine. I'll pull the bay... tonight. But keep this between us."},
{
"speaker": "Mira",
"target": "Soren",
"line": "The cargo manifests don't add up. Three containers unaccounted for."
},
{
"speaker": "Soren",
"target": "Mira",
"line": "Could be a logging error. Happens every... cycle."
},
{
"speaker": "Mira",
"target": "Soren",
"line": "Not like this. Someone moved them after... check."
},
{
"speaker": "Soren",
"target": "Mira",
"line": "You're reading too much into it. The docks are... these days."
},
{
"speaker": "Mira",
"target": "Soren",
"line": "Then explain the weight discrepancy. Two hundred kilos... just gone."
}, # gdlint:ignore = max-line-length
{
"speaker": "Soren",
"target": "Mira",
"line": "Fine. I'll pull the bay... tonight. But keep this between us."
},
]
var conv_tick_interval := 5
var conv_total_ticks := conv_lines.size() * conv_tick_interval
@@ -170,20 +255,26 @@ func snapshot() -> Dictionary:
var within_tick := (tick - conv_start) % conv_tick_interval
if within_tick == 0 and conv_index < conv_lines.size():
var cl: Dictionary = conv_lines[conv_index]
conv_events.append({
"speaker_id": 10,
"target_id": 11,
"speaker_name": cl.speaker,
"target_name": cl.target,
"occluded_line": cl.line,
})
(
conv_events
. append(
{
"speaker_id": 10,
"target_id": 11,
"speaker_name": cl.speaker,
"target_name": cl.target,
"occluded_line": cl.line,
}
)
)
elif tick == conv_start + conv_total_ticks:
conv_ended.append({"speaker_id": 10, "target_id": 11})
return {
"tick": tick,
"version": Protocol.PROTOCOL_VERSION,
"game_time": {
"game_time":
{
"day": 0,
"time_of_day": tick * 10,
"day_phase": "Morning",
@@ -207,6 +298,7 @@ func snapshot() -> Dictionary:
# -- Map generation ------------------------------------------------------------
func _tiles() -> Array:
var tiles: Array = []
var room_x := 7
@@ -216,8 +308,9 @@ func _tiles() -> Array:
for x in range(room_x, room_x + room_w):
for y in range(room_y, room_y + room_h):
var is_edge := (x == room_x or x == room_x + room_w - 1
or y == room_y or y == room_y + room_h - 1)
var is_edge := (
x == room_x or x == room_x + room_w - 1 or y == room_y or y == room_y + room_h - 1
)
var tile_type: String
if is_edge:
if y == room_y + room_h - 1 and x == room_x + room_w / 2:
@@ -253,7 +346,9 @@ func _visible_tiles() -> Array:
if dist <= radius:
if x >= room_x and x < room_x + room_w and y >= room_y and y < room_y + room_h:
var sector: String = "Forward" if y <= py else "Peripheral"
vtiles.append({"x": x, "y": y, "z": 0, "visibility": sector, "type": _get_tile_type(x, y)})
vtiles.append(
{"x": x, "y": y, "z": 0, "visibility": sector, "type": _get_tile_type(x, y)}
)
return vtiles
@@ -262,8 +357,9 @@ func _get_tile_type(x: int, y: int) -> String:
var room_y := 7
var room_w := 8
var room_h := 8
var is_edge := (x == room_x or x == room_x + room_w - 1
or y == room_y or y == room_y + room_h - 1)
var is_edge := (
x == room_x or x == room_x + room_w - 1 or y == room_y or y == room_y + room_h - 1
)
if is_edge:
if y == room_y + room_h - 1 and x == room_x + room_w / 2:
return "door"
@@ -273,6 +369,7 @@ func _get_tile_type(x: int, y: int) -> String:
# -- Spatial helpers -----------------------------------------------------------
func _is_walkable(pos: Vector2i) -> bool:
return not _WALLS.has(pos)
@@ -302,25 +399,43 @@ func has_los(from: Vector2i, to: Vector2i) -> bool:
static func action_to_delta(action_name: String) -> Vector2i:
match action_name:
"MoveNorth": return Vector2i(0, -1)
"MoveNortheast": return Vector2i(1, -1)
"MoveEast": return Vector2i(1, 0)
"MoveSoutheast": return Vector2i(1, 1)
"MoveSouth": return Vector2i(0, 1)
"MoveSouthwest": return Vector2i(-1, 1)
"MoveWest": return Vector2i(-1, 0)
"MoveNorthwest": return Vector2i(-1, -1)
_: return Vector2i.ZERO
"MoveNorth":
return Vector2i(0, -1)
"MoveNortheast":
return Vector2i(1, -1)
"MoveEast":
return Vector2i(1, 0)
"MoveSoutheast":
return Vector2i(1, 1)
"MoveSouth":
return Vector2i(0, 1)
"MoveSouthwest":
return Vector2i(-1, 1)
"MoveWest":
return Vector2i(-1, 0)
"MoveNorthwest":
return Vector2i(-1, -1)
_:
return Vector2i.ZERO
static func delta_to_facing(delta: Vector2i) -> String:
match delta:
Vector2i(0, -1): return "North"
Vector2i(1, -1): return "Northeast"
Vector2i(1, 0): return "East"
Vector2i(1, 1): return "Southeast"
Vector2i(0, 1): return "South"
Vector2i(-1, 1): return "Southwest"
Vector2i(-1, 0): return "West"
Vector2i(-1, -1): return "Northwest"
_: return "North"
Vector2i(0, -1):
return "North"
Vector2i(1, -1):
return "Northeast"
Vector2i(1, 0):
return "East"
Vector2i(1, 1):
return "Southeast"
Vector2i(0, 1):
return "South"
Vector2i(-1, 1):
return "Southwest"
Vector2i(-1, 0):
return "West"
Vector2i(-1, -1):
return "Northwest"
_:
return "North"