Alarm, Alarm!

Overview

In this demonstration, we are going to set up a camera at a pair of entrances. If and when the player is spotted by a camera, an alarm will sound and a small team of Civil Protection officers will rush toward the player. The map used in this example piece is an HL2DM map named dm_resistance.

The reader should already be familiar with mapadd syntax, grabbing coordinates, using the input/output system, and other basics.

This example makes particular use of these entities:
aiscripted_schedule
ambient_generic
instant_trig
npc_combine_camera
point_clientcommand

For its variant:
env_beam
info_target
prop_physics

How-To

After using the console to grab some coordinates (eg. noclip and getpos) and prepping the player, we can start work on the alarm system.

One place to start might be the alarm sound to use. This author found a suitable one by digging through source sounds.gcf and finding the sound's matching ID name in source engine\scripts\level_sounds_canals.txt, though you can just use the normal sound path instead. Below is a snippet of the author's script, where an ambient_generic has been placed in the Entities section (since they don't work within labels).

    "ambient_generic" // Ding dong
        {
        "origin" "-53 -527 -632"
        "keyvalues"
            {
            "targetname" "aud_Alarm"
            "message" "d1_canals.Floodgate_AlarmBellLoop"
            "health" "10"
            "spawnflags" "16" // Gag until triggered.
            }
        }

Message contains the sound's ID or filename, while health is the sound's volume (0-10). The spawnflags value makes it so that the sound doesn't automatically begin playing at map start.

Next, we might pause to think a bit on the exact sequence of events that will take place. In the example script, this author wanted to spawn the officers almost immediately after the player is spotted but not give them orders just yet, and give the cameras some eye time before folding them up. Next, the alarm would be sounded, the officers sent in, and the alarm would be squelched after a few moments' time.

In this example script, a label called Spawn_Combine is used to create the officers on demand, but labels can't be called by normal I/O. One way around this is to add a point_clientcommand, which can be used to send the needed console command:

"point_clientcommand"
        {
        "keyvalues"
            {
            "targetname" "cmd"
            }
        }

This is then used by either camera once they've spotted the player:

    "npc_combine_camera"
        {
        "origin"    "-544 -380 -950"
        "angle"        "0 90 0"
        "keyvalues"
            {
            "targetname" "CamW"
            "innerradius" "400"
            "outerradius" "1200"
            "OnFoundPlayer" "cmd,command,instant_trig_run Spawn_Combine,1,-1" // Tell the console to run the Spawn_Combine label.
            "OnFoundPlayer" "Cam*,Disable,,1.5,-1" // Fold both cameras up.
            "OnFoundPlayer" "aud_Alarm,PlaySound,,2,-1" // Start the alarm and
            "OnFoundPlayer" "aud_Alarm,StopSound,,12,-1" // 10 seconds later, shut it up.
            }
        }

So far, so good. But how do the officers know they're to charge the player? Even if the cameras and soldiers were given the same squad, the Combine often act defensively and hang back. How do we inform them about the player's whereabouts and get them to abandon that behavior?

In this example script, it's accomplished with an aiscripted_schedule entity, which is then triggered by the cameras. Below, a snippet details what each bit of the entity does

    "aiscripted_schedule"
        {
        "keyvalues"
            {
            "targetname" "AIS_Combine"
            "graball" "1"                    // Find NPCs in the area,
            "m_flradius" "0"                 // the area being anywhere in the map.
            "m_iszEntity" "npc_metropolice"  // We want to find Civil Protection units,
            "forcestate" "3"                 // have them fully alert and ready for combat,
            "goalent" "!player"              // then bring their attention to the player's current position.
            "schedule" "6"                   // The target is something we want to run to.  It is also an enemy.
            "interruptability" "1"           // Order will only be interrupted if the soldier is wounded or killed.
            "spawnflags" "4"                 // This order can be triggered more than once.
            }
        }

Afterward, all that is needed is an appropriate output on each camera to begin the schedule:

    "npc_combine_camera"
        {
        "origin"    "447 -392 -950"
        "angle"        "0 90 0"
        "keyvalues"
            {
            "targetname" "CamE"
            "innerradius" "400"
            "outerradius" "1200"
            "OnFoundPlayer" "cmd,command,instant_trig_run Spawn_Combine,1,-1"
            "OnFoundPlayer" "Cam*,Disable,,1.5,-1"
            "OnFoundPlayer" "AIS_Combine,StartSchedule,,2,-1" // Send in the metros.
            "OnFoundPlayer" "aud_Alarm,PlaySound,,2,-1"
            "OnFoundPlayer" "aud_Alarm,StopSound,,12,-1"
            }
        }

Done. We now have a very simple security system that makes a racket and summons in a handful of guards.

AlarmCamera1_t.jpg AlarmCamera2_t.jpg AlarmCamera3_t.jpg

Note that you can evade the guards by ducking into another room; the schedule summons the officers to the player's current position. This example was not made with the intention of tracking the player for the enemy.

Variant - Trip Laser

One could pretty easily mess with the script so that a laser beam triggers an alarm instead. A good starting point would be to grab some coordinates with Impulse 90. For the example map, you ought to look at the outer wall before using the command, then do the same for other hall's outer wall. Using the "trace" coordinates, put an info_target node at both locations, and take time afterward to make sure they're lined up with each other:

"info_target"
        {
        "origin" "-660 -400 -1200"
        "angle" "0 0 0"
        "keyvalues"
            {
            "targetname" "BeamWest1"
            }
        }
    "info_target"
        {
        "origin" "556 -400 -1200"
        "angle" "180 0 0"
        "keyvalues"
            {
            "targetname" "BeamEast1"
            }
        }

These won't do anything by themselves, but will act as start & end points for the beam, which will go through the building to the opposite hallway and save us the trouble of making another beam. In this example,prop_physics objects made to look like motion sensors were also put at each info_target so that the laser didn't seem to just appear out of thin air:

"prop_physics" // BeamWest1
        {
        "origin" "-660 -400 -1200"
        "angle" "0 0 0"
        "keyvalues"
            {
            "model" "models/weapons/w_msbomb.mdl"
            "spawnflags" "8" // Freeze in place.
            }
        }

The beam itself is nothing fancy at all:

    "env_beam"
        {
        "keyvalues"
            {
            "targetname" "Beam1"
            "spawnflags" "1" // Begin activated.
            "rendercolor" "0 0 128" // Make the beam dark blue to match the MSbomb model.
            "boltwidth" "4" // How thick is the beam?
            "texture" "sprites\bluelaser1" // Which texture to use?
            "lightningstart" "BeamWest1" // Start Point
            "lightningend" "BeamEast1" // End Point
            "touchtype" "3" // Players and NPCs can trigger the beam.
            "OnTouchedByEntity" "!self,kill,,0,-1"
            "OnTouchedByEntity" "cmd,command,instant_trig_run Spawn_Combine,1,-1"
            "OnTouchedByEntity" "AIS_Combine,StartSchedule,,2,-1"
            "OnTouchedByEntity" "aud_Alarm,PlaySound,,2,-1"
            "OnTouchedByEntity" "aud_Alarm,StopSound,,12,-1"
            }
        }

Once touched by the player or an NPC, the beam deletes itself and sounds the alarm. That wraps it up! You should now be able to trip the beam and send some bad guys your way.

Wrap-up

This page should be viewed as a starting point for your own ideas. One could, for instance, use scanners instead to mark a player's position. Once photographed, a dropship would swoop in and drop rollermines at the player's position. Just about anything's possible, it's just a matter of figuring how.

mapaddex_dl.png The example scripts this article is based on can be downloaded here for reference, with nodes for NPCs included.


Customization

Mapadd Command Reference (Non-LUA)Command Reference (LUA)Getting StartedPorts 'n' Doors
Alarm, Alarm!Color Correction in SMODDoor BreachingMobile APCsWorking With Dropships
Supply Drop (LUA)Countdown (LUA)
kh0rn3's Mapadd Generator
Scripts addcontentsoverride_classsmod_custom_explosivesmodaclistSMOD Soundscripts

npc_gib_modelnpc_replace_modelnpc_shieldsetnpc_weapon_randomizenpc_weaponweight

excludeweaponsweapon_categoryweapon_customConsole Command List
Other Crosshair CustomizationGenerating AI NodesUsing the NodemakerSubViewCam
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License