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.
This commit is contained in:
1 parent
86332cd401
commit
aa51ee331e
38 files changed
+1361
-1144
No files matched your search
@@ -0,0 +1,64 @@
|
||||
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({})
|
||||
Reference in new issue
Block a user