mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-21 11:18:08 +00:00
Add interactive guard with combat options to Mission 2
Implemented patrolling security guard in hallway_north with multiple player interaction options including combat/fighting mechanics. New Features: 1. Interactive Security Guard NPC - Patrols hallway_north corridor (4-waypoint route) - Line-of-sight detection (150px range, 120° angle) - Lockpicking detection (event-triggered confrontation) - Visual LOS cone for player awareness 2. Combat/Fighting Options Player can choose to physically confront the guard: - Knockout punch (quick but risky) - Wrestling/grappling (moderate difficulty) - Improvised weapon (fire extinguisher) - Back down from fight (de-escalation) Success depends on influence stat: - High influence: Guard knocked out, ~2 min window - Low influence: Failed attack, mission compromised 3. Alternative Approaches - Social engineering (claim authorization, emergency) - Persuasion (explain situation, build rapport) - De-escalation (apologize, back down) - Avoidance (wait for patrol to pass) 4. Consequences System - #hostile tag: Guard calls backup - #take_damage: Failed combat consequences - #mission_failed: Attacking security = mission end - Guard knockout: Time-limited stealth window Files Added: - m02_npc_security_guard.ink (500+ lines) - m02_npc_security_guard.json (compiled) Files Modified: - scenario.json.erb: - Added interactive guard NPC to hallway_north - Patrol behavior with 4 waypoints - LOS and lockpicking event detection - Global variables: guard_knocked_out, attacked_guard Validation: ✓ PASSED - Schema compliant - JSON valid - Ink script compiles successfully Design Notes: - Based on npc-patrol-lockpick test scenario - Integrated with M2's hospital crisis context - Multiple paths support different playstyles - Combat is high-risk/high-reward option - Aligns with SAFETYNET Field Rule 7: improvise as needed
This commit is contained in:
572
scenarios/m02_ransomed_trust/ink/m02_npc_security_guard.ink
Normal file
572
scenarios/m02_ransomed_trust/ink/m02_npc_security_guard.ink
Normal file
@@ -0,0 +1,572 @@
|
||||
// ===========================================
|
||||
// SECURITY GUARD NPC - Mission 2: Ransomed Trust
|
||||
// Break Escape - St. Catherine's Hospital
|
||||
// ===========================================
|
||||
// Interactive guard with multiple confrontation options
|
||||
// Based on security-guard.ink with M2-specific context
|
||||
// ===========================================
|
||||
|
||||
// Variables for tracking player choices and state
|
||||
VAR influence = 0
|
||||
VAR caught_lockpicking = false
|
||||
VAR confrontation_attempts = 0
|
||||
VAR warned_player = false
|
||||
VAR player_attacked_guard = false
|
||||
VAR guard_knocked_out = false
|
||||
VAR player_has_id_badge = false
|
||||
|
||||
// External variables (set by game)
|
||||
EXTERNAL player_name()
|
||||
|
||||
// ===========================================
|
||||
// INITIAL ENCOUNTER
|
||||
// ===========================================
|
||||
|
||||
=== start ===
|
||||
#speaker:security_guard
|
||||
|
||||
{not warned_player:
|
||||
#display:guard-patrol
|
||||
You see a hospital security guard patrolling the corridor. They're watching the area carefully.
|
||||
|
||||
The guard notices you and approaches.
|
||||
|
||||
~ warned_player = true
|
||||
Guard: Hold on. This is a restricted area during the crisis. What's your business here?
|
||||
|
||||
-> initial_response
|
||||
}
|
||||
|
||||
{warned_player and not caught_lockpicking and not guard_knocked_out:
|
||||
#display:guard-patrol
|
||||
The guard nods at you as they continue their patrol.
|
||||
|
||||
Guard: Still working on the crisis?
|
||||
|
||||
-> hub
|
||||
}
|
||||
|
||||
{guard_knocked_out:
|
||||
#display:guard-unconscious
|
||||
The security guard is unconscious on the floor. You should move quickly before they wake up.
|
||||
|
||||
#exit_conversation
|
||||
-> DONE
|
||||
}
|
||||
|
||||
-> hub
|
||||
|
||||
// ===========================================
|
||||
// INITIAL RESPONSE OPTIONS
|
||||
// ===========================================
|
||||
|
||||
=== initial_response ===
|
||||
|
||||
+ [I'm the security consultant Dr. Kim called in]
|
||||
~ influence += 20
|
||||
You: I'm the external security consultant. Dr. Kim authorized my access.
|
||||
|
||||
Guard: Oh, right. The ransomware crisis. Dr. Kim mentioned someone was coming.
|
||||
|
||||
Guard: Still, I need to see your visitor badge.
|
||||
|
||||
{player_has_id_badge:
|
||||
You show the visitor badge from reception.
|
||||
|
||||
~ influence += 10
|
||||
Guard: Checks out. Be careful in there. It's a mess.
|
||||
|
||||
-> hub
|
||||
- else:
|
||||
You: I... must have left it at reception.
|
||||
|
||||
~ influence -= 5
|
||||
Guard: Then go get it. Security protocols exist for a reason.
|
||||
|
||||
-> hub
|
||||
}
|
||||
|
||||
+ [Just passing through, officer]
|
||||
You: Just passing through. No trouble.
|
||||
|
||||
Guard: During a ransomware crisis? Nothing is "just passing through" right now.
|
||||
|
||||
-> hub
|
||||
|
||||
+ [Emergency - I need to access the server room]
|
||||
~ influence += 5
|
||||
You: This is urgent. The hospital systems are down. Lives are at stake.
|
||||
|
||||
Guard: I know. That's why I'm here securing this area.
|
||||
|
||||
Guard: You need proper authorization to access restricted systems.
|
||||
|
||||
-> hub
|
||||
|
||||
+ [None of your business]
|
||||
~ influence -= 30
|
||||
You: That's not your concern.
|
||||
|
||||
Guard: Wrong answer. Everything in this corridor is my concern.
|
||||
|
||||
#display:guard-hostile
|
||||
-> hostile_stance
|
||||
|
||||
// ===========================================
|
||||
// HUB - MAIN CONVERSATION LOOP
|
||||
// ===========================================
|
||||
|
||||
=== hub ===
|
||||
|
||||
+ [Ask about the ransomware attack]
|
||||
-> ask_about_attack
|
||||
|
||||
+ [Request access to restricted areas]
|
||||
-> request_access
|
||||
|
||||
+ {caught_lockpicking} [Explain the lockpicking situation]
|
||||
-> explain_lockpick_again
|
||||
|
||||
+ [End conversation]
|
||||
#exit_conversation
|
||||
Guard: Stay safe. This crisis has everyone on edge.
|
||||
-> DONE
|
||||
|
||||
// ===========================================
|
||||
// LOCKPICK DETECTION EVENT
|
||||
// ===========================================
|
||||
|
||||
=== on_lockpick_used ===
|
||||
#speaker:security_guard
|
||||
|
||||
{caught_lockpicking < 1:
|
||||
~ caught_lockpicking = true
|
||||
~ confrontation_attempts = 0
|
||||
}
|
||||
|
||||
~ confrontation_attempts++
|
||||
#display:guard-confrontation
|
||||
|
||||
{confrontation_attempts == 1:
|
||||
Guard: HEY! What the hell are you doing with those lockpicks?!
|
||||
|
||||
Guard: Step away from that door RIGHT NOW!
|
||||
|
||||
* [I have authorization from Dr. Kim!]
|
||||
-> claim_authorization
|
||||
|
||||
* [I'm trying to recover critical patient data!]
|
||||
-> explain_emergency
|
||||
|
||||
* [I was just... looking for something I dropped]
|
||||
-> poor_excuse
|
||||
|
||||
* [This is official security testing]
|
||||
-> claim_audit
|
||||
|
||||
* [Back off - this is more important than you know]
|
||||
-> hostile_response
|
||||
|
||||
* [Try to physically overpower the guard]
|
||||
-> attempt_fight
|
||||
}
|
||||
|
||||
{confrontation_attempts > 1:
|
||||
Guard: I ALREADY TOLD YOU TO STOP!
|
||||
|
||||
Guard: This is your FINAL warning before I call backup!
|
||||
|
||||
* [Okay, I'm leaving right now]
|
||||
-> back_down
|
||||
|
||||
* [You don't understand the stakes here]
|
||||
-> escalate_conflict
|
||||
|
||||
* [Attack the guard before they call backup]
|
||||
-> attempt_fight
|
||||
}
|
||||
|
||||
// ===========================================
|
||||
// LOCKPICK CONFRONTATION RESPONSES
|
||||
// ===========================================
|
||||
|
||||
=== claim_authorization ===
|
||||
#speaker:security_guard
|
||||
|
||||
{influence >= 30:
|
||||
~ influence -= 10
|
||||
Guard: Dr. Kim authorized lockpicking? That's... unusual.
|
||||
|
||||
Guard: Fine. But if she didn't, you're in deep trouble.
|
||||
|
||||
#display:guard-skeptical
|
||||
-> hub
|
||||
}
|
||||
|
||||
{influence < 30:
|
||||
~ influence -= 20
|
||||
Guard: Authorization doesn't mean breaking into rooms! Where's your paperwork?
|
||||
|
||||
Guard: Move along before this gets reported.
|
||||
|
||||
#display:guard-hostile
|
||||
#exit_conversation
|
||||
-> DONE
|
||||
}
|
||||
|
||||
=== explain_emergency ===
|
||||
#speaker:security_guard
|
||||
|
||||
{influence >= 25:
|
||||
~ influence -= 5
|
||||
Guard: Patient data? In a locked storage room?
|
||||
|
||||
Guard: Look, I get the emergency, but protocol is protocol.
|
||||
|
||||
Guard: Get proper authorization or I can't let this slide.
|
||||
|
||||
#display:guard-concerned
|
||||
-> hub
|
||||
}
|
||||
|
||||
{influence < 25:
|
||||
~ influence -= 15
|
||||
Guard: Nice try. Security breach is security breach, crisis or not.
|
||||
|
||||
Guard: Backup is on the way.
|
||||
|
||||
#display:guard-alert
|
||||
#exit_conversation
|
||||
-> DONE
|
||||
}
|
||||
|
||||
=== poor_excuse ===
|
||||
#speaker:security_guard
|
||||
~ influence -= 15
|
||||
|
||||
Guard: Looking for something you dropped? With lockpicks?
|
||||
|
||||
Guard: That's the weakest excuse I've heard all week.
|
||||
|
||||
#display:guard-annoyed
|
||||
-> hub
|
||||
|
||||
=== claim_audit ===
|
||||
#speaker:security_guard
|
||||
|
||||
{influence >= 40:
|
||||
~ influence -= 5
|
||||
Guard: Security audit during a ransomware crisis? Bold timing.
|
||||
|
||||
Guard: You better have documentation for this.
|
||||
|
||||
#display:guard-neutral
|
||||
-> hub
|
||||
}
|
||||
|
||||
{influence < 40:
|
||||
~ influence -= 25
|
||||
Guard: An audit would be scheduled with security. This isn't official.
|
||||
|
||||
Guard: You're coming with me to speak with my supervisor.
|
||||
|
||||
#display:guard-arrest
|
||||
#exit_conversation
|
||||
-> DONE
|
||||
}
|
||||
|
||||
// ===========================================
|
||||
// HOSTILE/COMBAT RESPONSES
|
||||
// ===========================================
|
||||
|
||||
=== hostile_response ===
|
||||
#speaker:security_guard
|
||||
~ influence -= 30
|
||||
|
||||
Guard: More important than hospital security? You just crossed a line.
|
||||
|
||||
Guard: SECURITY! CODE VIOLATION IN ADMINISTRATIVE WING!
|
||||
|
||||
#display:guard-aggressive
|
||||
#hostile:security_guard
|
||||
#exit_conversation
|
||||
-> DONE
|
||||
|
||||
=== escalate_conflict ===
|
||||
#speaker:security_guard
|
||||
~ influence -= 40
|
||||
|
||||
Guard: The stakes? You're breaking hospital protocol during an emergency!
|
||||
|
||||
Guard: LOCKDOWN! INTRUDER ALERT!
|
||||
|
||||
#display:guard-alarm
|
||||
#hostile:security_guard
|
||||
#exit_conversation
|
||||
-> DONE
|
||||
|
||||
=== attempt_fight ===
|
||||
#speaker:security_guard
|
||||
|
||||
Guard: You're really going to attack a security officer?!
|
||||
|
||||
You lunge at the guard, trying to knock them out before they can call for backup.
|
||||
|
||||
* [Go for a quick knockout punch]
|
||||
-> fight_punch
|
||||
|
||||
* [Try to wrestle them to the ground]
|
||||
-> fight_wrestle
|
||||
|
||||
* [Use a nearby object as a weapon]
|
||||
-> fight_improvise
|
||||
|
||||
* [Actually, back down from this]
|
||||
-> fight_backdown
|
||||
|
||||
=== fight_punch ===
|
||||
You swing at the guard's jaw.
|
||||
|
||||
{influence >= 20:
|
||||
Your punch connects! The guard staggers backward, dazed.
|
||||
|
||||
The guard slumps against the wall, unconscious.
|
||||
|
||||
~ guard_knocked_out = true
|
||||
~ player_attacked_guard = true
|
||||
#display:guard-unconscious
|
||||
#complete_task:neutralize_guard
|
||||
#set_global:attacked_guard:true
|
||||
|
||||
You have a limited window before they wake up or someone finds them.
|
||||
|
||||
#exit_conversation
|
||||
-> DONE
|
||||
}
|
||||
|
||||
{influence < 20:
|
||||
The guard blocks your punch and counters with a baton strike!
|
||||
|
||||
You fall back, stunned. The guard radios for backup.
|
||||
|
||||
Guard: ASSAULT ON SECURITY! BACKUP NEEDED NOW!
|
||||
|
||||
~ player_attacked_guard = true
|
||||
#display:guard-combat
|
||||
#hostile:security_guard
|
||||
#take_damage:moderate
|
||||
#mission_failed:attacked_security
|
||||
#exit_conversation
|
||||
-> DONE
|
||||
}
|
||||
|
||||
=== fight_wrestle ===
|
||||
You attempt to tackle the guard and pin them down.
|
||||
|
||||
{influence >= 15:
|
||||
You manage to get the guard in a headlock. They struggle but can't break free.
|
||||
|
||||
After a few seconds, the guard goes limp - unconscious.
|
||||
|
||||
~ guard_knocked_out = true
|
||||
~ player_attacked_guard = true
|
||||
#display:guard-unconscious
|
||||
#complete_task:neutralize_guard
|
||||
#set_global:attacked_guard:true
|
||||
|
||||
Move quickly. You only have a few minutes.
|
||||
|
||||
#exit_conversation
|
||||
-> DONE
|
||||
}
|
||||
|
||||
{influence < 15:
|
||||
The guard is stronger than you expected!
|
||||
|
||||
They break your grip and shove you hard against the wall.
|
||||
|
||||
Guard: ASSAULT! SECURITY BREACH! ALL UNITS TO ADMINISTRATIVE WING!
|
||||
|
||||
~ player_attacked_guard = true
|
||||
#display:guard-combat
|
||||
#hostile:security_guard
|
||||
#take_damage:moderate
|
||||
#mission_failed:attacked_security
|
||||
#exit_conversation
|
||||
-> DONE
|
||||
}
|
||||
|
||||
=== fight_improvise ===
|
||||
You grab a fire extinguisher from the wall mount.
|
||||
|
||||
{influence >= 25:
|
||||
You swing the extinguisher and connect with the guard's shoulder.
|
||||
|
||||
The guard drops to one knee, stunned. A second swing knocks them out cold.
|
||||
|
||||
~ guard_knocked_out = true
|
||||
~ player_attacked_guard = true
|
||||
#display:guard-unconscious
|
||||
#complete_task:neutralize_guard
|
||||
#set_global:attacked_guard:true
|
||||
#give_item:fire_extinguisher
|
||||
|
||||
The guard is unconscious. Work fast.
|
||||
|
||||
#exit_conversation
|
||||
-> DONE
|
||||
}
|
||||
|
||||
{influence < 25:
|
||||
The guard sees you reaching for the extinguisher and draws their baton!
|
||||
|
||||
They strike your arm hard before you can swing. The extinguisher clatters to the floor.
|
||||
|
||||
Guard: ARMED ASSAULT! REPEAT - ARMED ASSAULT!
|
||||
|
||||
~ player_attacked_guard = true
|
||||
#display:guard-combat
|
||||
#hostile:security_guard
|
||||
#take_damage:severe
|
||||
#mission_failed:attacked_security
|
||||
#exit_conversation
|
||||
-> DONE
|
||||
}
|
||||
|
||||
=== fight_backdown ===
|
||||
You raise your hands and step back.
|
||||
|
||||
~ influence -= 10
|
||||
|
||||
You: Wait, wait. I'm not going to fight you.
|
||||
|
||||
Guard: Smart choice. Now get out of here before I change my mind about calling this in.
|
||||
|
||||
#display:guard-wary
|
||||
#exit_conversation
|
||||
-> DONE
|
||||
|
||||
// ===========================================
|
||||
// DE-ESCALATION
|
||||
// ===========================================
|
||||
|
||||
=== back_down ===
|
||||
#speaker:security_guard
|
||||
|
||||
{influence >= 15:
|
||||
~ influence -= 5
|
||||
Guard: Smart move. Now get out of this wing and don't come back without authorization.
|
||||
|
||||
#display:guard-neutral
|
||||
#exit_conversation
|
||||
-> DONE
|
||||
}
|
||||
|
||||
{influence < 15:
|
||||
Guard: Good thinking. But I've got your description documented now.
|
||||
|
||||
Guard: One more incident and you're banned from the facility.
|
||||
|
||||
#display:guard-watchful
|
||||
#exit_conversation
|
||||
-> DONE
|
||||
}
|
||||
|
||||
// ===========================================
|
||||
// GENERAL CONVERSATION
|
||||
// ===========================================
|
||||
|
||||
=== ask_about_attack ===
|
||||
#speaker:security_guard
|
||||
|
||||
Guard: The ransomware? It's bad. Really bad.
|
||||
|
||||
Guard: 47 patients on life support. Backup power for maybe 12 hours.
|
||||
|
||||
Guard: IT says someone exploited our backup server. We're locked out of everything.
|
||||
|
||||
~ influence += 5
|
||||
|
||||
+ [Did anyone see suspicious activity?]
|
||||
Guard: Marcus in IT was warning about security issues for months.
|
||||
|
||||
Guard: Management ignored him. Now look where we are.
|
||||
|
||||
-> hub
|
||||
|
||||
+ [What's your job during the crisis?]
|
||||
Guard: Secure critical areas. Make sure nobody makes things worse.
|
||||
|
||||
Guard: And prevent anyone from... tampering with evidence, if you know what I mean.
|
||||
|
||||
-> hub
|
||||
|
||||
+ [Thanks for the info]
|
||||
-> hub
|
||||
|
||||
=== request_access ===
|
||||
#speaker:security_guard
|
||||
|
||||
{influence >= 50:
|
||||
Guard: Access to where? The server room?
|
||||
|
||||
Guard: That's locked down. Only Dr. Kim or Marcus can authorize that.
|
||||
|
||||
-> hub
|
||||
}
|
||||
|
||||
{influence >= 30:
|
||||
Guard: You need proper credentials for restricted areas.
|
||||
|
||||
Guard: Talk to Dr. Kim or IT if you have legitimate business.
|
||||
|
||||
-> hub
|
||||
}
|
||||
|
||||
{influence < 30:
|
||||
Guard: Access? Not without authorization from administration.
|
||||
|
||||
#display:guard-skeptical
|
||||
-> hub
|
||||
}
|
||||
|
||||
=== explain_lockpick_again ===
|
||||
#speaker:security_guard
|
||||
|
||||
Guard: We already discussed this. No lockpicking without authorization.
|
||||
|
||||
Guard: I'm being patient because of the crisis, but don't push it.
|
||||
|
||||
~ influence -= 5
|
||||
#display:guard-annoyed
|
||||
-> hub
|
||||
|
||||
// ===========================================
|
||||
// HOSTILE STANCE (AFTER AGGRESSIVE RESPONSE)
|
||||
// ===========================================
|
||||
|
||||
=== hostile_stance ===
|
||||
#speaker:security_guard
|
||||
|
||||
Guard: I don't like your attitude. You're on thin ice.
|
||||
|
||||
* [Apologize and explain you're stressed]
|
||||
~ influence += 10
|
||||
You: Sorry. This crisis has me on edge. I'm just trying to help.
|
||||
|
||||
Guard: Fine. We're all stressed. But watch your tone.
|
||||
|
||||
#display:guard-neutral
|
||||
-> hub
|
||||
|
||||
* [Double down on hostility]
|
||||
You: I don't have time for this security theater.
|
||||
|
||||
Guard: That's it. You're leaving. NOW.
|
||||
|
||||
#hostile:security_guard
|
||||
#exit_conversation
|
||||
-> DONE
|
||||
|
||||
* [Try to physically intimidate the guard]
|
||||
-> attempt_fight
|
||||
File diff suppressed because one or more lines are too long
@@ -706,7 +706,50 @@ marcus_warning_email = "From: Marcus Webb\nTo: Dr. Sarah Kim\nDate: May 17, 2024
|
||||
"west": "conference_room",
|
||||
"east": "server_room"
|
||||
},
|
||||
"npcs": [],
|
||||
"npcs": [
|
||||
{
|
||||
"id": "security_guard_patrol",
|
||||
"displayName": "Hospital Security Guard",
|
||||
"npcType": "person",
|
||||
"position": { "x": 10, "y": 2 },
|
||||
"spriteSheet": "hacker-red",
|
||||
"spriteTalk": "assets/characters/hacker-red-talk.png",
|
||||
"spriteConfig": {
|
||||
"idleFrameStart": 20,
|
||||
"idleFrameEnd": 23
|
||||
},
|
||||
"storyPath": "scenarios/m02_ransomed_trust/ink/m02_npc_security_guard.json",
|
||||
"currentKnot": "start",
|
||||
"behavior": {
|
||||
"patrol": {
|
||||
"enabled": true,
|
||||
"route": [
|
||||
{ "x": 3, "y": 2 },
|
||||
{ "x": 10, "y": 2 },
|
||||
{ "x": 17, "y": 2 },
|
||||
{ "x": 10, "y": 2 }
|
||||
],
|
||||
"speed": 40,
|
||||
"pauseTime": 20
|
||||
}
|
||||
},
|
||||
"los": {
|
||||
"enabled": true,
|
||||
"range": 150,
|
||||
"angle": 120,
|
||||
"visualize": true
|
||||
},
|
||||
"eventMappings": [
|
||||
{
|
||||
"eventPattern": "lockpick_used_in_view",
|
||||
"targetKnot": "on_lockpick_used",
|
||||
"conversationMode": "person-chat",
|
||||
"cooldown": 0
|
||||
}
|
||||
],
|
||||
"_comment": "Interactive guard with combat options - patrols hallway, can be fought, knocked out, or persuaded"
|
||||
}
|
||||
],
|
||||
"objects": [
|
||||
{
|
||||
"type": "notes",
|
||||
@@ -783,6 +826,8 @@ marcus_warning_email = "From: Marcus Webb\nTo: Dr. Sarah Kim\nDate: May 17, 2024
|
||||
"decoded_recovery_instructions": false,
|
||||
|
||||
"guard_detections": 0,
|
||||
"guard_knocked_out": false,
|
||||
"attacked_guard": false,
|
||||
"objectives_completed": 0,
|
||||
"lore_collected": 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user