From 9cb607ddf6959484c7455320b7046d793007bee5 Mon Sep 17 00:00:00 2001 From: "Z. Cliffe Schreuders" Date: Wed, 14 Jan 2026 09:46:31 +0000 Subject: [PATCH] Add interactive guard with combat options to Mission 2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../ink/m02_npc_security_guard.ink | 572 ++++++++++++++++++ .../ink/m02_npc_security_guard.json | 1 + .../m02_ransomed_trust/scenario.json.erb | 47 +- 3 files changed, 619 insertions(+), 1 deletion(-) create mode 100644 scenarios/m02_ransomed_trust/ink/m02_npc_security_guard.ink create mode 100644 scenarios/m02_ransomed_trust/ink/m02_npc_security_guard.json diff --git a/scenarios/m02_ransomed_trust/ink/m02_npc_security_guard.ink b/scenarios/m02_ransomed_trust/ink/m02_npc_security_guard.ink new file mode 100644 index 0000000..7b52bfa --- /dev/null +++ b/scenarios/m02_ransomed_trust/ink/m02_npc_security_guard.ink @@ -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 diff --git a/scenarios/m02_ransomed_trust/ink/m02_npc_security_guard.json b/scenarios/m02_ransomed_trust/ink/m02_npc_security_guard.json new file mode 100644 index 0000000..ed5e30f --- /dev/null +++ b/scenarios/m02_ransomed_trust/ink/m02_npc_security_guard.json @@ -0,0 +1 @@ +{"inkVersion":21,"root":[[["done",{"#n":"g-0"}],null],"done",{"start":["#","^speaker:security_guard","/#","ev",{"VAR?":"warned_player"},"!","/ev",[{"->":".^.b","c":true},{"b":["\n","#","^display:guard-patrol","/#","^You see a hospital security guard patrolling the corridor. They're watching the area carefully.","\n","^The guard notices you and approaches.","\n","ev",true,"/ev",{"VAR=":"warned_player","re":true},"^Guard: Hold on. This is a restricted area during the crisis. What's your business here?","\n",{"->":"initial_response"},{"->":"start.8"},null]}],"nop","\n","ev",{"VAR?":"warned_player"},{"VAR?":"caught_lockpicking"},"!","&&",{"VAR?":"guard_knocked_out"},"!","&&","/ev",[{"->":".^.b","c":true},{"b":["\n","#","^display:guard-patrol","/#","^The guard nods at you as they continue their patrol.","\n","^Guard: Still working on the crisis?","\n",{"->":"hub"},{"->":"start.20"},null]}],"nop","\n","ev",{"VAR?":"guard_knocked_out"},"/ev",[{"->":".^.b","c":true},{"b":["\n","#","^display:guard-unconscious","/#","^The security guard is unconscious on the floor. You should move quickly before they wake up.","\n","#","^exit_conversation","/#","done",{"->":"start.26"},null]}],"nop","\n",{"->":"hub"},null],"initial_response":[["ev","str","^I'm the security consultant Dr. Kim called in","/str","/ev",{"*":".^.c-0","flg":4},"ev","str","^Just passing through, officer","/str","/ev",{"*":".^.c-1","flg":4},"ev","str","^Emergency - I need to access the server room","/str","/ev",{"*":".^.c-2","flg":4},"ev","str","^None of your business","/str","/ev",{"*":".^.c-3","flg":4},{"c-0":["\n","ev",{"VAR?":"influence"},20,"+",{"VAR=":"influence","re":true},"/ev","^You: I'm the external security consultant. Dr. Kim authorized my access.","\n","^Guard: Oh, right. The ransomware crisis. Dr. Kim mentioned someone was coming.","\n","^Guard: Still, I need to see your visitor badge.","\n","ev",{"VAR?":"player_has_id_badge"},"/ev",[{"->":".^.b","c":true},{"b":["\n","^You show the visitor badge from reception.","\n","ev",{"VAR?":"influence"},10,"+",{"VAR=":"influence","re":true},"/ev","^Guard: Checks out. Be careful in there. It's a mess.","\n",{"->":"hub"},{"->":".^.^.^.18"},null]}],[{"->":".^.b"},{"b":["\n","^You: I... must have left it at reception.","\n","ev",{"VAR?":"influence"},5,"-",{"VAR=":"influence","re":true},"/ev","^Guard: Then go get it. Security protocols exist for a reason.","\n",{"->":"hub"},{"->":".^.^.^.18"},null]}],"nop","\n",null],"c-1":["\n","^You: Just passing through. No trouble.","\n","^Guard: During a ransomware crisis? Nothing is \"just passing through\" right now.","\n",{"->":"hub"},null],"c-2":["\n","ev",{"VAR?":"influence"},5,"+",{"VAR=":"influence","re":true},"/ev","^You: This is urgent. The hospital systems are down. Lives are at stake.","\n","^Guard: I know. That's why I'm here securing this area.","\n","^Guard: You need proper authorization to access restricted systems.","\n",{"->":"hub"},null],"c-3":["\n","ev",{"VAR?":"influence"},30,"-",{"VAR=":"influence","re":true},"/ev","^You: That's not your concern.","\n","^Guard: Wrong answer. Everything in this corridor is my concern.","\n","#","^display:guard-hostile","/#",{"->":"hostile_stance"},null]}],null],"hub":[["ev","str","^Ask about the ransomware attack","/str","/ev",{"*":".^.c-0","flg":4},"ev","str","^Request access to restricted areas","/str","/ev",{"*":".^.c-1","flg":4},"ev","str","^Explain the lockpicking situation","/str",{"VAR?":"caught_lockpicking"},"/ev",{"*":".^.c-2","flg":5},"ev","str","^End conversation","/str","/ev",{"*":".^.c-3","flg":4},{"c-0":["\n",{"->":"ask_about_attack"},null],"c-1":["\n",{"->":"request_access"},null],"c-2":["\n",{"->":"explain_lockpick_again"},null],"c-3":["\n","#","^exit_conversation","/#","^Guard: Stay safe. This crisis has everyone on edge.","\n","done",null]}],null],"on_lockpick_used":["#","^speaker:security_guard","/#","ev",{"VAR?":"caught_lockpicking"},1,"<","/ev",[{"->":".^.b","c":true},{"b":["\n","ev",true,"/ev",{"VAR=":"caught_lockpicking","re":true},"ev",0,"/ev",{"VAR=":"confrontation_attempts","re":true},{"->":".^.^.^.9"},null]}],"nop","\n","ev",{"VAR?":"confrontation_attempts"},1,"+",{"VAR=":"confrontation_attempts","re":true},"/ev","#","^display:guard-confrontation","/#","ev",{"VAR?":"confrontation_attempts"},1,"==","/ev",[{"->":".^.b","c":true},{"b":["\n","^Guard: HEY! What the hell are you doing with those lockpicks?!","\n","^Guard: Step away from that door RIGHT NOW!","\n","ev","str","^I have authorization from Dr. Kim!","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^I'm trying to recover critical patient data!","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^I was just... looking for something I dropped","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^This is official security testing","/str","/ev",{"*":".^.c-3","flg":20},"ev","str","^Back off - this is more important than you know","/str","/ev",{"*":".^.c-4","flg":20},"ev","str","^Try to physically overpower the guard","/str","/ev",{"*":".^.c-5","flg":20},{"->":".^.^.^.26"},{"c-0":["\n",{"->":"claim_authorization"},{"#f":5}],"c-1":["\n",{"->":"explain_emergency"},{"#f":5}],"c-2":["\n",{"->":"poor_excuse"},{"#f":5}],"c-3":["\n",{"->":"claim_audit"},{"#f":5}],"c-4":["\n",{"->":"hostile_response"},{"#f":5}],"c-5":["\n",{"->":"attempt_fight"},{"#f":5}]}]}],"nop","\n","ev",{"VAR?":"confrontation_attempts"},1,">","/ev",[{"->":".^.b","c":true},{"b":["\n","^Guard: I ALREADY TOLD YOU TO STOP!","\n","^Guard: This is your FINAL warning before I call backup!","\n","ev","str","^Okay, I'm leaving right now","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^You don't understand the stakes here","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Attack the guard before they call backup","/str","/ev",{"*":".^.c-2","flg":20},{"->":".^.^.^.34"},{"c-0":["\n",{"->":"back_down"},{"#f":5}],"c-1":["\n",{"->":"escalate_conflict"},{"#f":5}],"c-2":["\n",{"->":"attempt_fight"},{"#f":5}]}]}],"nop","\n",null],"claim_authorization":["#","^speaker:security_guard","/#","ev",{"VAR?":"influence"},30,">=","/ev",[{"->":".^.b","c":true},{"b":["\n","ev",{"VAR?":"influence"},10,"-",{"VAR=":"influence","re":true},"/ev","^Guard: Dr. Kim authorized lockpicking? That's... unusual.","\n","^Guard: Fine. But if she didn't, you're in deep trouble.","\n","#","^display:guard-skeptical","/#",{"->":"hub"},{"->":".^.^.^.9"},null]}],"nop","\n","ev",{"VAR?":"influence"},30,"<","/ev",[{"->":".^.b","c":true},{"b":["\n","ev",{"VAR?":"influence"},20,"-",{"VAR=":"influence","re":true},"/ev","^Guard: Authorization doesn't mean breaking into rooms! Where's your paperwork?","\n","^Guard: Move along before this gets reported.","\n","#","^display:guard-hostile","/#","#","^exit_conversation","/#","done",{"->":".^.^.^.17"},null]}],"nop","\n",null],"explain_emergency":["#","^speaker:security_guard","/#","ev",{"VAR?":"influence"},25,">=","/ev",[{"->":".^.b","c":true},{"b":["\n","ev",{"VAR?":"influence"},5,"-",{"VAR=":"influence","re":true},"/ev","^Guard: Patient data? In a locked storage room?","\n","^Guard: Look, I get the emergency, but protocol is protocol.","\n","^Guard: Get proper authorization or I can't let this slide.","\n","#","^display:guard-concerned","/#",{"->":"hub"},{"->":".^.^.^.9"},null]}],"nop","\n","ev",{"VAR?":"influence"},25,"<","/ev",[{"->":".^.b","c":true},{"b":["\n","ev",{"VAR?":"influence"},15,"-",{"VAR=":"influence","re":true},"/ev","^Guard: Nice try. Security breach is security breach, crisis or not.","\n","^Guard: Backup is on the way.","\n","#","^display:guard-alert","/#","#","^exit_conversation","/#","done",{"->":".^.^.^.17"},null]}],"nop","\n",null],"poor_excuse":["#","^speaker:security_guard","/#","ev",{"VAR?":"influence"},15,"-",{"VAR=":"influence","re":true},"/ev","^Guard: Looking for something you dropped? With lockpicks?","\n","^Guard: That's the weakest excuse I've heard all week.","\n","#","^display:guard-annoyed","/#",{"->":"hub"},null],"claim_audit":["#","^speaker:security_guard","/#","ev",{"VAR?":"influence"},40,">=","/ev",[{"->":".^.b","c":true},{"b":["\n","ev",{"VAR?":"influence"},5,"-",{"VAR=":"influence","re":true},"/ev","^Guard: Security audit during a ransomware crisis? Bold timing.","\n","^Guard: You better have documentation for this.","\n","#","^display:guard-neutral","/#",{"->":"hub"},{"->":".^.^.^.9"},null]}],"nop","\n","ev",{"VAR?":"influence"},40,"<","/ev",[{"->":".^.b","c":true},{"b":["\n","ev",{"VAR?":"influence"},25,"-",{"VAR=":"influence","re":true},"/ev","^Guard: An audit would be scheduled with security. This isn't official.","\n","^Guard: You're coming with me to speak with my supervisor.","\n","#","^display:guard-arrest","/#","#","^exit_conversation","/#","done",{"->":".^.^.^.17"},null]}],"nop","\n",null],"hostile_response":["#","^speaker:security_guard","/#","ev",{"VAR?":"influence"},30,"-",{"VAR=":"influence","re":true},"/ev","^Guard: More important than hospital security? You just crossed a line.","\n","^Guard: SECURITY! CODE VIOLATION IN ADMINISTRATIVE WING!","\n","#","^display:guard-aggressive","/#","#","^hostile:security_guard","/#","#","^exit_conversation","/#","done",null],"escalate_conflict":["#","^speaker:security_guard","/#","ev",{"VAR?":"influence"},40,"-",{"VAR=":"influence","re":true},"/ev","^Guard: The stakes? You're breaking hospital protocol during an emergency!","\n","^Guard: LOCKDOWN! INTRUDER ALERT!","\n","#","^display:guard-alarm","/#","#","^hostile:security_guard","/#","#","^exit_conversation","/#","done",null],"attempt_fight":[["#","^speaker:security_guard","/#","^Guard: You're really going to attack a security officer?!","\n","^You lunge at the guard, trying to knock them out before they can call for backup.","\n","ev","str","^Go for a quick knockout punch","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Try to wrestle them to the ground","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Use a nearby object as a weapon","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^Actually, back down from this","/str","/ev",{"*":".^.c-3","flg":20},{"c-0":["\n",{"->":"fight_punch"},{"#f":5}],"c-1":["\n",{"->":"fight_wrestle"},{"#f":5}],"c-2":["\n",{"->":"fight_improvise"},{"#f":5}],"c-3":["\n",{"->":"fight_backdown"},{"#f":5}]}],null],"fight_punch":["^You swing at the guard's jaw.","\n","ev",{"VAR?":"influence"},20,">=","/ev",[{"->":".^.b","c":true},{"b":["\n","^Your punch connects! The guard staggers backward, dazed.","\n","^The guard slumps against the wall, unconscious.","\n","ev",true,"/ev",{"VAR=":"guard_knocked_out","re":true},"ev",true,"/ev",{"VAR=":"player_attacked_guard","re":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.","\n","#","^exit_conversation","/#","done",{"->":".^.^.^.8"},null]}],"nop","\n","ev",{"VAR?":"influence"},20,"<","/ev",[{"->":".^.b","c":true},{"b":["\n","^The guard blocks your punch and counters with a baton strike!","\n","^You fall back, stunned. The guard radios for backup.","\n","^Guard: ASSAULT ON SECURITY! BACKUP NEEDED NOW!","\n","ev",true,"/ev",{"VAR=":"player_attacked_guard","re":true},"#","^display:guard-combat","/#","#","^hostile:security_guard","/#","#","^take_damage:moderate","/#","#","^mission_failed:attacked_security","/#","#","^exit_conversation","/#","done",{"->":".^.^.^.16"},null]}],"nop","\n",null],"fight_wrestle":["^You attempt to tackle the guard and pin them down.","\n","ev",{"VAR?":"influence"},15,">=","/ev",[{"->":".^.b","c":true},{"b":["\n","^You manage to get the guard in a headlock. They struggle but can't break free.","\n","^After a few seconds, the guard goes limp - unconscious.","\n","ev",true,"/ev",{"VAR=":"guard_knocked_out","re":true},"ev",true,"/ev",{"VAR=":"player_attacked_guard","re":true},"#","^display:guard-unconscious","/#","#","^complete_task:neutralize_guard","/#","#","^set_global:attacked_guard:true","/#","^Move quickly. You only have a few minutes.","\n","#","^exit_conversation","/#","done",{"->":".^.^.^.8"},null]}],"nop","\n","ev",{"VAR?":"influence"},15,"<","/ev",[{"->":".^.b","c":true},{"b":["\n","^The guard is stronger than you expected!","\n","^They break your grip and shove you hard against the wall.","\n","^Guard: ASSAULT! SECURITY BREACH! ALL UNITS TO ADMINISTRATIVE WING!","\n","ev",true,"/ev",{"VAR=":"player_attacked_guard","re":true},"#","^display:guard-combat","/#","#","^hostile:security_guard","/#","#","^take_damage:moderate","/#","#","^mission_failed:attacked_security","/#","#","^exit_conversation","/#","done",{"->":".^.^.^.16"},null]}],"nop","\n",null],"fight_improvise":["^You grab a fire extinguisher from the wall mount.","\n","ev",{"VAR?":"influence"},25,">=","/ev",[{"->":".^.b","c":true},{"b":["\n","^You swing the extinguisher and connect with the guard's shoulder.","\n","^The guard drops to one knee, stunned. A second swing knocks them out cold.","\n","ev",true,"/ev",{"VAR=":"guard_knocked_out","re":true},"ev",true,"/ev",{"VAR=":"player_attacked_guard","re":true},"#","^display:guard-unconscious","/#","#","^complete_task:neutralize_guard","/#","#","^set_global:attacked_guard:true","/#","#","^give_item:fire_extinguisher","/#","^The guard is unconscious. Work fast.","\n","#","^exit_conversation","/#","done",{"->":".^.^.^.8"},null]}],"nop","\n","ev",{"VAR?":"influence"},25,"<","/ev",[{"->":".^.b","c":true},{"b":["\n","^The guard sees you reaching for the extinguisher and draws their baton!","\n","^They strike your arm hard before you can swing. The extinguisher clatters to the floor.","\n","^Guard: ARMED ASSAULT! REPEAT - ARMED ASSAULT!","\n","ev",true,"/ev",{"VAR=":"player_attacked_guard","re":true},"#","^display:guard-combat","/#","#","^hostile:security_guard","/#","#","^take_damage:severe","/#","#","^mission_failed:attacked_security","/#","#","^exit_conversation","/#","done",{"->":".^.^.^.16"},null]}],"nop","\n",null],"fight_backdown":["^You raise your hands and step back.","\n","ev",{"VAR?":"influence"},10,"-",{"VAR=":"influence","re":true},"/ev","^You: Wait, wait. I'm not going to fight you.","\n","^Guard: Smart choice. Now get out of here before I change my mind about calling this in.","\n","#","^display:guard-wary","/#","#","^exit_conversation","/#","done",null],"back_down":["#","^speaker:security_guard","/#","ev",{"VAR?":"influence"},15,">=","/ev",[{"->":".^.b","c":true},{"b":["\n","ev",{"VAR?":"influence"},5,"-",{"VAR=":"influence","re":true},"/ev","^Guard: Smart move. Now get out of this wing and don't come back without authorization.","\n","#","^display:guard-neutral","/#","#","^exit_conversation","/#","done",{"->":".^.^.^.9"},null]}],"nop","\n","ev",{"VAR?":"influence"},15,"<","/ev",[{"->":".^.b","c":true},{"b":["\n","^Guard: Good thinking. But I've got your description documented now.","\n","^Guard: One more incident and you're banned from the facility.","\n","#","^display:guard-watchful","/#","#","^exit_conversation","/#","done",{"->":".^.^.^.17"},null]}],"nop","\n",null],"ask_about_attack":[["#","^speaker:security_guard","/#","^Guard: The ransomware? It's bad. Really bad.","\n","^Guard: 47 patients on life support. Backup power for maybe 12 hours.","\n","^Guard: IT says someone exploited our backup server. We're locked out of everything.","\n","ev",{"VAR?":"influence"},5,"+",{"VAR=":"influence","re":true},"/ev","ev","str","^Did anyone see suspicious activity?","/str","/ev",{"*":".^.c-0","flg":4},"ev","str","^What's your job during the crisis?","/str","/ev",{"*":".^.c-1","flg":4},"ev","str","^Thanks for the info","/str","/ev",{"*":".^.c-2","flg":4},{"c-0":["\n","^Guard: Marcus in IT was warning about security issues for months.","\n","^Guard: Management ignored him. Now look where we are.","\n",{"->":"hub"},null],"c-1":["\n","^Guard: Secure critical areas. Make sure nobody makes things worse.","\n","^Guard: And prevent anyone from... tampering with evidence, if you know what I mean.","\n",{"->":"hub"},null],"c-2":["\n",{"->":"hub"},null]}],null],"request_access":["#","^speaker:security_guard","/#","ev",{"VAR?":"influence"},50,">=","/ev",[{"->":".^.b","c":true},{"b":["\n","^Guard: Access to where? The server room?","\n","^Guard: That's locked down. Only Dr. Kim or Marcus can authorize that.","\n",{"->":"hub"},{"->":".^.^.^.9"},null]}],"nop","\n","ev",{"VAR?":"influence"},30,">=","/ev",[{"->":".^.b","c":true},{"b":["\n","^Guard: You need proper credentials for restricted areas.","\n","^Guard: Talk to Dr. Kim or IT if you have legitimate business.","\n",{"->":"hub"},{"->":".^.^.^.17"},null]}],"nop","\n","ev",{"VAR?":"influence"},30,"<","/ev",[{"->":".^.b","c":true},{"b":["\n","^Guard: Access? Not without authorization from administration.","\n","#","^display:guard-skeptical","/#",{"->":"hub"},{"->":".^.^.^.25"},null]}],"nop","\n",null],"explain_lockpick_again":["#","^speaker:security_guard","/#","^Guard: We already discussed this. No lockpicking without authorization.","\n","^Guard: I'm being patient because of the crisis, but don't push it.","\n","ev",{"VAR?":"influence"},5,"-",{"VAR=":"influence","re":true},"/ev","#","^display:guard-annoyed","/#",{"->":"hub"},null],"hostile_stance":[["#","^speaker:security_guard","/#","^Guard: I don't like your attitude. You're on thin ice.","\n","ev","str","^Apologize and explain you're stressed","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Double down on hostility","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Try to physically intimidate the guard","/str","/ev",{"*":".^.c-2","flg":20},{"c-0":["\n","ev",{"VAR?":"influence"},10,"+",{"VAR=":"influence","re":true},"/ev","^You: Sorry. This crisis has me on edge. I'm just trying to help.","\n","^Guard: Fine. We're all stressed. But watch your tone.","\n","#","^display:guard-neutral","/#",{"->":"hub"},{"#f":5}],"c-1":["\n","^You: I don't have time for this security theater.","\n","^Guard: That's it. You're leaving. NOW.","\n","#","^hostile:security_guard","/#","#","^exit_conversation","/#","done",{"#f":5}],"c-2":["\n",{"->":"attempt_fight"},{"#f":5}]}],null],"global decl":["ev",0,{"VAR=":"influence"},false,{"VAR=":"caught_lockpicking"},0,{"VAR=":"confrontation_attempts"},false,{"VAR=":"warned_player"},false,{"VAR=":"player_attacked_guard"},false,{"VAR=":"guard_knocked_out"},false,{"VAR=":"player_has_id_badge"},"/ev","end",null]}],"listDefs":{}} \ No newline at end of file diff --git a/scenarios/m02_ransomed_trust/scenario.json.erb b/scenarios/m02_ransomed_trust/scenario.json.erb index e96490e..e79009c 100644 --- a/scenarios/m02_ransomed_trust/scenario.json.erb +++ b/scenarios/m02_ransomed_trust/scenario.json.erb @@ -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 }