Record original-alignment implementation and traceability checkpoint
Capture current source, content data, tests, asset licenses, and original-specification traceability. Original implementation remains incomplete. The accepted matching UI generation passed 154 suites and 12,253 checks, with eight rendered staff-contract screens reviewed. Latest native Windows and full-original acceptance remain outstanding.
This commit is contained in:
@@ -5,6 +5,8 @@ const ServiceInstanceType = preload("res://scripts/facility/service_instance.gd"
|
||||
const FacilityPricingType = preload("res://scripts/facility/facility_pricing.gd")
|
||||
|
||||
## Values are deliberately ordered by operational priority.
|
||||
enum OperationState { INACTIVE, OPERATING, SUSPENDED }
|
||||
|
||||
enum State {
|
||||
BROKEN,
|
||||
NO_ACCESS,
|
||||
@@ -42,6 +44,13 @@ var statistics_today: Dictionary = {}
|
||||
var lifetime_statistics: Dictionary = {}
|
||||
var created_at := 0
|
||||
|
||||
var customer_capacity := -1 # Unspecified; never inferred from storage/production capacity.
|
||||
var service_attribute: StringName = &""
|
||||
var related_facility_id: StringName = &""
|
||||
var related_facility_operating := true
|
||||
var suspension_reason: StringName = &""
|
||||
var operation_state: OperationState = OperationState.INACTIVE
|
||||
|
||||
var capacity := 1
|
||||
var queue_capacity := 0
|
||||
var base_service_minutes := 1
|
||||
@@ -70,6 +79,11 @@ func configure(
|
||||
durability = clampi(int(_value(options, &"durability", DEFAULT_DURABILITY)), 0, DEFAULT_DURABILITY)
|
||||
local_inventory_id = StringName(_value(options, &"local_inventory_id", &""))
|
||||
capacity = maxi(int(_value(options, &"capacity", 1)), 1)
|
||||
customer_capacity = int(_value(options, &"customer_capacity", -1))
|
||||
service_attribute = StringName(_value(options, &"service_attribute", &""))
|
||||
related_facility_id = StringName(_value(options, &"related_facility_id", &""))
|
||||
related_facility_operating = related_facility_id.is_empty()
|
||||
suspension_reason = StringName(_value(options, &"suspension_reason", &""))
|
||||
queue_capacity = maxi(int(_value(options, &"queue_capacity", 0)), 0)
|
||||
base_service_minutes = maxi(int(_value(options, &"base_service_minutes", 1)), 1)
|
||||
base_quality = int(_value(options, &"base_quality", 0))
|
||||
@@ -97,6 +111,9 @@ func is_valid() -> bool:
|
||||
return not instance_id.is_empty() \
|
||||
and not definition_id.is_empty() \
|
||||
and capacity > 0 \
|
||||
and customer_capacity >= -1 \
|
||||
and service_attribute in [&"", &"appetite", &"relaxation", &"sexual", &"gambling"] \
|
||||
and suspension_reason in [&"", &"DESTROYED", &"RAIDED"] \
|
||||
and queue_capacity >= 0 \
|
||||
and base_service_minutes > 0 \
|
||||
and staff_min >= 0 \
|
||||
@@ -140,6 +157,11 @@ func is_within_opening_hours(absolute_minute: int) -> bool:
|
||||
|
||||
|
||||
func set_operational_conditions(conditions: Dictionary, absolute_minute: int) -> bool:
|
||||
if _has_value(conditions, &"related_facility_id"):
|
||||
related_facility_id = StringName(_value(conditions, &"related_facility_id", &""))
|
||||
related_facility_operating = related_facility_id.is_empty()
|
||||
if StringName(_value(conditions, &"suspension_reason", &"")) in [&"DESTROYED", &"RAIDED"]:
|
||||
suspension_reason = StringName(_value(conditions, &"suspension_reason", &""))
|
||||
if _has_value(conditions, &"durability"):
|
||||
durability = clampi(int(_value(conditions, &"durability", durability)), 0, DEFAULT_DURABILITY)
|
||||
if _has_value(conditions, &"access_available"):
|
||||
@@ -158,6 +180,8 @@ func set_operational_conditions(conditions: Dictionary, absolute_minute: int) ->
|
||||
|
||||
|
||||
func evaluate_state(absolute_minute: int) -> bool:
|
||||
if durability <= 0:
|
||||
suspension_reason = &"DESTROYED"
|
||||
var next_reasons: Array[StringName] = []
|
||||
var next_state := State.OPEN
|
||||
if durability <= 0:
|
||||
@@ -192,7 +216,19 @@ func evaluate_state(absolute_minute: int) -> bool:
|
||||
next_reasons.append(reason)
|
||||
if next_state > State.DEGRADED:
|
||||
next_state = State.DEGRADED
|
||||
var changed := state != next_state
|
||||
if not related_facility_operating:
|
||||
next_reasons.append(&"RELATED_FACILITY_INACTIVE")
|
||||
next_state = mini(next_state, State.CLOSED) as State
|
||||
if not suspension_reason.is_empty():
|
||||
next_reasons.append(suspension_reason)
|
||||
next_state = State.BROKEN
|
||||
var next_operation := OperationState.INACTIVE
|
||||
if not suspension_reason.is_empty():
|
||||
next_operation = OperationState.SUSPENDED
|
||||
elif next_state in [State.OPEN, State.DEGRADED]:
|
||||
next_operation = OperationState.OPERATING
|
||||
var changed := state != next_state or operation_state != next_operation
|
||||
operation_state = next_operation
|
||||
state = next_state
|
||||
state_reasons = next_reasons
|
||||
return changed
|
||||
@@ -203,8 +239,35 @@ func can_start_service(absolute_minute: int) -> bool:
|
||||
return state in [State.OPEN, State.DEGRADED] and available_slots() > 0
|
||||
|
||||
|
||||
func allows_logistics() -> bool:
|
||||
return operator_open and power_available and durability > 0 and suspension_reason.is_empty() and related_facility_operating
|
||||
|
||||
|
||||
func available_slots() -> int:
|
||||
return maxi(capacity - active_services.size(), 0)
|
||||
var slots := maxi(capacity - active_services.size(), 0)
|
||||
if customer_capacity >= 0:
|
||||
slots = mini(slots, maxi(customer_capacity - customer_count(), 0))
|
||||
return slots
|
||||
|
||||
|
||||
func customer_count() -> int:
|
||||
var customers: Dictionary = {}
|
||||
for service: ServiceInstance in active_services.values():
|
||||
for guest_id: StringName in service.guest_ids:
|
||||
customers[guest_id] = true
|
||||
return customers.size()
|
||||
|
||||
|
||||
func can_accept_customers(guest_ids: Array[StringName]) -> bool:
|
||||
if customer_capacity < 0:
|
||||
return true
|
||||
var customers: Dictionary = {}
|
||||
for service: ServiceInstance in active_services.values():
|
||||
for guest_id: StringName in service.guest_ids:
|
||||
customers[guest_id] = true
|
||||
for guest_id: StringName in guest_ids:
|
||||
customers[guest_id] = true
|
||||
return customers.size() <= customer_capacity
|
||||
|
||||
|
||||
func has_queue_space() -> bool:
|
||||
@@ -281,6 +344,10 @@ func create_snapshot() -> Dictionary:
|
||||
&"statistics_today": statistics_today.duplicate(true),
|
||||
&"lifetime_statistics": lifetime_statistics.duplicate(true),
|
||||
&"created_at": created_at,
|
||||
&"customer_capacity": customer_capacity,
|
||||
&"service_attribute": service_attribute,
|
||||
&"related_facility_id": related_facility_id,
|
||||
&"suspension_reason": suspension_reason,
|
||||
&"capacity": capacity,
|
||||
&"queue_capacity": queue_capacity,
|
||||
&"base_service_minutes": base_service_minutes,
|
||||
@@ -309,6 +376,10 @@ static func from_snapshot(snapshot: Dictionary) -> FacilityInstance:
|
||||
&"level": snapshot.get(&"level", 1),
|
||||
&"durability": snapshot.get(&"durability", DEFAULT_DURABILITY),
|
||||
&"local_inventory_id": snapshot.get(&"local_inventory_id", ""),
|
||||
&"customer_capacity": snapshot.get(&"customer_capacity", -1),
|
||||
&"service_attribute": snapshot.get(&"service_attribute", ""),
|
||||
&"related_facility_id": snapshot.get(&"related_facility_id", ""),
|
||||
&"suspension_reason": snapshot.get(&"suspension_reason", ""),
|
||||
&"capacity": snapshot.get(&"capacity", 1),
|
||||
&"queue_capacity": snapshot.get(&"queue_capacity", 0),
|
||||
&"base_service_minutes": snapshot.get(&"base_service_minutes", 1),
|
||||
@@ -350,10 +421,17 @@ static func from_snapshot(snapshot: Dictionary) -> FacilityInstance:
|
||||
instance.active_services[service.service_id] = service
|
||||
if not instance.is_valid() or instance.active_services.size() > instance.capacity:
|
||||
return null
|
||||
if instance.customer_capacity >= 0 and instance.customer_count() > instance.customer_capacity:
|
||||
return null
|
||||
return instance
|
||||
|
||||
|
||||
static func _snapshot_shapes_are_valid(snapshot: Dictionary) -> bool:
|
||||
if snapshot.has(&"customer_capacity") and (typeof(snapshot[&"customer_capacity"]) != TYPE_INT or int(snapshot[&"customer_capacity"]) < -1):
|
||||
return false
|
||||
for field: StringName in [&"service_attribute", &"related_facility_id", &"suspension_reason"]:
|
||||
if snapshot.has(field) and typeof(snapshot[field]) not in [TYPE_STRING, TYPE_STRING_NAME]:
|
||||
return false
|
||||
var array_fields := [
|
||||
&"origin", &"occupied_cells", &"state_reasons", &"active_staff_ids",
|
||||
&"queue_entries", &"active_services", &"opening_intervals", &"degraded_reasons",
|
||||
|
||||
@@ -27,6 +27,23 @@ static func quote(base_price: int, policy: Dictionary) -> int:
|
||||
return result
|
||||
|
||||
|
||||
static func apply_multiplier(price: int, multiplier_bp: int) -> int:
|
||||
# Same nearest-G, half-up convention as policy pricing.
|
||||
@warning_ignore("integer_division")
|
||||
return (maxi(price, 0) * maxi(multiplier_bp, 0) + 5000) / 10000
|
||||
|
||||
|
||||
## Caller supplies already-determined deficient attributes. Threshold and surcharge
|
||||
## are deliberately not invented. An unresolved quote must not be charged.
|
||||
static func quote_service(base_price: int, policy: Dictionary, service_attribute: StringName, deficient_attributes: Array[StringName], surcharge_amount: int = -1) -> Dictionary:
|
||||
var base := quote(base_price, policy)
|
||||
var matches := not service_attribute.is_empty() and deficient_attributes.has(service_attribute)
|
||||
var resolved := not matches or surcharge_amount > 0
|
||||
var surcharge := surcharge_amount if matches and resolved else 0
|
||||
return {&"base_price": base, &"matches": matches, &"resolved": resolved,
|
||||
&"surcharge": surcharge, &"total": base + surcharge, &"eligible": true}
|
||||
|
||||
|
||||
static func satisfaction_modifier(
|
||||
policy: Dictionary,
|
||||
quality: int,
|
||||
|
||||
@@ -123,6 +123,7 @@ func unregister_instance(instance_id: StringName) -> CommandResult:
|
||||
{&"instance_id": instance_id}
|
||||
)
|
||||
_instances.erase(instance_id)
|
||||
refresh_operating_dependencies(current_minute)
|
||||
instance_unregistered.emit(instance_id)
|
||||
last_error = ""
|
||||
return _success({&"instance_id": instance_id})
|
||||
@@ -136,9 +137,29 @@ func set_operational_status(
|
||||
var instance := get_instance(instance_id)
|
||||
if instance == null:
|
||||
return _not_found("Facility instance", instance_id)
|
||||
var minute := _resolve_minute(absolute_minute)
|
||||
var old_state := instance.state
|
||||
if _has_value(conditions, &"related_facility_id"):
|
||||
var raw_related: Variant = _value(conditions, &"related_facility_id", null)
|
||||
if typeof(raw_related) not in [TYPE_STRING, TYPE_STRING_NAME]:
|
||||
return _invalid("Related facility must be one facility ID.")
|
||||
var related := StringName(raw_related)
|
||||
if related == instance_id or (not related.is_empty() and not has_instance(related)):
|
||||
return _invalid("Related facility is missing or refers to itself.")
|
||||
var seen := {instance_id: true}
|
||||
var cursor := related
|
||||
while not cursor.is_empty() and has_instance(cursor):
|
||||
if seen.has(cursor):
|
||||
return _invalid("Related facilities cannot form a cycle.")
|
||||
seen[cursor] = true
|
||||
cursor = get_instance(cursor).related_facility_id
|
||||
if _has_value(conditions, &"related_facility_operating") or _has_value(conditions, &"operation_state"):
|
||||
return _invalid("Operating flags are computed from actual facility conditions.")
|
||||
if _has_value(conditions, &"suspension_reason") and (typeof(_value(conditions, &"suspension_reason", null)) not in [TYPE_STRING, TYPE_STRING_NAME] or StringName(_value(conditions, &"suspension_reason", &"")) not in [&"DESTROYED", &"RAIDED"]):
|
||||
return _invalid("Suspension recovery is not specified.")
|
||||
var minute := _resolve_minute(absolute_minute)
|
||||
instance.set_operational_conditions(conditions, minute)
|
||||
if old_state != instance.state or _has_value(conditions, &"related_facility_id"):
|
||||
refresh_operating_dependencies(minute)
|
||||
_emit_state_change(instance, old_state)
|
||||
last_error = ""
|
||||
return _success({
|
||||
@@ -161,6 +182,7 @@ func set_opening_hours(
|
||||
return _invalid("Opening hours must be valid minute-of-day values.")
|
||||
var old_state := instance.state
|
||||
instance.evaluate_state(_resolve_minute(absolute_minute))
|
||||
refresh_operating_dependencies(current_minute)
|
||||
_emit_state_change(instance, old_state)
|
||||
last_error = ""
|
||||
return _success({&"instance_id": instance_id})
|
||||
@@ -191,6 +213,7 @@ func set_policy(
|
||||
var changed := instance.apply_policy_patch(normalized_patch)
|
||||
var old_state := instance.state
|
||||
instance.evaluate_state(current_minute)
|
||||
refresh_operating_dependencies(current_minute)
|
||||
_emit_state_change(instance, old_state)
|
||||
last_error = ""
|
||||
return _success({
|
||||
@@ -319,6 +342,30 @@ func cancel_request(request_id: StringName, reason: StringName = &"GUEST_LEFT")
|
||||
return _not_found("Queued service request", request_id)
|
||||
|
||||
|
||||
func refresh_operating_dependencies(minute: int) -> void:
|
||||
var resolved: Dictionary = {}
|
||||
for instance_id: StringName in _sorted_keys(_instances):
|
||||
_resolve_operating_dependency(instance_id, minute, resolved, {})
|
||||
|
||||
|
||||
func _resolve_operating_dependency(id: StringName, minute: int, resolved: Dictionary, visiting: Dictionary) -> bool:
|
||||
if resolved.has(id):
|
||||
return bool(resolved[id])
|
||||
if visiting.has(id) or not has_instance(id):
|
||||
return false
|
||||
visiting[id] = true
|
||||
var instance := get_instance(id)
|
||||
instance.apply_pending_policy(minute)
|
||||
var related := instance.related_facility_id
|
||||
instance.related_facility_operating = related.is_empty() or _resolve_operating_dependency(related, minute, resolved, visiting)
|
||||
var old_state := instance.state
|
||||
instance.evaluate_state(minute)
|
||||
_emit_state_change(instance, old_state)
|
||||
visiting.erase(id)
|
||||
resolved[id] = instance.operation_state == FacilityInstanceType.OperationState.OPERATING
|
||||
return bool(resolved[id])
|
||||
|
||||
|
||||
func start_next_service(
|
||||
instance_id: StringName,
|
||||
absolute_minute: int = -1,
|
||||
@@ -328,6 +375,7 @@ func start_next_service(
|
||||
if instance == null:
|
||||
return _not_found("Facility instance", instance_id)
|
||||
var minute := _resolve_minute(absolute_minute)
|
||||
_resolve_operating_dependency(instance_id, minute, {}, {})
|
||||
instance.apply_pending_policy(minute)
|
||||
var old_state := instance.state
|
||||
instance.evaluate_state(minute)
|
||||
@@ -347,6 +395,8 @@ func start_next_service(
|
||||
var request := get_request(instance.queue_entries[0])
|
||||
if request == null:
|
||||
return _invalid("The next queue entry is corrupt.")
|
||||
if not instance.can_accept_customers(request.guest_ids):
|
||||
return _invalid("Simultaneous customer limit reached.", {&"reason": &"CUSTOMER_CAPACITY"})
|
||||
var effective_validator := validator if validator.is_valid() else _start_validator
|
||||
var callback_failure := _run_boundary_callback(
|
||||
effective_validator,
|
||||
@@ -376,6 +426,8 @@ func start_next_service(
|
||||
}
|
||||
)
|
||||
instance.queue_entries.remove_at(0)
|
||||
# Report this start's service index, independent of customer headcount and callbacks.
|
||||
var slot := instance.active_services.size()
|
||||
instance.active_services[service_id] = service
|
||||
_known_service_ids[service_id] = true
|
||||
_increment_stat(instance.statistics_today, &"services_started")
|
||||
@@ -386,7 +438,7 @@ func start_next_service(
|
||||
&"instance_id": instance_id,
|
||||
&"request_id": request.request_id,
|
||||
&"service_id": service_id,
|
||||
&"slot": instance.capacity - instance.available_slots() - 1,
|
||||
&"slot": slot,
|
||||
})
|
||||
|
||||
|
||||
@@ -416,6 +468,7 @@ func advance_one_minute(absolute_minute: int = -1) -> Array[CommandResult]:
|
||||
return [_invalid("FacilityService cannot advance backwards in time.")]
|
||||
else:
|
||||
current_minute = absolute_minute
|
||||
refresh_operating_dependencies(current_minute)
|
||||
var results: Array[CommandResult] = []
|
||||
for instance_id: StringName in _sorted_keys(_instances):
|
||||
var instance: FacilityInstance = _instances[instance_id]
|
||||
@@ -632,10 +685,23 @@ func restore_snapshot(snapshot: Dictionary) -> bool:
|
||||
_known_service_ids = restored_known_services
|
||||
_next_service_sequence = restored_next_sequence
|
||||
current_minute = restored_minute
|
||||
for instance: FacilityInstance in _instances.values():
|
||||
instance.related_facility_operating = _restored_dependency_operates(instance.related_facility_id, {})
|
||||
instance.operation_state = FacilityInstanceType.OperationState.SUSPENDED if not instance.suspension_reason.is_empty() else (FacilityInstanceType.OperationState.OPERATING if instance.state in [FacilityInstanceType.State.OPEN, FacilityInstanceType.State.DEGRADED] and instance.related_facility_operating else FacilityInstanceType.OperationState.INACTIVE)
|
||||
last_error = ""
|
||||
return true
|
||||
|
||||
|
||||
func _restored_dependency_operates(id: StringName, seen: Dictionary) -> bool:
|
||||
if id.is_empty():
|
||||
return true
|
||||
if seen.has(id) or not has_instance(id):
|
||||
return false
|
||||
seen[id] = true
|
||||
var instance := get_instance(id)
|
||||
return instance.suspension_reason.is_empty() and instance.state in [FacilityInstanceType.State.OPEN, FacilityInstanceType.State.DEGRADED] and _restored_dependency_operates(instance.related_facility_id, seen)
|
||||
|
||||
|
||||
func _saved_policy_is_valid(policy: Dictionary) -> bool:
|
||||
var validation := FacilityPricingType.validate_patch(policy)
|
||||
if not bool(validation[&"valid"]):
|
||||
@@ -656,6 +722,14 @@ func _validate_restored_graph(
|
||||
var active_service_ids: Dictionary = {}
|
||||
for instance_id: StringName in _sorted_keys(instances):
|
||||
var instance: FacilityInstance = instances[instance_id]
|
||||
var dependency_seen: Dictionary = {instance_id: true}
|
||||
var dependency := instance.related_facility_id
|
||||
while not dependency.is_empty() and instances.has(dependency):
|
||||
if dependency_seen.has(dependency):
|
||||
last_error = "Related facility cycle in snapshot."
|
||||
return false
|
||||
dependency_seen[dependency] = true
|
||||
dependency = (instances[dependency] as FacilityInstance).related_facility_id
|
||||
if not known_instances.has(instance_id):
|
||||
last_error = "Active facility ID is absent from known IDs."
|
||||
return false
|
||||
@@ -703,6 +777,13 @@ func _prepare_service_for_tick(
|
||||
if instance.state == FacilityInstanceType.State.BROKEN:
|
||||
_fail_service(instance, service, INTERRUPTION_BROKEN, current_minute)
|
||||
return _success({&"service_id": service.service_id, &"failed": true})
|
||||
if not instance.related_facility_operating:
|
||||
if service.state == ServiceInstanceType.State.ACTIVE:
|
||||
service.pause(&"RELATED_FACILITY_INACTIVE", current_minute)
|
||||
service_interrupted.emit(service, &"RELATED_FACILITY_INACTIVE")
|
||||
return null
|
||||
if service.state == ServiceInstanceType.State.PAUSED and service.interruption_reason == &"RELATED_FACILITY_INACTIVE":
|
||||
service.resume()
|
||||
if not instance.power_available:
|
||||
if service.state == ServiceInstanceType.State.ACTIVE:
|
||||
service.pause(INTERRUPTION_NO_POWER, current_minute)
|
||||
|
||||
Reference in New Issue
Block a user