- Delete Rules.Tone/TONE_NAMES, NpcProfile.tone_modifiers, tone params on NPCController.roll_reaction/apply_player_action; dialogue_lines flattened to Array[String]; HUD tone label, T binding, and hud.tone_prefix removed - Docs updated everywhere (PLAN, README, DONE, MEMORY); PLAN section heading 'Tone and Design Direction' -> 'Design Direction' - Add .gitea/workflows/build.yml: checks job (import+tests) on push/PR; full build job (export templates, Linux/Windows/macOS exports, artifact upload, and tag-based Gitea release publish via GITEA_TOKEN) on tags/dispatch - Remove old .github/workflows/ci.yml to avoid double runs - Add venue cycling (V) across all three scenarios with hud.venue_switched - Refresh README screenshots to match the new HUD - 53/53 tests pass, boot smoke clean
128 lines
2.7 KiB
GDScript
128 lines
2.7 KiB
GDScript
class_name Rules
|
|
## Shared constants and helpers for the simulation rules.
|
|
|
|
func _init() -> void:
|
|
push_error("Rules is a static utility class and must not be instantiated.")
|
|
|
|
## Escalation levels (0..5). Names must stay in sync with PLAN.md.
|
|
enum Level {
|
|
OBSERVATION = 0,
|
|
SIMPLE_DETERRENCE = 1,
|
|
FORMAL_WARNING = 2,
|
|
BLOCKING = 3,
|
|
RADIO_ASSIST = 4,
|
|
EMERGENCY = 5,
|
|
}
|
|
|
|
const LEVEL_NAMES := {
|
|
Level.OBSERVATION: "Observation",
|
|
Level.SIMPLE_DETERRENCE: "Simple Deterrence",
|
|
Level.FORMAL_WARNING: "Formal Warning",
|
|
Level.BLOCKING: "Blocking",
|
|
Level.RADIO_ASSIST: "Radio Assist",
|
|
Level.EMERGENCY: "Emergency",
|
|
}
|
|
|
|
## NPC behavioral archetypes from PLAN.md.
|
|
enum NpcType {
|
|
TOURIST,
|
|
PERFORMER,
|
|
INFLUENCER,
|
|
CONFUSED_VISITOR,
|
|
INTOXICATED,
|
|
TRESPASSER,
|
|
VIOLENT_THREAT,
|
|
MENTAL_CRISIS, # "51/50" style mental-health crisis character
|
|
AUTHORIZED_STAFF,
|
|
AUTHORIZED_GUEST,
|
|
DELIVERY,
|
|
RESPONDER,
|
|
PROTESTER,
|
|
}
|
|
|
|
const NPC_TYPE_NAMES := {
|
|
NpcType.TOURIST: "Tourist",
|
|
NpcType.PERFORMER: "Street Performer",
|
|
NpcType.INFLUENCER: "Influencer",
|
|
NpcType.CONFUSED_VISITOR: "Confused Visitor",
|
|
NpcType.INTOXICATED: "Intoxicated Pedestrian",
|
|
NpcType.TRESPASSER: "Trespasser",
|
|
NpcType.VIOLENT_THREAT: "Violent Threat",
|
|
NpcType.MENTAL_CRISIS: "Mental Health Crisis",
|
|
NpcType.AUTHORIZED_STAFF: "Authorized Staff",
|
|
NpcType.AUTHORIZED_GUEST: "Authorized Guest",
|
|
NpcType.DELIVERY: "Delivery",
|
|
NpcType.RESPONDER: "Responder",
|
|
NpcType.PROTESTER: "Protester",
|
|
}
|
|
|
|
## Access artifact kinds used by AccessVerifier.
|
|
enum AccessKind {
|
|
NONE = -1,
|
|
RECOGNITION = 0,
|
|
WRISTBAND = 1,
|
|
ID = 2,
|
|
TICKET = 3,
|
|
CREDENTIAL = 4,
|
|
GUEST_LIST = 5,
|
|
}
|
|
|
|
const ACCESS_KIND_NAMES := {
|
|
AccessKind.RECOGNITION: "Recognition",
|
|
AccessKind.WRISTBAND: "Wristband",
|
|
AccessKind.ID: "ID",
|
|
AccessKind.TICKET: "Ticket",
|
|
AccessKind.CREDENTIAL: "Credential",
|
|
AccessKind.GUEST_LIST: "Guest List",
|
|
}
|
|
|
|
## Artifact validity states.
|
|
enum ArtifactStatus {
|
|
VALID = 0,
|
|
EXPIRED = 1,
|
|
COUNTERFEIT = 2,
|
|
MISMATCHED = 3,
|
|
MISSING = 4,
|
|
AMBIGUOUS = 5,
|
|
}
|
|
|
|
const ARTIFACT_STATUS_NAMES := {
|
|
ArtifactStatus.VALID: "Valid",
|
|
ArtifactStatus.EXPIRED: "Expired",
|
|
ArtifactStatus.COUNTERFEIT: "Counterfeit",
|
|
ArtifactStatus.MISMATCHED: "Mismatched",
|
|
ArtifactStatus.MISSING: "Missing",
|
|
ArtifactStatus.AMBIGUOUS: "Ambiguous",
|
|
}
|
|
|
|
## NPC reaction outcomes after player actions.
|
|
enum Reaction {
|
|
COMPLY = 0,
|
|
LEAVE = 1,
|
|
ARGUE = 2,
|
|
IGNORE = 3,
|
|
RECORD = 4,
|
|
THREATEN = 5,
|
|
RETURN_LATER = 6,
|
|
FORCE_ENTRY = 7,
|
|
CALL_SOMEONE = 8,
|
|
}
|
|
|
|
## Shift phases by time of day.
|
|
enum Phase {
|
|
EARLY = 0,
|
|
MIDDAY = 1,
|
|
EVENING = 2,
|
|
LATE = 3,
|
|
}
|
|
|
|
const PHASE_NAMES := {
|
|
Phase.EARLY: "Early",
|
|
Phase.MIDDAY: "Midday",
|
|
Phase.EVENING: "Evening",
|
|
Phase.LATE: "Late",
|
|
}
|
|
|
|
static func level_name(level: int) -> String:
|
|
return LEVEL_NAMES.get(level, "Unknown")
|