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
@@ -11,6 +11,9 @@ signal event_ready(event_data: Dictionary)
|
||||
var rng := RandomNumberGenerator.new()
|
||||
var _scenario: VenueScenario = null
|
||||
var _weighted_pool: Array[Dictionary] = []
|
||||
## Difficulty/pacing knob: <1 is calmer, >1 sends more events and routine traffic.
|
||||
var spawn_rate_multiplier := 1.0
|
||||
var _recent_scripted: Array[String] = []
|
||||
|
||||
func _init() -> void:
|
||||
pass
|
||||
@@ -38,17 +41,47 @@ func pull_due(elapsed_s: float, phase: int) -> Array[Dictionary]:
|
||||
continue
|
||||
var prob: float = event.get("probability", 0.0)
|
||||
var base: float = event.get("base_weight", 1.0)
|
||||
var event_id := str(event.get("id", ""))
|
||||
if str(event.get("kind", "routine")) == "scripted" and event_id in _recent_scripted:
|
||||
continue
|
||||
var spawn_rate: float = event.get("spawn_rate", 0.0)
|
||||
var due_event := false
|
||||
if spawn_rate > 0.0:
|
||||
# Rate-based spawning: emit at most one per second window.
|
||||
if rng.randf() < spawn_rate:
|
||||
if rng.randf() < clampf(spawn_rate * spawn_rate_multiplier, 0.0, 1.0):
|
||||
if rng.randf() < prob:
|
||||
due.append(event.duplicate())
|
||||
due_event = true
|
||||
else:
|
||||
if rng.randf() < prob * base:
|
||||
due.append(event.duplicate())
|
||||
if rng.randf() < clampf(prob * base * spawn_rate_multiplier, 0.0, 1.0):
|
||||
due_event = true
|
||||
if due_event:
|
||||
due.append(event.duplicate())
|
||||
if str(event.get("kind", "routine")) == "scripted" and event_id != "":
|
||||
_recent_scripted.append(event_id)
|
||||
if _recent_scripted.size() > 4:
|
||||
_recent_scripted.pop_front()
|
||||
return due
|
||||
|
||||
## Debug/content preview: events that could be selected now, without consuming
|
||||
## RNG or marking anything as recently played.
|
||||
func preview(elapsed_s: float, phase: int) -> Array[String]:
|
||||
var out: Array[String] = []
|
||||
if _scenario == null:
|
||||
return out
|
||||
for event in _weighted_pool:
|
||||
var time_range: Vector2 = event.get("time_range_s", Vector2(0, _scenario.shift_duration_s))
|
||||
if elapsed_s < time_range.x or elapsed_s > time_range.y:
|
||||
continue
|
||||
if int(event.get("phase", -1)) != phase:
|
||||
continue
|
||||
var event_id := str(event.get("id", ""))
|
||||
if str(event.get("kind", "routine")) == "scripted" and event_id in _recent_scripted:
|
||||
continue
|
||||
out.append("%s (%s)" % [event_id, str(event.get("kind", "routine"))])
|
||||
if out.size() >= 8:
|
||||
break
|
||||
return out
|
||||
|
||||
func fallback_routine_traffic(phase: int) -> Array[Dictionary]:
|
||||
## Cheap routine traffic so the street never feels empty.
|
||||
var out: Array[Dictionary] = []
|
||||
@@ -56,10 +89,19 @@ func fallback_routine_traffic(phase: int) -> Array[Dictionary]:
|
||||
if pool.is_empty():
|
||||
return out
|
||||
for i in 3:
|
||||
if rng.randf() < 0.35:
|
||||
if rng.randf() < clampf(0.35 * spawn_rate_multiplier, 0.0, 1.0):
|
||||
out.append(pool[rng.randi_range(0, pool.size() - 1)].duplicate())
|
||||
return out
|
||||
|
||||
func snapshot() -> Dictionary:
|
||||
return {"rng_state": rng.state, "recent_scripted": _recent_scripted.duplicate()}
|
||||
|
||||
func restore(data: Dictionary) -> void:
|
||||
rng.state = int(data.get("rng_state", rng.state))
|
||||
_recent_scripted.clear()
|
||||
for event_id in data.get("recent_scripted", []):
|
||||
_recent_scripted.append(str(event_id))
|
||||
|
||||
func _routine_pool(phase: int) -> Array:
|
||||
var out: Array = []
|
||||
for event in _weighted_pool:
|
||||
|
||||
Reference in new issue
Block a user