P14-02: Split warps into guest FRONT and staff BACK service warp (A08)
The FRONT Mana warp is guest-only: its connectors carry the "!staff" access, which path access checks treat as open to everyone except staff. A new 2x2 BACK service warp links only to other service warps for staff, with A07 values. Registry and palette now hold 25 definitions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
619b5e07ed
commit
8917c190cf
@@ -67,8 +67,11 @@ const INFRASTRUCTURE_FACILITY_PATHS: Array[String] = [
|
||||
]
|
||||
|
||||
## A07 Mana warp: original 10.7 transport, kept apart from the stair list.
|
||||
const TRANSPORT_FACILITY_IDS: Array[StringName] = [&"mana_warp"]
|
||||
const TRANSPORT_FACILITY_PATHS: Array[String] = ["res://data/facilities/infrastructure/mana_warp.tres"]
|
||||
const TRANSPORT_FACILITY_IDS: Array[StringName] = [&"mana_warp", &"service_warp"]
|
||||
const TRANSPORT_FACILITY_PATHS: Array[String] = [
|
||||
"res://data/facilities/infrastructure/mana_warp.tres",
|
||||
"res://data/facilities/infrastructure/service_warp.tres",
|
||||
]
|
||||
|
||||
## Optional post-MVP expansion definitions. They live below a subdirectory so
|
||||
## DefinitionRegistry's baseline directory scan remains exactly compatible with
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
extends RefCounted
|
||||
|
||||
## A07 Mana warp: every completed warp is linked to every other warp by one
|
||||
## path connector, so crossing is a single instant step. Connectors are derived
|
||||
## from construction state; their operational state follows the reserve and the
|
||||
## warps' own power. Fares are charged by the Runtime when an actor steps.
|
||||
## A07/A08 Mana warp: every completed warp is linked to every other warp of the
|
||||
## same kind by one path connector, so crossing is a single instant step. The
|
||||
## FRONT guest warp excludes staff routes; the BACK service warp is staff-only.
|
||||
## Connectors are derived from construction state; their operational state
|
||||
## follows the reserve and the warps' own power. The Runtime charges fares.
|
||||
const PathType := preload("res://scripts/world/path_service.gd")
|
||||
const DEFINITION_ID := &"mana_warp"
|
||||
const SERVICE_DEFINITION_ID := &"service_warp"
|
||||
const DEFINITION_IDS: Array[StringName] = [DEFINITION_ID, SERVICE_DEFINITION_ID]
|
||||
const ACCESS_BY_DEFINITION := {&"mana_warp": &"!staff", &"service_warp": &"staff"}
|
||||
const PREFIX := "warp.connector:"
|
||||
const MANA_PER_TRIP := 3
|
||||
const PATH_COST := 400
|
||||
@@ -22,12 +26,14 @@ static func warps_from_facilities(facilities: Array) -> Array[Dictionary]:
|
||||
if not value is Dictionary:
|
||||
continue
|
||||
var facility: Dictionary = value
|
||||
if StringName(str(facility.get(&"definition_id", ""))) != DEFINITION_ID:
|
||||
var definition_id := StringName(str(facility.get(&"definition_id", "")))
|
||||
if definition_id not in DEFINITION_IDS:
|
||||
continue
|
||||
var origin: Variant = facility.get(&"origin")
|
||||
if not origin is Vector3i:
|
||||
continue
|
||||
warps.append({&"instance_id": StringName(str(facility.get(&"instance_id", ""))), &"origin": origin})
|
||||
warps.append({&"instance_id": StringName(str(facility.get(&"instance_id", ""))), &"origin": origin,
|
||||
&"definition_id": definition_id})
|
||||
warps.sort_custom(func(a: Dictionary, b: Dictionary) -> bool:
|
||||
return String(a[&"instance_id"]) < String(b[&"instance_id"]))
|
||||
return warps
|
||||
@@ -38,7 +44,10 @@ static func expected_connectors(facilities: Array) -> Array[Dictionary]:
|
||||
var result: Array[Dictionary] = []
|
||||
for i: int in warps.size():
|
||||
for j: int in range(i + 1, warps.size()):
|
||||
if warps[i][&"definition_id"] != warps[j][&"definition_id"]:
|
||||
continue
|
||||
result.append({
|
||||
&"access_id": ACCESS_BY_DEFINITION[warps[i][&"definition_id"]],
|
||||
&"id": StringName("%s%s|%s" % [PREFIX, warps[i][&"instance_id"], warps[j][&"instance_id"]]),
|
||||
&"from": warps[i][&"origin"],
|
||||
&"to": warps[j][&"origin"],
|
||||
@@ -71,14 +80,15 @@ static func synchronize(path: PathService, facilities: Array, available: Diction
|
||||
var usable := fare_affordable and bool(available.get(endpoints[0], false)) and bool(available.get(endpoints[1], false))
|
||||
var state := PathType.CONNECTOR_OPERATIONAL if usable else PathType.CONNECTOR_OUTAGE
|
||||
if not existing.is_empty() and existing[&"from"] == connector[&"from"] and existing[&"to"] == connector[&"to"] \
|
||||
and existing[&"operational_state"] == state:
|
||||
and existing[&"access_id"] == connector[&"access_id"] and existing[&"operational_state"] == state:
|
||||
continue
|
||||
if before == null:
|
||||
before = path.create_snapshot()
|
||||
if existing.is_empty() or existing[&"from"] != connector[&"from"] or existing[&"to"] != connector[&"to"]:
|
||||
if existing.is_empty() or existing[&"from"] != connector[&"from"] or existing[&"to"] != connector[&"to"] \
|
||||
or existing[&"access_id"] != connector[&"access_id"]:
|
||||
if not existing.is_empty():
|
||||
path.remove_connector(connector_id)
|
||||
if not path.configure_connector(connector_id, connector[&"from"], connector[&"to"], PATH_COST, true, &"", true,
|
||||
if not path.configure_connector(connector_id, connector[&"from"], connector[&"to"], PATH_COST, true, connector[&"access_id"], true,
|
||||
{&"movement_type": PathType.MOVEMENT_CONNECTOR}):
|
||||
path.restore_snapshot(before)
|
||||
return {&"ok": false, &"code": &"WARP_CONNECTOR_CONFIGURE_FAILED", &"reason": path.last_error}
|
||||
@@ -97,7 +107,7 @@ static func connectors_match(path: PathService, facilities: Array) -> bool:
|
||||
for connector: Dictionary in expected:
|
||||
var existing := path.get_connector(connector[&"id"])
|
||||
if existing.is_empty() or existing[&"from"] != connector[&"from"] or existing[&"to"] != connector[&"to"] \
|
||||
or int(existing[&"cost"]) != PATH_COST or StringName(existing[&"access_id"]) != &"" \
|
||||
or int(existing[&"cost"]) != PATH_COST or StringName(existing[&"access_id"]) != connector[&"access_id"] \
|
||||
or existing[&"movement_type"] != PathType.MOVEMENT_CONNECTOR:
|
||||
return false
|
||||
return true
|
||||
|
||||
@@ -89,7 +89,7 @@ static func room(canvas: CanvasItem, rect: Rect2, id: StringName, pixel: float,
|
||||
table(canvas, at + Vector2(-2, -7)*p, p)
|
||||
&"chapel":
|
||||
chapel_furnishings(canvas, rect, p)
|
||||
&"mana_warp":
|
||||
&"mana_warp", &"service_warp":
|
||||
# Original code-drawn transfer circle and rising motes; existing palette.
|
||||
var ring := Vector2(mid, floor_y - 3.0 * p)
|
||||
canvas.draw_circle(ring, 9.0 * p, INK)
|
||||
|
||||
@@ -36,6 +36,7 @@ const KIND_SERVICE_ELEVATOR: StringName = &"service_elevator"
|
||||
const KIND_GUEST_STAIRS: StringName = &"guest_stairs"
|
||||
const KIND_SERVICE_STAIRS: StringName = &"service_stairs"
|
||||
const KIND_MANA_WARP: StringName = &"mana_warp"
|
||||
const KIND_SERVICE_WARP: StringName = &"service_warp"
|
||||
const SUPPORTED_KINDS: Array[StringName] = [
|
||||
KIND_GUEST_CORRIDOR,
|
||||
KIND_SERVICE_CORRIDOR,
|
||||
@@ -45,6 +46,7 @@ const SUPPORTED_KINDS: Array[StringName] = [
|
||||
KIND_GUEST_STAIRS,
|
||||
KIND_SERVICE_STAIRS,
|
||||
KIND_MANA_WARP,
|
||||
KIND_SERVICE_WARP,
|
||||
]
|
||||
const KNOWN_KINDS: Array[StringName] = [
|
||||
KIND_GUEST_CORRIDOR,
|
||||
@@ -55,6 +57,7 @@ const KNOWN_KINDS: Array[StringName] = [
|
||||
KIND_GUEST_STAIRS,
|
||||
KIND_SERVICE_STAIRS,
|
||||
KIND_MANA_WARP,
|
||||
KIND_SERVICE_WARP,
|
||||
]
|
||||
|
||||
const UNSUPPORTED_VERTICAL_KINDS: Array[StringName] = []
|
||||
@@ -706,6 +709,16 @@ static func _kind_schema(kind: StringName) -> Dictionary:
|
||||
&"guest_access", &"movement", &"schema_facility_proxy", &"warp",
|
||||
]),
|
||||
}
|
||||
KIND_SERVICE_WARP:
|
||||
return {
|
||||
&"layer": PathType.BACK,
|
||||
&"footprint": Vector2i(2, 2),
|
||||
&"pass_through": true,
|
||||
&"staff_only": true,
|
||||
&"tags": _sorted_name_array([
|
||||
&"movement", &"schema_facility_proxy", &"staff_only", &"warp",
|
||||
]),
|
||||
}
|
||||
KIND_SERVICE_ELEVATOR:
|
||||
return {
|
||||
&"layer": PathType.BACK,
|
||||
|
||||
@@ -2099,7 +2099,11 @@ func _edge_meets_vertical_policy(from_cell: Vector3i, edge: Dictionary) -> bool:
|
||||
|
||||
func _edge_is_accessible(edge: Dictionary, allowed_access_ids: Array[StringName]) -> bool:
|
||||
var required_access: StringName = edge[&"access_id"]
|
||||
if not required_access.is_empty() and required_access not in allowed_access_ids:
|
||||
# "!id" is open to everyone except actors that carry id (guest-only warp).
|
||||
if String(required_access).begins_with("!"):
|
||||
if StringName(String(required_access).substr(1)) in allowed_access_ids:
|
||||
return false
|
||||
elif not required_access.is_empty() and required_access not in allowed_access_ids:
|
||||
return false
|
||||
var connector_id: StringName = edge[&"connector_id"]
|
||||
if connector_id.is_empty():
|
||||
|
||||
Reference in New Issue
Block a user