Overview
The automated_turret_device is a placed device that searches for nearby targets, rotates to track them, and fires automatically. Out of the box it solves the "I need a hostile defender" problem — guarding a vault, defending a capture point, or acting as a stationary boss.
Where Verse earns its keep is control and reaction. From code you can:
- Turn the turret on/off in response to game events (an alarm, a button, a round start) with
Enable()/Disable(). - Tune its behavior live with
SetDamage(),SetActivationRange(), andSetTargetRange()— great for difficulty ramps. - Override its AI by forcing a target with
SetTarget(), reading the current one withGetTarget(), or releasing it withClearTarget(). - React to the fight with
TargetFoundEvent,TargetLostEvent,ActivatedEvent,DamagedEvent, andDestroyedEvent.
Because the device implements healthful/healable, you can also read/set its health and heal it — handy for repairable defenses.
Reach for it whenever you want an enemy that aims and shoots without writing your own pathfinding or aiming code.
API Reference
automated_turret_device
Used to create a customizable turret that can search for nearby targets.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
automated_turret_device<public> := class<concrete><final>(creative_device_base, healthful, healable):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
ActivatedEvent |
ActivatedEvent<public>:listenable(?agent) |
Triggers when someone enters the activation radius while nobody else is there. Sends the activating agent. If the activator is a non-agent then false is returned. |
DamagedEvent |
DamagedEvent<public>:listenable(?agent) |
Triggers when the turret is damaged. Sends the triggering agent. If the activator is a non-agent then false is returned. |
DestroyedEvent |
DestroyedEvent<public>:listenable(?agent) |
Triggers when the turret is destroyed. Sends the triggering agent. If the activator is a non-agent then false is returned. |
TargetFoundEvent |
TargetFoundEvent<public>:listenable(agent) |
Triggers when the turret finds a target. Sends the agent that was found. |
TargetLostEvent |
TargetLostEvent<public>:listenable(agent) |
Triggers when the turret loses a target. Sends the agent that was lost. |
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Enable |
Enable<public>():void |
Enables the turret to rotate, target, and track. |
Disable |
Disable<public>():void |
Disables the turret, causing it to close and ignore its activation radius. |
UseDefaultTeam |
UseDefaultTeam<public>():void |
Set the turret to the Default Team. * Only usable if Possible Targets is not set to Everyone. |
UseTeamWildlifeAndCreatures |
UseTeamWildlifeAndCreatures<public>():void |
Set the turret to the Wildlife & Creatures team. * Only usable if Possible Targets is not set to Everyone. |
GetTarget |
GetTarget<public>():?agent |
Returns the agent currently targeted by the device. |
SetTarget |
SetTarget<public>(Agent:agent):void |
Set the supplied Agent as the turret's target. * The target will only change if Agent is within the activation radius, has direct line-of-sight to the turret, is on a targetable team as determined by Possible Targets, and is not Down |
ClearTarget |
ClearTarget<public>():void |
Clears the turret's current target and returns the turret to searching for targets. * If the current target is still in range, it'll likely be the best target, and will be reacquired. * Combine with disabled targeting for best results. |
SetDamage |
SetDamage<public>(Damage:float):void |
Sets the amount of damage the turret will do per shot to targets to Damage. |
SetActivationRange |
SetActivationRange<public>(Range:float):void |
Sets the range in meters at which the turret will activate to Range. This is clamped between 2.0 and 100.0 meters. |
SetTargetRange |
SetTargetRange<public>(Range:float):void |
Sets the range in meters at which the turret will target to Range. This is clamped between 2.0 and 100.0 meters. Setting it lower than 2m will disable Targeting. |
Walkthrough
Let's build a vault defense: the turret starts disabled and harmless. When a player steps on a security plate (a button_device), the turret arms, its damage ramps up, and we light a warning VFX. We announce on the HUD when the turret locks a target, when it loses one, and we disable it (and clear its target) the moment it's destroyed so it doesn't keep firing as a ghost.
Every placed device is referenced through an @editable field, then we subscribe handlers in OnBegin.
automated_turret_guard := class(creative_device):
# The turret we are scripting. Drag your placed Automated Turret here in the Details panel.
@editable
Turret : automated_turret_device = automated_turret_device{}
# A button players press to arm the defense.
@editable
ArmButton : button_device = button_device{}
# An optional warning effect that pulses while the turret is hot.
@editable
WarningVFX : vfx_spawner_device = vfx_spawner_device{}
# HUD announcer for combat callouts.
@editable
Announcer : hud_message_device = hud_message_device{}
# Localized text helper — message params need a localized value, not a raw string.
Msg<localizes>(S : string) : message = "{S}"
OnBegin<override>()<suspends> : void =
# Start safe: turret off, no VFX.
Turret.Disable()
WarningVFX.Disable()
# Wire up gameplay reactions.
ArmButton.InteractedWithEvent.Subscribe(OnArmPressed)
Turret.TargetFoundEvent.Subscribe(OnTargetFound)
Turret.TargetLostEvent.Subscribe(OnTargetLost)
Turret.DestroyedEvent.Subscribe(OnTurretDestroyed)
# Player pressed the security plate — arm and tune the turret.
OnArmPressed(Agent : agent) : void =
Turret.SetDamage(25.0) # damage per shot
Turret.SetActivationRange(20.0) # wakes up at 20m
Turret.SetTargetRange(30.0) # fires out to 30m
Turret.Enable() # start rotating + tracking
WarningVFX.Enable()
Announcer.Show(Msg("Vault defenses ARMED"))
# TargetFoundEvent hands us a plain agent (not optional).
OnTargetFound(Target : agent) : void =
Announcer.Show(Msg("Turret has acquired a target!"))
OnTargetLost(Target : agent) : void =
Announcer.Show(Msg("Turret lost its target."))
# DestroyedEvent sends ?agent (could be a non-agent source), so unwrap it.
OnTurretDestroyed(Attacker : ?agent) : void =
Turret.ClearTarget() # stop chasing whatever it was on
Turret.Disable() # silence the wreck
WarningVFX.Disable()
if (A := Attacker?):
Announcer.Show(Msg("Turret destroyed by an attacker!"))
else:
Announcer.Show(Msg("Turret destroyed."))
Line by line:
- The four
@editablefields are the only way to call placed devices — a bareTurret.Enable()with no field would fail withUnknown identifier. Msg<localizes>(S:string):messageis the standard trick to feed a localizedmessageintoShow(). There is noStringToMessage.- In
OnBeginwe put the turret in a safe state, then subscribe handlers. Each handler is a method at class scope. OnArmPressedcalls four real turret setters beforeEnable(). Note the float literals (25.0, not25) — Verse never auto-converts int to float.TargetFoundEvent/TargetLostEventarelistenable(agent)— the handler gets a plainagent, no unwrap needed.DestroyedEventislistenable(?agent), soOnTurretDestroyedtakes?agentand we unwrap withif (A := Attacker?):.
Common patterns
Force the turret onto a specific player (boss-target lock)
Use SetTarget() to override the AI — e.g. make the turret laser-focus the player who triggered a trap. We also read it back with GetTarget() to confirm the lock took (the engine ignores out-of-range or no-line-of-sight targets).
turret_focus_lock := class(creative_device):
@editable
Turret : automated_turret_device = automated_turret_device{}
# Stepping here makes the turret hunt YOU.
@editable
TrapPlate : trigger_device = trigger_device{}
OnBegin<override>()<suspends> : void =
Turret.Enable()
TrapPlate.TriggeredEvent.Subscribe(OnPlateStepped)
# TriggeredEvent is listenable(?agent) — unwrap the agent.
OnPlateStepped(Agent : ?agent) : void =
if (Victim := Agent?):
Turret.SetTarget(Victim) # try to lock on
if (Locked := Turret.GetTarget?):
# GetTarget returned a value — the lock succeeded.
Turret.SetDamage(40.0)
Pick a team and react to activation
If your turret's Possible Targets isn't set to Everyone, you can assign it a team from Verse. Here we make it defend the Default Team against wildlife by switching teams, and we announce whenever someone first walks into its activation radius via ActivatedEvent.
turret_team_setup := class(creative_device):
@editable
Turret : automated_turret_device = automated_turret_device{}
@editable
Announcer : hud_message_device = hud_message_device{}
Msg<localizes>(S : string) : message = "{S}"
OnBegin<override>()<suspends> : void =
# Only valid when Possible Targets is NOT 'Everyone'.
Turret.UseTeamWildlifeAndCreatures()
Turret.SetActivationRange(15.0)
Turret.Enable()
Turret.ActivatedEvent.Subscribe(OnActivated)
OnActivated(Agent : ?agent) : void =
if (A := Agent?):
Announcer.Show(Msg("Something entered the turret's zone!"))
Repair the turret when it takes damage
Because the turret is healthful/healable, you can read its health on DamagedEvent and Heal() it back up — a self-repairing defense.
turret_self_repair := class(creative_device):
@editable
Turret : automated_turret_device = automated_turret_device{}
OnBegin<override>()<suspends> : void =
Turret.Enable()
Turret.DamagedEvent.Subscribe(OnDamaged)
OnDamaged(Attacker : ?agent) : void =
CurrentHealth := Turret.GetHealth()
MaxHealth := Turret.GetMaxHealth()
# Top it back up to full whenever it's hurt.
if (CurrentHealth < MaxHealth):
Turret.Heal(MaxHealth - CurrentHealth)
Gotchas
messageparams need localized text.Show()takes amessage, not astring. Declare aMsg<localizes>(S:string):message = "{S}"helper and passMsg("..."). There is noStringToMessagefunction.- Optional vs plain agent events.
ActivatedEvent,DamagedEvent, andDestroyedEventarelistenable(?agent)— unwrap withif (A := Agent?):. ButTargetFoundEventandTargetLostEventarelistenable(agent)— the handler receives a plainagentand unwrapping it would fail to compile. GetTarget()returns?agent. Don't use the result directly. Unwrap it:if (T := Turret.GetTarget?):.SetTarget()can silently no-op. The target only changes if the agent is within the activation radius, has line-of-sight, is on a targetable team, and isn't Down. Always read back withGetTarget()if you depend on the lock.- Float literals only.
SetDamage,SetActivationRange, andSetTargetRangeall takefloat. Write25.0, never25— Verse does not auto-convert int to float. - Range clamping.
SetActivationRange/SetTargetRangeclamp to 2.0–100.0 meters. Setting target range below 2m disables targeting entirely. UseDefaultTeam/UseTeamWildlifeAndCreaturesonly work when the device's Possible Targets option isn'tEveryone. Set that in the Details panel first.- Disable a destroyed turret. A destroyed turret can keep behaving oddly; in
DestroyedEventcallClearTarget()andDisable()to make it inert.