mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-07-14 08:35:39 +01:00
Ports the new parts of https://github.com/Baystation12/Baystation12/pull/15298 back to Polaris
* Changes navbeacons to no longer use radios (Doing so was slower and didn't really help anything) Note: var/freq remains for mapping compatibility until all maps are updated. * Fixes navbeacons to actually hide under flooring if you put plating over them. * Changed how navbeacons are mapped in. Don't use the picky "code_txt" variable, instead use appropriate subtype. * Made useful reusable subtypes so you don't have to code in a type for every. single. one. * Updated mulebot to use new navbeacon codes. * Re-activate patrolling! With the new navbeacons, bots with will_patrol can follow the patrol navbeacons. * Note: various "should_patrol" variables on each bot type unified under /mob/living/bot/var/will_patrol * Securitrons (beepsky) got an overhaul to the new patrol routing. * Note: BayStation replaced the snowflake handcuffs code with acutal handcuffs. Polaris handcuffs requiere a grab to work, so are more complicated. Kept our existing attack code. * Behavior procs reorganized to use better movement detection and just be more flexible. * Floorbot fixes & removal of bridgemode * Floorbot will now remove & replace broken floor tiles. * Floorbot will no longer decide its okay to pave over all of SPACE. * For the moment patching hull breaches is disabled, it is too laggy. * Sundry bugfixes to all bots * Use forceMove() instead of setting loc * Use "\The [X]" message strings. * Pass target to do_after() when doing something to a target. * Fixed events that were supposed to emag bots to now do so again.
This commit is contained in:
@@ -27,7 +27,7 @@
|
||||
var/turf/obstacle = null
|
||||
|
||||
var/wait_if_pulled = 0 // Only applies to moving to the target
|
||||
var/will_patrol = 0 // Not a setting - whether or no this type of bots patrols at all
|
||||
var/will_patrol = 0 // If set to 1, will patrol, duh
|
||||
var/patrol_speed = 1 // How many times per tick we move when patrolling
|
||||
var/target_speed = 2 // Ditto for chasing the target
|
||||
var/min_target_dist = 1 // How close we try to get to the target
|
||||
@@ -49,7 +49,11 @@
|
||||
access_scanner.req_access = req_access.Copy()
|
||||
access_scanner.req_one_access = req_one_access.Copy()
|
||||
|
||||
turn_on()
|
||||
// Make sure mapped in units start turned on.
|
||||
/mob/living/bot/initialize()
|
||||
..()
|
||||
if(on)
|
||||
turn_on() // Update lights and other stuff
|
||||
|
||||
/mob/living/bot/Life()
|
||||
..()
|
||||
@@ -61,7 +65,8 @@
|
||||
paralysis = 0
|
||||
|
||||
if(on && !client && !busy)
|
||||
handleAI()
|
||||
spawn(0)
|
||||
handleAI()
|
||||
|
||||
/mob/living/bot/updatehealth()
|
||||
if(status_flags & GODMODE)
|
||||
@@ -145,20 +150,18 @@
|
||||
handleRangedTarget()
|
||||
if(!wait_if_pulled || !pulledby)
|
||||
for(var/i = 1 to target_speed)
|
||||
sleep(20 / (target_speed + 1))
|
||||
stepToTarget()
|
||||
if(i < target_speed)
|
||||
sleep(20 / target_speed)
|
||||
if(max_frustration && frustration > max_frustration * target_speed)
|
||||
handleFrustrated(1)
|
||||
else
|
||||
resetTarget()
|
||||
lookForTargets()
|
||||
if(will_patrol && !pulledby && !target)
|
||||
if(patrol_path.len)
|
||||
if(patrol_path && patrol_path.len)
|
||||
for(var/i = 1 to patrol_speed)
|
||||
sleep(20 / (patrol_speed + 1))
|
||||
handlePatrol()
|
||||
if(i < patrol_speed)
|
||||
sleep(20 / patrol_speed)
|
||||
if(max_frustration && frustration > max_frustration * patrol_speed)
|
||||
handleFrustrated(0)
|
||||
else
|
||||
@@ -219,6 +222,25 @@
|
||||
return
|
||||
|
||||
/mob/living/bot/proc/getPatrolTurf()
|
||||
var/minDist = INFINITY
|
||||
var/obj/machinery/navbeacon/targ = locate() in get_turf(src)
|
||||
|
||||
if(!targ)
|
||||
for(var/obj/machinery/navbeacon/N in navbeacons)
|
||||
if(!N.codes["patrol"])
|
||||
continue
|
||||
if(get_dist(src, N) < minDist)
|
||||
minDist = get_dist(src, N)
|
||||
targ = N
|
||||
|
||||
if(targ && targ.codes["next_patrol"])
|
||||
for(var/obj/machinery/navbeacon/N in navbeacons)
|
||||
if(N.location == targ.codes["next_patrol"])
|
||||
targ = N
|
||||
break
|
||||
|
||||
if(targ)
|
||||
return get_turf(targ)
|
||||
return null
|
||||
|
||||
/mob/living/bot/proc/handleIdle()
|
||||
@@ -255,15 +277,16 @@
|
||||
on = 1
|
||||
set_light(light_strength)
|
||||
update_icons()
|
||||
resetTarget()
|
||||
patrol_path = list()
|
||||
ignore_list = list()
|
||||
return 1
|
||||
|
||||
/mob/living/bot/proc/turn_off()
|
||||
on = 0
|
||||
busy = 0 // If ever stuck... reboot!
|
||||
set_light(0)
|
||||
update_icons()
|
||||
resetTarget()
|
||||
patrol_path = list()
|
||||
ignore_list = list()
|
||||
|
||||
/mob/living/bot/proc/explode()
|
||||
qdel(src)
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
var/cleaning = 0
|
||||
var/screwloose = 0
|
||||
var/oddbutton = 0
|
||||
var/should_patrol = 0
|
||||
var/blood = 1
|
||||
var/list/target_types = list()
|
||||
|
||||
@@ -32,9 +31,11 @@
|
||||
if(oddbutton && prob(5)) // Make a big mess
|
||||
visible_message("Something flies out of [src]. He seems to be acting oddly.")
|
||||
var/obj/effect/decal/cleanable/blood/gibs/gib = new /obj/effect/decal/cleanable/blood/gibs(loc)
|
||||
ignore_list += gib
|
||||
// TODO - I have a feeling weakrefs will not work in ignore_list, verify this ~Leshana
|
||||
var/weakref/g = weakref(gib)
|
||||
ignore_list += g
|
||||
spawn(600)
|
||||
ignore_list -= gib
|
||||
ignore_list -= g
|
||||
|
||||
/mob/living/bot/cleanbot/lookForTargets()
|
||||
for(var/obj/effect/decal/cleanable/D in view(world.view, src)) // There was some odd code to make it start with nearest decals, it's unnecessary, this works
|
||||
@@ -110,7 +111,7 @@
|
||||
dat += "Maintenance panel is [open ? "opened" : "closed"]"
|
||||
if(!locked || issilicon(user))
|
||||
dat += "<BR>Cleans Blood: <A href='?src=\ref[src];operation=blood'>[blood ? "Yes" : "No"]</A><BR>"
|
||||
dat += "<BR>Patrol station: <A href='?src=\ref[src];operation=patrol'>[should_patrol ? "Yes" : "No"]</A><BR>"
|
||||
dat += "<BR>Patrol station: <A href='?src=\ref[src];operation=patrol'>[will_patrol ? "Yes" : "No"]</A><BR>"
|
||||
if(open && !locked)
|
||||
dat += "Odd looking screw twiddled: <A href='?src=\ref[src];operation=screw'>[screwloose ? "Yes" : "No"]</A><BR>"
|
||||
dat += "Weird button pressed: <A href='?src=\ref[src];operation=oddbutton'>[oddbutton ? "Yes" : "No"]</A>"
|
||||
@@ -134,7 +135,7 @@
|
||||
blood = !blood
|
||||
get_targets()
|
||||
if("patrol")
|
||||
should_patrol = !should_patrol
|
||||
will_patrol = !will_patrol
|
||||
patrol_path = null
|
||||
if("screw")
|
||||
screwloose = !screwloose
|
||||
|
||||
@@ -170,7 +170,7 @@
|
||||
visible_message("<span class='notice'>[src] starts [T.dead? "removing the plant from" : "harvesting"] \the [A].</span>")
|
||||
|
||||
busy = 1
|
||||
if(do_after(src, 30))
|
||||
if(do_after(src, 30, A))
|
||||
visible_message("<span class='notice'>[src] [T.dead? "removes the plant from" : "harvests"] \the [A].</span>")
|
||||
T.attack_hand(src)
|
||||
if(FARMBOT_WATER)
|
||||
@@ -179,7 +179,7 @@
|
||||
visible_message("<span class='notice'>[src] starts watering \the [A].</span>")
|
||||
|
||||
busy = 1
|
||||
if(do_after(src, 30))
|
||||
if(do_after(src, 30, A))
|
||||
playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
|
||||
visible_message("<span class='notice'>[src] waters \the [A].</span>")
|
||||
tank.reagents.trans_to(T, 100 - T.waterlevel)
|
||||
@@ -198,7 +198,7 @@
|
||||
visible_message("<span class='notice'>[src] starts fertilizing \the [A].</span>")
|
||||
|
||||
busy = 1
|
||||
if(do_after(src, 30))
|
||||
if(do_after(src, 30, A))
|
||||
|
||||
visible_message("<span class='notice'>[src] fertilizes \the [A].</span>")
|
||||
T.reagents.add_reagent("ammonia", 10)
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
// Configure whether or not floorbot will fix hull breaches.
|
||||
// This can be a problem if it tries to pave over space or shuttles. That should be fixed but...
|
||||
// If it can see space outside windows, it can be laggy since it keeps wondering if it should fix them.
|
||||
// Therefore that functionality is disabled for now. But it can be turned on by uncommenting this.
|
||||
// #define FLOORBOT_PATCHES_HOLES 1
|
||||
|
||||
/mob/living/bot/floorbot
|
||||
name = "Floorbot"
|
||||
desc = "A little floor repairing robot, he looks so excited!"
|
||||
@@ -25,7 +31,7 @@
|
||||
|
||||
/mob/living/bot/floorbot/attack_hand(var/mob/user)
|
||||
user.set_machine(src)
|
||||
var/dat
|
||||
var/list/dat = list()
|
||||
dat += "<TT><B>Automatic Station Floor Repairer v1.0</B></TT><BR><BR>"
|
||||
dat += "Status: <A href='?src=\ref[src];operation=start'>[src.on ? "On" : "Off"]</A><BR>"
|
||||
dat += "Maintenance panel is [open ? "opened" : "closed"]<BR>"
|
||||
@@ -41,9 +47,9 @@
|
||||
else
|
||||
bmode = "Disabled"
|
||||
dat += "<BR><BR>Bridge Mode : <A href='?src=\ref[src];operation=bridgemode'>[bmode]</A><BR>"
|
||||
|
||||
user << browse("<HEAD><TITLE>Repairbot v1.0 controls</TITLE></HEAD>[dat]", "window=autorepair")
|
||||
onclose(user, "autorepair")
|
||||
var/datum/browser/popup = new(user, "autorepair", "Repairbot v1.1 controls")
|
||||
popup.set_content(jointext(dat,null))
|
||||
popup.open()
|
||||
return
|
||||
|
||||
/mob/living/bot/floorbot/emag_act(var/remaining_charges, var/mob/user)
|
||||
@@ -115,23 +121,24 @@
|
||||
target = T
|
||||
return
|
||||
T = get_step(T, targetdirection)
|
||||
return // In bridge mode we don't want to step off that line even to eat plates!
|
||||
|
||||
else // Fixing floors
|
||||
for(var/turf/space/T in view(src)) // Breaches are of higher priority
|
||||
if(confirmTarget(T))
|
||||
target = T
|
||||
return
|
||||
#ifdef FLOORBOT_PATCHES_HOLES
|
||||
for(var/turf/space/T in view(src)) // Breaches are of higher priority
|
||||
if(confirmTarget(T))
|
||||
target = T
|
||||
return
|
||||
|
||||
for(var/turf/simulated/mineral/floor/T in view(src)) // Asteroids are of smaller priority
|
||||
if(confirmTarget(T))
|
||||
target = T
|
||||
return
|
||||
|
||||
if(improvefloors)
|
||||
for(var/turf/simulated/floor/T in view(src))
|
||||
if(confirmTarget(T))
|
||||
target = T
|
||||
return
|
||||
for(var/turf/simulated/mineral/floor/T in view(src)) // Asteroids are of smaller priority
|
||||
if(confirmTarget(T))
|
||||
target = T
|
||||
return
|
||||
#endif
|
||||
// Look for broken floors even if we aren't improvefloors
|
||||
for(var/turf/simulated/floor/T in view(src))
|
||||
if(confirmTarget(T))
|
||||
target = T
|
||||
return
|
||||
|
||||
if(amount < maxAmount && (eattiles || maketiles))
|
||||
for(var/obj/item/stack/S in view(src))
|
||||
@@ -148,7 +155,11 @@
|
||||
if(istype(A, /obj/item/stack/material/steel))
|
||||
return (amount < maxAmount && maketiles)
|
||||
|
||||
if(A.loc.name == "Space")
|
||||
// Don't pave over all of space, build there only if in bridge mode
|
||||
if(!targetdirection && istype(A.loc, /area/space)) // Note name == "Space" does not work!
|
||||
return 0
|
||||
|
||||
if(istype(A.loc, /area/shuttle)) // Do NOT mess with shuttle drop zones
|
||||
return 0
|
||||
|
||||
if(emagged)
|
||||
@@ -157,14 +168,16 @@
|
||||
if(!amount)
|
||||
return 0
|
||||
|
||||
#ifdef FLOORBOT_PATCHES_HOLES
|
||||
if(istype(A, /turf/space))
|
||||
return 1
|
||||
|
||||
if(istype(A, /turf/simulated/mineral/floor))
|
||||
return 1
|
||||
#endif
|
||||
|
||||
var/turf/simulated/floor/T = A
|
||||
return (istype(T) && improvefloors && !T.flooring && (get_turf(T) == loc || prob(40)))
|
||||
return (istype(T) && (T.broken || T.burnt || (improvefloors && !T.flooring)) && (get_turf(T) == loc || prob(40)))
|
||||
|
||||
/mob/living/bot/floorbot/UnarmedAttack(var/atom/A, var/proximity)
|
||||
if(!..())
|
||||
@@ -181,12 +194,12 @@
|
||||
busy = 1
|
||||
update_icons()
|
||||
if(F.flooring)
|
||||
visible_message("<span class='warning'>[src] begins to tear the floor tile from the floor!</span>")
|
||||
visible_message("<span class='warning'>\The [src] begins to tear the floor tile from the floor!</span>")
|
||||
if(do_after(src, 50))
|
||||
F.break_tile_to_plating()
|
||||
addTiles(1)
|
||||
else
|
||||
visible_message("<span class='danger'>[src] begins to tear through the floor!</span>")
|
||||
visible_message("<span class='danger'>\The [src] begins to tear through the floor!</span>")
|
||||
if(do_after(src, 150)) // Extra time because this can and will kill.
|
||||
F.ReplaceWithLattice()
|
||||
addTiles(1)
|
||||
@@ -201,7 +214,7 @@
|
||||
return
|
||||
busy = 1
|
||||
update_icons()
|
||||
visible_message("<span class='notice'>[src] begins to repair the hole.</span>")
|
||||
visible_message("<span class='notice'>\The [src] begins to repair the hole.</span>")
|
||||
if(do_after(src, 50))
|
||||
if(A && (locate(/obj/structure/lattice, A) && building == 1 || !locate(/obj/structure/lattice, A) && building == 2)) // Make sure that it still needs repairs
|
||||
var/obj/item/I
|
||||
@@ -215,10 +228,20 @@
|
||||
update_icons()
|
||||
else if(istype(A, /turf/simulated/floor))
|
||||
var/turf/simulated/floor/F = A
|
||||
if(!F.flooring && amount)
|
||||
if(F.broken || F.burnt)
|
||||
busy = 1
|
||||
update_icons()
|
||||
visible_message("<span class='notice'>[src] begins to improve the floor.</span>")
|
||||
visible_message("<span class='notice'>\The [src] begins to remove the broken floor.</span>")
|
||||
if(do_after(src, 50, F))
|
||||
if(F.broken || F.burnt)
|
||||
F.make_plating()
|
||||
target = null
|
||||
busy = 0
|
||||
update_icons()
|
||||
else if(!F.flooring && amount)
|
||||
busy = 1
|
||||
update_icons()
|
||||
visible_message("<span class='notice'>\The [src] begins to improve the floor.</span>")
|
||||
if(do_after(src, 50))
|
||||
if(!F.flooring)
|
||||
F.set_flooring(get_flooring_data(floor_build_type))
|
||||
@@ -228,7 +251,7 @@
|
||||
update_icons()
|
||||
else if(istype(A, /obj/item/stack/tile/floor) && amount < maxAmount)
|
||||
var/obj/item/stack/tile/floor/T = A
|
||||
visible_message("<span class='notice'>[src] begins to collect tiles.</span>")
|
||||
visible_message("<span class='notice'>\The [src] begins to collect tiles.</span>")
|
||||
busy = 1
|
||||
update_icons()
|
||||
if(do_after(src, 20))
|
||||
@@ -242,7 +265,7 @@
|
||||
else if(istype(A, /obj/item/stack/material) && amount + 4 <= maxAmount)
|
||||
var/obj/item/stack/material/M = A
|
||||
if(M.get_material_name() == DEFAULT_WALL_MATERIAL)
|
||||
visible_message("<span class='notice'>[src] begins to make tiles.</span>")
|
||||
visible_message("<span class='notice'>\The [src] begins to make tiles.</span>")
|
||||
busy = 1
|
||||
update_icons()
|
||||
if(do_after(50))
|
||||
@@ -252,7 +275,7 @@
|
||||
|
||||
/mob/living/bot/floorbot/explode()
|
||||
turn_off()
|
||||
visible_message("<span class='danger'>[src] blows apart!</span>")
|
||||
visible_message("<span class='danger'>\The [src] blows apart!</span>")
|
||||
var/turf/Tsec = get_turf(src)
|
||||
|
||||
var/obj/item/weapon/storage/toolbox/mechanical/N = new /obj/item/weapon/storage/toolbox/mechanical(Tsec)
|
||||
@@ -353,4 +376,4 @@
|
||||
return
|
||||
if(!in_range(src, user) && loc != user)
|
||||
return
|
||||
created_name = t
|
||||
created_name = t
|
||||
|
||||
@@ -130,10 +130,7 @@
|
||||
|
||||
if("sethome")
|
||||
var/new_dest
|
||||
var/list/beaconlist = new()
|
||||
for(var/obj/machinery/navbeacon/N in navbeacons)
|
||||
beaconlist.Add(N.location)
|
||||
beaconlist[N.location] = N
|
||||
var/list/beaconlist = GetBeaconList()
|
||||
if(beaconlist.len)
|
||||
new_dest = input("Select new home tag", "Mulebot [suffix ? "([suffix])" : ""]", null) in null|beaconlist
|
||||
else
|
||||
@@ -168,10 +165,7 @@
|
||||
targetName = "Home"
|
||||
if("SetD")
|
||||
var/new_dest
|
||||
var/list/beaconlist = new()
|
||||
for(var/obj/machinery/navbeacon/N in navbeacons)
|
||||
beaconlist.Add(N.location)
|
||||
beaconlist[N.location] = N
|
||||
var/list/beaconlist = GetBeaconList()
|
||||
if(beaconlist.len)
|
||||
new_dest = input("Select new destination tag", "Mulebot [suffix ? "([suffix])" : ""]") in null|beaconlist
|
||||
else
|
||||
@@ -285,6 +279,15 @@
|
||||
new /obj/effect/decal/cleanable/blood/oil(Tsec)
|
||||
..()
|
||||
|
||||
/mob/living/bot/mulebot/proc/GetBeaconList()
|
||||
var/list/beaconlist = list()
|
||||
for(var/obj/machinery/navbeacon/N in navbeacons)
|
||||
if(!N.codes["delivery"])
|
||||
continue
|
||||
beaconlist.Add(N.location)
|
||||
beaconlist[N.location] = N
|
||||
return beaconlist
|
||||
|
||||
/mob/living/bot/mulebot/proc/load(var/atom/movable/C)
|
||||
if(busy || load || get_dist(C, src) > 1 || !isturf(C.loc))
|
||||
return
|
||||
@@ -304,11 +307,11 @@
|
||||
|
||||
busy = 1
|
||||
|
||||
C.loc = loc
|
||||
C.forceMove(loc)
|
||||
sleep(2)
|
||||
if(C.loc != loc) //To prevent you from going onto more than one bot.
|
||||
return
|
||||
C.loc = src
|
||||
C.forceMove(src)
|
||||
load = C
|
||||
|
||||
C.pixel_y += 9
|
||||
@@ -325,7 +328,7 @@
|
||||
busy = 1
|
||||
overlays.Cut()
|
||||
|
||||
load.loc = loc
|
||||
load.forceMove(loc)
|
||||
load.pixel_y -= 9
|
||||
load.layer = initial(load.layer)
|
||||
|
||||
@@ -338,7 +341,7 @@
|
||||
if(AM == botcard || AM == access_scanner)
|
||||
continue
|
||||
|
||||
AM.loc = loc
|
||||
AM.forceMove(loc)
|
||||
AM.layer = initial(AM.layer)
|
||||
AM.pixel_y = initial(AM.pixel_y)
|
||||
busy = 0
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
#define SECBOT_WAIT_TIME 5 //number of in-game seconds to wait for someone to surrender
|
||||
#define SECBOT_THREAT_ARREST 4 //threat level at which we decide to arrest someone
|
||||
#define SECBOT_THREAT_ATTACK 8 //threat level at which was assume immediate danger and attack right away
|
||||
|
||||
/mob/living/bot/secbot
|
||||
name = "Securitron"
|
||||
desc = "A little security robot. He looks less than thrilled."
|
||||
icon_state = "secbot0"
|
||||
maxHealth = 100
|
||||
health = 100
|
||||
req_one_access = list(access_robotics, access_security, access_forensics_lockers)
|
||||
req_one_access = list(access_security, access_forensics_lockers)
|
||||
botcard_access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels)
|
||||
patrol_speed = 2
|
||||
target_speed = 3
|
||||
@@ -14,18 +18,17 @@
|
||||
var/check_arrest = 1 // If true, arrests people who are set to arrest.
|
||||
var/arrest_type = 0 // If true, doesn't handcuff. You monster.
|
||||
var/declare_arrests = 0 // If true, announces arrests over sechuds.
|
||||
var/auto_patrol = 0 // If true, patrols on its own
|
||||
|
||||
var/is_ranged = 0
|
||||
var/awaiting_surrender = 0
|
||||
|
||||
var/list/threat_found_sounds = new('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg')
|
||||
var/list/preparing_arrest_sounds = new('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg')
|
||||
var/list/threat_found_sounds = list('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg')
|
||||
var/list/preparing_arrest_sounds = list('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/bcreep.ogg')
|
||||
|
||||
/mob/living/bot/secbot/beepsky
|
||||
name = "Officer Beepsky"
|
||||
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
|
||||
auto_patrol = 1
|
||||
will_patrol = 1
|
||||
|
||||
/mob/living/bot/secbot/update_icons()
|
||||
if(on && busy)
|
||||
@@ -40,7 +43,7 @@
|
||||
|
||||
/mob/living/bot/secbot/attack_hand(var/mob/user)
|
||||
user.set_machine(src)
|
||||
var/dat
|
||||
var/list/dat = list()
|
||||
dat += "<TT><B>Automatic Security Unit</B></TT><BR><BR>"
|
||||
dat += "Status: <A href='?src=\ref[src];power=1'>[on ? "On" : "Off"]</A><BR>"
|
||||
dat += "Behaviour controls are [locked ? "locked" : "unlocked"]<BR>"
|
||||
@@ -51,10 +54,10 @@
|
||||
dat += "Check Arrest Status: <A href='?src=\ref[src];operation=ignorearr'>[check_arrest ? "Yes" : "No"]</A><BR>"
|
||||
dat += "Operating Mode: <A href='?src=\ref[src];operation=switchmode'>[arrest_type ? "Detain" : "Arrest"]</A><BR>"
|
||||
dat += "Report Arrests: <A href='?src=\ref[src];operation=declarearrests'>[declare_arrests ? "Yes" : "No"]</A><BR>"
|
||||
dat += "Auto Patrol: <A href='?src=\ref[src];operation=patrol'>[auto_patrol ? "On" : "Off"]</A>"
|
||||
user << browse("<HEAD><TITLE>Securitron controls</TITLE></HEAD>[dat]", "window=autosec")
|
||||
onclose(user, "autosec")
|
||||
return
|
||||
dat += "Auto Patrol: <A href='?src=\ref[src];operation=patrol'>[will_patrol ? "On" : "Off"]</A>"
|
||||
var/datum/browser/popup = new(user, "autosec", "Securitron controls")
|
||||
popup.set_content(jointext(dat,null))
|
||||
popup.open()
|
||||
|
||||
/mob/living/bot/secbot/Topic(href, href_list)
|
||||
if(..())
|
||||
@@ -80,7 +83,7 @@
|
||||
if("switchmode")
|
||||
arrest_type = !arrest_type
|
||||
if("patrol")
|
||||
auto_patrol = !auto_patrol
|
||||
will_patrol = !will_patrol
|
||||
if("declarearrests")
|
||||
declare_arrests = !declare_arrests
|
||||
attack_hand(usr)
|
||||
@@ -99,10 +102,46 @@
|
||||
|
||||
/mob/living/bot/secbot/attackby(var/obj/item/O, var/mob/user)
|
||||
var/curhealth = health
|
||||
..()
|
||||
. = ..()
|
||||
if(health < curhealth)
|
||||
target = user
|
||||
awaiting_surrender = 5
|
||||
react_to_attack(user)
|
||||
|
||||
/mob/living/bot/secbot/bullet_act(var/obj/item/projectile/P)
|
||||
var/curhealth = health
|
||||
var/mob/shooter = P.firer
|
||||
. = ..()
|
||||
//if we already have a target just ignore to avoid lots of checking
|
||||
if(!target && health < curhealth && shooter && (shooter in view(world.view, src)))
|
||||
react_to_attack(shooter)
|
||||
|
||||
/mob/living/bot/secbot/proc/react_to_attack(mob/attacker)
|
||||
if(!target)
|
||||
playsound(src.loc, pick(threat_found_sounds), 50)
|
||||
broadcast_security_hud_message("[src] was attacked by a hostile <b>[target_name(attacker)]</b> in <b>[get_area(src)]</b>.", src)
|
||||
target = attacker
|
||||
awaiting_surrender = INFINITY // Don't try and wait for surrender
|
||||
|
||||
// Say "freeze!" and demand surrender
|
||||
/mob/living/bot/secbot/proc/demand_surrender(mob/target, var/threat)
|
||||
var/suspect_name = target_name(target)
|
||||
if(declare_arrests)
|
||||
broadcast_security_hud_message("[src] is [arrest_type ? "detaining" : "arresting"] a level [threat] suspect <b>[suspect_name]</b> in <b>[get_area(src)]</b>.", src)
|
||||
say("Down on the floor, [suspect_name]! You have [SECBOT_WAIT_TIME] seconds to comply.")
|
||||
playsound(src.loc, pick(preparing_arrest_sounds), 50)
|
||||
// Register to be told when the target moves
|
||||
moved_event.register(target, src, /mob/living/bot/secbot/proc/target_moved)
|
||||
|
||||
// Callback invoked if the registered target moves
|
||||
/mob/living/bot/secbot/proc/target_moved(atom/movable/moving_instance, atom/old_loc, atom/new_loc)
|
||||
if(get_dist(get_turf(src), get_turf(target)) >= 1)
|
||||
awaiting_surrender = INFINITY // Done waiting!
|
||||
moved_event.unregister(moving_instance, src)
|
||||
|
||||
/mob/living/bot/secbot/resetTarget()
|
||||
..()
|
||||
moved_event.unregister(target, src)
|
||||
awaiting_surrender = -1
|
||||
walk_to(src, 0)
|
||||
|
||||
/mob/living/bot/secbot/startPatrol()
|
||||
if(!locked) // Stop running away when we set you up
|
||||
@@ -112,8 +151,7 @@
|
||||
/mob/living/bot/secbot/confirmTarget(var/atom/A)
|
||||
if(!..())
|
||||
return 0
|
||||
|
||||
return (check_threat(A) > 3)
|
||||
return (check_threat(A) >= SECBOT_THREAT_ARREST)
|
||||
|
||||
/mob/living/bot/secbot/lookForTargets()
|
||||
for(var/mob/living/M in view(src))
|
||||
@@ -127,23 +165,17 @@
|
||||
custom_emote(1, "points at [M.name]!")
|
||||
return
|
||||
|
||||
/mob/living/bot/secbot/calcTargetPath()
|
||||
..()
|
||||
if(awaiting_surrender != -1)
|
||||
awaiting_surrender = 5 // This implies that a) we have already approached the target and b) it has moved after the warning
|
||||
|
||||
/mob/living/bot/secbot/handleAdjacentTarget()
|
||||
if(awaiting_surrender < 5 && ishuman(target) && !target:lying)
|
||||
if(awaiting_surrender == -1)
|
||||
say("Down on the floor, [target]! You have five seconds to comply.")
|
||||
var/mob/living/carbon/human/H = target
|
||||
var/threat = check_threat(target)
|
||||
if(awaiting_surrender < SECBOT_WAIT_TIME && istype(H) && !H.lying && threat < SECBOT_THREAT_ATTACK)
|
||||
if(awaiting_surrender == -1) // On first tick of awaiting...
|
||||
demand_surrender(target, threat)
|
||||
++awaiting_surrender
|
||||
else
|
||||
if(declare_arrests)
|
||||
broadcast_security_hud_message("[src] is [arrest_type ? "detaining" : "arresting"] a level [threat] suspect <b>[target_name(target)]</b> in <b>[get_area(src)]</b>.", src)
|
||||
UnarmedAttack(target)
|
||||
if(ishuman(target) && declare_arrests)
|
||||
var/area/location = get_area(src)
|
||||
broadcast_security_hud_message("[src] is [arrest_type ? "detaining" : "arresting"] a level [check_threat(target)] suspect <b>[target]</b> in <b>[location]</b>.", src)
|
||||
|
||||
// say("Engaging patrol mode.")
|
||||
|
||||
/mob/living/bot/secbot/UnarmedAttack(var/mob/M, var/proximity)
|
||||
if(!..())
|
||||
@@ -170,17 +202,15 @@
|
||||
spawn(2)
|
||||
busy = 0
|
||||
update_icons()
|
||||
visible_message("<span class='warning'>[C] was prodded by [src] with a stun baton!</span>")
|
||||
visible_message("<span class='warning'>\The [C] was prodded by \the [src] with a stun baton!</span>")
|
||||
else
|
||||
playsound(loc, 'sound/weapons/handcuffs.ogg', 30, 1, -2)
|
||||
visible_message("<span class='warning'>[src] is trying to put handcuffs on [C]!</span>")
|
||||
visible_message("<span class='warning'>\The [src] is trying to put handcuffs on \the [C]!</span>")
|
||||
busy = 1
|
||||
if(do_mob(src, C, 60))
|
||||
if(!C.handcuffed)
|
||||
C.handcuffed = new /obj/item/weapon/handcuffs(C)
|
||||
C.update_inv_handcuffed()
|
||||
if(preparing_arrest_sounds.len)
|
||||
playsound(loc, pick(preparing_arrest_sounds), 50, 0)
|
||||
busy = 0
|
||||
else if(istype(M, /mob/living/simple_animal))
|
||||
var/mob/living/simple_animal/S = M
|
||||
@@ -193,7 +223,8 @@
|
||||
spawn(2)
|
||||
busy = 0
|
||||
update_icons()
|
||||
visible_message("<span class='warning'>[M] was beaten by [src] with a stun baton!</span>")
|
||||
visible_message("<span class='warning'>\The [M] was beaten by \the [src] with a stun baton!</span>")
|
||||
|
||||
|
||||
/mob/living/bot/secbot/explode()
|
||||
visible_message("<span class='warning'>[src] blows apart!</span>")
|
||||
@@ -215,11 +246,17 @@
|
||||
new /obj/effect/decal/cleanable/blood/oil(Tsec)
|
||||
qdel(src)
|
||||
|
||||
/mob/living/bot/secbot/proc/target_name(mob/living/T)
|
||||
if(ishuman(T))
|
||||
var/mob/living/carbon/human/H = T
|
||||
return H.get_id_name("unidentified person")
|
||||
return "unidentified lifeform"
|
||||
|
||||
/mob/living/bot/secbot/proc/check_threat(var/mob/living/M)
|
||||
if(!M || !istype(M) || M.stat == DEAD || src == M)
|
||||
return 0
|
||||
|
||||
if(emagged)
|
||||
if(emagged && !M.incapacitated()) //check incapacitated so emagged secbots don't keep attacking the same target forever
|
||||
return 10
|
||||
|
||||
return M.assess_perp(access_scanner, 0, idcheck, check_records, check_arrest)
|
||||
@@ -297,4 +334,4 @@
|
||||
return
|
||||
if(!in_range(src, usr) && loc != usr)
|
||||
return
|
||||
created_name = t
|
||||
created_name = t
|
||||
|
||||
Reference in New Issue
Block a user