142 lines
5.5 KiB
GDScript
142 lines
5.5 KiB
GDScript
extends RefCounted
|
|
|
|
## Reproducible, disposable viewing scenario. All buildings, employees, inventory,
|
|
## and jobs go through Runtime commands; visitors come from production arrivals.
|
|
## The normal new-game state and the player's saves are never changed by this file.
|
|
|
|
var failure := ""
|
|
var facility_ids: Dictionary = {}
|
|
var _runtime: Variant
|
|
var _clock: Variant
|
|
var _tree: SceneTree
|
|
var _sequence := 0
|
|
|
|
|
|
func prepare(runtime: Variant, clock: Variant, tree: SceneTree) -> bool:
|
|
_runtime = runtime
|
|
_clock = clock
|
|
_tree = tree
|
|
_clock.set_paused(true)
|
|
var operations: Dictionary = _runtime.enable_production_operations()
|
|
if not bool(operations.get(&"ok", false)):
|
|
return _fail("Could not enable production operations: %s" % operations)
|
|
for row: Array in [
|
|
[&"reception", Vector3i(-8, 0, 0)],
|
|
[&"cafeteria", Vector3i(2, 0, 0)],
|
|
[&"kitchen", Vector3i(2, 0, 1)],
|
|
]:
|
|
if not _build(row[0], row[1]):
|
|
return false
|
|
if not await advance(180):
|
|
return false
|
|
for facility: Dictionary in _runtime.construction_service.get_facilities():
|
|
facility_ids[facility[&"definition_id"]] = facility[&"instance_id"]
|
|
# Four rooms sit on the completed reception and dining structure. One
|
|
# continuous, paid staircase in the center joins all three upper landings;
|
|
# same-floor corridor construction links the rooms on either side.
|
|
for x: int in [-8, -6, 2, 4]:
|
|
if not _build(&"standard_room", Vector3i(x, 2, 0)):
|
|
return false
|
|
for x: int in range(-4, 2):
|
|
if not _build(&"guest_stairs" if x == -4 else &"guest_corridor", Vector3i(x, 1, 0)):
|
|
return false
|
|
if not await advance(60):
|
|
return false
|
|
for x: int in range(-4, 2):
|
|
if not _build(&"guest_stairs" if x == -4 else &"guest_corridor", Vector3i(x, 2, 0)):
|
|
return false
|
|
if not await advance(10):
|
|
return false
|
|
# This walkway follows the upper side of the rooms. The final stair segment
|
|
# gives real guests and the cleaner a legal route to this floor.
|
|
for x: int in range(-8, 6):
|
|
if not _build(&"guest_stairs" if x == -4 else &"guest_corridor", Vector3i(x, 3, 0)):
|
|
return false
|
|
if not await advance(10):
|
|
return false
|
|
for row: Array in [
|
|
[&"staff_akane", facility_ids[&"reception"], Vector3i(-8, 0, 0)],
|
|
[&"staff_chika", facility_ids[&"cafeteria"], Vector3i(2, 0, 0)],
|
|
[&"staff_iris", facility_ids[&"cafeteria"], Vector3i(4, 0, 0)],
|
|
[&"staff_eri", &"", Vector3i(0, 0, 0)],
|
|
]:
|
|
if not _command(&"hire_staff_candidate", {
|
|
&"candidate_id": row[0], &"facility_id": row[1], &"current_cell": row[2],
|
|
}):
|
|
return false
|
|
# A small explicitly seeded pantry is part of the disposable scenario; its
|
|
# stacks are real and get consumed by the same service pipeline as gameplay.
|
|
var cafeteria: Variant = _runtime.facility_service.get_instance(facility_ids[&"cafeteria"])
|
|
if not _command(&"add_inventory_stack", {
|
|
&"owner_inventory_id": cafeteria.local_inventory_id,
|
|
&"item_id": &"ingredient/basic_meal", &"quantity": 32,
|
|
}):
|
|
return false
|
|
if not await advance(1):
|
|
return false
|
|
# The cleaner actually accepts, walks to, and completes these queued tasks.
|
|
for index: int in 6:
|
|
var target := Vector3i(-8 if index % 2 == 0 else 5, 3, 0)
|
|
if not _command(&"create_staff_task", {
|
|
&"task_id": StringName("pixel_view.clean.%02d" % index),
|
|
&"task_type": &"clean", &"priority": 70 - index,
|
|
&"options": {
|
|
&"target_entity_id": facility_ids[&"reception"] if index % 2 == 0 else facility_ids[&"cafeteria"],
|
|
&"target_cell": target, &"required_role_tags": [&"cleaner"],
|
|
&"task_tags": [&"cleaning"], &"estimated_minutes": 8,
|
|
},
|
|
}):
|
|
return false
|
|
return await advance(1)
|
|
|
|
|
|
func advance(minutes: int) -> bool:
|
|
for index: int in minutes:
|
|
var before: int = _clock.absolute_minute
|
|
_clock.advance_minutes(1)
|
|
if _clock.absolute_minute != before + 1:
|
|
return _fail("Scenario stopped at %s: %s" % [_clock.formatted_time(), _runtime.get_operations_report()])
|
|
var report: Dictionary = _runtime.get_operations_report()
|
|
if bool(report.get(&"runtime_failure_latched", false)):
|
|
return _fail("Operations failed: %s" % report)
|
|
if index % 30 == 29:
|
|
await _tree.process_frame
|
|
return true
|
|
|
|
|
|
func describe() -> Dictionary:
|
|
var facilities: Array[Dictionary] = []
|
|
for facility: Variant in _runtime.facility_service.get_instances():
|
|
facilities.append({
|
|
"definition": String(facility.definition_id), "state": int(facility.state),
|
|
"origin": [facility.origin.x, facility.origin.y, facility.origin.z],
|
|
})
|
|
var actors: Array[Dictionary] = []
|
|
for guest: Variant in _runtime.guest_service.get_guests():
|
|
actors.append({"id": String(guest.guest_id), "kind": "guest", "state": int(guest.state),
|
|
"cell": [guest.current_cell.x, guest.current_cell.y, guest.current_cell.z]})
|
|
for staff: Variant in _runtime.staff_service.get_staff_members():
|
|
actors.append({"id": String(staff.staff_id), "kind": "staff", "state": int(staff.state),
|
|
"cell": [staff.current_cell.x, staff.current_cell.y, staff.current_cell.z]})
|
|
return {"time": _clock.formatted_time(), "minute": _clock.absolute_minute,
|
|
"facilities": facilities, "actors": actors, "pantry_seed_meals": 32}
|
|
|
|
|
|
func _build(definition_id: StringName, cell: Vector3i) -> bool:
|
|
return _command(&"build_facility", {&"definition_id": definition_id, &"origin": cell})
|
|
|
|
|
|
func _command(type: StringName, payload: Dictionary) -> bool:
|
|
_sequence += 1
|
|
var result: Variant = _runtime.submit_command(type, payload, &"player", &"", 50, -1,
|
|
StringName("pixel_view.command.%04d" % _sequence))
|
|
if not result.is_success():
|
|
return _fail("%s failed for %s: %s %s" % [type, payload, result.message, result.details])
|
|
return true
|
|
|
|
|
|
func _fail(message: String) -> bool:
|
|
failure = message
|
|
push_error(message)
|
|
return false
|