diff --git a/code/defines/global.dm b/code/defines/global.dm
index 712d0dc9e14..ba58eb24e62 100644
--- a/code/defines/global.dm
+++ b/code/defines/global.dm
@@ -101,6 +101,7 @@ var
viroMax = 1
wardenMax = 1
cmoMax = 1
+ mimeMax = 1
list/bombers = list( )
list/admin_log = list ( )
diff --git a/code/defines/obj/radio.dm b/code/defines/obj/radio.dm
index 07aeb3fd96f..32ef45e0e70 100644
--- a/code/defines/obj/radio.dm
+++ b/code/defines/obj/radio.dm
@@ -1,4 +1,5 @@
/obj/item/device/radio
+ icon = 'radio.dmi'
name = "station bounced radio"
suffix = "\[3\]"
icon_state = "walkietalkie"
@@ -116,7 +117,7 @@
name = "Captain's Headset"
icon_state = "com_headset"
item_state = "headset"
- channels = list("Command" = 1, "Science" = 0, "Medical" = 0, "Security" = 1, "Engineering" = 0)
+ channels = list("Command" = 1, "Science" = 0, "Medical" = 0, "Security" = 1, "Engineering" = 0, "Mining" = 0, "Cargo" = 0)
/obj/item/device/radio/headset/heads/rd // -- Bar
name = "Research Director's Headset"
@@ -134,10 +135,34 @@
name = "Chief Engineer's Headset"
icon_state = "com_headset"
item_state = "headset"
- channels = list("Engineering" = 1, "Command" = 1)
+ channels = list("Engineering" = 1, "Command" = 1, "Mining" = 1)
/obj/item/device/radio/headset/heads/cmo // -- Bar
name = "Chief Medical Officer's Headset"
icon_state = "com_headset"
item_state = "headset"
- channels = list("Medical" = 1, "Command" = 1)
\ No newline at end of file
+ channels = list("Medical" = 1, "Command" = 1)
+
+/obj/item/device/radio/headset/heads/hop // -- rastaf0
+ name = "Head of Personnel's Headset"
+ icon_state = "com_headset"
+ item_state = "headset"
+ channels = list("Command" = 1, "Security" = 1, "Cargo" = 0)
+
+/obj/item/device/radio/headset/headset_mine // -- rastaf0
+ name = "Mining Radio Headset"
+ icon_state = "mine_headset"
+ item_state = "headset"
+ channels = list("Mining" = 1)
+
+/obj/item/device/radio/headset/headset_cargo // -- rastaf0
+ name = "Cargo Radio Headset"
+ icon_state = "cargo_headset"
+ item_state = "headset"
+ channels = list("Cargo" = 1)
+
+/obj/item/device/radio/headset/heads/qm // -- rastaf0 //he is not a real head but he gives orders sometimes
+ name = "Quartermaster's Headset"
+ icon_state = "cargo_headset"
+ item_state = "headset"
+ channels = list("Cargo" = 1, "Mining" = 1) //no command frequency yet
diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm
index becb0ee43a3..51df169d756 100644
--- a/code/defines/obj/weapon.dm
+++ b/code/defines/obj/weapon.dm
@@ -376,6 +376,10 @@
item_state = "wrench"
w_class = 2.0
m_amt = 50
+
+/obj/item/weapon/crowbar/red
+ icon = 'items.dmi'
+ icon_state = "red_crowbar"
/obj/item/weapon/disk
name = "disk"
@@ -991,7 +995,7 @@ Total SMES charging rate should not exceed total power generation rate, or an ov
/obj/item/weapon/syndicate_uplink
name = "station bounced radio"
- icon = 'device.dmi'
+ icon = 'radio.dmi'
icon_state = "radio"
var/temp = null
var/uses = 10.0
@@ -1007,7 +1011,7 @@ Total SMES charging rate should not exceed total power generation rate, or an ov
/obj/item/weapon/SWF_uplink
name = "station bounced radio"
- icon = 'device.dmi'
+ icon = 'radio.dmi'
icon_state = "radio"
var/temp = null
var/uses = 4.0
diff --git a/code/game/asteroid/asteroid.dm b/code/game/asteroid/asteroid.dm
index 62e2d97b8c5..6d288d76643 100644
--- a/code/game/asteroid/asteroid.dm
+++ b/code/game/asteroid/asteroid.dm
@@ -1,5 +1,5 @@
proc/spawn_asteroid(var/atom/start_loc,var/type,var/size,var/richness)//type: 0 or null - random, 1 - nothing, 2 - iron, 3 - silicon
- if(start_loc.x - size < 3 || start_loc.x + size >= world.maxx - 3 || start_loc.y - size < 3 || start_loc.y + size > world.maxy -3)
+ if(start_loc.x - size < 5 || start_loc.x + size >= world.maxx - 5 || start_loc.y - size < 5 || start_loc.y + size > world.maxy -5)
return 0
if(!size)
size = pick(100;2,50;3,35;4,25;6,10;12)
diff --git a/code/game/communications.dm b/code/game/communications.dm
index c2748c90a2d..763e80696e4 100644
--- a/code/game/communications.dm
+++ b/code/game/communications.dm
@@ -74,6 +74,8 @@ Radio:
1359 - Security
1441 - death squad
1443 - Confession Intercom
+1349 - Miners
+1347 - Cargo techs
Devices:
1451 - tracking implant
@@ -104,10 +106,12 @@ var/list/radiochannels = list(
"Security" = 1359,
"Deathsquad" = 1441,
"Syndicate" = 1213,
+ "Mining" = 1349,
+ "Cargo" = 1347,
)
//depenging helpers
-var/list/DEPT_FREQS = list(1351,1355,1357,1359,1213,1441)
-var/const/COMM_FREQ = 1353
+var/list/DEPT_FREQS = list(1351,1355,1357,1359,1213,1441,1349,1347)
+var/const/COMM_FREQ = 1353 //command, colored gold in chat window
var/const/SYND_FREQ = 1213
#define TRANSMISSION_WIRE 0
diff --git a/code/game/jobs/jobprocs.dm b/code/game/jobs/jobprocs.dm
index 6293afd8da7..5eff0949634 100644
--- a/code/game/jobs/jobprocs.dm
+++ b/code/game/jobs/jobprocs.dm
@@ -367,6 +367,7 @@
src.equip_if_possible(new /obj/item/device/t_scanner(src), slot_r_store)
if ("Shaft Miner")
+ src.equip_if_possible(new /obj/item/device/radio/headset/headset_mine (src), slot_ears)
src.equip_if_possible(new /obj/item/clothing/under/color/white(src), slot_w_uniform)
src.equip_if_possible(new /obj/item/clothing/shoes/black(src), slot_shoes)
src.equip_if_possible(new /obj/item/clothing/gloves/black(src), slot_gloves)
@@ -475,7 +476,7 @@
if ("Head of Personnel")
- src.equip_if_possible(new /obj/item/device/radio/headset/headset_com (src), slot_ears) // -- TLE
+ src.equip_if_possible(new /obj/item/device/radio/headset/heads/hop (src), slot_ears) // -- TLE
src.equip_if_possible(new /obj/item/weapon/storage/backpack(src), slot_back)
src.equip_if_possible(new /obj/item/device/pda/heads(src), slot_belt)
src.equip_if_possible(new /obj/item/clothing/under/rank/head_of_personnel(src), slot_w_uniform)
@@ -546,6 +547,7 @@
src.equip_if_possible(new /obj/item/weapon/storage/briefcase(src), slot_l_hand)
if ("Quartermaster")
+ src.equip_if_possible(new /obj/item/device/radio/headset/heads/qm (src), slot_ears)
src.equip_if_possible(new /obj/item/clothing/gloves/black(src), slot_gloves)
src.equip_if_possible(new /obj/item/clothing/shoes/black(src), slot_shoes)
src.equip_if_possible(new /obj/item/clothing/under/rank/cargo(src), slot_w_uniform)
@@ -555,6 +557,7 @@
//src.equip_if_possible(new /obj/item/clothing/suit/exo_suit(src), slot_wear_suit)
if ("Cargo Technician")
+ src.equip_if_possible(new /obj/item/device/radio/headset/headset_cargo(src), slot_ears)
src.equip_if_possible(new /obj/item/clothing/gloves/black(src), slot_gloves)
src.equip_if_possible(new /obj/item/clothing/shoes/black(src), slot_shoes)
src.equip_if_possible(new /obj/item/clothing/under/rank/cargo(src), slot_w_uniform)
diff --git a/code/game/machinery/bots/bots.dm b/code/game/machinery/bots/bots.dm
index c2da21c1670..7d3b24cb6c9 100644
--- a/code/game/machinery/bots/bots.dm
+++ b/code/game/machinery/bots/bots.dm
@@ -4,9 +4,132 @@
icon = 'aibots.dmi'
layer = MOB_LAYER
var/obj/item/weapon/card/id/botcard // the ID card that the bot "holds"
+ var/on = 1
+ var/health = 0 //do not forget to set health for your bot!
+ var/maxhealth = 0
+ var/fire_dam_coeff = 1.0
+ var/brute_dam_coeff = 1.0
+
+
+/obj/machinery/bot/proc/turn_on()
+ if (stat)
+ return 0
+ src.on = 1
+ return 1
+
+/obj/machinery/bot/proc/turn_off()
+ src.on = 0
+
+/obj/machinery/bot/proc/explode()
+ del(src)
+
+/obj/machinery/bot/proc/healthcheck()
+ if (src.health <= 0)
+ src.explode()
+
+/obj/machinery/bot/examine()
+ set src in view()
+ ..()
+ if (src.health < maxhealth)
+ if (src.health > maxhealth/3)
+ usr << text("\red [src]'s parts look loose.")
+ else
+ usr << text("\red [src]'s parts look very loose!")
+ return
+
+/obj/machinery/bot/attack_alien(var/mob/living/carbon/alien/user as mob)
+ /* Well, aliums dislike machines and do not want to caress them.
+ if (user.a_intent == "help")
+ for(var/mob/O in viewers(src, null))
+ if ((O.client && !( O.blinded )))
+ O.show_message(text("\blue [user] caresses [src.name] with its scythe like arm."), 1)
+ else
+ */
+ src.health -= rand(15,30)*brute_dam_coeff
+ src.visible_message("\red [user] has slashed [src]!")
+ playsound(src.loc, 'slice.ogg', 25, 1, -1)
+ if(prob(10))
+ new /obj/decal/cleanable/oil(src.loc)
+ healthcheck()
+/obj/machinery/bot/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if (istype(W, /obj/item/weapon/screwdriver))
+ if (src.health < maxhealth)
+ src.health = min(maxhealth, src.health+25)
+ user.visible_message(
+ "\red [user] repairs [src]!",
+ "\blue You repair [src]!"
+ )
+ else
+ user << "\blue [src] does not need a repair!"
+ else
+ switch(W.damtype)
+ if("fire")
+ src.health -= W.force * fire_dam_coeff
+ if("brute")
+ src.health -= W.force * brute_dam_coeff
+ ..()
+ healthcheck()
+
+/obj/machinery/bot/bullet_act(flag, A as obj)
+ switch(flag)
+ if (PROJECTILE_BULLET)
+ src.health -= 20
+ //if (PROJECTILE_WEAKBULLET || PROJECTILE_BEANBAG) //Detective's revolver fires marshmallows
+ // src.health -= 2
+ if (PROJECTILE_LASER)
+ src.health -= 10
+ if (PROJECTILE_PULSE)
+ src.health -= 40
+ healthcheck()
+
+/obj/machinery/bot/meteorhit()
+ src.explode()
+ return
+
+/obj/machinery/bot/blob_act()
+ src.health -= rand(20,40)*fire_dam_coeff
+ healthcheck()
+ return
+
+/obj/machinery/bot/ex_act(severity)
+ switch(severity)
+ if(1.0)
+ src.explode()
+ return
+ if(2.0)
+ src.health -= rand(5,10)*fire_dam_coeff
+ src.health -= rand(10,20)*brute_dam_coeff
+ healthcheck()
+ return
+ if(3.0)
+ if (prob(50))
+ src.health -= rand(1,5)*fire_dam_coeff
+ src.health -= rand(1,5)*brute_dam_coeff
+ healthcheck()
+ return
+ return
+
+/obj/machinery/bot/emp_act(severity)
+ var/was_on = on
+ stat |= EMPED
+ var/obj/overlay/pulse2 = new/obj/overlay ( src.loc )
+ pulse2.icon = 'effects.dmi'
+ pulse2.icon_state = "empdisable"
+ pulse2.name = "emp sparks"
+ pulse2.anchored = 1
+ pulse2.dir = pick(cardinal)
+
+ spawn(10)
+ del(pulse2)
+ if (on)
+ turn_off()
+ spawn(severity*300)
+ stat &= ~EMPED
+ if (was_on)
+ turn_on()
/******************************************************************/
// Navigation procs
// Used for A-star pathfinding
diff --git a/code/game/machinery/bots/cleanbot.dm b/code/game/machinery/bots/cleanbot.dm
index 2ddb9e985a5..8afc5a5b6de 100644
--- a/code/game/machinery/bots/cleanbot.dm
+++ b/code/game/machinery/bots/cleanbot.dm
@@ -23,7 +23,8 @@
density = 0
anchored = 0
//weight = 1.0E7
- var/on = 1
+ health = 25
+ maxhealth = 25
var/cleaning = 0
var/locked = 1
var/screwloose = 0
@@ -36,15 +37,35 @@
var/oldloc = null
req_access = list(access_janitor)
var/path[] = new()
-
-
+
/obj/machinery/bot/cleanbot/New()
..()
src.get_targets()
src.icon_state = "cleanbot[src.on]"
-/obj/machinery/bot/cleanbot/attack_hand(user as mob)
+/obj/machinery/bot/cleanbot/turn_on()
+ . = ..()
+ src.icon_state = "cleanbot[src.on]"
+ src.updateUsrDialog()
+
+/obj/machinery/bot/cleanbot/turn_off()
+ ..()
+ src.target = null
+ src.oldtarget = null
+ src.oldloc = null
+ src.icon_state = "cleanbot[src.on]"
+ src.path = new()
+ src.updateUsrDialog()
+
+/obj/machinery/bot/cleanbot/attack_hand(mob/user as mob)
+ . = ..()
+ if (.)
+ return
+ usr.machine = src
+ interact(user)
+
+/obj/machinery/bot/cleanbot/proc/interact(mob/user as mob)
var/dat
dat += text({"
Automatic Station Cleaner v1.0
@@ -73,13 +94,10 @@ text("[src.oddbutton ? "Yes" : "No"
src.add_fingerprint(usr)
switch(href_list["operation"])
if("start")
- src.on = !src.on
- src.target = null
- src.oldtarget = null
- src.oldloc = null
- src.icon_state = "cleanbot[src.on]"
- src.path = new()
- src.updateUsrDialog()
+ if (src.on)
+ turn_off()
+ else
+ turn_on()
if("blood")
src.blood =!src.blood
src.get_targets()
@@ -94,12 +112,10 @@ text("[src.oddbutton ? "Yes" : "No"
src.updateUsrDialog()
/obj/machinery/bot/cleanbot/attack_ai()
- src.on = !src.on
- src.target = null
- src.oldtarget = null
- src.oldloc = null
- src.icon_state = "cleanbot[src.on]"
- src.path = new()
+ if (src.on)
+ turn_off()
+ else
+ turn_on()
/obj/machinery/bot/cleanbot/attackby(obj/item/weapon/W, mob/user as mob)
if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
@@ -108,7 +124,7 @@ text("[src.oddbutton ? "Yes" : "No"
user << "You [ src.locked ? "lock" : "unlock"] the [src] behaviour controls."
else
user << "\red This [src] doesn't seem to accept your authority."
- if (istype(W, /obj/item/weapon/screwdriver))
+ else if (istype(W, /obj/item/weapon/screwdriver))
if(!src.locked)
src.panelopen = !src.panelopen
user << "You [ src.panelopen ? "open" : "close"] the hidden panel on [src]."
@@ -118,6 +134,8 @@ text("[src.oddbutton ? "Yes" : "No"
src.screwloose = 1
src.panelopen = 0
src.locked = 1*/
+ else
+ return ..()
/obj/machinery/bot/cleanbot/process()
set background = 1
@@ -211,6 +229,24 @@ text("[src.oddbutton ? "Yes" : "No"
src.anchored = 0
src.target = null
+/obj/machinery/bot/cleanbot/explode()
+ src.on = 0
+ src.visible_message("\red [src] blows apart!", 1)
+ var/turf/Tsec = get_turf(src)
+
+ new /obj/item/weapon/reagent_containers/glass/bucket(Tsec)
+
+ new /obj/item/device/prox_sensor(Tsec)
+
+ if (prob(50))
+ new /obj/item/robot_parts/l_arm(Tsec)
+
+ var/datum/effects/system/spark_spread/s = new /datum/effects/system/spark_spread
+ s.set_up(3, 1, src)
+ s.start()
+ del(src)
+ return
+
/obj/item/weapon/bucket_sensor/attackby(var/obj/item/W, mob/user as mob)
if(istype(W, /obj/item/robot_parts/l_arm) || istype(W, /obj/item/robot_parts/r_arm))
var/obj/machinery/bot/cleanbot/A = new /obj/machinery/bot/cleanbot
diff --git a/code/game/machinery/bots/ed209bot.dm b/code/game/machinery/bots/ed209bot.dm
index 62cda87a4df..ed8b745127d 100644
--- a/code/game/machinery/bots/ed209bot.dm
+++ b/code/game/machinery/bots/ed209bot.dm
@@ -8,13 +8,16 @@
anchored = 0
// weight = 1.0E7
req_access = list(access_security)
+ health = 100
+ maxhealth = 100
+ fire_dam_coeff = 0.7
+ brute_dam_coeff = 0.5
var/lastfired = 0
var/shot_delay = 3 //.3 seconds between shots
- var/lasers = 0
+ //var/lasers = 0
- var/on = 1
var/locked = 1 //Behavior Controls lock
var/mob/living/carbon/target
var/oldtarget_name
@@ -23,7 +26,6 @@
var/last_found //There's a delay
var/frustration = 0
var/emagged = 0 //Emagged Secbots view everyone as a criminal
- var/health = 100
var/idcheck = 1 //If false, all station IDs are authorized for weapons.
var/check_records = 1 //Does it check security records?
var/arrest_type = 0 //If true, don't handcuff
@@ -68,44 +70,50 @@
var/created_name = "ED-209 Security Robot" //To preserve the name if it's a unique securitron I guess
+/obj/machinery/bot/ed209/New()
+ ..()
+ src.icon_state = "ed209[src.on]"
+ spawn(3)
+ src.botcard = new /obj/item/weapon/card/id(src)
+ src.botcard.access = get_access("Detective")
+ src.cam = new /obj/machinery/camera(src)
+ src.cam.c_tag = src.name
+ src.cam.network = "SS13"
+ if(radio_controller)
+ radio_controller.add_object(src, control_freq, filter = RADIO_SECBOT)
+ radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
-/obj/machinery/bot/ed209
- New()
- ..()
- src.icon_state = "ed209[src.on]"
- spawn(3)
- src.botcard = new /obj/item/weapon/card/id(src)
- src.botcard.access = get_access("Detective")
- src.cam = new /obj/machinery/camera(src)
- src.cam.c_tag = src.name
- src.cam.network = "SS13"
- if(radio_controller)
- radio_controller.add_object(src, control_freq, filter = RADIO_SECBOT)
- radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
+/obj/machinery/bot/ed209/turn_on()
+ . = ..()
+ src.icon_state = "ed209[src.on]"
+ src.mode = SECBOT_IDLE
+ src.updateUsrDialog()
- examine()
- set src in view()
- ..()
+/obj/machinery/bot/ed209/turn_off()
+ ..()
+ src.target = null
+ src.oldtarget_name = null
+ src.anchored = 0
+ src.mode = SECBOT_IDLE
+ walk_to(src,0)
+ src.icon_state = "ed209[src.on]"
+ src.updateUsrDialog()
- if (src.health < 25)
- if (src.health > 15)
- usr << text("\red [src]'s parts look loose.")
- else
- usr << text("\red [src]'s parts look very loose!")
+/obj/machinery/bot/ed209/attack_hand(mob/user as mob)
+ . = ..()
+ if (.)
return
+ var/dat
- attack_hand(user as mob)
- var/dat
-
- dat += text({"
+ dat += text({"
Automatic Security Unit v2.5
Status: []
Behaviour controls are [src.locked ? "locked" : "unlocked"]"},
"[src.on ? "On" : "Off"]" )
- if(!src.locked)
- dat += text({"
+ if(!src.locked)
+ dat += text({"
Check for Weapon Authorization: []
Check Security Records: []
Operating Mode: []
@@ -117,650 +125,669 @@ Auto Patrol: []"},
"[auto_patrol ? "On" : "Off"]" )
- user << browse("
Securitron v2.5 controls[dat]", "window=autosec")
- onclose(user, "autosec")
+ user << browse("Securitron v2.5 controls[dat]", "window=autosec")
+ onclose(user, "autosec")
+ return
+
+/obj/machinery/bot/ed209/Topic(href, href_list)
+ if (..())
+ return
+ usr.machine = src
+ src.add_fingerprint(usr)
+ if ((href_list["power"]) && (src.allowed(usr)))
+ if (src.on)
+ turn_off()
+ else
+ turn_on()
return
- Topic(href, href_list)
- usr.machine = src
- src.add_fingerprint(usr)
- if ((href_list["power"]) && (src.allowed(usr)))
- src.on = !src.on
- src.target = null
- src.oldtarget_name = null
- src.anchored = 0
- src.mode = SECBOT_IDLE
- walk_to(src,0)
- src.icon_state = "ed209[src.on]"
+ switch(href_list["operation"])
+ if ("idcheck")
+ src.idcheck = !src.idcheck
src.updateUsrDialog()
-
- switch(href_list["operation"])
- if ("idcheck")
- src.idcheck = !src.idcheck
- src.updateUsrDialog()
- if ("ignorerec")
- src.check_records = !src.check_records
- src.updateUsrDialog()
- if ("switchmode")
- src.arrest_type = !src.arrest_type
- src.updateUsrDialog()
- if("patrol")
- auto_patrol = !auto_patrol
- mode = SECBOT_IDLE
- updateUsrDialog()
-
- attack_ai(mob/user as mob)
- src.on = !src.on
- src.target = null
- src.oldtarget_name = null
- mode = SECBOT_IDLE
- src.anchored = 0
- src.icon_state = "ed209[src.on]"
- walk_to(src,0)
-
- attackby(obj/item/weapon/W as obj, mob/user as mob)
- if ((istype(W, /obj/item/weapon/card/emag)) && (!src.emagged))
- user << "\red You short out [src]'s target assessment circuits."
- spawn(0)
- for(var/mob/O in hearers(src, null))
- O.show_message("\red [src] buzzes oddly!", 1)
- src.target = null
- src.oldtarget_name = user.name
- src.last_found = world.time
- src.anchored = 0
- src.emagged = 1
- src.on = 1
- src.icon_state = "ed209[src.on]"
+ if ("ignorerec")
+ src.check_records = !src.check_records
+ src.updateUsrDialog()
+ if ("switchmode")
+ src.arrest_type = !src.arrest_type
+ src.updateUsrDialog()
+ if("patrol")
+ auto_patrol = !auto_patrol
mode = SECBOT_IDLE
- else if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
- if (src.allowed(user))
- src.locked = !src.locked
- user << "Controls are now [src.locked ? "locked." : "unlocked."]"
- else
- user << "\red Access denied."
+ updateUsrDialog()
- else if (istype(W, /obj/item/weapon/screwdriver))
- if (src.health < 25)
- src.health = 25
- for(var/mob/O in viewers(src, null))
- O << "\red [user] repairs [src]!"
+/obj/machinery/bot/ed209/attack_ai(mob/user as mob)
+ if (src.on)
+ turn_off()
+ else
+ turn_on()
+
+/obj/machinery/bot/ed209/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if ((istype(W, /obj/item/weapon/card/emag)) && (!src.emagged))
+ user << "\red You short out [src]'s target assessment circuits."
+ spawn(0)
+ for(var/mob/O in hearers(src, null))
+ O.show_message("\red [src] buzzes oddly!", 1)
+ src.target = null
+ src.oldtarget_name = user.name
+ src.last_found = world.time
+ src.anchored = 0
+ src.emagged = 1
+ src.on = 1
+ src.icon_state = "ed209[src.on]"
+ mode = SECBOT_IDLE
+ else if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
+ if (src.allowed(user))
+ src.locked = !src.locked
+ user << "Controls are now [src.locked ? "locked." : "unlocked."]"
else
- switch(W.damtype)
- if("fire")
- src.health -= W.force * 0.75
- if("brute")
- src.health -= W.force * 0.5
- else
- if (src.health <= 0)
- src.explode()
- else if ((W.force) && (!src.target))
- src.target = user
- src.mode = SECBOT_HUNT
- ..()
+ user << "\red Access denied."
+ else
+ ..()
+ if (!istype(W, /obj/item/weapon/screwdriver) && (W.force) && (!src.target))
+ src.target = user
+ src.mode = SECBOT_HUNT
+/obj/machinery/bot/ed209/process()
+ set background = 1
+ if (!src.on)
+ return
+ var/list/targets = list()
+ for (var/mob/living/carbon/C in view(12,src)) //Let's find us a target
+ var/threatlevel = 0
+ if ((C.stat) || (C.lying))
+ continue
+ if (istype(C, /mob/living/carbon/human))
+ threatlevel = src.assess_perp(C)
+ else if ((istype(C, /mob/living/carbon/monkey)) && (C.client) && (ticker.mode.name == "monkey"))
+ threatlevel = 4
+ //src.speak(C.real_name + text(": threat: []", threatlevel))
+ if (threatlevel < 4 )
+ continue
- process()
- set background = 1
+ var/dst = get_dist(src, C)
+ if ( dst <= 1 || dst > 12)
+ continue
- if (!src.on)
- return
- var/list/targets = list()
- for (var/mob/living/carbon/C in view(12,src)) //Let's find us a target
- var/threatlevel = 0
- if ((C.stat) || (C.lying))
- continue
- if (istype(C, /mob/living/carbon/human))
- threatlevel = src.assess_perp(C)
- else if ((istype(C, /mob/living/carbon/monkey)) && (C.client) && (ticker.mode.name == "monkey"))
- threatlevel = 4
- //src.speak(C.real_name + text(": threat: []", threatlevel))
- if (threatlevel < 4 )
- continue
+ targets += C
+ if (targets.len>0)
+ var/mob/t = pick(targets)
+ if (istype(t, /mob/living))
+ if (t.stat!=2)
+ //src.speak("selected target: " + t.real_name)
+ src.shootAt(t)
+ switch(mode)
- var/dst = get_dist(src, C)
- if ( dst <= 1 || dst > 12)
- continue
+ if(SECBOT_IDLE) // idle
+ walk_to(src,0)
+ look_for_perp() // see if any criminals are in range
+ if(!mode && auto_patrol) // still idle, and set to patrol
+ mode = SECBOT_START_PATROL // switch to patrol mode
- targets += C
- if (targets.len>0)
- var/mob/t = pick(targets)
- if (istype(t, /mob/living))
- if (t.stat!=2)
- //src.speak("selected target: " + t.real_name)
- src.shootAt(t)
- switch(mode)
+ if(SECBOT_HUNT) // hunting for perp
- if(SECBOT_IDLE) // idle
+ // if can't reach perp for long enough, go idle
+ if (src.frustration >= 8)
+ // for(var/mob/O in hearers(src, null))
+ // O << "[src] beeps, \"Backup requested! Suspect has evaded arrest.\""
+ src.target = null
+ src.last_found = world.time
+ src.frustration = 0
+ src.mode = 0
walk_to(src,0)
- look_for_perp() // see if any criminals are in range
- if(!mode && auto_patrol) // still idle, and set to patrol
- mode = SECBOT_START_PATROL // switch to patrol mode
- if(SECBOT_HUNT) // hunting for perp
-
- // if can't reach perp for long enough, go idle
- if (src.frustration >= 8)
- // for(var/mob/O in hearers(src, null))
- // O << "[src] beeps, \"Backup requested! Suspect has evaded arrest.\""
- src.target = null
- src.last_found = world.time
- src.frustration = 0
- src.mode = 0
- walk_to(src,0)
-
- if (target) // make sure target exists
- if (get_dist(src, src.target) <= 1) // if right next to perp
- playsound(src.loc, 'Egloves.ogg', 50, 1, -1)
- src.icon_state = "ed209-c"
- spawn(2)
- src.icon_state = "ed209[src.on]"
- var/mob/living/carbon/M = src.target
- var/maxstuns = 4
- if (istype(M, /mob/living/carbon/human))
- if (M.weakened < 10 && (!(M.mutations & 8)) /*&& (!istype(M:wear_suit, /obj/item/clothing/suit/judgerobe))*/)
- M.weakened = 10
- if (M.stuttering < 10 && (!(M.mutations & 8)) /*&& (!istype(M:wear_suit, /obj/item/clothing/suit/judgerobe))*/)
- M.stuttering = 10
- if (M.stunned < 10 && (!(M.mutations & 8)) /*&& (!istype(M:wear_suit, /obj/item/clothing/suit/judgerobe))*/)
- M.stunned = 10
- else
+ if (target) // make sure target exists
+ if (get_dist(src, src.target) <= 1) // if right next to perp
+ playsound(src.loc, 'Egloves.ogg', 50, 1, -1)
+ src.icon_state = "ed209-c"
+ spawn(2)
+ src.icon_state = "ed209[src.on]"
+ var/mob/living/carbon/M = src.target
+ var/maxstuns = 4
+ if (istype(M, /mob/living/carbon/human))
+ if (M.weakened < 10 && (!(M.mutations & 8)) /*&& (!istype(M:wear_suit, /obj/item/clothing/suit/judgerobe))*/)
M.weakened = 10
+ if (M.stuttering < 10 && (!(M.mutations & 8)) /*&& (!istype(M:wear_suit, /obj/item/clothing/suit/judgerobe))*/)
M.stuttering = 10
+ if (M.stunned < 10 && (!(M.mutations & 8)) /*&& (!istype(M:wear_suit, /obj/item/clothing/suit/judgerobe))*/)
M.stunned = 10
- maxstuns--
- if (maxstuns <= 0)
- target = null
- for(var/mob/O in viewers(src, null))
- O.show_message("\red [src.target] has been stunned by [src]!", 1, "\red You hear someone fall", 2)
-
- mode = SECBOT_PREP_ARREST
- src.anchored = 1
- src.target_lastloc = M.loc
- return
-
- else // not next to perp
- var/turf/olddist = get_dist(src, src.target)
- walk_to(src, src.target,1,4)
- if ((get_dist(src, src.target)) >= (olddist))
- src.frustration++
- else
- src.frustration = 0
-
- if(SECBOT_PREP_ARREST) // preparing to arrest target
-
- // see if he got away
- if ((get_dist(src, src.target) > 1) || ((src.target:loc != src.target_lastloc) && src.target:weakened < 2))
- src.anchored = 0
- mode = SECBOT_HUNT
- return
-
- if (!src.target.handcuffed && !src.arrest_type)
- playsound(src.loc, 'handcuffs.ogg', 30, 1, -2)
- mode = SECBOT_ARREST
+ else
+ M.weakened = 10
+ M.stuttering = 10
+ M.stunned = 10
+ maxstuns--
+ if (maxstuns <= 0)
+ target = null
for(var/mob/O in viewers(src, null))
- O.show_message("\red [src] is trying to put handcuffs on [src.target]!", 1)
+ O.show_message("\red [src.target] has been stunned by [src]!", 1, "\red You hear someone fall", 2)
- spawn(60)
- if (get_dist(src, src.target) <= 1)
- if (src.target.handcuffed)
- return
-
- if(istype(src.target,/mob/living/carbon))
- src.target.handcuffed = new /obj/item/weapon/handcuffs(src.target)
-
- mode = SECBOT_IDLE
- src.target = null
- src.anchored = 0
- src.last_found = world.time
- src.frustration = 0
-
- // playsound(src.loc, pick('bgod.ogg', 'biamthelaw.ogg', 'bsecureday.ogg', 'bradio.ogg', 'binsult.ogg', 'bcreep.ogg'), 50, 0)
- // var/arrest_message = pick("Have a secure day!","I AM THE LAW.", "God made tomorrow for the crooks we don't catch today.","You can't outrun a radio.")
- // src.speak(arrest_message)
-
- if(SECBOT_ARREST) // arresting
- if (src.target.handcuffed)
- src.anchored = 0
- mode = SECBOT_IDLE
+ mode = SECBOT_PREP_ARREST
+ src.anchored = 1
+ src.target_lastloc = M.loc
return
+ else // not next to perp
+ var/turf/olddist = get_dist(src, src.target)
+ walk_to(src, src.target,1,4)
+ if ((get_dist(src, src.target)) >= (olddist))
+ src.frustration++
+ else
+ src.frustration = 0
- if(SECBOT_START_PATROL) // start a patrol
+ if(SECBOT_PREP_ARREST) // preparing to arrest target
+ if (!target)
+ mode = SECBOT_IDLE
+ src.anchored = 0
+ return
+ // see if he got away
+ if ((get_dist(src, src.target) > 1) || ((src.target:loc != src.target_lastloc) && src.target:weakened < 2))
+ src.anchored = 0
+ mode = SECBOT_HUNT
+ return
- if(path.len > 0 && patrol_target) // have a valid path, so just resume
- mode = SECBOT_PATROL
- return
+ if (!src.target.handcuffed && !src.arrest_type)
+ playsound(src.loc, 'handcuffs.ogg', 30, 1, -2)
+ mode = SECBOT_ARREST
+ for(var/mob/O in viewers(src, null))
+ O.show_message("\red [src] is trying to put handcuffs on [src.target]!", 1)
- else if(patrol_target) // has patrol target already
- spawn(0)
- calc_path() // so just find a route to it
- if(path.len == 0)
- patrol_target = 0
+ spawn(60)
+ if (get_dist(src, src.target) <= 1)
+ if (src.target.handcuffed)
return
- mode = SECBOT_PATROL
+ if(istype(src.target,/mob/living/carbon))
+ src.target.handcuffed = new /obj/item/weapon/handcuffs(src.target)
- else // no patrol target, so need a new one
- find_patrol_target()
- speak("Engaging patrol mode.")
+ mode = SECBOT_IDLE
+ src.target = null
+ src.anchored = 0
+ src.last_found = world.time
+ src.frustration = 0
+ // playsound(src.loc, pick('bgod.ogg', 'biamthelaw.ogg', 'bsecureday.ogg', 'bradio.ogg', 'binsult.ogg', 'bcreep.ogg'), 50, 0)
+ // var/arrest_message = pick("Have a secure day!","I AM THE LAW.", "God made tomorrow for the crooks we don't catch today.","You can't outrun a radio.")
+ // src.speak(arrest_message)
- if(SECBOT_PATROL) // patrol mode
- patrol_step()
- spawn(5)
- if(mode == SECBOT_PATROL)
- patrol_step()
-
- if(SECBOT_SUMMON) // summoned to PDA
- patrol_step()
- spawn(4)
- if(mode == SECBOT_SUMMON)
- patrol_step()
- sleep(4)
- patrol_step()
-
- return
-
-
- // perform a single patrol step
-
- proc/patrol_step()
-
- if(loc == patrol_target) // reached target
- at_patrol_target()
- return
-
- else if(path.len > 0 && patrol_target) // valid path
-
- var/turf/next = path[1]
- if(next == loc)
- path -= next
+ if(SECBOT_ARREST) // arresting
+ if (!target || src.target.handcuffed)
+ src.anchored = 0
+ mode = SECBOT_IDLE
return
- if(istype( next, /turf/simulated))
+ if(SECBOT_START_PATROL) // start a patrol
- var/moved = step_towards(src, next) // attempt to move
- if(moved) // successful move
- blockcount = 0
- path -= loc
-
- look_for_perp()
- else // failed to move
-
- blockcount++
-
- if(blockcount > 5) // attempt 5 times before recomputing
- // find new path excluding blocked turf
-
- spawn(2)
- calc_path(next)
- if(path.len == 0)
- find_patrol_target()
- else
- blockcount = 0
+ if(path.len > 0 && patrol_target) // have a valid path, so just resume
+ mode = SECBOT_PATROL
+ return
+ else if(patrol_target) // has patrol target already
+ spawn(0)
+ calc_path() // so just find a route to it
+ if(path.len == 0)
+ patrol_target = 0
return
+ mode = SECBOT_PATROL
+
+
+ else // no patrol target, so need a new one
+ find_patrol_target()
+ speak("Engaging patrol mode.")
+
+
+ if(SECBOT_PATROL) // patrol mode
+ patrol_step()
+ spawn(5)
+ if(mode == SECBOT_PATROL)
+ patrol_step()
+
+ if(SECBOT_SUMMON) // summoned to PDA
+ patrol_step()
+ spawn(4)
+ if(mode == SECBOT_SUMMON)
+ patrol_step()
+ sleep(4)
+ patrol_step()
+
+ return
+
+
+// perform a single patrol step
+
+/obj/machinery/bot/ed209/proc/patrol_step()
+
+ if(loc == patrol_target) // reached target
+ at_patrol_target()
+ return
+
+ else if(path.len > 0 && patrol_target) // valid path
+
+ var/turf/next = path[1]
+ if(next == loc)
+ path -= next
+ return
+
+
+ if(istype( next, /turf/simulated))
+
+ var/moved = step_towards(src, next) // attempt to move
+ if(moved) // successful move
+ blockcount = 0
+ path -= loc
+
+ look_for_perp()
+ else // failed to move
+
+ blockcount++
+
+ if(blockcount > 5) // attempt 5 times before recomputing
+ // find new path excluding blocked turf
+
+ spawn(2)
+ calc_path(next)
+ if(path.len == 0)
+ find_patrol_target()
+ else
+ blockcount = 0
return
- else // not a valid turf
- mode = SECBOT_IDLE
return
- else // no path, so calculate new one
- mode = SECBOT_START_PATROL
-
-
- // finds a new patrol target
- proc/find_patrol_target()
- send_status()
- if(awaiting_beacon) // awaiting beacon response
- awaiting_beacon++
- if(awaiting_beacon > 5) // wait 5 secs for beacon response
- find_nearest_beacon() // then go to nearest instead
+ else // not a valid turf
+ mode = SECBOT_IDLE
return
- if(next_destination)
- set_destination(next_destination)
+ else // no path, so calculate new one
+ mode = SECBOT_START_PATROL
+
+
+// finds a new patrol target
+/obj/machinery/bot/ed209/proc/find_patrol_target()
+ send_status()
+ if(awaiting_beacon) // awaiting beacon response
+ awaiting_beacon++
+ if(awaiting_beacon > 5) // wait 5 secs for beacon response
+ find_nearest_beacon() // then go to nearest instead
+ return
+
+ if(next_destination)
+ set_destination(next_destination)
+ else
+ find_nearest_beacon()
+ return
+
+
+// finds the nearest beacon to self
+// signals all beacons matching the patrol code
+/obj/machinery/bot/ed209/proc/find_nearest_beacon()
+ nearest_beacon = null
+ new_destination = "__nearest__"
+ post_signal(beacon_freq, "findbeacon", "patrol")
+ awaiting_beacon = 1
+ spawn(10)
+ awaiting_beacon = 0
+ if(nearest_beacon)
+ set_destination(nearest_beacon)
else
- find_nearest_beacon()
- return
-
-
- // finds the nearest beacon to self
- // signals all beacons matching the patrol code
- proc/find_nearest_beacon()
- nearest_beacon = null
- new_destination = "__nearest__"
- post_signal(beacon_freq, "findbeacon", "patrol")
- awaiting_beacon = 1
- spawn(10)
- awaiting_beacon = 0
- if(nearest_beacon)
- set_destination(nearest_beacon)
- else
- auto_patrol = 0
- mode = SECBOT_IDLE
- speak("Disengaging patrol mode.")
- send_status()
-
-
- proc/at_patrol_target()
- find_patrol_target()
- return
-
-
- // sets the current destination
- // signals all beacons matching the patrol code
- // beacons will return a signal giving their locations
- proc/set_destination(var/new_dest)
- new_destination = new_dest
- post_signal(beacon_freq, "findbeacon", "patrol")
- awaiting_beacon = 1
-
-
- // receive a radio signal
- // used for beacon reception
-
- receive_signal(datum/signal/signal)
-
- if(!on)
- return
-
- /*
- world << "rec signal: [signal.source]"
- for(var/x in signal.data)
- world << "* [x] = [signal.data[x]]"
- */
-
- var/recv = signal.data["command"]
- // process all-bot input
- if(recv=="bot_status")
+ auto_patrol = 0
+ mode = SECBOT_IDLE
+ speak("Disengaging patrol mode.")
send_status()
- // check to see if we are the commanded bot
- if(signal.data["active"] == src)
- // process control input
- switch(recv)
- if("stop")
- mode = SECBOT_IDLE
- auto_patrol = 0
- return
- if("go")
- mode = SECBOT_IDLE
- auto_patrol = 1
- return
-
- if("summon")
- patrol_target = signal.data["target"]
- next_destination = destination
- destination = null
- awaiting_beacon = 0
- mode = SECBOT_SUMMON
- calc_path()
- speak("Responding.")
-
- return
+/obj/machinery/bot/ed209/proc/at_patrol_target()
+ find_patrol_target()
+ return
+// sets the current destination
+// signals all beacons matching the patrol code
+// beacons will return a signal giving their locations
+/obj/machinery/bot/ed209/proc/set_destination(var/new_dest)
+ new_destination = new_dest
+ post_signal(beacon_freq, "findbeacon", "patrol")
+ awaiting_beacon = 1
- // receive response from beacon
- recv = signal.data["beacon"]
- var/valid = signal.data["patrol"]
- if(!recv || !valid)
- return
- if(recv == new_destination) // if the recvd beacon location matches the set destination
- // the we will navigate there
- destination = new_destination
- patrol_target = signal.source.loc
- next_destination = signal.data["next_patrol"]
- awaiting_beacon = 0
+// receive a radio signal
+// used for beacon reception
- // if looking for nearest beacon
- else if(new_destination == "__nearest__")
- var/dist = get_dist(src,signal.source.loc)
- if(nearest_beacon)
+/obj/machinery/bot/ed209/receive_signal(datum/signal/signal)
- // note we ignore the beacon we are located at
- if(dist>1 && dist 1)
- nearest_beacon = recv
- nearest_beacon_loc = signal.source.loc
+ if(!on)
return
+ /*
+ world << "rec signal: [signal.source]"
+ for(var/x in signal.data)
+ world << "* [x] = [signal.data[x]]"
+ */
- // send a radio signal with a single data key/value pair
- proc/post_signal(var/freq, var/key, var/value)
- post_signal_multiple(freq, list("[key]" = value) )
+ var/recv = signal.data["command"]
+ // process all-bot input
+ if(recv=="bot_status")
+ send_status()
- // send a radio signal with multiple data key/values
- proc/post_signal_multiple(var/freq, var/list/keyval)
+ // check to see if we are the commanded bot
+ if(signal.data["active"] == src)
+ // process control input
+ switch(recv)
+ if("stop")
+ mode = SECBOT_IDLE
+ auto_patrol = 0
+ return
- var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
+ if("go")
+ mode = SECBOT_IDLE
+ auto_patrol = 1
+ return
- if(!frequency) return
+ if("summon")
+ patrol_target = signal.data["target"]
+ next_destination = destination
+ destination = null
+ awaiting_beacon = 0
+ mode = SECBOT_SUMMON
+ calc_path()
+ speak("Responding.")
- var/datum/signal/signal = new()
- signal.source = src
- signal.transmission_method = 1
- //for(var/key in keyval)
- // signal.data[key] = keyval[key]
- //world << "sent [key],[keyval[key]] on [freq]"
- signal.data = keyval
- if (signal.data["findbeacon"])
- frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
- else if (signal.data["type"] == "secbot")
- frequency.post_signal(src, signal, filter = RADIO_SECBOT)
- else
- frequency.post_signal(src, signal)
+ return
- // signals bot status etc. to controller
- proc/send_status()
- var/list/kv = list(
- "type" = "secbot",
- "name" = name,
- "loca" = loc.loc, // area
- "mode" = mode,
- )
- post_signal_multiple(control_freq, kv)
+
+
+ // receive response from beacon
+ recv = signal.data["beacon"]
+ var/valid = signal.data["patrol"]
+ if(!recv || !valid)
+ return
+
+ if(recv == new_destination) // if the recvd beacon location matches the set destination
+ // the we will navigate there
+ destination = new_destination
+ patrol_target = signal.source.loc
+ next_destination = signal.data["next_patrol"]
+ awaiting_beacon = 0
+
+ // if looking for nearest beacon
+ else if(new_destination == "__nearest__")
+ var/dist = get_dist(src,signal.source.loc)
+ if(nearest_beacon)
+
+ // note we ignore the beacon we are located at
+ if(dist>1 && dist 1)
+ nearest_beacon = recv
+ nearest_beacon_loc = signal.source.loc
+ return
+
+
+// send a radio signal with a single data key/value pair
+/obj/machinery/bot/ed209/proc/post_signal(var/freq, var/key, var/value)
+ post_signal_multiple(freq, list("[key]" = value) )
+
+// send a radio signal with multiple data key/values
+/obj/machinery/bot/ed209/proc/post_signal_multiple(var/freq, var/list/keyval)
+
+ var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
+
+ if(!frequency) return
+
+ var/datum/signal/signal = new()
+ signal.source = src
+ signal.transmission_method = 1
+ //for(var/key in keyval)
+ // signal.data[key] = keyval[key]
+ //world << "sent [key],[keyval[key]] on [freq]"
+ signal.data = keyval
+ if (signal.data["findbeacon"])
+ frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
+ else if (signal.data["type"] == "secbot")
+ frequency.post_signal(src, signal, filter = RADIO_SECBOT)
+ else
+ frequency.post_signal(src, signal)
+
+// signals bot status etc. to controller
+/obj/machinery/bot/ed209/proc/send_status()
+ var/list/kv = list(
+ "type" = "secbot",
+ "name" = name,
+ "loca" = loc.loc, // area
+ "mode" = mode,
+ )
+ post_signal_multiple(control_freq, kv)
// calculates a path to the current destination
// given an optional turf to avoid
- proc/calc_path(var/turf/avoid = null)
- src.path = AStar(src.loc, patrol_target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 120, id=botcard, exclude=avoid)
- src.path = reverselist(src.path)
+/obj/machinery/bot/ed209/proc/calc_path(var/turf/avoid = null)
+ src.path = AStar(src.loc, patrol_target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 120, id=botcard, exclude=avoid)
+ src.path = reverselist(src.path)
// look for a criminal in view of the bot
- proc/look_for_perp()
- src.anchored = 0
- src.threatlevel = 0
- for (var/mob/living/carbon/C in view(12,src)) //Let's find us a criminal
- if ((C.stat) || (C.handcuffed))
- continue
+/obj/machinery/bot/ed209/proc/look_for_perp()
+ src.anchored = 0
+ src.threatlevel = 0
+ for (var/mob/living/carbon/C in view(12,src)) //Let's find us a criminal
+ if ((C.stat) || (C.handcuffed))
+ continue
- if ((C.name == src.oldtarget_name) && (world.time < src.last_found + 100))
- continue
+ if ((C.name == src.oldtarget_name) && (world.time < src.last_found + 100))
+ continue
- if (istype(C, /mob/living/carbon/human))
- src.threatlevel = src.assess_perp(C)
- else if ((istype(C, /mob/living/carbon/monkey)) && (C.client) && (ticker.mode.name == "monkey"))
- src.threatlevel = 4
+ if (istype(C, /mob/living/carbon/human))
+ src.threatlevel = src.assess_perp(C)
+ else if ((istype(C, /mob/living/carbon/monkey)) && (C.client) && (ticker.mode.name == "monkey"))
+ src.threatlevel = 4
- if (!src.threatlevel)
- continue
+ if (!src.threatlevel)
+ continue
- else if (src.threatlevel >= 4)
- src.target = C
- src.oldtarget_name = C.name
- src.speak("Level [src.threatlevel] infraction alert!")
- playsound(src.loc, pick('ed209_20sec.ogg', 'ed209_15sec.ogg'), 50, 0)
- src.visible_message("[src] points at [C.name]!")
- mode = SECBOT_HUNT
- spawn(0)
- process() // ensure bot quickly responds to a perp
- break
- else
- continue
+ else if (src.threatlevel >= 4)
+ src.target = C
+ src.oldtarget_name = C.name
+ src.speak("Level [src.threatlevel] infraction alert!")
+ playsound(src.loc, pick('ed209_20sec.ogg', 'ed209_15sec.ogg'), 50, 0)
+ src.visible_message("[src] points at [C.name]!")
+ mode = SECBOT_HUNT
+ spawn(0)
+ process() // ensure bot quickly responds to a perp
+ break
+ else
+ continue
//If the security records say to arrest them, arrest them
//Or if they have weapons and aren't security, arrest them.
- proc/assess_perp(mob/living/carbon/human/perp as mob)
- var/threatcount = 0
+/obj/machinery/bot/ed209/proc/assess_perp(mob/living/carbon/human/perp as mob)
+ var/threatcount = 0
- if(src.emagged) return 10 //Everyone is a criminal!
+ if(src.emagged) return 10 //Everyone is a criminal!
- if((src.idcheck) || (isnull(perp:wear_id)) || (istype(perp:wear_id, /obj/item/weapon/card/id/syndicate)))
- if(src.allowed(perp)) //Corrupt cops cannot exist beep boop
- return 0
+ if((src.idcheck) || (isnull(perp:wear_id)) || (istype(perp:wear_id, /obj/item/weapon/card/id/syndicate)))
+ if(src.allowed(perp)) //Corrupt cops cannot exist beep boop
+ return 0
- if((istype(perp.l_hand, /obj/item/weapon/gun) && !istype(perp.l_hand, /obj/item/weapon/gun/shotgun)) || istype(perp.l_hand, /obj/item/weapon/baton))
- threatcount += 4
+ if((istype(perp.l_hand, /obj/item/weapon/gun) && !istype(perp.l_hand, /obj/item/weapon/gun/shotgun)) || istype(perp.l_hand, /obj/item/weapon/baton))
+ threatcount += 4
- if((istype(perp.r_hand, /obj/item/weapon/gun) && !istype(perp.r_hand, /obj/item/weapon/gun/shotgun)) || istype(perp.r_hand, /obj/item/weapon/baton))
- threatcount += 4
+ if((istype(perp.r_hand, /obj/item/weapon/gun) && !istype(perp.r_hand, /obj/item/weapon/gun/shotgun)) || istype(perp.r_hand, /obj/item/weapon/baton))
+ threatcount += 4
- if(istype(perp:belt, /obj/item/weapon/gun) || istype(perp:belt, /obj/item/weapon/baton))
- threatcount += 2
+ if(istype(perp:belt, /obj/item/weapon/gun) || istype(perp:belt, /obj/item/weapon/baton))
+ threatcount += 2
- if(istype(perp:wear_suit, /obj/item/clothing/suit/wizrobe))
- threatcount += 2
+ if(istype(perp:wear_suit, /obj/item/clothing/suit/wizrobe))
+ threatcount += 2
- if(perp.mutantrace && perp.mutantrace != "none")
- threatcount += 2
+ if(perp.mutantrace && perp.mutantrace != "none")
+ threatcount += 2
- //Agent cards lower threatlevel when normal idchecking is off.
- if((istype(perp:wear_id, /obj/item/weapon/card/id/syndicate)) && src.idcheck)
- threatcount -= 2
+//Agent cards lower threatlevel when normal idchecking is off.
+ if((istype(perp:wear_id, /obj/item/weapon/card/id/syndicate)) && src.idcheck)
+ threatcount -= 2
- if (src.check_records)
- for (var/datum/data/record/E in data_core.general)
- var/perpname = perp.name
- if (perp:wear_id)
- var/obj/item/weapon/card/id/id = perp:wear_id
- if(istype(perp:wear_id, /obj/item/device/pda))
- var/obj/item/device/pda/pda = perp:wear_id
- id = pda.id
- if (id)
- perpname = id.registered
- else
- var/obj/item/device/pda/pda = perp:wear_id
- perpname = pda.owner
- if (E.fields["name"] == perpname)
- for (var/datum/data/record/R in data_core.security)
- if ((R.fields["id"] == E.fields["id"]) && (R.fields["criminal"] == "*Arrest*"))
- threatcount = 4
- break
+ if (src.check_records)
+ for (var/datum/data/record/E in data_core.general)
+ var/perpname = perp.name
+ if (perp:wear_id)
+ var/obj/item/weapon/card/id/id = perp:wear_id
+ if(istype(perp:wear_id, /obj/item/device/pda))
+ var/obj/item/device/pda/pda = perp:wear_id
+ id = pda.id
+ if (id)
+ perpname = id.registered
+ else
+ var/obj/item/device/pda/pda = perp:wear_id
+ perpname = pda.owner
+ if (E.fields["name"] == perpname)
+ for (var/datum/data/record/R in data_core.security)
+ if ((R.fields["id"] == E.fields["id"]) && (R.fields["criminal"] == "*Arrest*"))
+ threatcount = 4
+ break
- return threatcount
+ return threatcount
- Bump(M as mob|obj) //Leave no door unopened!
- spawn(0)
- if ((istype(M, /obj/machinery/door)) && (!isnull(src.botcard)))
- var/obj/machinery/door/D = M
- if (!istype(D, /obj/machinery/door/firedoor) && D.check_access(src.botcard))
- D.open()
- src.frustration = 0
- else if ((istype(M, /mob/living/)) && (!src.anchored))
- src.loc = M:loc
+/obj/machinery/bot/ed209/Bump(M as mob|obj) //Leave no door unopened!
+ spawn(0)
+ if ((istype(M, /obj/machinery/door)) && (!isnull(src.botcard)))
+ var/obj/machinery/door/D = M
+ if (!istype(D, /obj/machinery/door/firedoor) && D.check_access(src.botcard))
+ D.open()
src.frustration = 0
+ else if ((istype(M, /mob/living/)) && (!src.anchored))
+ src.loc = M:loc
+ src.frustration = 0
- return
+ return
+ return
+
+/obj/machinery/bot/ed209/Bumped(M as mob|obj)
+ spawn(0)
+ var/turf/T = get_turf(src)
+ M:loc = T
+
+/obj/machinery/bot/ed209/proc/speak(var/message)
+ for(var/mob/O in hearers(src, null))
+ O << "[src] beeps, \"[message]\""
+ return
+
+/obj/machinery/bot/ed209/explode()
+ walk_to(src,0)
+ src.visible_message("\red [src] blows apart!", 1)
+ var/turf/Tsec = get_turf(src)
+
+ var/obj/item/weapon/ed209_assembly/Sa = new /obj/item/weapon/ed209_assembly(Tsec)
+ Sa.build_step = 1
+ Sa.overlays += image('aibots.dmi', "hs_hole")
+ Sa.created_name = src.name
+ new /obj/item/device/prox_sensor(Tsec)
+
+ var/obj/item/weapon/baton/B = new /obj/item/weapon/baton(Tsec)
+ B.charges = 0
+
+ if (prob(50))
+ new /obj/item/robot_parts/l_arm(Tsec)
+
+ var/datum/effects/system/spark_spread/s = new /datum/effects/system/spark_spread
+ s.set_up(3, 1, src)
+ s.start()
+
+ new /obj/decal/cleanable/oil(src.loc)
+ del(src)
+
+
+/obj/machinery/bot/ed209/proc/shootAt(var/mob/target)
+ if(lastfired && world.time - lastfired < shot_delay)
+ return
+ lastfired = world.time
+ var/turf/T = loc
+ var/atom/U = (istype(target, /atom/movable) ? target.loc : target)
+ if ((!( U ) || !( T )))
+ return
+ while(!( istype(U, /turf) ))
+ U = U.loc
+ if (!( istype(T, /turf) ))
return
- Bumped(M as mob|obj)
- spawn(0)
- var/turf/T = get_turf(src)
- M:loc = T
+ //if(lastfired && world.time - lastfired < 100)
+ // playsound(src.loc, 'ed209_shoot.ogg', 50, 0)
- bullet_act(flag, A as obj)
- switch(flag)
- if (PROJECTILE_BULLET)
- src.health -= 20
- //if (PROJECTILE_WEAKBULLET || PROJECTILE_BEANBAG) //Detective's revolver fires marshmallows
- // src.health -= 2
- if (PROJECTILE_LASER)
- src.health -= 10
- if (PROJECTILE_PULSE)
- src.health -=40
- if (src.health <= 0)
- src.explode()
+ var/obj/beam/a_laser/A
+ if (src.emagged)
+ A = new /obj/beam/a_laser( loc )
+ else
+ A = new /obj/bullet/electrode( loc )
- proc/speak(var/message)
- for(var/mob/O in hearers(src, null))
- O << "[src] beeps, \"[message]\""
+ if (!( istype(U, /turf) ))
+ //A = null
+ del(A)
return
-
- //Generally we want to explode() instead of just deleting the securitron.
- ex_act(severity)
- switch(severity)
- if(1.0)
- src.explode()
- return
- if(2.0)
- src.health -= 15
- if (src.health <= 0)
- src.explode()
- return
+ A.current = U
+ A.yo = U.y - T.y
+ A.xo = U.x - T.x
+ spawn( 0 )
+ A.process()
return
+ return
- meteorhit()
- src.explode()
- return
+/obj/machinery/bot/ed209/attack_alien(var/mob/living/carbon/alien/user as mob)
+ ..()
+ if (!isalien(target))
+ src.target = user
+ src.mode = SECBOT_HUNT
- blob_act()
- if(prob(50))
- src.explode()
- return
-
- proc/explode()
-
- walk_to(src,0)
- for(var/mob/O in hearers(src, null))
- O.show_message("\red [src] blows apart!", 1)
- var/turf/Tsec = get_turf(src)
-
- var/obj/item/weapon/ed209_assembly/Sa = new /obj/item/weapon/ed209_assembly(Tsec)
- Sa.build_step = 1
- Sa.overlays += image('aibots.dmi', "hs_hole")
- Sa.created_name = src.name
- new /obj/item/device/prox_sensor(Tsec)
-
- var/obj/item/weapon/baton/B = new /obj/item/weapon/baton(Tsec)
- B.charges = 0
+/obj/machinery/bot/ed209/emp_act(severity)
+ if (severity > 2)
+ ..(severity-1)
+ else if (severity==2 && prob(70))
+ ..(severity-1)
+ else
+ var/obj/overlay/pulse2 = new/obj/overlay ( src.loc )
+ pulse2.icon = 'effects.dmi'
+ pulse2.icon_state = "empdisable"
+ pulse2.name = "emp sparks"
+ pulse2.anchored = 1
+ pulse2.dir = pick(cardinal)
+ spawn(10)
+ del(pulse2)
+ var/list/mob/living/carbon/targets = new
+ for (var/mob/living/carbon/C in view(12,src))
+ if (C.stat==2)
+ continue
+ targets += C
if (prob(50))
- new /obj/item/robot_parts/l_arm(Tsec)
-
- var/datum/effects/system/spark_spread/s = new /datum/effects/system/spark_spread
- s.set_up(3, 1, src)
- s.start()
- del(src)
-
-
-
-
-
+ var/mob/toshoot = pick(targets)
+ if (toshoot)
+ targets-=toshoot
+ if (prob(50) && !emagged)
+ emagged = 1
+ shootAt(toshoot)
+ emagged = 0
+ else
+ shootAt(toshoot)
+ if (/*prob(50)*/ 1 )
+ var/mob/toarrest = pick(targets)
+ if (toarrest)
+ //targets-=toarrest
+ src.target = toarrest
+ src.mode = SECBOT_HUNT
/obj/item/weapon/ed209_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob)
-
-
if (((istype(W, /obj/item/robot_parts/l_leg)) || (istype(W, /obj/item/robot_parts/r_leg))) && (src.build_step == 0 || src.build_step == 1))
src.build_step++
user << "You add the robot leg to [src]!"
@@ -845,36 +872,3 @@ Auto Patrol: []"},
src.created_name = t
-/obj/machinery/bot/ed209/proc/shootAt(var/mob/target)
- if(lastfired && world.time - lastfired < shot_delay)
- return
- lastfired = world.time
- var/turf/T = loc
- var/atom/U = (istype(target, /atom/movable) ? target.loc : target)
- if ((!( U ) || !( T )))
- return
- while(!( istype(U, /turf) ))
- U = U.loc
- if (!( istype(T, /turf) ))
- return
-
- //if(lastfired && world.time - lastfired < 100)
- // playsound(src.loc, 'ed209_shoot.ogg', 50, 0)
-
- var/obj/beam/a_laser/A
- if (src.emagged)
- A = new /obj/beam/a_laser( loc )
- else
- A = new /obj/bullet/electrode( loc )
-
- if (!( istype(U, /turf) ))
- //A = null
- del(A)
- return
- A.current = U
- A.yo = U.y - T.y
- A.xo = U.x - T.x
- spawn( 0 )
- A.process()
- return
- return
\ No newline at end of file
diff --git a/code/game/machinery/bots/floorbot.dm b/code/game/machinery/bots/floorbot.dm
index ae279596d10..ea1711ca088 100644
--- a/code/game/machinery/bots/floorbot.dm
+++ b/code/game/machinery/bots/floorbot.dm
@@ -34,9 +34,10 @@
layer = 5.0
density = 0
anchored = 0
+ health = 25
+ maxhealth = 25
//weight = 1.0E7
var/amount = 10
- var/on = 1
var/repairing = 0
var/improvefloors = 0
var/eattiles = 0
@@ -54,7 +55,28 @@
..()
src.updateicon()
-/obj/machinery/bot/floorbot/attack_hand(user as mob)
+/obj/machinery/bot/floorbot/turn_on()
+ . = ..()
+ src.updateicon()
+ src.updateUsrDialog()
+
+/obj/machinery/bot/floorbot/turn_off()
+ ..()
+ src.target = null
+ src.oldtarget = null
+ src.oldloc = null
+ src.updateicon()
+ src.path = new()
+ src.updateUsrDialog()
+
+/obj/machinery/bot/floorbot/attack_hand(mob/user as mob)
+ . = ..()
+ if (.)
+ return
+ usr.machine = src
+ interact(user)
+
+/obj/machinery/bot/floorbot/proc/interact(mob/user as mob)
var/dat
dat += "Automatic Station Floor Repairer v1.0
"
dat += "Status: [src.on ? "On" : "Off"]
"
@@ -86,13 +108,15 @@
src.amount += loaded
user << "\red You load [loaded] tiles into the floorbot. He now contains [src.amount] tiles!"
src.updateicon()
- if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
+ else if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
if(src.allowed(usr))
src.locked = !src.locked
user << "You [src.locked ? "lock" : "unlock"] the [src] behaviour controls."
else
user << "The [src] doesn't seem to accept your authority."
src.updateUsrDialog()
+ else
+ ..()
/obj/machinery/bot/floorbot/Topic(href, href_list)
@@ -102,13 +126,10 @@
src.add_fingerprint(usr)
switch(href_list["operation"])
if("start")
- src.on = !src.on
- src.target = null
- src.oldtarget = null
- src.oldloc = null
- src.updateicon()
- src.path = new()
- src.updateUsrDialog()
+ if (src.on)
+ turn_off()
+ else
+ turn_on()
if("improve")
src.improvefloors = !src.improvefloors
src.updateUsrDialog()
@@ -136,12 +157,10 @@
/obj/machinery/bot/floorbot/attack_ai()
- src.on = !src.on
- src.target = null
- src.oldtarget = null
- src.oldloc = null
- src.updateicon()
- src.path = new()
+ if (src.on)
+ turn_off()
+ else
+ turn_on()
/obj/machinery/bot/floorbot/process()
set background = 1
@@ -327,6 +346,26 @@
else
src.icon_state = "floorbot[src.on]e"
+/obj/machinery/bot/floorbot/explode()
+ src.on = 0
+ src.visible_message("\red [src] blows apart!", 1)
+ var/turf/Tsec = get_turf(src)
+
+ new /obj/item/weapon/storage/toolbox/mechanical(Tsec)
+
+ new /obj/item/device/prox_sensor(Tsec)
+
+ if (prob(50))
+ new /obj/item/robot_parts/l_arm(Tsec)
+
+ if (amount)
+ new /obj/item/stack/tile(Tsec) // only one tile, yes
+
+ var/datum/effects/system/spark_spread/s = new /datum/effects/system/spark_spread
+ s.set_up(3, 1, src)
+ s.start()
+ del(src)
+ return
/obj/item/weapon/storage/toolbox/mechanical/attackby(var/obj/item/stack/tile/T, mob/user as mob)
diff --git a/code/game/machinery/bots/medbot.dm b/code/game/machinery/bots/medbot.dm
index 07b38a56ed1..3ff800b2d33 100644
--- a/code/game/machinery/bots/medbot.dm
+++ b/code/game/machinery/bots/medbot.dm
@@ -11,9 +11,9 @@
layer = 5.0
density = 1
anchored = 0
+ health = 20
+ maxhealth = 20
req_access =list(access_medical)
- var/on = 1
- var/health = 20
var/stunned = 0 //It can be stunned by tasers. Delicate circuits.
var/locked = 1
var/emagged = 0
@@ -79,16 +79,22 @@
src.cam.c_tag = src.name
src.cam.network = "SS13"
-/obj/machinery/bot/medbot/examine()
- set src in view()
- ..()
+/obj/machinery/bot/medbot/turn_on()
+ . = ..()
+ src.icon_state = "medibot[src.on]"
+ src.updateUsrDialog()
+
+/obj/machinery/bot/medbot/turn_off()
+ ..()
+ src.patient = null
+ src.oldpatient = null
+ src.oldloc = null
+ src.path = new()
+ src.currently_healing = 0
+ src.last_found = world.time
+ src.icon_state = "medibot[src.on]"
+ src.updateUsrDialog()
- if (src.health < 20)
- if (src.health > 15)
- usr << text("\red [src]'s parts look loose.")
- else
- usr << text("\red [src]'s parts look very loose!")
- return
/obj/machinery/bot/medbot/attack_ai(mob/user as mob)
return toggle_power()
@@ -97,6 +103,9 @@
return attack_hand(user)
/obj/machinery/bot/medbot/attack_hand(mob/user as mob)
+ . = ..()
+ if (.)
+ return
var/dat
dat += "Automatic Medical Unit v1.0
"
dat += "Status: [src.on ? "On" : "Off"]
"
@@ -190,12 +199,6 @@
else
user << "\red Access denied."
- else if (istype(W, /obj/item/weapon/screwdriver))
- if (src.health < initial(src.health))
- src.health = initial(src.health)
- for(var/mob/O in viewers(src, null))
- O << "\red [user] repairs [src]!"
-
else if (istype(W, /obj/item/weapon/reagent_containers/glass))
if(src.locked)
user << "You cannot insert a beaker because the panel is locked!"
@@ -212,17 +215,9 @@
return
else
- switch(W.damtype)
- if("fire")
- src.health -= W.force * 0.75
- if("brute")
- src.health -= W.force * 0.5
- else
- if (src.health <= 0)
- src.explode()
- else if (W.force)
- step_to(src, (get_step_away(src,user)))
..()
+ if (health < maxhealth && !istype(W, /obj/item/weapon/screwdriver) && W.force)
+ step_to(src, (get_step_away(src,user)))
/obj/machinery/bot/medbot/process()
@@ -317,15 +312,10 @@
/obj/machinery/bot/medbot/proc/toggle_power()
- src.on = !src.on
- src.patient = null
- src.oldpatient = null
- src.oldloc = null
- src.path = new()
- src.currently_healing = 0
- src.last_found = world.time
- src.icon_state = "medibot[src.on]"
- src.updateUsrDialog()
+ if (src.on)
+ turn_off()
+ else
+ turn_on()
return
/obj/machinery/bot/medbot/proc/assess_patient(mob/living/carbon/C as mob)
@@ -453,43 +443,11 @@
return
/obj/machinery/bot/medbot/bullet_act(flag, A as obj)
- if (flag == PROJECTILE_BULLET)
- src.health -= 18
+ if (flag == PROJECTILE_TASER)
+ src.stunned = min(stunned+10,20)
+ ..()
- else if (flag == PROJECTILE_TASER)
- src.stunned += 10
- if(src.stunned > 20)
- src.stunned = 20
-
- else if (flag == PROJECTILE_LASER)
- src.health -= 8
-
-
- if (src.health <= 0)
- src.explode()
-
-/obj/machinery/bot/medbot/ex_act(severity)
- switch(severity)
- if(1.0)
- src.explode()
- return
- if(2.0)
- src.health -= 15
- if (src.health <= 0)
- src.explode()
- return
- return
-
-/obj/machinery/bot/medbot/meteorhit()
- src.explode()
- return
-
-/obj/machinery/bot/medbot/blob_act()
- if(prob(50))
- src.explode()
- return
-
-/obj/machinery/bot/medbot/proc/explode()
+/obj/machinery/bot/medbot/explode()
src.on = 0
for(var/mob/O in hearers(src, null))
O.show_message("\red [src] blows apart!", 1)
diff --git a/code/game/machinery/bots/mulebot.dm b/code/game/machinery/bots/mulebot.dm
index 890cac9d833..5461bd1bf10 100644
--- a/code/game/machinery/bots/mulebot.dm
+++ b/code/game/machinery/bots/mulebot.dm
@@ -11,7 +11,10 @@
density = 1
anchored = 1
animate_movement=1
- var/on = 1
+ health = 150 //yeah, it's tougher than ed209 because it is a big metal box with wheels --rastaf0
+ maxhealth = 150
+ fire_dam_coeff = 0.7
+ brute_dam_coeff = 0.5
var/locked = 1
var/atom/movable/load = null // the loaded crate (usually)
@@ -69,853 +72,895 @@
var/bloodiness = 0 // count of bloodiness
- New()
- ..()
- botcard = new(src)
- botcard.access = get_access("Quartermaster")
- cell = new(src)
- cell.charge = 2000
- cell.maxcharge = 2000
- setup_wires()
+/obj/machinery/bot/mulebot/New()
+ ..()
+ botcard = new(src)
+ botcard.access = get_access("Quartermaster")
+ cell = new(src)
+ cell.charge = 2000
+ cell.maxcharge = 2000
+ setup_wires()
- spawn(5) // must wait for map loading to finish
- if(radio_controller)
- radio_controller.add_object(src, control_freq, filter = RADIO_MULEBOT)
- radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
+ spawn(5) // must wait for map loading to finish
+ if(radio_controller)
+ radio_controller.add_object(src, control_freq, filter = RADIO_MULEBOT)
+ radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
- var/count = 0
- for(var/obj/machinery/bot/mulebot/other in world)
- count++
- if(!suffix)
- suffix = "#[count]"
- name = "Mulebot ([suffix])"
+ var/count = 0
+ for(var/obj/machinery/bot/mulebot/other in world)
+ count++
+ if(!suffix)
+ suffix = "#[count]"
+ name = "Mulebot ([suffix])"
- verbs -= /atom/movable/verb/pull
+ verbs -= /atom/movable/verb/pull
- // set up the wire colours in random order
- // and the random wire display order
- // needs 10 wire colours
- proc/setup_wires()
- var/list/colours = list("Red", "Green", "Blue", "Magenta", "Cyan", "Yellow", "Black", "White", "Orange", "Grey")
- var/list/orders = list("0","1","2","3","4","5","6","7","8","9")
- wire_text = list()
- wire_order = list()
- while(colours.len > 0)
- var/colour = colours[ rand(1,colours.len) ]
- wire_text += colour
- colours -= colour
+// set up the wire colours in random order
+// and the random wire display order
+// needs 10 wire colours
+/obj/machinery/bot/mulebot/proc/setup_wires()
+ var/list/colours = list("Red", "Green", "Blue", "Magenta", "Cyan", "Yellow", "Black", "White", "Orange", "Grey")
+ var/list/orders = list("0","1","2","3","4","5","6","7","8","9")
+ wire_text = list()
+ wire_order = list()
+ while(colours.len > 0)
+ var/colour = colours[ rand(1,colours.len) ]
+ wire_text += colour
+ colours -= colour
- var/order = orders[ rand(1,orders.len) ]
- wire_order += text2num(order)
- orders -= order
+ var/order = orders[ rand(1,orders.len) ]
+ wire_order += text2num(order)
+ orders -= order
- // attack by item
- // emag : lock/unlock,
- // screwdriver: open/close hatch
- // cell: insert it
- // other: chance to knock rider off bot
- attackby(var/obj/item/I, var/mob/user)
- if(istype(I,/obj/item/weapon/card/emag))
- locked = !locked
- user << "\blue You [locked ? "lock" : "unlock"] the mulebot's controls!"
- flick("mulebot-emagged", src)
- playsound(src.loc, 'sparks1.ogg', 100, 0)
- else if(istype(I,/obj/item/weapon/cell) && open && !cell)
- var/obj/item/weapon/cell/C = I
- user.drop_item()
- C.loc = src
- cell = C
- updateDialog()
- else if(istype(I,/obj/item/weapon/screwdriver))
- if(locked)
- user << "\blue The maintenance hatch cannot be opened or closed while the controls are locked."
- return
+// attack by item
+// emag : lock/unlock,
+// screwdriver: open/close hatch
+// cell: insert it
+// other: chance to knock rider off bot
+/obj/machinery/bot/mulebot/attackby(var/obj/item/I, var/mob/user)
+ if(istype(I,/obj/item/weapon/card/emag))
+ locked = !locked
+ user << "\blue You [locked ? "lock" : "unlock"] the mulebot's controls!"
+ flick("mulebot-emagged", src)
+ playsound(src.loc, 'sparks1.ogg', 100, 0)
+ else if(istype(I,/obj/item/weapon/cell) && open && !cell)
+ var/obj/item/weapon/cell/C = I
+ user.drop_item()
+ C.loc = src
+ cell = C
+ updateDialog()
+ else if(istype(I,/obj/item/weapon/screwdriver))
+ if(locked)
+ user << "\blue The maintenance hatch cannot be opened or closed while the controls are locked."
+ return
- open = !open
- if(open)
- src.visible_message("[user] opens the maintenance hatch of [src]", "\blue You open [src]'s maintenance hatch.")
- on = 0
- icon_state="mulebot-hatch"
- else
- src.visible_message("[user] closes the maintenance hatch of [src]", "\blue You close [src]'s maintenance hatch.")
- icon_state = "mulebot0"
-
- updateDialog()
- else if(load && ismob(load)) // chance to knock off rider
- if(prob(1+I.force * 2))
- unload(0)
- user.visible_message("\red [user] knocks [load] off [src] with \the [I]!", "\red You knock [load] off [src] with \the [I]!")
- else
- user << "You hit [src] with \the [I] but to no effect."
+ open = !open
+ if(open)
+ src.visible_message("[user] opens the maintenance hatch of [src]", "\blue You open [src]'s maintenance hatch.")
+ on = 0
+ icon_state="mulebot-hatch"
else
- ..()
- return
+ src.visible_message("[user] closes the maintenance hatch of [src]", "\blue You close [src]'s maintenance hatch.")
+ icon_state = "mulebot0"
-
- ex_act(var/severity)
- unload(0)
- switch(severity)
- if(1)
- del(src)
- if(2)
- wires &= ~(1 << rand(0,9))
- wires &= ~(1 << rand(0,9))
- wires &= ~(1 << rand(0,9))
- if(3)
- wires &= ~(1 << rand(0,9))
-
- return
-
- bullet_act()
- if(prob(50) && !isnull(load))
- load.bullet_act()
+ updateDialog()
+ else if (istype(I, /obj/item/weapon/wrench))
+ if (src.health < maxhealth)
+ src.health = min(maxhealth, src.health+25)
+ user.visible_message(
+ "\red [user] repairs [src]!",
+ "\blue You repair [src]!"
+ )
+ else
+ user << "\blue [src] does not need a repair!"
+ else if(load && ismob(load)) // chance to knock off rider
+ if(prob(1+I.force * 2))
unload(0)
- if(prob(25))
- src.visible_message("Something shorts out inside [src]!")
- var/index = 1<< (rand(0,9))
- if(wires & index)
- wires &= ~index
- else
- wires |= index
-
-
- attack_ai(var/mob/user)
- interact(user, 1)
-
- attack_hand(var/mob/user)
- interact(user, 0)
-
- proc/interact(var/mob/user, var/ai=0)
- var/dat
- dat += "Multiple Utility Load Effector Mk. III
"
- dat += "ID: [suffix]
"
- dat += "Power: [on ? "On" : "Off"]
"
-
- if(!open)
-
- dat += "Status: "
- switch(mode)
- if(0)
- dat += "Ready"
- if(1)
- dat += "Loading/Unloading"
- if(2)
- dat += "Navigating to Delivery Location"
- if(3)
- dat += "Navigating to Home"
- if(4)
- dat += "Waiting for clear path"
- if(5,6)
- dat += "Calculating navigation path"
- if(7)
- dat += "Unable to locate destination"
-
-
- dat += "
Current Load: [load ? load.name : "none"]
"
- dat += "Destination: [!destination ? "none" : destination]
"
- dat += "Power level: [cell ? cell.percent() : 0]%
"
-
- if(locked && !ai)
- dat += "
Controls are locked (unlock)"
- else
- dat += "
Controls are unlocked (lock)
"
-
- dat += "Toggle Power
"
- dat += "Stop
"
- dat += "Proceed
"
- dat += "Return to Home
"
- dat += "Set Destination
"
- dat += "Set Bot ID
"
- dat += "Set Home
"
- dat += "Toggle Auto Return Home ([auto_return ? "On":"Off"])
"
- dat += "Toggle Auto Pickup Crate ([auto_pickup ? "On":"Off"])
"
-
- if(load)
- dat += "Unload Now
"
- dat += "
The maintenance hatch is closed.
"
-
+ user.visible_message("\red [user] knocks [load] off [src] with \the [I]!", "\red You knock [load] off [src] with \the [I]!")
else
- if(!ai)
- dat += "The maintenance hatch is open.
"
- dat += "Power cell: "
- if(cell)
- dat += "Installed
"
- else
- dat += "Removed
"
+ user << "You hit [src] with \the [I] but to no effect."
+ else
+ ..()
+ return
- dat += wires()
- else
- dat += "The bot is in maintenance mode and cannot be controlled.
"
- user << browse("Mulebot [suffix ? "([suffix])" : ""][dat]", "window=mulebot;size=350x500")
- onclose(user, "mulebot")
+/obj/machinery/bot/mulebot/ex_act(var/severity)
+ unload(0)
+ switch(severity)
+ if(2)
+ wires &= ~(1 << rand(0,9))
+ wires &= ~(1 << rand(0,9))
+ wires &= ~(1 << rand(0,9))
+ if(3)
+ wires &= ~(1 << rand(0,9))
+ ..()
+ return
+
+/obj/machinery/bot/mulebot/bullet_act()
+ if(prob(50) && !isnull(load))
+ load.bullet_act()
+ unload(0)
+ if(prob(25))
+ src.visible_message("\red Something shorts out inside [src]!")
+ var/index = 1<< (rand(0,9))
+ if(wires & index)
+ wires &= ~index
+ else
+ wires |= index
+ ..()
+
+
+/obj/machinery/bot/mulebot/attack_ai(var/mob/user)
+ usr.machine = src
+ interact(user, 1)
+
+/obj/machinery/bot/mulebot/attack_hand(var/mob/user)
+ . = ..()
+ if (.)
return
+ usr.machine = src
+ interact(user, 0)
- // returns the wire panel text
- proc/wires()
- var/t = ""
- for(var/i = 0 to 9)
- var/index = 1<(cut) (pulse)
"
+/obj/machinery/bot/mulebot/proc/interact(var/mob/user, var/ai=0)
+ var/dat
+ dat += "Multiple Utility Load Effector Mk. III
"
+ dat += "ID: [suffix]
"
+ dat += "Power: [on ? "On" : "Off"]
"
+
+ if(!open)
+
+ dat += "Status: "
+ switch(mode)
+ if(0)
+ dat += "Ready"
+ if(1)
+ dat += "Loading/Unloading"
+ if(2)
+ dat += "Navigating to Delivery Location"
+ if(3)
+ dat += "Navigating to Home"
+ if(4)
+ dat += "Waiting for clear path"
+ if(5,6)
+ dat += "Calculating navigation path"
+ if(7)
+ dat += "Unable to locate destination"
+
+
+ dat += "
Current Load: [load ? load.name : "none"]
"
+ dat += "Destination: [!destination ? "none" : destination]
"
+ dat += "Power level: [cell ? cell.percent() : 0]%
"
+
+ if(locked && !ai)
+ dat += "
Controls are locked (unlock)"
+ else
+ dat += "
Controls are unlocked (lock)
"
+
+ dat += "Toggle Power
"
+ dat += "Stop
"
+ dat += "Proceed
"
+ dat += "Return to Home
"
+ dat += "Set Destination
"
+ dat += "Set Bot ID
"
+ dat += "Set Home
"
+ dat += "Toggle Auto Return Home ([auto_return ? "On":"Off"])
"
+ dat += "Toggle Auto Pickup Crate ([auto_pickup ? "On":"Off"])
"
+
+ if(load)
+ dat += "Unload Now
"
+ dat += "
The maintenance hatch is closed.
"
+
+ else
+ if(!ai)
+ dat += "The maintenance hatch is open.
"
+ dat += "Power cell: "
+ if(cell)
+ dat += "Installed
"
else
- t += "(mend)
"
+ dat += "Removed
"
- return t
+ dat += wires()
+ else
+ dat += "The bot is in maintenance mode and cannot be controlled.
"
+
+ user << browse("Mulebot [suffix ? "([suffix])" : ""][dat]", "window=mulebot;size=350x500")
+ onclose(user, "mulebot")
+ return
+
+// returns the wire panel text
+/obj/machinery/bot/mulebot/proc/wires()
+ var/t = ""
+ for(var/i = 0 to 9)
+ var/index = 1<(cut) (pulse)
"
+ else
+ t += "(mend)
"
+
+ return t
- Topic(href, href_list)
- if(..())
- return
- if (usr.stat)
- return
- if ((in_range(src, usr) && istype(src.loc, /turf)) || (istype(usr, /mob/living/silicon)))
- usr.machine = src
+/obj/machinery/bot/mulebot/Topic(href, href_list)
+ if(..())
+ return
+ if (usr.stat)
+ return
+ if ((in_range(src, usr) && istype(src.loc, /turf)) || (istype(usr, /mob/living/silicon)))
+ usr.machine = src
- switch(href_list["op"])
- if("lock", "unlock")
- if(src.allowed(usr))
- locked = !locked
- updateDialog()
+ switch(href_list["op"])
+ if("lock", "unlock")
+ if(src.allowed(usr))
+ locked = !locked
+ updateDialog()
+ else
+ usr << "\red Access denied."
+ return
+ if("power")
+ if (src.on)
+ turn_off()
+ else if (cell && !open)
+ if (!turn_on())
+ usr << "\red You can't switch on [src]."
+ return
+ else
+ return
+ usr << "You switch [on ? "on" : "off"] [src]."
+ for(var/mob/M in viewers(src))
+ if(M==usr) continue
+ M << "[usr] switches [on ? "on" : "off"] [src]."
+ updateDialog()
+
+
+ if("cellremove")
+ if(open && cell && !usr.equipped())
+ cell.loc = usr
+ cell.layer = 20
+ if(usr.hand)
+ usr.l_hand = cell
else
- usr << "\red Access denied."
- return
- if("power")
- on = !on
- if(!cell || open)
- on = 0
- return
- usr << "You switch [on ? "on" : "off"] [src]."
- for(var/mob/M in viewers(src))
- if(M==usr) continue
- M << "[usr] switches [on ? "on" : "off"] [src]."
+ usr.r_hand = cell
+
+ cell.add_fingerprint(usr)
+ cell.updateicon()
+ cell = null
+
+ usr.visible_message("\blue [usr] removes the power cell from [src].", "\blue You remove the power cell from [src].")
updateDialog()
+ if("cellinsert")
+ if(open && !cell)
+ var/obj/item/weapon/cell/C = usr.equipped()
+ if(istype(C))
+ usr.drop_item()
+ cell = C
+ C.loc = src
+ C.add_fingerprint(usr)
- if("cellremove")
- if(open && cell && !usr.equipped())
- cell.loc = usr
- cell.layer = 20
- if(usr.hand)
- usr.l_hand = cell
- else
- usr.r_hand = cell
-
- cell.add_fingerprint(usr)
- cell.updateicon()
- cell = null
-
- usr.visible_message("\blue [usr] removes the power cell from [src].", "\blue You remove the power cell from [src].")
+ usr.visible_message("\blue [usr] inserts a power cell into [src].", "\blue You insert the power cell into [src].")
updateDialog()
- if("cellinsert")
- if(open && !cell)
- var/obj/item/weapon/cell/C = usr.equipped()
- if(istype(C))
- usr.drop_item()
- cell = C
- C.loc = src
- C.add_fingerprint(usr)
- usr.visible_message("\blue [usr] inserts a power cell into [src].", "\blue You insert the power cell into [src].")
- updateDialog()
-
-
- if("stop")
- if(mode >=2)
- mode = 0
- updateDialog()
-
- if("go")
- if(mode == 0)
- start()
- updateDialog()
-
- if("home")
- if(mode == 0 || mode == 2)
- start_home()
- updateDialog()
-
- if("destination")
- refresh=0
- var/new_dest = input("Enter new destination tag", "Mulebot [suffix ? "([suffix])" : ""]", destination) as text|null
- refresh=1
- if(new_dest)
- set_destination(new_dest)
-
-
- if("setid")
- refresh=0
- var/new_id = input("Enter new bot ID", "Mulebot [suffix ? "([suffix])" : ""]", suffix) as text|null
- refresh=1
- if(new_id)
- suffix = new_id
- name = "Mulebot ([suffix])"
- updateDialog()
-
- if("sethome")
- refresh=0
- var/new_home = input("Enter new home tag", "Mulebot [suffix ? "([suffix])" : ""]", home_destination) as text|null
- refresh=1
- if(new_home)
- home_destination = new_home
- updateDialog()
-
- if("unload")
- if(load && mode !=1)
- if(loc == target)
- unload(loaddir)
- else
- unload(0)
-
- if("autoret")
- auto_return = !auto_return
-
- if("autopick")
- auto_pickup = !auto_pickup
-
- if("close")
- usr.machine = null
- usr << browse(null,"window=mulebot")
-
-
- if("wirecut")
- if(istype(usr.equipped(), /obj/item/weapon/wirecutters))
- var/wirebit = text2num(href_list["wire"])
- wires &= ~wirebit
- else
- usr << "\blue You need wirecutters!"
- if("wiremend")
- if(istype(usr.equipped(), /obj/item/weapon/wirecutters))
- var/wirebit = text2num(href_list["wire"])
- wires |= wirebit
- else
- usr << "\blue You need wirecutters!"
-
- if("wirepulse")
- if(istype(usr.equipped(), /obj/item/device/multitool))
- switch(href_list["wire"])
- if("1","2")
- usr << "\blue \icon[src] The charge light flickers."
- if("4")
- usr << "\blue \icon[src] The external warning lights flash briefly."
- if("8")
- usr << "\blue \icon[src] The load platform clunks."
- if("16", "32")
- usr << "\blue \icon[src] The drive motor whines briefly."
- else
- usr << "\blue \icon[src] You hear a radio crackle."
- else
- usr << "\blue You need a multitool!"
-
-
-
- updateDialog()
- //src.updateUsrDialog()
- else
- usr << browse(null, "window=mulebot")
- usr.machine = null
- return
-
-
-
- // returns true if the bot has power
- proc/has_power()
- return !open && cell && cell.charge>0 && (wires & wire_power1) && (wires & wire_power2)
-
- // mousedrop a crate to load the bot
- // can load anything if emagged
-
- MouseDrop_T(var/atom/movable/C, mob/user)
-
- if(user.stat)
- return
-
- if (!on || !istype(C)|| C.anchored || get_dist(user, src) > 1 || get_dist(src,C) > 1 )
- return
-
- if(load)
- return
-
- load(C)
-
-
- // called to load a crate
- proc/load(var/atom/movable/C)
- if((wires & wire_loadcheck) && !istype(C,/obj/crate))
- src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
- playsound(src.loc, 'buzz-sigh.ogg', 50, 0)
- return // if not emagged, only allow crates to be loaded
-
- if(get_dist(C, src) > 1 || load || !on)
- return
- mode = 1
-
- // if a create, close before loading
- var/obj/crate/crate = C
- if(istype(crate))
- crate.close()
-
- C.loc = src.loc
- sleep(2)
- C.loc = src
- load = C
-
- C.pixel_y += 9
- if(C.layer < layer)
- C.layer = layer + 0.1
- overlays += C
-
- if(ismob(C))
- var/mob/M = C
- if(M.client)
- M.client.perspective = EYE_PERSPECTIVE
- M.client.eye = src
-
- mode = 0
- send_status()
-
- // called to unload the bot
- // argument is optional direction to unload
- // if zero, unload at bot's location
- proc/unload(var/dirn = 0)
- if(!load)
- return
-
- mode = 1
- overlays = null
-
- load.loc = src.loc
- load.pixel_y -= 9
- load.layer = initial(load.layer)
- if(ismob(load))
- var/mob/M = load
- if(M.client)
- M.client.perspective = MOB_PERSPECTIVE
- M.client.eye = src
-
-
- if(dirn)
- step(load, dirn)
-
- load = null
-
- // in case non-load items end up in contents, dump every else too
- // this seems to happen sometimes due to race conditions
- // with items dropping as mobs are loaded
-
- for(var/atom/movable/AM in src)
- if(AM == cell || AM == botcard) continue
-
- AM.loc = src.loc
- AM.layer = initial(AM.layer)
- AM.pixel_y = initial(AM.pixel_y)
- if(ismob(AM))
- var/mob/M = AM
- if(M.client)
- M.client.perspective = MOB_PERSPECTIVE
- M.client.eye = src
- mode = 0
-
-
- process()
- if(!has_power())
- on = 0
- return
- if(on)
- var/speed = ((wires & wire_motor1) ? 1:0) + ((wires & wire_motor2) ? 2:0)
- //world << "speed: [speed]"
- switch(speed)
- if(0)
- // do nothing
- if(1)
- process_bot()
- spawn(3)
- process_bot()
- sleep(3)
- process_bot()
- if(2)
- process_bot()
- spawn(5)
- process_bot()
- if(3)
- process_bot()
-
- if(refresh) updateDialog()
-
- proc/process_bot()
- //if(mode) world << "Mode: [mode]"
- switch(mode)
- if(0) // idle
- icon_state = "mulebot0"
- return
- if(1) // loading/unloading
- return
- if(2,3,4) // navigating to deliver,home, or blocked
-
- if(loc == target) // reached target
- at_target()
- return
-
- else if(path.len > 0 && target) // valid path
-
- var/turf/next = path[1]
- reached_target = 0
- if(next == loc)
- path -= next
- return
-
-
- if(istype( next, /turf/simulated))
- //world << "at ([x],[y]) moving to ([next.x],[next.y])"
-
-
- if(bloodiness)
- var/obj/decal/cleanable/blood/tracks/B = new(loc)
- var/newdir = get_dir(next, loc)
- if(newdir == dir)
- B.dir = newdir
- else
- newdir = newdir | dir
- if(newdir == 3)
- newdir = 1
- else if(newdir == 12)
- newdir = 4
- B.dir = newdir
- bloodiness--
-
-
-
- var/moved = step_towards(src, next) // attempt to move
- if(cell) cell.use(1)
- if(moved) // successful move
- //world << "Successful move."
- blockcount = 0
- path -= loc
-
-
- if(mode==4)
- spawn(1)
- send_status()
-
- if(destination == home_destination)
- mode = 3
- else
- mode = 2
-
- else // failed to move
-
- //world << "Unable to move."
-
-
-
- blockcount++
- mode = 4
- if(blockcount == 3)
- src.visible_message("[src] makes an annoyed buzzing sound", "You hear an electronic buzzing sound.")
- playsound(src.loc, 'buzz-two.ogg', 50, 0)
-
- if(blockcount > 5) // attempt 5 times before recomputing
- // find new path excluding blocked turf
- src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
- playsound(src.loc, 'buzz-sigh.ogg', 50, 0)
-
- spawn(2)
- calc_path(next)
- if(path.len > 0)
- src.visible_message("[src] makes a delighted ping!", "You hear a ping.")
- playsound(src.loc, 'ping.ogg', 50, 0)
- mode = 4
- mode =6
- return
- return
- else
- src.visible_message("[src] makes an annoyed buzzing sound", "You hear an electronic buzzing sound.")
- playsound(src.loc, 'buzz-two.ogg', 50, 0)
- //world << "Bad turf."
- mode = 5
- return
- else
- //world << "No path."
- mode = 5
- return
-
- if(5) // calculate new path
- //world << "Calc new path."
- mode = 6
- spawn(0)
-
- calc_path()
-
- if(path.len > 0)
- blockcount = 0
- mode = 4
- src.visible_message("[src] makes a delighted ping!", "You hear a ping.")
- playsound(src.loc, 'ping.ogg', 50, 0)
-
- else
- src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
- playsound(src.loc, 'buzz-sigh.ogg', 50, 0)
-
- mode = 7
- //if(6)
- //world << "Pending path calc."
- //if(7)
- //world << "No dest / no route."
- return
-
-
- // calculates a path to the current destination
- // given an optional turf to avoid
- proc/calc_path(var/turf/avoid = null)
- src.path = AStar(src.loc, src.target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 250, id=botcard, exclude=avoid)
- src.path = reverselist(src.path)
-
-
- // sets the current destination
- // signals all beacons matching the delivery code
- // beacons will return a signal giving their locations
- proc/set_destination(var/new_dest)
- spawn(0)
- new_destination = new_dest
- post_signal(beacon_freq, "findbeacon", "delivery")
- updateDialog()
-
- // starts bot moving to current destination
- proc/start()
- if(destination == home_destination)
- mode = 3
- else
- mode = 2
- icon_state = "mulebot[(wires & wire_mobavoid) == wire_mobavoid]"
-
- // starts bot moving to home
- // sends a beacon query to find
- proc/start_home()
- spawn(0)
- set_destination(home_destination)
- mode = 4
- icon_state = "mulebot[(wires & wire_mobavoid) == wire_mobavoid]"
-
- // called when bot reaches current target
- proc/at_target()
- if(!reached_target)
- src.visible_message("[src] makes a chiming sound!", "You hear a chime.")
- playsound(src.loc, 'chime.ogg', 50, 0)
- reached_target = 1
-
- if(load) // if loaded, unload at target
- unload(loaddir)
- else
- // not loaded
- if(auto_pickup) // find a crate
- var/atom/movable/AM
- if(!(wires & wire_loadcheck)) // if emagged, load first unanchored thing we find
- for(var/atom/movable/A in get_step(loc, loaddir))
- if(!A.anchored)
- AM = A
- break
- else // otherwise, look for crates only
- AM = locate(/obj/crate) in get_step(loc,loaddir)
- if(AM)
- load(AM)
- // whatever happened, check to see if we return home
-
- if(auto_return && destination != home_destination)
- // auto return set and not at home already
- start_home()
- mode = 4
- else
- mode = 0 // otherwise go idle
-
- send_status() // report status to anyone listening
-
- return
-
- // called when bot bumps into anything
- Bump(var/atom/obs)
- if(!(wires & wire_mobavoid)) //usually just bumps, but if avoidance disabled knock over mobs
- var/mob/M = obs
- if(ismob(M))
- if(istype(M,/mob/living/silicon/robot))
- src.visible_message("\red [src] bumps into [M]!")
- else
- src.visible_message("\red [src] knocks over [M]!")
- M.pulling = null
- M.stunned = 8
- M.weakened = 5
- M.lying = 1
- ..()
-
- alter_health()
- return get_turf(src)
-
-
- // called from mob/living/carbon/human/HasEntered()
- // when mulebot is in the same loc
- proc/RunOver(var/mob/living/carbon/human/H)
- src.visible_message("\red [src] drives over [H]!")
- playsound(src.loc, 'splat.ogg', 50, 1)
-
- /*
- if(ismob(load))
- var/mob/M = load
- if(M.reagents.has_reagent("beer"))
- M.unlock_medal("DUI", 1)
- if(M.reagents.has_reagent("space_drugs") && istype(H) && H.wear_id.assignment == "Security Officer")
- M.unlock_medel("Ridin' Dirty",1)
- */
-
- var/damage = rand(5,15)
-
- H.TakeDamage("head", 2*damage, 0)
- H.TakeDamage("chest",2*damage, 0)
- H.TakeDamage("l_leg",0.5*damage, 0)
- H.TakeDamage("r_leg",0.5*damage, 0)
- H.TakeDamage("l_arm",0.5*damage, 0)
- H.TakeDamage("r_arm",0.5*damage, 0)
-
- var/obj/decal/cleanable/blood/B = new(src.loc)
- B.blood_DNA = H.dna.unique_enzymes
- B.blood_type = H.b_type
-
- bloodiness += 4
-
- // player on mulebot attempted to move
- relaymove(var/mob/user)
- if(user.stat)
- return
- if(load == user)
- unload(0)
- return
-
- // receive a radio signal
- // used for control and beacon reception
-
- receive_signal(datum/signal/signal)
-
- if(!on)
- return
-
- /*
- world << "rec signal: [signal.source]"
- for(var/x in signal.data)
- world << "* [x] = [signal.data[x]]"
- */
- var/recv = signal.data["command"]
- // process all-bot input
- if(recv=="bot_status" && (wires & wire_remote_rx))
- send_status()
-
-
- recv = signal.data["command [suffix]"]
- if(wires & wire_remote_rx)
- // process control input
- switch(recv)
- if("stop")
+ if("stop")
+ if(mode >=2)
mode = 0
- return
+ updateDialog()
- if("go")
+ if("go")
+ if(mode == 0)
start()
- return
+ updateDialog()
- if("target")
- set_destination(signal.data["destination"] )
- return
+ if("home")
+ if(mode == 0 || mode == 2)
+ start_home()
+ updateDialog()
- if("unload")
+ if("destination")
+ refresh=0
+ var/new_dest = input("Enter new destination tag", "Mulebot [suffix ? "([suffix])" : ""]", destination) as text|null
+ refresh=1
+ if(new_dest)
+ set_destination(new_dest)
+
+
+ if("setid")
+ refresh=0
+ var/new_id = input("Enter new bot ID", "Mulebot [suffix ? "([suffix])" : ""]", suffix) as text|null
+ refresh=1
+ if(new_id)
+ suffix = new_id
+ name = "Mulebot ([suffix])"
+ updateDialog()
+
+ if("sethome")
+ refresh=0
+ var/new_home = input("Enter new home tag", "Mulebot [suffix ? "([suffix])" : ""]", home_destination) as text|null
+ refresh=1
+ if(new_home)
+ home_destination = new_home
+ updateDialog()
+
+ if("unload")
+ if(load && mode !=1)
if(loc == target)
unload(loaddir)
else
unload(0)
- return
- if("home")
- start_home()
- return
+ if("autoret")
+ auto_return = !auto_return
- if("bot_status")
- send_status()
- return
+ if("autopick")
+ auto_pickup = !auto_pickup
- if("autoret")
- auto_return = text2num(signal.data["value"])
- return
+ if("close")
+ usr.machine = null
+ usr << browse(null,"window=mulebot")
- if("autopick")
- auto_pickup = text2num(signal.data["value"])
- return
- // receive response from beacon
- recv = signal.data["beacon"]
- if(wires & wire_beacon_rx)
- if(recv == new_destination) // if the recvd beacon location matches the set destination
- // the we will navigate there
- destination = new_destination
- target = signal.source.loc
- var/direction = signal.data["dir"] // this will be the load/unload dir
- if(direction)
- loaddir = text2num(direction)
+ if("wirecut")
+ if(istype(usr.equipped(), /obj/item/weapon/wirecutters))
+ var/wirebit = text2num(href_list["wire"])
+ wires &= ~wirebit
else
- loaddir = 0
- icon_state = "mulebot[(wires & wire_mobavoid) == wire_mobavoid]"
+ usr << "\blue You need wirecutters!"
+ if("wiremend")
+ if(istype(usr.equipped(), /obj/item/weapon/wirecutters))
+ var/wirebit = text2num(href_list["wire"])
+ wires |= wirebit
+ else
+ usr << "\blue You need wirecutters!"
+
+ if("wirepulse")
+ if(istype(usr.equipped(), /obj/item/device/multitool))
+ switch(href_list["wire"])
+ if("1","2")
+ usr << "\blue \icon[src] The charge light flickers."
+ if("4")
+ usr << "\blue \icon[src] The external warning lights flash briefly."
+ if("8")
+ usr << "\blue \icon[src] The load platform clunks."
+ if("16", "32")
+ usr << "\blue \icon[src] The drive motor whines briefly."
+ else
+ usr << "\blue \icon[src] You hear a radio crackle."
+ else
+ usr << "\blue You need a multitool!"
+
+
+
+ updateDialog()
+ //src.updateUsrDialog()
+ else
+ usr << browse(null, "window=mulebot")
+ usr.machine = null
+ return
+
+
+
+// returns true if the bot has power
+/obj/machinery/bot/mulebot/proc/has_power()
+ return !open && cell && cell.charge>0 && (wires & wire_power1) && (wires & wire_power2)
+
+// mousedrop a crate to load the bot
+// can load anything if emagged
+
+/obj/machinery/bot/mulebot/MouseDrop_T(var/atom/movable/C, mob/user)
+
+ if(user.stat)
+ return
+
+ if (!on || !istype(C)|| C.anchored || get_dist(user, src) > 1 || get_dist(src,C) > 1 )
+ return
+
+ if(load)
+ return
+
+ load(C)
+
+
+// called to load a crate
+/obj/machinery/bot/mulebot/proc/load(var/atom/movable/C)
+ if((wires & wire_loadcheck) && !istype(C,/obj/crate))
+ src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
+ playsound(src.loc, 'buzz-sigh.ogg', 50, 0)
+ return // if not emagged, only allow crates to be loaded
+
+ if(get_dist(C, src) > 1 || load || !on)
+ return
+ mode = 1
+
+ // if a create, close before loading
+ var/obj/crate/crate = C
+ if(istype(crate))
+ crate.close()
+
+ C.loc = src.loc
+ sleep(2)
+ C.loc = src
+ load = C
+
+ C.pixel_y += 9
+ if(C.layer < layer)
+ C.layer = layer + 0.1
+ overlays += C
+
+ if(ismob(C))
+ var/mob/M = C
+ if(M.client)
+ M.client.perspective = EYE_PERSPECTIVE
+ M.client.eye = src
+
+ mode = 0
+ send_status()
+
+// called to unload the bot
+// argument is optional direction to unload
+// if zero, unload at bot's location
+/obj/machinery/bot/mulebot/proc/unload(var/dirn = 0)
+ if(!load)
+ return
+
+ mode = 1
+ overlays = null
+
+ load.loc = src.loc
+ load.pixel_y -= 9
+ load.layer = initial(load.layer)
+ if(ismob(load))
+ var/mob/M = load
+ if(M.client)
+ M.client.perspective = MOB_PERSPECTIVE
+ M.client.eye = src
+
+
+ if(dirn)
+ step(load, dirn)
+
+ load = null
+
+ // in case non-load items end up in contents, dump every else too
+ // this seems to happen sometimes due to race conditions
+ // with items dropping as mobs are loaded
+
+ for(var/atom/movable/AM in src)
+ if(AM == cell || AM == botcard) continue
+
+ AM.loc = src.loc
+ AM.layer = initial(AM.layer)
+ AM.pixel_y = initial(AM.pixel_y)
+ if(ismob(AM))
+ var/mob/M = AM
+ if(M.client)
+ M.client.perspective = MOB_PERSPECTIVE
+ M.client.eye = src
+ mode = 0
+
+
+/obj/machinery/bot/mulebot/process()
+ if(!has_power())
+ on = 0
+ return
+ if(on)
+ var/speed = ((wires & wire_motor1) ? 1:0) + ((wires & wire_motor2) ? 2:0)
+ //world << "speed: [speed]"
+ switch(speed)
+ if(0)
+ // do nothing
+ if(1)
+ process_bot()
+ spawn(3)
+ process_bot()
+ sleep(3)
+ process_bot()
+ if(2)
+ process_bot()
+ spawn(5)
+ process_bot()
+ if(3)
+ process_bot()
+
+ if(refresh) updateDialog()
+
+/obj/machinery/bot/mulebot/proc/process_bot()
+ //if(mode) world << "Mode: [mode]"
+ switch(mode)
+ if(0) // idle
+ icon_state = "mulebot0"
+ return
+ if(1) // loading/unloading
+ return
+ if(2,3,4) // navigating to deliver,home, or blocked
+
+ if(loc == target) // reached target
+ at_target()
+ return
+
+ else if(path.len > 0 && target) // valid path
+
+ var/turf/next = path[1]
+ reached_target = 0
+ if(next == loc)
+ path -= next
+ return
+
+
+ if(istype( next, /turf/simulated))
+ //world << "at ([x],[y]) moving to ([next.x],[next.y])"
+
+
+ if(bloodiness)
+ var/obj/decal/cleanable/blood/tracks/B = new(loc)
+ var/newdir = get_dir(next, loc)
+ if(newdir == dir)
+ B.dir = newdir
+ else
+ newdir = newdir | dir
+ if(newdir == 3)
+ newdir = 1
+ else if(newdir == 12)
+ newdir = 4
+ B.dir = newdir
+ bloodiness--
+
+
+
+ var/moved = step_towards(src, next) // attempt to move
+ if(cell) cell.use(1)
+ if(moved) // successful move
+ //world << "Successful move."
+ blockcount = 0
+ path -= loc
+
+
+ if(mode==4)
+ spawn(1)
+ send_status()
+
+ if(destination == home_destination)
+ mode = 3
+ else
+ mode = 2
+
+ else // failed to move
+
+ //world << "Unable to move."
+
+
+
+ blockcount++
+ mode = 4
+ if(blockcount == 3)
+ src.visible_message("[src] makes an annoyed buzzing sound", "You hear an electronic buzzing sound.")
+ playsound(src.loc, 'buzz-two.ogg', 50, 0)
+
+ if(blockcount > 5) // attempt 5 times before recomputing
+ // find new path excluding blocked turf
+ src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
+ playsound(src.loc, 'buzz-sigh.ogg', 50, 0)
+
+ spawn(2)
+ calc_path(next)
+ if(path.len > 0)
+ src.visible_message("[src] makes a delighted ping!", "You hear a ping.")
+ playsound(src.loc, 'ping.ogg', 50, 0)
+ mode = 4
+ mode =6
+ return
+ return
+ else
+ src.visible_message("[src] makes an annoyed buzzing sound", "You hear an electronic buzzing sound.")
+ playsound(src.loc, 'buzz-two.ogg', 50, 0)
+ //world << "Bad turf."
+ mode = 5
+ return
+ else
+ //world << "No path."
+ mode = 5
+ return
+
+ if(5) // calculate new path
+ //world << "Calc new path."
+ mode = 6
+ spawn(0)
+
calc_path()
- updateDialog()
- // send a radio signal with a single data key/value pair
- proc/post_signal(var/freq, var/key, var/value)
- post_signal_multiple(freq, list("[key]" = value) )
+ if(path.len > 0)
+ blockcount = 0
+ mode = 4
+ src.visible_message("[src] makes a delighted ping!", "You hear a ping.")
+ playsound(src.loc, 'ping.ogg', 50, 0)
- // send a radio signal with multiple data key/values
- proc/post_signal_multiple(var/freq, var/list/keyval)
+ else
+ src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
+ playsound(src.loc, 'buzz-sigh.ogg', 50, 0)
- if(freq == beacon_freq && !(wires & wire_beacon_tx))
- return
- if(freq == control_freq && !(wires & wire_remote_tx))
- return
-
- var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
-
- if(!frequency) return
+ mode = 7
+ //if(6)
+ //world << "Pending path calc."
+ //if(7)
+ //world << "No dest / no route."
+ return
+// calculates a path to the current destination
+// given an optional turf to avoid
+/obj/machinery/bot/mulebot/proc/calc_path(var/turf/avoid = null)
+ src.path = AStar(src.loc, src.target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 250, id=botcard, exclude=avoid)
+ src.path = reverselist(src.path)
- var/datum/signal/signal = new()
- signal.source = src
- signal.transmission_method = 1
- //for(var/key in keyval)
- // signal.data[key] = keyval[key]
- signal.data = keyval
- //world << "sent [key],[keyval[key]] on [freq]"
- if (signal.data["findbeacon"])
- frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
- else if (signal.data["type"] == "mulebot")
- frequency.post_signal(src, signal, filter = RADIO_MULEBOT)
+
+// sets the current destination
+// signals all beacons matching the delivery code
+// beacons will return a signal giving their locations
+/obj/machinery/bot/mulebot/proc/set_destination(var/new_dest)
+ spawn(0)
+ new_destination = new_dest
+ post_signal(beacon_freq, "findbeacon", "delivery")
+ updateDialog()
+
+// starts bot moving to current destination
+/obj/machinery/bot/mulebot/proc/start()
+ if(destination == home_destination)
+ mode = 3
+ else
+ mode = 2
+ icon_state = "mulebot[(wires & wire_mobavoid) == wire_mobavoid]"
+
+// starts bot moving to home
+// sends a beacon query to find
+/obj/machinery/bot/mulebot/proc/start_home()
+ spawn(0)
+ set_destination(home_destination)
+ mode = 4
+ icon_state = "mulebot[(wires & wire_mobavoid) == wire_mobavoid]"
+
+// called when bot reaches current target
+/obj/machinery/bot/mulebot/proc/at_target()
+ if(!reached_target)
+ src.visible_message("[src] makes a chiming sound!", "You hear a chime.")
+ playsound(src.loc, 'chime.ogg', 50, 0)
+ reached_target = 1
+
+ if(load) // if loaded, unload at target
+ unload(loaddir)
else
- frequency.post_signal(src, signal)
+ // not loaded
+ if(auto_pickup) // find a crate
+ var/atom/movable/AM
+ if(!(wires & wire_loadcheck)) // if emagged, load first unanchored thing we find
+ for(var/atom/movable/A in get_step(loc, loaddir))
+ if(!A.anchored)
+ AM = A
+ break
+ else // otherwise, look for crates only
+ AM = locate(/obj/crate) in get_step(loc,loaddir)
+ if(AM)
+ load(AM)
+ // whatever happened, check to see if we return home
- // signals bot status etc. to controller
- proc/send_status()
- var/list/kv = list(
- "type" = "mulebot",
- "name" = suffix,
- "loca" = loc.loc, // area
- "mode" = mode,
- "powr" = (cell ? cell.percent() : 0),
- "dest" = destination,
- "home" = home_destination,
- "load" = load,
- "retn" = auto_return,
- "pick" = auto_pickup,
- )
- post_signal_multiple(control_freq, kv)
+ if(auto_return && destination != home_destination)
+ // auto return set and not at home already
+ start_home()
+ mode = 4
+ else
+ mode = 0 // otherwise go idle
+
+ send_status() // report status to anyone listening
+
+ return
+
+// called when bot bumps into anything
+/obj/machinery/bot/mulebot/Bump(var/atom/obs)
+ if(!(wires & wire_mobavoid)) //usually just bumps, but if avoidance disabled knock over mobs
+ var/mob/M = obs
+ if(ismob(M))
+ if(istype(M,/mob/living/silicon/robot))
+ src.visible_message("\red [src] bumps into [M]!")
+ else
+ src.visible_message("\red [src] knocks over [M]!")
+ M.pulling = null
+ M.stunned = 8
+ M.weakened = 5
+ M.lying = 1
+ ..()
+
+/obj/machinery/bot/mulebot/alter_health()
+ return get_turf(src)
+
+
+// called from mob/living/carbon/human/HasEntered()
+// when mulebot is in the same loc
+/obj/machinery/bot/mulebot/proc/RunOver(var/mob/living/carbon/human/H)
+ src.visible_message("\red [src] drives over [H]!")
+ playsound(src.loc, 'splat.ogg', 50, 1)
+
+ /*
+ if(ismob(load))
+ var/mob/M = load
+ if(M.reagents.has_reagent("beer"))
+ M.unlock_medal("DUI", 1)
+ if(M.reagents.has_reagent("space_drugs") && istype(H) && H.wear_id.assignment == "Security Officer")
+ M.unlock_medel("Ridin' Dirty",1)
+ */
+
+ var/damage = rand(5,15)
+
+ H.TakeDamage("head", 2*damage, 0)
+ H.TakeDamage("chest",2*damage, 0)
+ H.TakeDamage("l_leg",0.5*damage, 0)
+ H.TakeDamage("r_leg",0.5*damage, 0)
+ H.TakeDamage("l_arm",0.5*damage, 0)
+ H.TakeDamage("r_arm",0.5*damage, 0)
+
+ var/obj/decal/cleanable/blood/B = new(src.loc)
+ B.blood_DNA = H.dna.unique_enzymes
+ B.blood_type = H.b_type
+
+ bloodiness += 4
+
+// player on mulebot attempted to move
+/obj/machinery/bot/mulebot/relaymove(var/mob/user)
+ if(user.stat)
+ return
+ if(load == user)
+ unload(0)
+ return
+
+// receive a radio signal
+// used for control and beacon reception
+
+/obj/machinery/bot/mulebot/receive_signal(datum/signal/signal)
+
+ if(!on)
+ return
+
+ /*
+ world << "rec signal: [signal.source]"
+ for(var/x in signal.data)
+ world << "* [x] = [signal.data[x]]"
+ */
+ var/recv = signal.data["command"]
+ // process all-bot input
+ if(recv=="bot_status" && (wires & wire_remote_rx))
+ send_status()
+
+
+ recv = signal.data["command [suffix]"]
+ if(wires & wire_remote_rx)
+ // process control input
+ switch(recv)
+ if("stop")
+ mode = 0
+ return
+
+ if("go")
+ start()
+ return
+
+ if("target")
+ set_destination(signal.data["destination"] )
+ return
+
+ if("unload")
+ if(loc == target)
+ unload(loaddir)
+ else
+ unload(0)
+ return
+
+ if("home")
+ start_home()
+ return
+
+ if("bot_status")
+ send_status()
+ return
+
+ if("autoret")
+ auto_return = text2num(signal.data["value"])
+ return
+
+ if("autopick")
+ auto_pickup = text2num(signal.data["value"])
+ return
+
+ // receive response from beacon
+ recv = signal.data["beacon"]
+ if(wires & wire_beacon_rx)
+ if(recv == new_destination) // if the recvd beacon location matches the set destination
+ // the we will navigate there
+ destination = new_destination
+ target = signal.source.loc
+ var/direction = signal.data["dir"] // this will be the load/unload dir
+ if(direction)
+ loaddir = text2num(direction)
+ else
+ loaddir = 0
+ icon_state = "mulebot[(wires & wire_mobavoid) == wire_mobavoid]"
+ calc_path()
+ updateDialog()
+
+// send a radio signal with a single data key/value pair
+/obj/machinery/bot/mulebot/proc/post_signal(var/freq, var/key, var/value)
+ post_signal_multiple(freq, list("[key]" = value) )
+
+// send a radio signal with multiple data key/values
+/obj/machinery/bot/mulebot/proc/post_signal_multiple(var/freq, var/list/keyval)
+
+ if(freq == beacon_freq && !(wires & wire_beacon_tx))
+ return
+ if(freq == control_freq && !(wires & wire_remote_tx))
+ return
+
+ var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
+
+ if(!frequency) return
+ var/datum/signal/signal = new()
+ signal.source = src
+ signal.transmission_method = 1
+ //for(var/key in keyval)
+ // signal.data[key] = keyval[key]
+ signal.data = keyval
+ //world << "sent [key],[keyval[key]] on [freq]"
+ if (signal.data["findbeacon"])
+ frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
+ else if (signal.data["type"] == "mulebot")
+ frequency.post_signal(src, signal, filter = RADIO_MULEBOT)
+ else
+ frequency.post_signal(src, signal)
+
+// signals bot status etc. to controller
+/obj/machinery/bot/mulebot/proc/send_status()
+ var/list/kv = list(
+ "type" = "mulebot",
+ "name" = suffix,
+ "loca" = loc.loc, // area
+ "mode" = mode,
+ "powr" = (cell ? cell.percent() : 0),
+ "dest" = destination,
+ "home" = home_destination,
+ "load" = load,
+ "retn" = auto_return,
+ "pick" = auto_pickup,
+ )
+ post_signal_multiple(control_freq, kv)
+
+/obj/machinery/bot/mulebot/emp_act(severity)
+ if (cell)
+ cell.emp_act(severity)
+ if(load)
+ load.emp_act(severity)
+ ..()
+
+
+/obj/machinery/bot/mulebot/explode()
+ src.visible_message("\red [src] blows apart!", 1)
+ var/turf/Tsec = get_turf(src)
+
+ new /obj/item/device/prox_sensor(Tsec)
+ new /obj/item/stack/rods(Tsec)
+ new /obj/item/stack/rods(Tsec)
+ new /obj/item/weapon/cable_coil/cut(Tsec)
+ if (cell)
+ cell.loc = Tsec
+ cell.update_icon()
+ cell = null
+
+ var/datum/effects/system/spark_spread/s = new /datum/effects/system/spark_spread
+ s.set_up(3, 1, src)
+ s.start()
+
+ new /obj/decal/cleanable/oil(src.loc)
+ del(src)
\ No newline at end of file
diff --git a/code/game/machinery/bots/secbot.dm b/code/game/machinery/bots/secbot.dm
index 294f6d1445b..b76a5964d26 100644
--- a/code/game/machinery/bots/secbot.dm
+++ b/code/game/machinery/bots/secbot.dm
@@ -6,9 +6,12 @@
layer = 5.0
density = 1
anchored = 0
+ health = 25
+ maxhealth = 25
+ fire_dam_coeff = 0.7
+ brute_dam_coeff = 0.5
// weight = 1.0E7
req_access = list(access_security)
- var/on = 1
var/locked = 1 //Behavior Controls lock
var/mob/living/carbon/target
var/oldtarget_name
@@ -17,7 +20,6 @@
var/last_found //There's a delay
var/frustration = 0
var/emagged = 0 //Emagged Secbots view everyone as a criminal
- var/health = 25
var/idcheck = 1 //If false, all station IDs are authorized for weapons.
var/check_records = 1 //Does it check security records?
var/arrest_type = 0 //If true, don't handcuff
@@ -83,33 +85,45 @@
radio_controller.add_object(src, control_freq, filter = RADIO_SECBOT)
radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
- examine()
- set src in view()
- ..()
- if (src.health < 25)
- if (src.health > 15)
- usr << text("\red [src]'s parts look loose.")
- else
- usr << text("\red [src]'s parts look very loose!")
+/obj/machinery/bot/secbot/turn_on()
+ ..()
+ src.icon_state = "secbot[src.on]"
+ src.updateUsrDialog()
+
+/obj/machinery/bot/secbot/turn_off()
+ ..()
+ src.target = null
+ src.oldtarget_name = null
+ src.anchored = 0
+ src.mode = SECBOT_IDLE
+ walk_to(src,0)
+ src.icon_state = "secbot[src.on]"
+ src.updateUsrDialog()
+
+/obj/machinery/bot/secbot/attack_hand(mob/user as mob)
+ . = ..()
+ if (.)
return
+ usr.machine = src
+ interact(user)
- attack_hand(user as mob)
- var/dat
+/obj/machinery/bot/secbot/proc/interact(mob/user as mob)
+ var/dat
- dat += text({"
+ dat += text({"
Automatic Security Unit v1.3
-Status: []
-Behaviour controls are [src.locked ? "locked" : "unlocked"]"},
+/obj/machinery/bot/secbot/Status: []
+/obj/machinery/bot/secbot/Behaviour controls are [src.locked ? "locked" : "unlocked"]"},
"[src.on ? "On" : "Off"]" )
- if(!src.locked)
- dat += text({"
-Check for Weapon Authorization: []
-Check Security Records: []
-Operating Mode: []
-Auto Patrol: []"},
+ if(!src.locked)
+ dat += text({"
+/obj/machinery/bot/secbot/Check for Weapon Authorization: []
+/obj/machinery/bot/secbot/Check Security Records: []
+/obj/machinery/bot/secbot/Operating Mode: []
+/obj/machinery/bot/secbot/Auto Patrol: []"},
"[src.idcheck ? "Yes" : "No"]",
"[src.check_records ? "Yes" : "No"]",
@@ -117,621 +131,570 @@ Auto Patrol: []"},
"[auto_patrol ? "On" : "Off"]" )
- user << browse("Securitron v1.3 controls[dat]", "window=autosec")
- onclose(user, "autosec")
+ user << browse("Securitron v1.3 controls[dat]", "window=autosec")
+ onclose(user, "autosec")
+ return
+
+/obj/machinery/bot/secbot/Topic(href, href_list)
+ usr.machine = src
+ src.add_fingerprint(usr)
+ if ((href_list["power"]) && (src.allowed(usr)))
+ if (src.on)
+ turn_off()
+ else
+ turn_on()
return
- Topic(href, href_list)
- usr.machine = src
- src.add_fingerprint(usr)
- if ((href_list["power"]) && (src.allowed(usr)))
- src.on = !src.on
- src.target = null
- src.oldtarget_name = null
- src.anchored = 0
- src.mode = SECBOT_IDLE
- walk_to(src,0)
- src.icon_state = "secbot[src.on]"
+ switch(href_list["operation"])
+ if ("idcheck")
+ src.idcheck = !src.idcheck
src.updateUsrDialog()
-
- switch(href_list["operation"])
- if ("idcheck")
- src.idcheck = !src.idcheck
- src.updateUsrDialog()
- if ("ignorerec")
- src.check_records = !src.check_records
- src.updateUsrDialog()
- if ("switchmode")
- src.arrest_type = !src.arrest_type
- src.updateUsrDialog()
- if("patrol")
- auto_patrol = !auto_patrol
- mode = SECBOT_IDLE
- updateUsrDialog()
-
- attack_ai(mob/user as mob)
- src.on = !src.on
- src.target = null
- src.oldtarget_name = null
- mode = SECBOT_IDLE
- src.anchored = 0
- src.icon_state = "secbot[src.on]"
- walk_to(src,0)
-
- attackby(obj/item/weapon/W as obj, mob/user as mob)
- if ((istype(W, /obj/item/weapon/card/emag)) && (!src.emagged))
- user << "\red You short out [src]'s target assessment circuits."
- spawn(0)
- for(var/mob/O in hearers(src, null))
- O.show_message("\red [src] buzzes oddly!", 1)
- src.target = null
- src.oldtarget_name = user.name
- src.last_found = world.time
- src.anchored = 0
- src.emagged = 1
- src.on = 1
- src.icon_state = "secbot[src.on]"
+ if ("ignorerec")
+ src.check_records = !src.check_records
+ src.updateUsrDialog()
+ if ("switchmode")
+ src.arrest_type = !src.arrest_type
+ src.updateUsrDialog()
+ if("patrol")
+ auto_patrol = !auto_patrol
mode = SECBOT_IDLE
- else if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
- if (src.allowed(user))
- src.locked = !src.locked
- user << "Controls are now [src.locked ? "locked." : "unlocked."]"
- else
- user << "\red Access denied."
+ updateUsrDialog()
- else if (istype(W, /obj/item/weapon/screwdriver))
- if (src.health < 25)
- src.health = 25
- for(var/mob/O in viewers(src, null))
- O << "\red [user] repairs [src]!"
+/obj/machinery/bot/secbot/attack_ai(mob/user as mob)
+ if (src.on)
+ turn_off()
+ else
+ turn_on()
+
+/obj/machinery/bot/secbot/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if ((istype(W, /obj/item/weapon/card/emag)) && (!src.emagged))
+ user << "\red You short out [src]'s target assessment circuits."
+ spawn(0)
+ for(var/mob/O in hearers(src, null))
+ O.show_message("\red [src] buzzes oddly!", 1)
+ src.target = null
+ src.oldtarget_name = user.name
+ src.last_found = world.time
+ src.anchored = 0
+ src.emagged = 1
+ src.on = 1
+ src.icon_state = "secbot[src.on]"
+ mode = SECBOT_IDLE
+ else if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
+ if (src.allowed(user))
+ src.locked = !src.locked
+ user << "Controls are now [src.locked ? "locked." : "unlocked."]"
else
- switch(W.damtype)
- if("fire")
- src.health -= W.force * 0.75
- if("brute")
- src.health -= W.force * 0.5
- else
- if (src.health <= 0)
- src.explode()
- else if ((W.force) && (!src.target))
- src.target = user
- src.mode = SECBOT_HUNT
- ..()
+ user << "\red Access denied."
+ else
+ ..()
+ if (!istype(W, /obj/item/weapon/screwdriver) && (W.force) && (!src.target))
+ src.target = user
+ src.mode = SECBOT_HUNT
- process()
- set background = 1
+/obj/machinery/bot/secbot/process()
+ set background = 1
- if (!src.on)
- return
+ if (!src.on)
+ return
- switch(mode)
+ switch(mode)
- if(SECBOT_IDLE) // idle
+ if(SECBOT_IDLE) // idle
+ walk_to(src,0)
+ look_for_perp() // see if any criminals are in range
+ if(!mode && auto_patrol) // still idle, and set to patrol
+ mode = SECBOT_START_PATROL // switch to patrol mode
+
+ if(SECBOT_HUNT) // hunting for perp
+
+ // if can't reach perp for long enough, go idle
+ if (src.frustration >= 8)
+ // for(var/mob/O in hearers(src, null))
+ // O << "[src] beeps, \"Backup requested! Suspect has evaded arrest.\""
+ src.target = null
+ src.last_found = world.time
+ src.frustration = 0
+ src.mode = 0
walk_to(src,0)
- look_for_perp() // see if any criminals are in range
- if(!mode && auto_patrol) // still idle, and set to patrol
- mode = SECBOT_START_PATROL // switch to patrol mode
- if(SECBOT_HUNT) // hunting for perp
-
- // if can't reach perp for long enough, go idle
- if (src.frustration >= 8)
- // for(var/mob/O in hearers(src, null))
- // O << "[src] beeps, \"Backup requested! Suspect has evaded arrest.\""
- src.target = null
- src.last_found = world.time
- src.frustration = 0
- src.mode = 0
- walk_to(src,0)
-
- if (target) // make sure target exists
- if (get_dist(src, src.target) <= 1) // if right next to perp
- playsound(src.loc, 'Egloves.ogg', 50, 1, -1)
- src.icon_state = "secbot-c"
- spawn(2)
- src.icon_state = "secbot[src.on]"
- var/mob/living/carbon/M = src.target
- var/maxstuns = 4
- if (istype(M, /mob/living/carbon/human))
- if (M.weakened < 10 && (!(M.mutations & 8)) /*&& (!istype(M:wear_suit, /obj/item/clothing/suit/judgerobe))*/)
- M.weakened = 10
- if (M.stuttering < 10 && (!(M.mutations & 8)) /*&& (!istype(M:wear_suit, /obj/item/clothing/suit/judgerobe))*/)
- M.stuttering = 10
- if (M.stunned < 10 && (!(M.mutations & 8)) /*&& (!istype(M:wear_suit, /obj/item/clothing/suit/judgerobe))*/)
- M.stunned = 10
- else
+ if (target) // make sure target exists
+ if (get_dist(src, src.target) <= 1) // if right next to perp
+ playsound(src.loc, 'Egloves.ogg', 50, 1, -1)
+ src.icon_state = "secbot-c"
+ spawn(2)
+ src.icon_state = "secbot[src.on]"
+ var/mob/living/carbon/M = src.target
+ var/maxstuns = 4
+ if (istype(M, /mob/living/carbon/human))
+ if (M.weakened < 10 && (!(M.mutations & 8)) /*&& (!istype(M:wear_suit, /obj/item/clothing/suit/judgerobe))*/)
M.weakened = 10
+ if (M.stuttering < 10 && (!(M.mutations & 8)) /*&& (!istype(M:wear_suit, /obj/item/clothing/suit/judgerobe))*/)
M.stuttering = 10
+ if (M.stunned < 10 && (!(M.mutations & 8)) /*&& (!istype(M:wear_suit, /obj/item/clothing/suit/judgerobe))*/)
M.stunned = 10
- maxstuns--
- if (maxstuns <= 0)
- target = null
- for(var/mob/O in viewers(src, null))
- O.show_message("\red [src.target] has been stunned by [src]!", 1, "\red You hear someone fall", 2)
-
- mode = SECBOT_PREP_ARREST
- src.anchored = 1
- src.target_lastloc = M.loc
- return
-
- else // not next to perp
- var/turf/olddist = get_dist(src, src.target)
- walk_to(src, src.target,1,4)
- if ((get_dist(src, src.target)) >= (olddist))
- src.frustration++
- else
- src.frustration = 0
-
- if(SECBOT_PREP_ARREST) // preparing to arrest target
-
- // see if he got away
- if ((get_dist(src, src.target) > 1) || ((src.target:loc != src.target_lastloc) && src.target:weakened < 2))
- src.anchored = 0
- mode = SECBOT_HUNT
- return
-
- if (!src.target.handcuffed && !src.arrest_type)
- playsound(src.loc, 'handcuffs.ogg', 30, 1, -2)
- mode = SECBOT_ARREST
+ else
+ M.weakened = 10
+ M.stuttering = 10
+ M.stunned = 10
+ maxstuns--
+ if (maxstuns <= 0)
+ target = null
for(var/mob/O in viewers(src, null))
- O.show_message("\red [src] is trying to put handcuffs on [src.target]!", 1)
+ O.show_message("\red [src.target] has been stunned by [src]!", 1, "\red You hear someone fall", 2)
- spawn(60)
- if (get_dist(src, src.target) <= 1)
- if (src.target.handcuffed)
- return
-
- if(istype(src.target,/mob/living/carbon))
- src.target.handcuffed = new /obj/item/weapon/handcuffs(src.target)
-
- mode = SECBOT_IDLE
- src.target = null
- src.anchored = 0
- src.last_found = world.time
- src.frustration = 0
-
- playsound(src.loc, pick('bgod.ogg', 'biamthelaw.ogg', 'bsecureday.ogg', 'bradio.ogg', 'binsult.ogg', 'bcreep.ogg'), 50, 0)
- // var/arrest_message = pick("Have a secure day!","I AM THE LAW.", "God made tomorrow for the crooks we don't catch today.","You can't outrun a radio.")
- // src.speak(arrest_message)
-
- if(SECBOT_ARREST) // arresting
-
- if (src.target.handcuffed)
- src.anchored = 0
- mode = SECBOT_IDLE
+ mode = SECBOT_PREP_ARREST
+ src.anchored = 1
+ src.target_lastloc = M.loc
return
+ else // not next to perp
+ var/turf/olddist = get_dist(src, src.target)
+ walk_to(src, src.target,1,4)
+ if ((get_dist(src, src.target)) >= (olddist))
+ src.frustration++
+ else
+ src.frustration = 0
- if(SECBOT_START_PATROL) // start a patrol
+ if(SECBOT_PREP_ARREST) // preparing to arrest target
- if(path.len > 0 && patrol_target) // have a valid path, so just resume
- mode = SECBOT_PATROL
- return
+ // see if he got away
+ if ((get_dist(src, src.target) > 1) || ((src.target:loc != src.target_lastloc) && src.target:weakened < 2))
+ src.anchored = 0
+ mode = SECBOT_HUNT
+ return
- else if(patrol_target) // has patrol target already
- spawn(0)
- calc_path() // so just find a route to it
- if(path.len == 0)
- patrol_target = 0
+ if (!src.target.handcuffed && !src.arrest_type)
+ playsound(src.loc, 'handcuffs.ogg', 30, 1, -2)
+ mode = SECBOT_ARREST
+ for(var/mob/O in viewers(src, null))
+ O.show_message("\red [src] is trying to put handcuffs on [src.target]!", 1)
+
+ spawn(60)
+ if (get_dist(src, src.target) <= 1)
+ if (src.target.handcuffed)
return
- mode = SECBOT_PATROL
+ if(istype(src.target,/mob/living/carbon))
+ src.target.handcuffed = new /obj/item/weapon/handcuffs(src.target)
- else // no patrol target, so need a new one
- find_patrol_target()
- speak("Engaging patrol mode.")
+ mode = SECBOT_IDLE
+ src.target = null
+ src.anchored = 0
+ src.last_found = world.time
+ src.frustration = 0
+ playsound(src.loc, pick('bgod.ogg', 'biamthelaw.ogg', 'bsecureday.ogg', 'bradio.ogg', 'binsult.ogg', 'bcreep.ogg'), 50, 0)
+ // var/arrest_message = pick("Have a secure day!","I AM THE LAW.", "God made tomorrow for the crooks we don't catch today.","You can't outrun a radio.")
+ // src.speak(arrest_message)
- if(SECBOT_PATROL) // patrol mode
+ if(SECBOT_ARREST) // arresting
- patrol_step()
- spawn(5)
- if(mode == SECBOT_PATROL)
- patrol_step()
-
- if(SECBOT_SUMMON) // summoned to PDA
- patrol_step()
- spawn(4)
- if(mode == SECBOT_SUMMON)
- patrol_step()
- sleep(4)
- patrol_step()
-
- return
-
-
- // perform a single patrol step
-
- proc/patrol_step()
-
- if(loc == patrol_target) // reached target
- at_patrol_target()
- return
-
- else if(path.len > 0 && patrol_target) // valid path
-
- var/turf/next = path[1]
- if(next == loc)
- path -= next
+ if (src.target.handcuffed)
+ src.anchored = 0
+ mode = SECBOT_IDLE
return
- if(istype( next, /turf/simulated))
+ if(SECBOT_START_PATROL) // start a patrol
- var/moved = step_towards(src, next) // attempt to move
- if(moved) // successful move
- blockcount = 0
- path -= loc
-
- look_for_perp()
- else // failed to move
-
- blockcount++
-
- if(blockcount > 5) // attempt 5 times before recomputing
- // find new path excluding blocked turf
-
- spawn(2)
- calc_path(next)
- if(path.len == 0)
- find_patrol_target()
- else
- blockcount = 0
+ if(path.len > 0 && patrol_target) // have a valid path, so just resume
+ mode = SECBOT_PATROL
+ return
+ else if(patrol_target) // has patrol target already
+ spawn(0)
+ calc_path() // so just find a route to it
+ if(path.len == 0)
+ patrol_target = 0
return
+ mode = SECBOT_PATROL
+
+
+ else // no patrol target, so need a new one
+ find_patrol_target()
+ speak("Engaging patrol mode.")
+
+
+ if(SECBOT_PATROL) // patrol mode
+
+ patrol_step()
+ spawn(5)
+ if(mode == SECBOT_PATROL)
+ patrol_step()
+
+ if(SECBOT_SUMMON) // summoned to PDA
+ patrol_step()
+ spawn(4)
+ if(mode == SECBOT_SUMMON)
+ patrol_step()
+ sleep(4)
+ patrol_step()
+
+ return
+
+
+// perform a single patrol step
+
+/obj/machinery/bot/secbot/proc/patrol_step()
+
+ if(loc == patrol_target) // reached target
+ at_patrol_target()
+ return
+
+ else if(path.len > 0 && patrol_target) // valid path
+
+ var/turf/next = path[1]
+ if(next == loc)
+ path -= next
+ return
+
+
+ if(istype( next, /turf/simulated))
+
+ var/moved = step_towards(src, next) // attempt to move
+ if(moved) // successful move
+ blockcount = 0
+ path -= loc
+
+ look_for_perp()
+ else // failed to move
+
+ blockcount++
+
+ if(blockcount > 5) // attempt 5 times before recomputing
+ // find new path excluding blocked turf
+
+ spawn(2)
+ calc_path(next)
+ if(path.len == 0)
+ find_patrol_target()
+ else
+ blockcount = 0
return
- else // not a valid turf
- mode = SECBOT_IDLE
return
- else // no path, so calculate new one
- mode = SECBOT_START_PATROL
-
-
- // finds a new patrol target
- proc/find_patrol_target()
- send_status()
- if(awaiting_beacon) // awaiting beacon response
- awaiting_beacon++
- if(awaiting_beacon > 5) // wait 5 secs for beacon response
- find_nearest_beacon() // then go to nearest instead
+ else // not a valid turf
+ mode = SECBOT_IDLE
return
- if(next_destination)
- set_destination(next_destination)
+ else // no path, so calculate new one
+ mode = SECBOT_START_PATROL
+
+
+// finds a new patrol target
+/obj/machinery/bot/secbot/proc/find_patrol_target()
+ send_status()
+ if(awaiting_beacon) // awaiting beacon response
+ awaiting_beacon++
+ if(awaiting_beacon > 5) // wait 5 secs for beacon response
+ find_nearest_beacon() // then go to nearest instead
+ return
+
+ if(next_destination)
+ set_destination(next_destination)
+ else
+ find_nearest_beacon()
+ return
+
+
+// finds the nearest beacon to self
+// signals all beacons matching the patrol code
+/obj/machinery/bot/secbot/proc/find_nearest_beacon()
+ nearest_beacon = null
+ new_destination = "__nearest__"
+ post_signal(beacon_freq, "findbeacon", "patrol")
+ awaiting_beacon = 1
+ spawn(10)
+ awaiting_beacon = 0
+ if(nearest_beacon)
+ set_destination(nearest_beacon)
else
- find_nearest_beacon()
- return
-
-
- // finds the nearest beacon to self
- // signals all beacons matching the patrol code
- proc/find_nearest_beacon()
- nearest_beacon = null
- new_destination = "__nearest__"
- post_signal(beacon_freq, "findbeacon", "patrol")
- awaiting_beacon = 1
- spawn(10)
- awaiting_beacon = 0
- if(nearest_beacon)
- set_destination(nearest_beacon)
- else
- auto_patrol = 0
- mode = SECBOT_IDLE
- speak("Disengaging patrol mode.")
- send_status()
-
-
- proc/at_patrol_target()
- find_patrol_target()
- return
-
-
- // sets the current destination
- // signals all beacons matching the patrol code
- // beacons will return a signal giving their locations
- proc/set_destination(var/new_dest)
- new_destination = new_dest
- post_signal(beacon_freq, "findbeacon", "patrol")
- awaiting_beacon = 1
-
-
- // receive a radio signal
- // used for beacon reception
-
- receive_signal(datum/signal/signal)
- //log_admin("DEBUG \[[world.timeofday]\]: /obj/machinery/bot/secbot/receive_signal([signal.debug_print()])")
- if(!on)
- return
-
- /*
- world << "rec signal: [signal.source]"
- for(var/x in signal.data)
- world << "* [x] = [signal.data[x]]"
- */
-
- var/recv = signal.data["command"]
- // process all-bot input
- if(recv=="bot_status")
+ auto_patrol = 0
+ mode = SECBOT_IDLE
+ speak("Disengaging patrol mode.")
send_status()
- // check to see if we are the commanded bot
- if(signal.data["active"] == src)
- // process control input
- switch(recv)
- if("stop")
- mode = SECBOT_IDLE
- auto_patrol = 0
- return
- if("go")
- mode = SECBOT_IDLE
- auto_patrol = 1
- return
-
- if("summon")
- patrol_target = signal.data["target"]
- next_destination = destination
- destination = null
- awaiting_beacon = 0
- mode = SECBOT_SUMMON
- calc_path()
- speak("Responding.")
-
- return
+/obj/machinery/bot/secbot/proc/at_patrol_target()
+ find_patrol_target()
+ return
+// sets the current destination
+// signals all beacons matching the patrol code
+// beacons will return a signal giving their locations
+/obj/machinery/bot/secbot/proc/set_destination(var/new_dest)
+ new_destination = new_dest
+ post_signal(beacon_freq, "findbeacon", "patrol")
+ awaiting_beacon = 1
- // receive response from beacon
- recv = signal.data["beacon"]
- var/valid = signal.data["patrol"]
- if(!recv || !valid)
- return
- if(recv == new_destination) // if the recvd beacon location matches the set destination
- // the we will navigate there
- destination = new_destination
- patrol_target = signal.source.loc
- next_destination = signal.data["next_patrol"]
- awaiting_beacon = 0
+// receive a radio signal
+// used for beacon reception
- // if looking for nearest beacon
- else if(new_destination == "__nearest__")
- var/dist = get_dist(src,signal.source.loc)
- if(nearest_beacon)
-
- // note we ignore the beacon we are located at
- if(dist>1 && dist 1)
- nearest_beacon = recv
- nearest_beacon_loc = signal.source.loc
+/obj/machinery/bot/secbot/receive_signal(datum/signal/signal)
+ //log_admin("DEBUG \[[world.timeofday]\]: /obj/machinery/bot/secbot/receive_signal([signal.debug_print()])")
+ if(!on)
return
+ /*
+ world << "rec signal: [signal.source]"
+ for(var/x in signal.data)
+ world << "* [x] = [signal.data[x]]"
+ */
- // send a radio signal with a single data key/value pair
- proc/post_signal(var/freq, var/key, var/value)
- post_signal_multiple(freq, list("[key]" = value) )
+ var/recv = signal.data["command"]
+ // process all-bot input
+ if(recv=="bot_status")
+ send_status()
- // send a radio signal with multiple data key/values
- proc/post_signal_multiple(var/freq, var/list/keyval)
+ // check to see if we are the commanded bot
+ if(signal.data["active"] == src)
+ // process control input
+ switch(recv)
+ if("stop")
+ mode = SECBOT_IDLE
+ auto_patrol = 0
+ return
- var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
+ if("go")
+ mode = SECBOT_IDLE
+ auto_patrol = 1
+ return
- if(!frequency) return
+ if("summon")
+ patrol_target = signal.data["target"]
+ next_destination = destination
+ destination = null
+ awaiting_beacon = 0
+ mode = SECBOT_SUMMON
+ calc_path()
+ speak("Responding.")
- var/datum/signal/signal = new()
- signal.source = src
- signal.transmission_method = 1
- //for(var/key in keyval)
- // signal.data[key] = keyval[key]
- signal.data = keyval
- //world << "sent [key],[keyval[key]] on [freq]"
- if (signal.data["findbeacon"])
- frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
- else if (signal.data["type"] == "secbot")
- frequency.post_signal(src, signal, filter = RADIO_SECBOT)
- else
- frequency.post_signal(src, signal)
+ return
- // signals bot status etc. to controller
- proc/send_status()
- var/list/kv = new()
- kv["type"] = "secbot"
- kv["name"] = name
- kv["loca"] = loc.loc // area
- kv["mode"] = mode
- post_signal_multiple(control_freq, kv)
+
+
+ // receive response from beacon
+ recv = signal.data["beacon"]
+ var/valid = signal.data["patrol"]
+ if(!recv || !valid)
+ return
+
+ if(recv == new_destination) // if the recvd beacon location matches the set destination
+ // the we will navigate there
+ destination = new_destination
+ patrol_target = signal.source.loc
+ next_destination = signal.data["next_patrol"]
+ awaiting_beacon = 0
+
+ // if looking for nearest beacon
+ else if(new_destination == "__nearest__")
+ var/dist = get_dist(src,signal.source.loc)
+ if(nearest_beacon)
+
+ // note we ignore the beacon we are located at
+ if(dist>1 && dist 1)
+ nearest_beacon = recv
+ nearest_beacon_loc = signal.source.loc
+ return
+
+
+// send a radio signal with a single data key/value pair
+/obj/machinery/bot/secbot/proc/post_signal(var/freq, var/key, var/value)
+ post_signal_multiple(freq, list("[key]" = value) )
+
+// send a radio signal with multiple data key/values
+/obj/machinery/bot/secbot/proc/post_signal_multiple(var/freq, var/list/keyval)
+
+ var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
+
+ if(!frequency) return
+
+ var/datum/signal/signal = new()
+ signal.source = src
+ signal.transmission_method = 1
+ //for(var/key in keyval)
+ // signal.data[key] = keyval[key]
+ signal.data = keyval
+ //world << "sent [key],[keyval[key]] on [freq]"
+ if (signal.data["findbeacon"])
+ frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
+ else if (signal.data["type"] == "secbot")
+ frequency.post_signal(src, signal, filter = RADIO_SECBOT)
+ else
+ frequency.post_signal(src, signal)
+
+// signals bot status etc. to controller
+/obj/machinery/bot/secbot/proc/send_status()
+ var/list/kv = list(
+ "type" = "secbot",
+ "name" = name,
+ "loca" = loc.loc, // area
+ "mode" = mode
+ )
+ post_signal_multiple(control_freq, kv)
// calculates a path to the current destination
// given an optional turf to avoid
- proc/calc_path(var/turf/avoid = null)
- src.path = AStar(src.loc, patrol_target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 120, id=botcard, exclude=avoid)
- src.path = reverselist(src.path)
+/obj/machinery/bot/secbot/proc/calc_path(var/turf/avoid = null)
+ src.path = AStar(src.loc, patrol_target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 120, id=botcard, exclude=avoid)
+ src.path = reverselist(src.path)
// look for a criminal in view of the bot
- proc/look_for_perp()
- src.anchored = 0
- for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal
- if ((C.stat) || (C.handcuffed))
- continue
+/obj/machinery/bot/secbot/proc/look_for_perp()
+ src.anchored = 0
+ for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal
+ if ((C.stat) || (C.handcuffed))
+ continue
- if ((C.name == src.oldtarget_name) && (world.time < src.last_found + 100))
- continue
+ if ((C.name == src.oldtarget_name) && (world.time < src.last_found + 100))
+ continue
- if (istype(C, /mob/living/carbon/human))
- src.threatlevel = src.assess_perp(C)
- else if ((istype(C, /mob/living/carbon/monkey)) && (C.client) && (ticker.mode.name == "monkey"))
- src.threatlevel = 4
+ if (istype(C, /mob/living/carbon/human))
+ src.threatlevel = src.assess_perp(C)
+ else if ((istype(C, /mob/living/carbon/monkey)) && (C.client) && (ticker.mode.name == "monkey"))
+ src.threatlevel = 4
- if (!src.threatlevel)
- continue
+ if (!src.threatlevel)
+ continue
- else if (src.threatlevel >= 4)
- src.target = C
- src.oldtarget_name = C.name
- src.speak("Level [src.threatlevel] infraction alert!")
- playsound(src.loc, pick('bcriminal.ogg', 'bjustice.ogg', 'bfreeze.ogg'), 50, 0)
- src.visible_message("[src] points at [C.name]!")
- mode = SECBOT_HUNT
- spawn(0)
- process() // ensure bot quickly responds to a perp
- break
- else
- continue
+ else if (src.threatlevel >= 4)
+ src.target = C
+ src.oldtarget_name = C.name
+ src.speak("Level [src.threatlevel] infraction alert!")
+ playsound(src.loc, pick('bcriminal.ogg', 'bjustice.ogg', 'bfreeze.ogg'), 50, 0)
+ src.visible_message("[src] points at [C.name]!")
+ mode = SECBOT_HUNT
+ spawn(0)
+ process() // ensure bot quickly responds to a perp
+ break
+ else
+ continue
//If the security records say to arrest them, arrest them
//Or if they have weapons and aren't security, arrest them.
- proc/assess_perp(mob/living/carbon/human/perp as mob)
- var/threatcount = 0
+/obj/machinery/bot/secbot/proc/assess_perp(mob/living/carbon/human/perp as mob)
+ var/threatcount = 0
- if(src.emagged) return 10 //Everyone is a criminal!
+ if(src.emagged) return 10 //Everyone is a criminal!
- if((src.idcheck) || (isnull(perp:wear_id)) || (istype(perp:wear_id, /obj/item/weapon/card/id/syndicate)))
- if(src.allowed(perp)) //Corrupt cops cannot exist beep boop
- return 0
+ if((src.idcheck) || (isnull(perp:wear_id)) || (istype(perp:wear_id, /obj/item/weapon/card/id/syndicate)))
+ if(src.allowed(perp)) //Corrupt cops cannot exist beep boop
+ return 0
- if((istype(perp.l_hand, /obj/item/weapon/gun) && !istype(perp.l_hand, /obj/item/weapon/gun/shotgun)) || istype(perp.l_hand, /obj/item/weapon/baton))
- threatcount += 4
+ if((istype(perp.l_hand, /obj/item/weapon/gun) && !istype(perp.l_hand, /obj/item/weapon/gun/shotgun)) || istype(perp.l_hand, /obj/item/weapon/baton))
+ threatcount += 4
- if((istype(perp.r_hand, /obj/item/weapon/gun) && !istype(perp.r_hand, /obj/item/weapon/gun/shotgun)) || istype(perp.r_hand, /obj/item/weapon/baton))
- threatcount += 4
+ if((istype(perp.r_hand, /obj/item/weapon/gun) && !istype(perp.r_hand, /obj/item/weapon/gun/shotgun)) || istype(perp.r_hand, /obj/item/weapon/baton))
+ threatcount += 4
- if(istype(perp:belt, /obj/item/weapon/gun) || istype(perp:belt, /obj/item/weapon/baton))
- threatcount += 2
+ if(istype(perp:belt, /obj/item/weapon/gun) || istype(perp:belt, /obj/item/weapon/baton))
+ threatcount += 2
- if(istype(perp:wear_suit, /obj/item/clothing/suit/wizrobe))
- threatcount += 2
+ if(istype(perp:wear_suit, /obj/item/clothing/suit/wizrobe))
+ threatcount += 2
- if(perp.mutantrace && perp.mutantrace != "none")
- threatcount += 2
+ if(perp.mutantrace && perp.mutantrace != "none")
+ threatcount += 2
- //Agent cards lower threatlevel when normal idchecking is off.
- if((istype(perp:wear_id, /obj/item/weapon/card/id/syndicate)) && src.idcheck)
- threatcount -= 2
+//Agent cards lower threatlevel when normal idchecking is off.
+ if((istype(perp:wear_id, /obj/item/weapon/card/id/syndicate)) && src.idcheck)
+ threatcount -= 2
- if (src.check_records)
- for (var/datum/data/record/E in data_core.general)
- var/perpname = perp.name
- if (perp:wear_id)
- var/obj/item/weapon/card/id/id = perp:wear_id
- if(istype(perp:wear_id, /obj/item/device/pda))
- var/obj/item/device/pda/pda = perp:wear_id
- id = pda.id
- if (id)
- perpname = id.registered
- else
- var/obj/item/device/pda/pda = perp:wear_id
- perpname = pda.owner
- if (E.fields["name"] == perpname)
- for (var/datum/data/record/R in data_core.security)
- if ((R.fields["id"] == E.fields["id"]) && (R.fields["criminal"] == "*Arrest*"))
- threatcount = 4
- break
+ if (src.check_records)
+ for (var/datum/data/record/E in data_core.general)
+ var/perpname = perp.name
+ if (perp:wear_id)
+ var/obj/item/weapon/card/id/id = perp:wear_id
+ if(istype(perp:wear_id, /obj/item/device/pda))
+ var/obj/item/device/pda/pda = perp:wear_id
+ id = pda.id
+ if (id)
+ perpname = id.registered
+ else
+ var/obj/item/device/pda/pda = perp:wear_id
+ perpname = pda.owner
+ if (E.fields["name"] == perpname)
+ for (var/datum/data/record/R in data_core.security)
+ if ((R.fields["id"] == E.fields["id"]) && (R.fields["criminal"] == "*Arrest*"))
+ threatcount = 4
+ break
- return threatcount
+ return threatcount
- Bump(M as mob|obj) //Leave no door unopened!
- spawn(0)
- if ((istype(M, /obj/machinery/door)) && (!isnull(src.botcard)))
- var/obj/machinery/door/D = M
- if (!istype(D, /obj/machinery/door/firedoor) && D.check_access(src.botcard))
- D.open()
- src.frustration = 0
- else if ((istype(M, /mob/living/)) && (!src.anchored))
- src.loc = M:loc
+/obj/machinery/bot/secbot/Bump(M as mob|obj) //Leave no door unopened!
+ spawn(0)
+ if ((istype(M, /obj/machinery/door)) && (!isnull(src.botcard)))
+ var/obj/machinery/door/D = M
+ if (!istype(D, /obj/machinery/door/firedoor) && D.check_access(src.botcard))
+ D.open()
src.frustration = 0
+ else if ((istype(M, /mob/living/)) && (!src.anchored))
+ src.loc = M:loc
+ src.frustration = 0
- return
return
+ return
- Bumped(M as mob|obj)
- spawn(0)
- var/turf/T = get_turf(src)
- M:loc = T
+/obj/machinery/bot/secbot/Bumped(M as mob|obj)
+ spawn(0)
+ var/turf/T = get_turf(src)
+ M:loc = T
- bullet_act(flag, A as obj)
- switch(flag)
- if (PROJECTILE_BULLET)
- src.health -= 20
- //if (PROJECTILE_WEAKBULLET || PROJECTILE_BEANBAG) //Detective's revolver fires marshmallows
- // src.health -= 2
- if (PROJECTILE_LASER)
- src.health -= 10
- if (PROJECTILE_PULSE)
- src.health -=40
- if (src.health <= 0)
- src.explode()
-
- proc/speak(var/message)
- for(var/mob/O in hearers(src, null))
- O << "[src] beeps, \"[message]\""
- return
-
- //Generally we want to explode() instead of just deleting the securitron.
- ex_act(severity)
- switch(severity)
- if(1.0)
- src.explode()
- return
- if(2.0)
- src.health -= 15
- if (src.health <= 0)
- src.explode()
- return
- return
-
- meteorhit()
- src.explode()
- return
-
- blob_act()
- if(prob(50))
- src.explode()
- return
-
- proc/explode()
-
- walk_to(src,0)
- for(var/mob/O in hearers(src, null))
- O.show_message("\red [src] blows apart!", 1)
- var/turf/Tsec = get_turf(src)
-
- var/obj/item/weapon/secbot_assembly/Sa = new /obj/item/weapon/secbot_assembly(Tsec)
- Sa.build_step = 1
- Sa.overlays += image('aibots.dmi', "hs_hole")
- Sa.created_name = src.name
- new /obj/item/device/prox_sensor(Tsec)
-
- var/obj/item/weapon/baton/B = new /obj/item/weapon/baton(Tsec)
- B.charges = 0
-
- if (prob(50))
- new /obj/item/robot_parts/l_arm(Tsec)
-
- var/datum/effects/system/spark_spread/s = new /datum/effects/system/spark_spread
- s.set_up(3, 1, src)
- s.start()
- del(src)
+/obj/machinery/bot/secbot/proc/speak(var/message)
+ for(var/mob/O in hearers(src, null))
+ O << "[src] beeps, \"[message]\""
+ return
+/obj/machinery/bot/secbot/explode()
+ walk_to(src,0)
+ src.visible_message("\red [src] blows apart!", 1)
+ var/turf/Tsec = get_turf(src)
+ var/obj/item/weapon/secbot_assembly/Sa = new /obj/item/weapon/secbot_assembly(Tsec)
+ Sa.build_step = 1
+ Sa.overlays += image('aibots.dmi', "hs_hole")
+ Sa.created_name = src.name
+ new /obj/item/device/prox_sensor(Tsec)
+ var/obj/item/weapon/baton/B = new /obj/item/weapon/baton(Tsec)
+ B.charges = 0
+
+ if (prob(50))
+ new /obj/item/robot_parts/l_arm(Tsec)
+
+ var/datum/effects/system/spark_spread/s = new /datum/effects/system/spark_spread
+ s.set_up(3, 1, src)
+ s.start()
+
+ new /obj/decal/cleanable/oil(src.loc)
+ del(src)
+
+/obj/machinery/bot/secbot/attack_alien(var/mob/living/carbon/alien/user as mob)
+ ..()
+ if (!isalien(target))
+ src.target = user
+ src.mode = SECBOT_HUNT
//Secbot Construction
@@ -798,4 +761,4 @@ Auto Patrol: []"},
if (!in_range(src, usr) && src.loc != usr)
return
- src.created_name = t
\ No newline at end of file
+ src.created_name = t
diff --git a/code/game/objects/devices/PDA/radio.dm b/code/game/objects/devices/PDA/radio.dm
index de232604e5f..8cd587dac5d 100644
--- a/code/game/objects/devices/PDA/radio.dm
+++ b/code/game/objects/devices/PDA/radio.dm
@@ -127,7 +127,7 @@
radio_controller.add_object(src, control_freq, filter = RADIO_MULEBOT)
radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
spawn(10)
- post_signal(beacon_freq, "findbeacon", "delivery", filter = RADIO_NAVBEACONS)
+ post_signal(beacon_freq, "findbeacon", "delivery", s_filter = RADIO_NAVBEACONS)
// receive radio signals
// can detect bot status signals
diff --git a/code/game/objects/storage/toolbox.dm b/code/game/objects/storage/toolbox.dm
index 410ad545262..c91050ce95c 100644
--- a/code/game/objects/storage/toolbox.dm
+++ b/code/game/objects/storage/toolbox.dm
@@ -6,7 +6,7 @@
/obj/item/weapon/storage/toolbox/emergency/New()
..()
- new /obj/item/weapon/crowbar(src)
+ new /obj/item/weapon/crowbar/red(src)
new /obj/item/weapon/extinguisher(src)
new /obj/item/device/flashlight(src)
new /obj/item/device/radio(src)
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 3621ca01c8c..47b88f6af7e 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -1402,7 +1402,9 @@
src << "Here's your rightclick admin verbs back"
src.verbs -= /client/proc/unstealthadmin
+ var/temp = src.deadchat
src.update_admins(src.holder.rank)
+ src.deadchat = temp
/client/proc/stealthadmin()
set name = "Toggle admin verb visibility"
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index 3d9dc9f9edf..a4aec223567 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -63,6 +63,8 @@
":b" = "binary",
":a" = "alientalk",
":t" = "Syndicate",
+ ":d" = "Mining",
+ ":q" = "Cargo",
//kinda localization -- rastaf0
//same keys as above, but on russian keyboard layout. This file uses cp1251 as encoding.
@@ -79,6 +81,8 @@
":è" = "binary",
":ô" = "alientalk",
":å" = "Syndicate",
+ ":â" = "Mining",
+ ":é" = "Cargo",
)
message_mode = keys[channel_prefix]
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index fb868f79b66..1a8b86fa36a 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -1222,7 +1222,8 @@
var/obj/item/weapon/grab/G = src.l_hand
if (!( L.container.Find(G.affecting) ))
L.container += G.affecting
- G.affecting.ret_grab(L, 1)
+ if (G.affecting)
+ G.affecting.ret_grab(L, 1)
if (istype(src.r_hand, /obj/item/weapon/grab))
var/obj/item/weapon/grab/G = src.r_hand
if (!( L.container.Find(G.affecting) ))
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index b7b66db72c8..275f637b5d2 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -232,6 +232,8 @@ mob/new_player
AttemptLateSpawn("Warden", wardenMax)
if ("29")
AttemptLateSpawn("Shaft Miner", minerMax)
+ if ("30")
+ AttemptLateSpawn("Mime", mimeMax)
if(!ready && href_list["preferences"])
preferences.process_link(src, href_list)
@@ -376,6 +378,9 @@ mob/new_player
if (IsJobAvailable("Clown",clownMax))
dat += "Clown
"
+ if (IsJobAvailable("Mime",mimeMax))
+ dat += "Mime
"
+
if (IsJobAvailable("Chef",chefMax))
dat += "Chef
"
diff --git a/code/setup.dm b/code/setup.dm
index b1e928ac466..9d4f7003476 100644
--- a/code/setup.dm
+++ b/code/setup.dm
@@ -135,6 +135,7 @@
#define NOPOWER 2
#define POWEROFF 4 // tbd
#define MAINT 8 // under maintaince
+#define EMPED 16 // temporary broken by EMP pulse
#define ENGINE_EJECT_Z 3
diff --git a/icons/changelog.html b/icons/changelog.html
index 6647b9b4595..ba0ac8e8d06 100644
--- a/icons/changelog.html
+++ b/icons/changelog.html
@@ -30,7 +30,7 @@
Credits:
- Coders: TLE, NEO, Errorage, muskets, veryinky, Skie, Numbers, Agouri, Noka, Urist McDorf, Uhangi, Darem, Mport
+ Coders: TLE, NEO, Errorage, muskets, veryinky, Skie, Numbers, Agouri, Noka, Urist McDorf, Uhangi, Darem, Mport, rastaf0
Spriters: Agouri, Cheridan, Cruazy Guest, Deeaych, Deuryn, Matty406, Microwave, ShiftyEyesShady, Skie, Uhangi, Veyveyr
Sounds: Skie
Thanks to: CDK Station devs, GoonStation devs, the original SpaceStation developers and Erikat for the title image
@@ -43,6 +43,11 @@
- Rastaf0 updated:
+ - Added radio channels and headsets for miners (:h or :d ("diggers" lol)) and for cargo techs (:h or :q )
+ - Added a personal headsets to HoP and QM.
+ - Aliens now attack bots instead of opening control window.
+ - All bots can be damaged and repaired.
+ - All bots are effected to EMP now.
- Atmos now starts with nitrous oxide in storage tank.
diff --git a/icons/obj/aibots.dmi b/icons/obj/aibots.dmi
index f1cfac3305e..8651fa47b27 100644
Binary files a/icons/obj/aibots.dmi and b/icons/obj/aibots.dmi differ
diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi
index 24f78b1d334..7b5aa3b599c 100644
Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ
diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi
index 2c875cd0dfb..498c0e7d151 100644
Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ
diff --git a/icons/obj/radio.dmi b/icons/obj/radio.dmi
new file mode 100644
index 00000000000..d066b144abb
Binary files /dev/null and b/icons/obj/radio.dmi differ
|