Files
security-game/src/core/campaign.gd
T
zwitschi aa51ee331e
Full build / Import + headless tests (push) Successful in 41s
Full build / Full desktop build + optional release (push) Successful in 4m18s
Ship the 0.8.0 first-hour and campaign milestone
Add the campaign shell, pause-safe checkpoint resume, post-shift campaign
continue, confirmed campaign reset, difficulty presets, searchable Help,
content-matrix validation, recovery events, contextual dialogue, policy/debrief
context and eligible-event previews. Extend persistence with atomic separate
files and add campaign/checkpoint/tutorial smokes. Headless 247/247, Python
94/94, tutorial/campaign/session/scenario smokes green.
2026-11-01 21:21:43 +01:00

65 lines
1.8 KiB
GDScript

class_name Campaign
extends RefCounted
## Small campaign/session progression model. Venue rules stay in VenueScenario;
## this only owns order, completed shifts, difficulty and the next venue.
const ORDER := ["hollywood_building", "joke_shop", "tv_studio"]
var index := 0
var shift_number := 1
var completed: Array[String] = []
var difficulty := "normal"
var complete := false
var last_grade := ""
func setup(data: Dictionary = {}) -> void:
index = clampi(int(data.get("index", 0)), 0, ORDER.size())
shift_number = maxi(1, int(data.get("shift_number", 1)))
difficulty = str(data.get("difficulty", "normal"))
completed.clear()
for item in data.get("completed", []):
var value := str(item)
if value in ORDER and value not in completed:
completed.append(value)
complete = bool(data.get("complete", index >= ORDER.size()))
last_grade = str(data.get("last_grade", ""))
func next_venue() -> String:
if complete or index >= ORDER.size():
return ""
return ORDER[index]
func summary() -> Dictionary:
return {
"index": index,
"next_venue": next_venue(),
"shift_number": shift_number,
"difficulty": difficulty,
"complete": complete,
"completed": completed.duplicate(),
"last_grade": last_grade,
}
## Record one finished shift. Idempotent per venue for a single campaign run.
func record_shift(scenario_id: String, review: Dictionary = {}) -> bool:
if complete:
return false
if scenario_id != next_venue():
return false
if scenario_id not in completed:
completed.append(scenario_id)
var rep: Dictionary = review.get("reputation", {})
last_grade = str(rep.get("grade", last_grade))
index += 1
shift_number = index + 1
if index >= ORDER.size():
complete = true
return true
func set_difficulty(value: String) -> void:
if value in ["easy", "normal", "hard"]:
difficulty = value
func reset() -> void:
setup({})