1)
- nearest_beacon = recv
- nearest_beacon_loc = signal.source.loc
+ mode = BOT_PREP_ARREST
+ anchored = 0
+
+ if(BOT_START_PATROL)
+ look_for_perp()
+ start_patrol()
+
+ if(BOT_PATROL)
+ look_for_perp()
+ bot_patrol()
+
+ if(BOT_SUMMON)
+ bot_summon()
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
-/obj/machinery/bot/ed209/proc/calc_path(var/turf/avoid = null)
- src.path = AStar(src.loc, patrol_target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 120, id=botcard, exclude=avoid)
- if(!src.path)
- src.path = list()
-
-
// look for a criminal in view of the bot
/obj/machinery/bot/ed209/proc/look_for_perp()
@@ -681,7 +389,7 @@ Auto Patrol: []"},
if(!src.lasercolor)
playsound(src.loc, pick('sound/voice/ed209_20sec.ogg', 'sound/voice/EDPlaceholder.ogg'), 50, 0)
src.visible_message("[src] points at [C.name]!")
- mode = SECBOT_HUNT
+ mode = BOT_HUNT
spawn(0)
process() // ensure bot quickly responds to a perp
break
@@ -807,7 +515,7 @@ Auto Patrol: []"},
..()
if (!isalien(target))
src.target = user
- src.mode = SECBOT_HUNT
+ src.mode = BOT_HUNT
/obj/machinery/bot/ed209/emp_act(severity)
@@ -844,7 +552,7 @@ Auto Patrol: []"},
var/mob/toarrest = pick(targets)
if (toarrest)
src.target = toarrest
- src.mode = SECBOT_HUNT
+ src.mode = BOT_HUNT
@@ -958,14 +666,14 @@ Auto Patrol: []"},
return
build_step++
user << "You add [W] to [src]."
- src.item_state = "[lasercolor]ed209_taser"
- src.icon_state = "[lasercolor]ed209_taser"
+ item_state = "[lasercolor]ed209_taser"
+ icon_state = "[lasercolor]ed209_taser"
user.drop_item()
qdel(W)
if(8)
if(istype(W, /obj/item/weapon/screwdriver))
- playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1)
+ playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1)
var/turf/T = get_turf(user)
user << "Now attaching the gun to the frame..."
sleep(40)
@@ -989,18 +697,18 @@ Auto Patrol: []"},
/obj/machinery/bot/ed209/bullet_act(var/obj/item/projectile/Proj)
if(!disabled)
var/lasertag_check = 0
- if((src.lasercolor == "b"))
+ if((lasercolor == "b"))
if(istype(Proj, /obj/item/projectile/lasertag/redtag))
lasertag_check++
- else if((src.lasercolor == "r"))
+ else if((lasercolor == "r"))
if(istype(Proj, /obj/item/projectile/lasertag/bluetag))
lasertag_check++
if(lasertag_check)
icon_state = "[lasercolor]ed2090"
- src.disabled = 1
+ disabled = 1
target = null
spawn(100)
- src.disabled = 0
+ disabled = 0
icon_state = "[lasercolor]ed2091"
return 1
else
diff --git a/code/game/machinery/bots/floorbot.dm b/code/game/machinery/bots/floorbot.dm
index 8f0e67df3b4..ff349864af9 100644
--- a/code/game/machinery/bots/floorbot.dm
+++ b/code/game/machinery/bots/floorbot.dm
@@ -36,35 +36,56 @@
maxhealth = 25
//weight = 1.0E7
var/amount = 10
- var/repairing = 0
- var/improvefloors = 0
+ var/replacetiles = 0
var/eattiles = 0
var/maketiles = 0
+ var/fixfloors = 0
+ var/autotile = 0
+ var/nag_on_empty = 1
+ var/nagged = 0 //Prevents the Floorbot nagging more than once per refill.
+ var/max_targets = 50
var/turf/target
var/turf/oldtarget
+ var/list/ignore_list = list() //List of unreachable targets
var/oldloc = null
- req_access = list(access_construction)
- var/path[] = new()
+ req_one_access = list(access_construction, access_robotics)
var/targetdirection
-
+ radio_frequency = 1357 //Engineering channel
+ bot_type = FLOOR_BOT
+ bot_filter = RADIO_FLOORBOT
/obj/machinery/bot/floorbot/New()
..()
- src.updateicon()
+ updateicon()
+ var/datum/job/engineer/J = new/datum/job/engineer
+ botcard.access = J.get_access()
+ prev_access = botcard.access
+
+ spawn(5)
+ add_to_beacons(bot_filter)
/obj/machinery/bot/floorbot/turn_on()
. = ..()
- src.updateicon()
- src.updateUsrDialog()
+ updateicon()
+ updateUsrDialog()
/obj/machinery/bot/floorbot/turn_off()
..()
- src.target = null
- src.oldtarget = null
- src.oldloc = null
- src.updateicon()
- src.path = new()
- src.updateUsrDialog()
+ updateicon()
+ updateUsrDialog()
+
+/obj/machinery/bot/floorbot/bot_reset()
+ ..()
+ target = null
+ oldtarget = null
+ oldloc = null
+ ignore_list = list()
+ nagged = 0
+
+/obj/machinery/bot/floorbot/set_custom_texts()
+ text_hack = "You corrupt [name]'s construction protocols."
+ text_dehack = "You detect errors in [name] and reset his programming."
+ text_dehack_fail = "[name] is not responding to reset commands!"
/obj/machinery/bot/floorbot/attack_hand(mob/user as mob)
. = ..()
@@ -76,44 +97,50 @@
/obj/machinery/bot/floorbot/interact(mob/user as mob)
var/dat
dat += hack(user)
- dat += "Automatic Station Floor Repairer v1.0
"
- dat += "Status: [src.on ? "On" : "Off"]
"
- dat += "Maintenance panel panel is [src.open ? "opened" : "closed"]
"
- dat += "Tiles left: [src.amount]
"
- dat += "Behvaiour controls are [src.locked ? "locked" : "unlocked"]
"
- if(!src.locked || issilicon(user))
- dat += "Improves floors: [src.improvefloors ? "Yes" : "No"]
"
- dat += "Finds tiles: [src.eattiles ? "Yes" : "No"]
"
- dat += "Make singles pieces of metal into tiles when empty: [src.maketiles ? "Yes" : "No"]
"
+ dat += "Floor Repairer Controls v1.1
"
+ dat += "Status: [on ? "On" : "Off"]
"
+ dat += "Maintenance panel panel is [open ? "opened" : "closed"]
"
+ dat += "Tiles left: [amount]
"
+ dat += "Behvaiour controls are [locked ? "locked" : "unlocked"]
"
+ if(!locked || issilicon(user))
+ dat += "Add tiles to new hull plating: [autotile ? "Yes" : "No"]
"
+ dat += "Replace floor tiles: [replacetiles ? "Yes" : "No"]
"
+ dat += "Finds tiles: [eattiles ? "Yes" : "No"]
"
+ dat += "Make pieces of metal into tiles when empty: [maketiles ? "Yes" : "No"]
"
+ dat += "Transmit notice when empty: [nag_on_empty ? "Yes" : "No"]
"
+ dat += "Repair damaged tiles and platings: [fixfloors ? "Yes" : "No"]
"
+ dat += "Patrol Station: [auto_patrol ? "Yes" : "No"]
"
var/bmode
- if (src.targetdirection)
- bmode = dir2text(src.targetdirection)
+ if (targetdirection)
+ bmode = dir2text(targetdirection)
else
bmode = "Disabled"
dat += "
Bridge Mode : [bmode]
"
- user << browse("Repairbot v1.0 controls[dat]", "window=autorepair")
- onclose(user, "autorepair")
+ var/datum/browser/popup = new(user, "autofloor", "Automatic Station Floor Repairer v1.1")
+ popup.set_content(dat)
+ popup.open()
return
/obj/machinery/bot/floorbot/attackby(var/obj/item/W , mob/user as mob)
if(istype(W, /obj/item/stack/tile/plasteel))
var/obj/item/stack/tile/plasteel/T = W
- if(src.amount >= 50)
+ if(amount >= 50)
return
- var/loaded = min(50 - src.amount, T.get_amount())
+ var/loaded = min(50-amount, T.amount)
T.use(loaded)
- src.amount += loaded
+ amount += loaded
if (loaded > 0)
- user << "You load [loaded] tiles into the floorbot. He now contains [src.amount] tiles."
- src.updateicon()
+ user << "You load [loaded] tiles into the floorbot. He now contains [amount] tiles."
+ nagged = 0
+ updateicon()
else
- user << "You need at least one floor tile to put into the floorbot."
+ user << "You need at least one floor tile to put into [src]"
else if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
- if(src.allowed(usr) && !open && !emagged)
- src.locked = !src.locked
- user << "You [src.locked ? "lock" : "unlock"] the [src] behaviour controls."
+ if(allowed(user) && !open && !emagged)
+ locked = !locked
+ user << "You [locked ? "lock" : "unlock"] the [src] behaviour controls."
else
if(emagged)
user << "ERROR"
@@ -121,49 +148,33 @@
user << "Please close the access panel before locking it."
else
user << "Access denied."
- src.updateUsrDialog()
+ updateUsrDialog()
else
..()
/obj/machinery/bot/floorbot/Emag(mob/user as mob)
..()
- if(open && !locked)
- if(user) user << "The [src] buzzes and beeps."
+ if(emagged == 2)
+ if(user) user << "[src] buzzes and beeps."
/obj/machinery/bot/floorbot/Topic(href, href_list)
- if(..())
- return
- usr.set_machine(src)
- src.add_fingerprint(usr)
+ ..()
switch(href_list["operation"])
- if("start")
- if (src.on && !src.emagged)
- turn_off()
- else
- turn_on()
- if("improve")
- src.improvefloors = !src.improvefloors
- src.updateUsrDialog()
+ if("replace")
+ replacetiles = !replacetiles
if("tiles")
- src.eattiles = !src.eattiles
- src.updateUsrDialog()
+ eattiles = !eattiles
if("make")
- src.maketiles = !src.maketiles
- src.updateUsrDialog()
- if("hack")
- if(!src.emagged)
- src.emagged = 2
- src.hacked = 1
- usr << "You corrupt [src]'s construction protocols."
- else if(!src.hacked)
- usr << "[src] is not responding to reset commands!"
- else
- src.emagged = 0
- src.hacked = 0
- usr << "You detect errors in [src] and reset its programming."
- src.updateUsrDialog()
+ maketiles = !maketiles
+ if("fix")
+ fixfloors = !fixfloors
+ if("autotile")
+ autotile = !autotile
+ if("emptynag")
+ nag_on_empty = !nag_on_empty
+
if("bridgemode")
- switch(src.targetdirection)
+ switch(targetdirection)
if(null)
targetdirection = 1
if(1)
@@ -176,210 +187,269 @@
targetdirection = null
else
targetdirection = null
- src.updateUsrDialog()
+ updateUsrDialog()
/obj/machinery/bot/floorbot/process()
set background = BACKGROUND_ENABLED
- if(!src.on)
+ if(!on)
return
- if(src.repairing)
+
+ if(call_path)
+ call_mode()
return
- var/list/floorbottargets = list()
- if(src.amount <= 0 && ((src.target == null) || !src.target))
- if(src.eattiles)
+
+ if(mode == BOT_SUMMON)
+ bot_summon()
+ return
+
+ if(amount <= 0 && !target)
+ if(eattiles)
for(var/obj/item/stack/tile/plasteel/T in view(7, src))
- if(T != src.oldtarget && !(target in floorbottargets))
- src.oldtarget = T
- src.target = T
+ if(T != oldtarget && !(target in ignore_list))
+ oldtarget = T
+ target = T
break
- if(src.target == null || !src.target)
- if(src.maketiles)
- if(src.target == null || !src.target)
+ if(!target)
+ if(maketiles)
+ if(!target)
for(var/obj/item/stack/sheet/metal/M in view(7, src))
- if(!(M in floorbottargets) && M != src.oldtarget && M.amount == 1 && !(istype(M.loc, /turf/simulated/wall)))
- src.oldtarget = M
- src.target = M
+ if(!(M in ignore_list) && M != oldtarget && !(istype(M.loc, /turf/simulated/wall)))
+ oldtarget = M
+ target = M
break
else
return
+ if(nag_on_empty) //Floorbot is empty and cannot acquire more tiles, nag the engineers for more!
+ nag()
if(prob(5))
visible_message("[src] makes an excited booping beeping sound!")
- if((!src.target || src.target == null) && emagged < 2)
- if(targetdirection != null)
- /*
+ if(!target && emagged < 2 && amount > 0)
+ if(targetdirection != null) //The bot is in bridge mode.
+
for (var/turf/space/D in view(7,src))
- if(!(D in floorbottargets) && D != src.oldtarget) // Added for bridging mode
+ if(!(D in ignore_list) && D != oldtarget) // Added for bridging mode
if(get_dir(src, D) == targetdirection)
- src.oldtarget = D
- src.target = D
+ oldtarget = D
+ target = D
break
- */
+
var/turf/T = get_step(src, targetdirection)
if(istype(T, /turf/space))
- src.oldtarget = T
- src.target = T
- if(!src.target || src.target == null)
- for (var/turf/space/D in view(7,src))
- if(!(D in floorbottargets) && D != src.oldtarget && (D.loc.name != "Space"))
- src.oldtarget = D
- src.target = D
+ oldtarget = T
+ target = T
+ if(!target)
+ for (var/turf/space/D in view(7,src)) //Ensures the floorbot does not try to "fix" space areas or shuttle docking zones.
+ if(!(D in ignore_list) && D != oldtarget && is_hull_breach(D))
+ mode = BOT_MOVING
+ oldtarget = D
+ target = D
break
- if((!src.target || src.target == null ) && src.improvefloors)
+ if(!target && replacetiles) //Finds a floor without a tile and gives it one.
for (var/turf/simulated/floor/F in view(7,src))
- if(!(F in floorbottargets) && F != src.oldtarget && F.icon_state == "Floor1" && !(istype(F, /turf/simulated/floor/plating)))
- src.oldtarget = F
- src.target = F
+ //The target must be the floor and not a tile. The floor must not already have a floortile.
+ if(!(F in ignore_list) && F != oldtarget && F.is_plating())
+ oldtarget = F
+ target = F
+ mode = BOT_MOVING
break
- if((!src.target || src.target == null) && src.eattiles)
- for(var/obj/item/stack/tile/plasteel/T in view(7, src))
- if(!(T in floorbottargets) && T != src.oldtarget)
- src.oldtarget = T
- src.target = T
+ if(!target && fixfloors) //Repairs damaged floors and tiles.
+ for(var/turf/simulated/floor/F in view(7, src))
+ if(!(F in ignore_list) && F != oldtarget && (F.broken || F.burnt))
+ oldtarget = F
+ target = F
+ mode = BOT_MOVING
break
- if((!src.target || src.target == null) && emagged == 2)
- if(!src.target || src.target == null)
+ if(!target && emagged == 2)
+ if(!target)
for (var/turf/simulated/floor/D in view(7,src))
- if(!(D in floorbottargets) && D != src.oldtarget && D.floor_tile)
- src.oldtarget = D
- src.target = D
+ if(!(D in ignore_list) && D != oldtarget && D.floor_tile)
+ oldtarget = D
+ target = D
+ mode = BOT_MOVING
break
- if(!src.target || src.target == null)
- if(src.loc != src.oldloc)
- src.oldtarget = null
+ if(!target)
+
+ if(auto_patrol)
+ if(mode == BOT_IDLE || mode == BOT_START_PATROL)
+ start_patrol()
+
+ if(mode == BOT_PATROL)
+ bot_patrol()
+
+ if(!target)
+ if(loc != oldloc)
+ oldtarget = null
return
- if(src.target && (src.target != null) && src.path.len == 0)
+ if(target && path.len == 0)
spawn(0)
- if(!istype(src.target, /turf/))
+ if(!istype(target, /turf/))
var/turf/TL = get_turf(target)
- src.path = AStar(src.loc, TL, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30)
+ path = AStar(loc, TL, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30, id=botcard)
else
- src.path = AStar(src.loc, src.target, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30)
- if(!src.path)
- src.path = list()
- if(src.path.len == 0)
- src.oldtarget = src.target
- src.target = null
+ path = AStar(loc, target, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30, id=botcard)
+ if(!path)
+ path = list()
+ if(path.len == 0)
+ add_to_ignore(target)
+ oldtarget = target
+ target = null
+ mode = BOT_IDLE
return
- if(src.path.len > 0 && src.target && (src.target != null))
- step_to(src, src.path[1])
- src.path -= src.path[1]
- else if(src.path.len == 1)
+ if(path.len > 0 && target)
+ step_to(src, path[1])
+ path -= path[1]
+ else if(path.len == 1)
step_to(src, target)
- src.path = new()
+ path = new()
- if(src.loc == src.target || src.loc == src.target.loc)
- if(istype(src.target, /obj/item/stack/tile/plasteel))
- src.eattile(src.target)
- else if(istype(src.target, /obj/item/stack/sheet/metal))
- src.maketile(src.target)
- else if(istype(src.target, /turf/) && emagged < 2)
- repair(src.target)
- else if(emagged == 2 && istype(src.target,/turf/simulated/floor))
- var/turf/simulated/floor/F = src.target
- src.anchored = 1
- src.repairing = 1
+ if(loc == target || loc == target.loc)
+ if(istype(target, /obj/item/stack/tile/plasteel))
+ eattile(target)
+ else if(istype(target, /obj/item/stack/sheet/metal))
+ maketile(target)
+ else if(istype(target, /turf/) && emagged < 2)
+ repair(target)
+ else if(emagged == 2 && istype(target,/turf/simulated/floor))
+ var/turf/simulated/floor/F = target
+ anchored = 1
+ mode = BOT_REPAIRING
if(prob(90))
F.break_tile_to_plating()
else
F.ReplaceWithLattice()
visible_message("[src] makes an excited booping sound.")
spawn(50)
- src.amount ++
- src.anchored = 0
- src.repairing = 0
- src.target = null
- src.path = new()
+ amount ++
+ anchored = 0
+ mode = BOT_IDLE
+ target = null
+ path = new()
return
- src.oldloc = src.loc
+ oldloc = loc
+/obj/machinery/bot/floorbot/proc/nag() //Annoy everyone on the channel to refill us!
+ if(!nagged)
+ speak("Requesting refill at [get_area(src)]!", radio_frequency)
+ nagged = 1
+
+/obj/machinery/bot/floorbot/proc/add_to_ignore(target) //Often objects may block access to damaged tiles or open space.
+ if(ignore_list.len < max_targets && !(target in ignore_list)) //This will help keep track of them, so the bot is always trying to reach a blocked spot.
+ ignore_list += target
+ else if (ignore_list.len >= max_targets) //If the list is full, insert newest, delete oldest.
+ ignore_list -= ignore_list[1]
+ ignore_list += target
+
+/obj/machinery/bot/floorbot/proc/is_hull_breach(var/turf/t) //Ignore space tiles not considered part of a structure, also ignores shuttle docking areas.
+ var/area/t_area = get_area(t)
+ if (t_area && (t_area.name == "Space" || findtext(t_area.name, "huttle")))
+ return 0
+ else
+ return 1
/obj/machinery/bot/floorbot/proc/repair(var/turf/target)
+
if(istype(target, /turf/space/))
- if(target.loc.name == "Space")
+ //Must be a hull breach or in bridge mode to continue.
+ if(!is_hull_breach(target) && !targetdirection)
+ target = null
return
else if(!istype(target, /turf/simulated/floor))
return
- if(src.amount <= 0)
+ if(amount <= 0)
+ mode = BOT_IDLE
+ target = null
return
- src.anchored = 1
- src.icon_state = "floorbot-c"
- if(istype(target, /turf/space/))
- visible_message("[src] begins to repair the hole.")
- var/obj/item/stack/tile/plasteel/T = new /obj/item/stack/tile/plasteel
- src.repairing = 1
+ var/turf/simulated/floor/F
+ var/obj/item/stack/tile/plasteel/T = new /obj/item/stack/tile/plasteel
+ anchored = 1
+ icon_state = "floorbot-c"
+ if(istype(target, /turf/space/)) //If we are fixing an area not part of pure space, it is
+ visible_message(" [targetdirection ? "[src] begins installing a bridge plating." : "[src] begins to repair the hole."] ")
+ mode = BOT_REPAIRING
spawn(50)
- T.build(src.loc)
- src.repairing = 0
- src.amount -= 1
- src.updateicon()
- src.anchored = 0
- src.target = null
+ if(mode == BOT_REPAIRING)
+ if(autotile) //Build the floor and include a tile.
+ F = target.ChangeTurf(/turf/simulated/floor)
+ else //Build a hull plating without a floor tile.
+ T.build(loc)
+
+ mode = BOT_IDLE
+ amount -= 1
+ updateicon()
+ anchored = 0
+ src.target = null
else
- visible_message("[src] begins to improve the floor.")
- src.repairing = 1
+
+ F = target
+
+ mode = BOT_REPAIRING
+ visible_message(" [src] begins repairing the floor.")
spawn(50)
- src.loc.icon_state = "floor"
- src.repairing = 0
- src.amount -= 1
- src.updateicon()
- src.anchored = 0
- src.target = null
+ if(mode == BOT_REPAIRING)
+ F = target
+ F.make_plasteel_floor(T)
+ mode = BOT_IDLE
+ amount -= 1
+ updateicon()
+ anchored = 0
+ src.target = null
/obj/machinery/bot/floorbot/proc/eattile(var/obj/item/stack/tile/plasteel/T)
if(!istype(T, /obj/item/stack/tile/plasteel))
return
- visible_message("[src] begins to collect tiles.")
- src.repairing = 1
+ visible_message(" [src] begins to collect tiles.")
+ mode = BOT_REPAIRING
spawn(20)
if(isnull(T))
- src.target = null
- src.repairing = 0
+ target = null
+ mode = BOT_IDLE
return
- if(src.amount + T.amount > 50)
- var/i = 50 - src.amount
- src.amount += i
+ if(amount + T.amount > 50)
+ var/i = 50 - amount
+ amount += i
T.amount -= i
else
- src.amount += T.amount
+ amount += T.amount
qdel(T)
- src.updateicon()
- src.target = null
- src.repairing = 0
+ updateicon()
+ target = null
+ mode = BOT_IDLE
/obj/machinery/bot/floorbot/proc/maketile(var/obj/item/stack/sheet/metal/M)
if(!istype(M, /obj/item/stack/sheet/metal))
return
- if(M.amount > 1)
- return
- visible_message("[src] begins to create tiles.")
- src.repairing = 1
+ visible_message(" [src] begins to create tiles.")
+ mode = BOT_REPAIRING
spawn(20)
if(isnull(M))
- src.target = null
- src.repairing = 0
+ target = null
+ mode = BOT_IDLE
return
var/obj/item/stack/tile/plasteel/T = new /obj/item/stack/tile/plasteel
T.amount = 4
T.loc = M.loc
- qdel(M)
- src.target = null
- src.repairing = 0
+ if(M.amount > 1)
+ M.amount--
+ else
+ qdel(M)
+ target = null
+ mode = BOT_IDLE
/obj/machinery/bot/floorbot/proc/updateicon()
- if(src.amount > 0)
- src.icon_state = "floorbot[src.on]"
+ if(amount > 0)
+ icon_state = "floorbot[on]"
else
- src.icon_state = "floorbot[src.on]e"
+ icon_state = "floorbot[on]e"
/obj/machinery/bot/floorbot/explode()
- src.on = 0
- src.visible_message("[src] blows apart!", 1)
+ on = 0
+ visible_message("[src] blows apart!", 1)
var/turf/Tsec = get_turf(src)
var/obj/item/weapon/storage/toolbox/mechanical/N = new /obj/item/weapon/storage/toolbox/mechanical(Tsec)
@@ -397,7 +467,7 @@
amount -= 16
else
var/obj/item/stack/tile/plasteel/T = new (Tsec)
- T.amount = src.amount
+ T.amount = amount
amount = 0
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
@@ -411,7 +481,7 @@
if(!istype(T, /obj/item/stack/tile/plasteel))
..()
return
- if(src.contents.len >= 1)
+ if(contents.len >= 1)
user << "They won't fit in, as there is already stuff inside."
return
if(T.use(10))
@@ -431,7 +501,7 @@
if(isprox(W))
qdel(W)
var/obj/item/weapon/toolbox_tiles_sensor/B = new /obj/item/weapon/toolbox_tiles_sensor()
- B.created_name = src.created_name
+ B.created_name = created_name
user.put_in_hands(B)
user << "You add the sensor to the toolbox and tiles!"
user.unEquip(src, 1)
@@ -441,10 +511,10 @@
var/t = copytext(stripped_input(user, "Enter new robot name", src.name, src.created_name),1,MAX_NAME_LEN)
if (!t)
return
- if (!in_range(src, usr) && src.loc != usr)
+ if (!in_range(src, usr) && loc != usr)
return
- src.created_name = t
+ created_name = t
/obj/item/weapon/toolbox_tiles_sensor/attackby(var/obj/item/W, mob/user as mob)
..()
@@ -452,16 +522,16 @@
qdel(W)
var/turf/T = get_turf(user.loc)
var/obj/machinery/bot/floorbot/A = new /obj/machinery/bot/floorbot(T)
- A.name = src.created_name
+ A.name = created_name
user << "You add the robot arm to the odd looking toolbox assembly! Boop beep!"
user.unEquip(src, 1)
qdel(src)
else if (istype(W, /obj/item/weapon/pen))
- var/t = stripped_input(user, "Enter new robot name", src.name, src.created_name)
+ var/t = stripped_input(user, "Enter new robot name", name, created_name)
if (!t)
return
- if (!in_range(src, usr) && src.loc != usr)
+ if (!in_range(src, usr) && loc != usr)
return
- src.created_name = t
\ No newline at end of file
+ created_name = t
\ No newline at end of file
diff --git a/code/game/machinery/bots/medbot.dm b/code/game/machinery/bots/medbot.dm
index a9754377d85..d4f7dd72c98 100644
--- a/code/game/machinery/bots/medbot.dm
+++ b/code/game/machinery/bots/medbot.dm
@@ -13,31 +13,34 @@
anchored = 0
health = 20
maxhealth = 20
- req_access =list(access_medical)
+ req_one_access =list(access_medical, access_robotics)
var/stunned = 0 //It can be stunned by tasers. Delicate circuits.
// var/emagged = 0
var/list/botcard_access = list(access_medical)
var/obj/item/weapon/reagent_containers/glass/reagent_glass = null //Can be set to draw from this for reagents.
var/skin = null //Set to "tox", "ointment" or "o2" for the other two firstaid kits.
- var/frustration = 0
- var/path[] = new()
var/mob/living/carbon/patient = null
var/mob/living/carbon/oldpatient = null
var/oldloc = null
var/last_found = 0
var/last_newpatient_speak = 0 //Don't spam the "HEY I'M COMING" messages
- var/currently_healing = 0
var/injection_amount = 15 //How much reagent do we inject at a time?
var/heal_threshold = 10 //Start healing when they have this much damage in a category
var/use_beaker = 0 //Use reagents in beaker instead of default treatment agents.
-
+ var/declare_crit = 1 //If active, the bot will transmit a critical patient alert to MedHUD users.
+ var/declare_cooldown = 0 //Prevents spam of critical patient alerts.
+ var/stationary_mode = 0 //If enabled, the Medibot will not move automatically.
+ radio_frequency = 1355 //Medical frequency
//Setting which reagents to use to treat what by default. By id.
var/treatment_brute = "tricordrazine"
var/treatment_oxy = "tricordrazine"
var/treatment_fire = "tricordrazine"
var/treatment_tox = "tricordrazine"
var/treatment_virus = "spaceacillin"
+ var/treat_virus = 1 //If on, the bot will attempt to treat viral infections, curing them if possible.
var/shut_up = 0 //self explanatory :)
+ bot_type = MED_BOT
+ bot_filter = RADIO_MEDBOT
/obj/machinery/bot/medbot/mysterious
name = "\improper Mysterious Medibot"
@@ -58,43 +61,63 @@
var/skin = null //Same as medbot, set to tox or ointment for the respective kits.
w_class = 3.0
- New()
+ /obj/item/weapon/firstaid_arm_assembly/New()
..()
spawn(5)
- if(src.skin)
- src.overlays += image('icons/obj/aibots.dmi', "kit_skin_[src.skin]")
+ if(skin)
+ overlays += image('icons/obj/aibots.dmi', "kit_skin_[skin]")
+/obj/machinery/bot/medbot/proc/updateicon()
+ if(!on)
+ icon_state = "medibot0"
+ return
+ if(mode == BOT_HEALING)
+ icon_state = "medibots[stationary_mode]"
+ return
+ else if(stationary_mode) //Bot has yellow light to indicate stationary mode.
+ icon_state = "medibot2"
+ else
+ icon_state = "medibot1"
/obj/machinery/bot/medbot/New()
..()
- src.icon_state = "medibot[src.on]"
+ updateicon()
spawn(4)
- if(src.skin)
- src.overlays += image('icons/obj/aibots.dmi', "medskin_[src.skin]")
+ if(skin)
+ overlays += image('icons/obj/aibots.dmi', "medskin_[skin]")
- src.botcard = new /obj/item/weapon/card/id(src)
- if(isnull(src.botcard_access) || (src.botcard_access.len < 1))
+ if(isnull(botcard_access) || (botcard_access.len < 1))
var/datum/job/doctor/J = new/datum/job/doctor
- src.botcard.access = J.get_access()
+ botcard.access = J.get_access()
else
- src.botcard.access = src.botcard_access
+ botcard.access = botcard_access
+ prev_access = botcard.access
+ add_to_beacons(bot_filter)
/obj/machinery/bot/medbot/turn_on()
. = ..()
- src.icon_state = "medibot[src.on]"
- src.updateUsrDialog()
+ updateicon()
+ 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()
+ updateicon()
+ updateUsrDialog()
+
+/obj/machinery/bot/medbot/bot_reset()
+ ..()
+ patient = null
+ oldpatient = null
+ oldloc = null
+ last_found = world.time
+ declare_cooldown = 0
+
+/obj/machinery/bot/medbot/set_custom_texts()
+
+ text_hack = "You corrupt [name]'s reagent processor circuits."
+ text_dehack = "You reset [name]'s reagent processor circuits."
+ text_dehack_fail = "[name] seems damaged and does not respond to reprogramming!"
/obj/machinery/bot/medbot/attack_paw(mob/user as mob)
return attack_hand(user)
@@ -105,99 +128,93 @@
return
var/dat
dat += hack(user)
- dat += "Automatic Medical Unit v1.0
"
- dat += "Status: [src.on ? "On" : "Off"]
"
- dat += "Maintenance panel panel is [src.open ? "opened" : "closed"]
"
+ dat += "Medical Unit Controls v1.1
"
+ dat += "Status: [on ? "On" : "Off"]
"
+ dat += "Maintenance panel panel is [open ? "opened" : "closed"]
"
dat += "Beaker: "
- if (src.reagent_glass)
- dat += "Loaded \[[src.reagent_glass.reagents.total_volume]/[src.reagent_glass.reagents.maximum_volume]\]"
+ if (reagent_glass)
+ dat += "Loaded \[[reagent_glass.reagents.total_volume]/[reagent_glass.reagents.maximum_volume]\]"
else
dat += "None Loaded"
- dat += "
Behaviour controls are [src.locked ? "locked" : "unlocked"]
"
- if(!src.locked || issilicon(user))
+ dat += "
Behaviour controls are [locked ? "locked" : "unlocked"]
"
+ if(!locked || issilicon(user))
dat += "Healing Threshold: "
dat += "-- "
dat += "- "
- dat += "[src.heal_threshold] "
+ dat += "[heal_threshold] "
dat += "+ "
dat += "++"
dat += "
"
dat += "Injection Level: "
dat += "- "
- dat += "[src.injection_amount] "
+ dat += "[injection_amount] "
dat += "+ "
dat += "
"
dat += "Reagent Source: "
- dat += "[src.use_beaker ? "Loaded Beaker (When available)" : "Internal Synthesizer"]
"
+ dat += "[use_beaker ? "Loaded Beaker (When available)" : "Internal Synthesizer"]
"
- dat += "The speaker switch is [src.shut_up ? "off" : "on"]. Toggle"
+ dat += "Treat Viral Infections: [treat_virus ? "Yes" : "No"]
"
+ dat += "The speaker switch is [shut_up ? "off" : "on"]. Toggle
"
+ dat += "Critical Patient Alerts: [declare_crit ? "Yes" : "No"]
"
+ dat += "Patrol Station: [auto_patrol ? "Yes" : "No"]
"
+ dat += "Stationary Mode: [stationary_mode ? "Yes" : "No"]
"
- user << browse("Medibot v1.0 controls[dat]", "window=automed")
- onclose(user, "automed")
+ var/datum/browser/popup = new(user, "automed", "Automatic Medical Unit v1.1")
+ popup.set_content(dat)
+ popup.open()
return
/obj/machinery/bot/medbot/Topic(href, href_list)
- if(..())
- return
- usr.set_machine(src)
- src.add_fingerprint(usr)
- if ((href_list["power"]) && (src.allowed(usr)))
- if (src.on && !src.emagged)
- turn_off()
- else
- turn_on()
+ ..()
- else if((href_list["adj_threshold"]) && (!src.locked || issilicon(usr)))
+ if(href_list["adj_threshold"])
var/adjust_num = text2num(href_list["adj_threshold"])
- src.heal_threshold += adjust_num
- if(src.heal_threshold < 5)
- src.heal_threshold = 5
- if(src.heal_threshold > 75)
- src.heal_threshold = 75
+ heal_threshold += adjust_num
+ if(heal_threshold < 5)
+ heal_threshold = 5
+ if(heal_threshold > 75)
+ heal_threshold = 75
- else if((href_list["adj_inject"]) && (!src.locked || issilicon(usr)))
+ else if(href_list["adj_inject"])
var/adjust_num = text2num(href_list["adj_inject"])
- src.injection_amount += adjust_num
- if(src.injection_amount < 5)
- src.injection_amount = 5
- if(src.injection_amount > 15)
- src.injection_amount = 15
+ injection_amount += adjust_num
+ if(injection_amount < 5)
+ injection_amount = 5
+ if(injection_amount > 15)
+ injection_amount = 15
- else if((href_list["use_beaker"]) && (!src.locked || issilicon(usr)))
- src.use_beaker = !src.use_beaker
+ else if(href_list["use_beaker"])
+ use_beaker = !use_beaker
- else if (href_list["eject"] && (!isnull(src.reagent_glass)))
- if(!src.locked)
- src.reagent_glass.loc = get_turf(src)
- src.reagent_glass = null
- else
- usr << "You cannot eject the beaker because the panel is locked."
+ else if (href_list["eject"] && (!isnull(reagent_glass)))
+ reagent_glass.loc = get_turf(src)
+ reagent_glass = null
- else if ((href_list["togglevoice"]) && (!src.locked || issilicon(usr)))
- src.shut_up = !src.shut_up
+ else if (href_list["togglevoice"])
+ shut_up = !shut_up
- else if (href_list["operation"])
- if(!src.emagged)
- src.emagged = 2
- src.hacked = 1
- usr << "You corrupt [src]'s reagent processor circuits."
- else if(!src.hacked)
- usr << "[src] seems damaged and does not respond to reprogramming!"
- else
- src.hacked = 0
- src.emagged = 0
- usr << "You reset [src]'s reagent circuits."
- src.updateUsrDialog()
+ else if (href_list["critalerts"])
+ declare_crit = !declare_crit
+
+ else if (href_list["stationary"])
+ stationary_mode = !stationary_mode
+ path = new()
+ updateicon()
+
+ else if (href_list["virus"])
+ treat_virus = !treat_virus
+
+ updateUsrDialog()
return
/obj/machinery/bot/medbot/attackby(obj/item/weapon/W as obj, mob/user as mob)
if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
- if (src.allowed(user) && !open && !emagged)
- src.locked = !src.locked
- user << "Controls are now [src.locked ? "locked." : "unlocked."]"
- src.updateUsrDialog()
+ if (allowed(user) && !open && !emagged)
+ locked = !locked
+ user << "Controls are now [locked ? "locked." : "unlocked."]"
+ updateUsrDialog()
else
if(emagged)
user << "ERROR"
@@ -207,18 +224,18 @@
user << "Access denied."
else if (istype(W, /obj/item/weapon/reagent_containers/glass))
- if(src.locked)
+ if(locked)
user << "You cannot insert a beaker because the panel is locked."
return
- if(!isnull(src.reagent_glass))
+ if(!isnull(reagent_glass))
user << "There is already a beaker loaded."
return
user.drop_item()
W.loc = src
- src.reagent_glass = W
+ reagent_glass = W
user << "You insert [W]."
- src.updateUsrDialog()
+ updateUsrDialog()
return
else
@@ -228,106 +245,118 @@
/obj/machinery/bot/medbot/Emag(mob/user as mob)
..()
- if(open && !locked)
- if(user) user << "You short out [src]'s reagent synthesis circuits."
+ if(emagged == 2)
+ declare_crit = 0
+ if(user)
+ user << "You short out [src]'s reagent synthesis circuits."
spawn(0)
- src.visible_message("[src] buzzes oddly!", 1)
+ visible_message("[src] buzzes oddly!", 1)
flick("medibot_spark", src)
- src.patient = null
- if(user) src.oldpatient = user
- src.currently_healing = 0
- src.last_found = world.time
- src.anchored = 0
- src.emagged = 2
- src.on = 1
- src.icon_state = "medibot[src.on]"
+ if(user)
+ oldpatient = user
/obj/machinery/bot/medbot/process()
set background = BACKGROUND_ENABLED
- if(!src.on)
- src.stunned = 0
+ if(!on)
return
- if(src.stunned)
- src.icon_state = "medibota"
- src.stunned--
-
- src.oldpatient = src.patient
- src.patient = null
- src.currently_healing = 0
-
- if(src.stunned <= 0)
- src.icon_state = "medibot[src.on]"
- src.stunned = 0
+ if(call_path)
+ call_mode()
return
- if(src.frustration > 8)
- src.oldpatient = src.patient
- src.patient = null
- src.currently_healing = 0
- src.last_found = world.time
- src.path = new()
+ if(stunned)
+ icon_state = "medibota"
+ stunned--
- if(!src.patient)
- if(!src.shut_up && prob(1))
+ oldpatient = patient
+ patient = null
+ mode = BOT_IDLE
+
+ if(stunned <= 0)
+ updateicon()
+ stunned = 0
+ return
+
+ if(frustration > 8)
+ oldpatient = patient
+ patient = null
+ mode = BOT_IDLE
+ last_found = world.time
+ path = new()
+
+ if(!patient)
+ if(mode == BOT_SUMMON) //A medibot will not search for new patients when summoned!
+ bot_summon()
+ return
+
+ if(!shut_up && prob(1))
var/message = pick("Radar, put a mask on!","There's always a catch, and it's the best there is.","I knew it, I should've been a plastic surgeon.","What kind of medbay is this? Everyone's dropping like dead flies.","Delicious!")
- src.speak(message)
+ speak(message)
- for (var/mob/living/carbon/C in view(7,src)) //Time to find a patient!
+ var/scan_range = (stationary_mode ? 1 : 7) //If in stationary mode, scan range is limited to adjacent patients.
+ for (var/mob/living/carbon/C in view(scan_range,src)) //Time to find a patient!
if ((C.stat == 2) || !istype(C, /mob/living/carbon/human))
continue
- if ((C == src.oldpatient) && (world.time < src.last_found + 100))
+ if ((C == oldpatient) && (world.time < last_found + 100))
continue
- if(src.assess_patient(C))
- src.patient = C
- src.oldpatient = C
- src.last_found = world.time
- if((src.last_newpatient_speak + 300) < world.time) //Don't spam these messages!
+ if(assess_patient(C))
+ patient = C
+ oldpatient = C
+ last_found = world.time
+ if((last_newpatient_speak + 300) < world.time) //Don't spam these messages!
var/message = pick("Hey, [C.name]! Hold on, I'm coming.","Wait [C.name]! I want to help!","[C.name], you appear to be injured!")
- src.speak(message)
- src.last_newpatient_speak = world.time
+ speak(message)
+ last_newpatient_speak = world.time
break
else
continue
- if(src.patient && (get_dist(src,src.patient) <= 1))
- if(!src.currently_healing)
- src.currently_healing = 1
- src.frustration = 0
- src.medicate_patient(src.patient)
+ if(patient && (get_dist(src,patient) <= 1))
+ if(mode != BOT_HEALING)
+ mode = BOT_HEALING
+ updateicon()
+ frustration = 0
+ medicate_patient(patient)
return
- else if(src.patient && (src.path.len) && (get_dist(src.patient,src.path[src.path.len]) > 2))
- src.path = new()
- src.currently_healing = 0
- src.last_found = world.time
+ else if(patient && (path.len) && (get_dist(patient,path[path.len]) > 2))
+ path = new()
+ mode = BOT_IDLE
+ last_found = world.time
- if(src.patient && src.path.len == 0 && (get_dist(src,src.patient) > 1))
+ if(!stationary_mode && patient && path.len == 0 && (get_dist(src,patient) > 1))
spawn(0)
- src.path = AStar(src.loc, get_turf(src.patient), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 30,id=botcard)
- if(!src.path)
- src.path = list()
- if(src.path.len == 0)
- src.oldpatient = src.patient
- src.patient = null
- src.currently_healing = 0
- src.last_found = world.time
+ path = AStar(loc, get_turf(patient), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 30,id=botcard)
+ if(!path)
+ path = list()
+ if(path.len == 0)
+ oldpatient = patient
+ patient = null
+ mode = BOT_IDLE
+ last_found = world.time
return
- if(src.path.len > 0 && src.patient)
- step_to(src, src.path[1])
- src.path -= src.path[1]
+ if(path.len > 0 && patient)
+ step_to(src, path[1])
+ path -= path[1]
spawn(3)
- if(src.path.len)
- step_to(src, src.path[1])
- src.path -= src.path[1]
+ if(path.len)
+ step_to(src, path[1])
+ path -= path[1]
- if(src.path.len > 8 && src.patient)
- src.frustration++
+ if(path.len > 8 && patient)
+ frustration++
+
+ if(auto_patrol && !stationary_mode && !patient)
+ if(mode == BOT_IDLE || mode == BOT_START_PATROL)
+ start_patrol()
+
+ if(mode == BOT_PATROL)
+ bot_patrol()
return
@@ -339,113 +368,117 @@
if(C.suiciding)
return 0 //Kevorkian school of robotic medical assistants.
- if(src.emagged == 2) //Everyone needs our medicine. (Our medicine is toxins)
+ if(emagged == 2) //Everyone needs our medicine. (Our medicine is toxins)
return 1
+ if(declare_crit && C.health <= 0) //Critical condition! Call for help!
+ declare(C)
+
//If they're injured, we're using a beaker, and don't have one of our WONDERCHEMS.
- if((src.reagent_glass) && (src.use_beaker) && ((C.getBruteLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getOxyLoss() >= (heal_threshold + 15))))
- for(var/datum/reagent/R in src.reagent_glass.reagents.reagent_list)
+ if((reagent_glass) && (use_beaker) && ((C.getBruteLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getOxyLoss() >= (heal_threshold + 15))))
+ for(var/datum/reagent/R in reagent_glass.reagents.reagent_list)
if(!C.reagents.has_reagent(R.id))
return 1
//They're injured enough for it!
- if((C.getBruteLoss() >= heal_threshold) && (!C.reagents.has_reagent(src.treatment_brute)))
+ if((C.getBruteLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_brute)))
return 1 //If they're already medicated don't bother!
- if((C.getOxyLoss() >= (15 + heal_threshold)) && (!C.reagents.has_reagent(src.treatment_oxy)))
+ if((C.getOxyLoss() >= (15 + heal_threshold)) && (!C.reagents.has_reagent(treatment_oxy)))
return 1
- if((C.getFireLoss() >= heal_threshold) && (!C.reagents.has_reagent(src.treatment_fire)))
+ if((C.getFireLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_fire)))
return 1
- if((C.getToxLoss() >= heal_threshold) && (!C.reagents.has_reagent(src.treatment_tox)))
+ if((C.getToxLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_tox)))
return 1
+ if(treat_virus)
+ for(var/datum/disease/D in C.viruses)
+ if((D.hidden[SCANNER]) || (D.hidden[PANDEMIC])) //the medibot can't detect viruses that are undetectable to Health Analyzers or Pandemic machines.
+ return 0
+ if(D.severity == D.non_threat) // medibot doesn't try to heal truly harmless viruses
+ return 0
+ if((D.stage > 1) || (D.spread_type == AIRBORNE)) // medibot can't detect a virus in its initial stage unless it spreads airborne.
- for(var/datum/disease/D in C.viruses)
- if((D.hidden[SCANNER]) || (D.hidden[PANDEMIC])) //the medibot can't detect viruses that are undetectable to Health Analyzers or Pandemic machines.
- return 0
- if(D.severity == D.non_threat) // medibot doesn't try to heal truly harmless viruses
- return 0
- if((D.stage > 1) || (D.spread_type == AIRBORNE)) // medibot can't detect a virus in its initial stage unless it spreads airborne.
-
- if (!C.reagents.has_reagent(src.treatment_virus))
- return 1 //STOP DISEASE FOREVER
+ if (!C.reagents.has_reagent(src.treatment_virus))
+ return 1 //STOP DISEASE FOREVER
return 0
/obj/machinery/bot/medbot/proc/medicate_patient(mob/living/carbon/C as mob)
- if(!src.on)
+ if(!on)
return
if(!istype(C))
- src.oldpatient = src.patient
- src.patient = null
- src.currently_healing = 0
- src.last_found = world.time
+ oldpatient = patient
+ patient = null
+ mode = BOT_IDLE
+ last_found = world.time
return
if(C.stat == 2)
var/death_message = pick("No! NO!","Live, damnit! LIVE!","I...I've never lost a patient before. Not today, I mean.")
- src.speak(death_message)
- src.oldpatient = src.patient
- src.patient = null
- src.currently_healing = 0
- src.last_found = world.time
+ speak(death_message)
+ oldpatient = patient
+ patient = null
+ mode = BOT_IDLE
+ last_found = world.time
return
var/reagent_id = null
- if(src.emagged == 2) //Emagged! Time to poison everybody.
+ if(emagged == 2) //Emagged! Time to poison everybody.
reagent_id = "toxin"
else
- var/virus = 0
- for(var/datum/disease/D in C.viruses)
- if((!D.hidden[SCANNER]) && (!D.hidden[PANDEMIC])) //detectable virus
- if(D.severity != D.non_threat) //virus is harmful
- if((D.stage > 1) || (D.spread_type == AIRBORNE))
- virus = 1
+ if(treat_virus)
+ var/virus = 0
+ for(var/datum/disease/D in C.viruses)
+ if((!D.hidden[SCANNER]) && (!D.hidden[PANDEMIC])) //detectable virus
+ if(D.severity != D.non_threat) //virus is harmful
+ if((D.stage > 1) || (D.spread_type == AIRBORNE))
+ virus = 1
- if (!reagent_id && (virus))
- if(!C.reagents.has_reagent(src.treatment_virus))
- reagent_id = src.treatment_virus
+ if (!reagent_id && (virus))
+ if(!C.reagents.has_reagent(treatment_virus))
+ reagent_id = treatment_virus
if (!reagent_id && (C.getBruteLoss() >= heal_threshold))
- if(!C.reagents.has_reagent(src.treatment_brute))
- reagent_id = src.treatment_brute
+ if(!C.reagents.has_reagent(treatment_brute))
+ reagent_id = treatment_brute
if (!reagent_id && (C.getOxyLoss() >= (15 + heal_threshold)))
- if(!C.reagents.has_reagent(src.treatment_oxy))
- reagent_id = src.treatment_oxy
+ if(!C.reagents.has_reagent(treatment_oxy))
+ reagent_id = treatment_oxy
if (!reagent_id && (C.getFireLoss() >= heal_threshold))
- if(!C.reagents.has_reagent(src.treatment_fire))
- reagent_id = src.treatment_fire
+ if(!C.reagents.has_reagent(treatment_fire))
+ reagent_id = treatment_fire
if (!reagent_id && (C.getToxLoss() >= heal_threshold))
- if(!C.reagents.has_reagent(src.treatment_tox))
- reagent_id = src.treatment_tox
+ if(!C.reagents.has_reagent(treatment_tox))
+ reagent_id = treatment_tox
//If the patient is injured but doesn't have our special reagent in them then we should give it to them first
- if(reagent_id && src.use_beaker && src.reagent_glass && src.reagent_glass.reagents.total_volume)
- for(var/datum/reagent/R in src.reagent_glass.reagents.reagent_list)
+ if(reagent_id && use_beaker && reagent_glass && reagent_glass.reagents.total_volume)
+ for(var/datum/reagent/R in reagent_glass.reagents.reagent_list)
if(!C.reagents.has_reagent(R.id))
reagent_id = "internal_beaker"
break
if(!reagent_id) //If they don't need any of that they're probably cured!
- src.oldpatient = src.patient
- src.patient = null
- src.currently_healing = 0
- src.last_found = world.time
+ oldpatient = patient
+ patient = null
+ mode = BOT_IDLE
+ last_found = world.time
var/message = pick("All patched up!","An apple a day keeps me away.","Feel better soon!")
- src.speak(message)
+ speak(message)
+ updateicon()
return
else
- src.icon_state = "medibots"
- C.visible_message("[src] is trying to inject [src.patient]!", \
- "[src] is trying to inject [src.patient]!")
+ C.visible_message("[src] is trying to inject [patient]!", \
+ "[src] is trying to inject [patient]!")
spawn(30)
if ((get_dist(src, src.patient) <= 1) && (src.on))
@@ -454,12 +487,12 @@
src.reagent_glass.reagents.trans_to(src.patient,src.injection_amount) //Inject from beaker instead.
src.reagent_glass.reagents.reaction(src.patient, 2)
else
- src.patient.reagents.add_reagent(reagent_id,src.injection_amount)
- C.visible_message("[src] injects [src.patient] with the syringe!", \
- "[src] injects [src.patient] with the syringe!")
+ patient.reagents.add_reagent(reagent_id,injection_amount)
+ C.visible_message("[src] injects [patient] with the syringe!", \
+ "[src] injects [patient] with the syringe!")
- src.icon_state = "medibot[src.on]"
- src.currently_healing = 0
+ mode = BOT_IDLE
+ updateicon()
return
reagent_id = null
@@ -467,11 +500,11 @@
/obj/machinery/bot/medbot/bullet_act(var/obj/item/projectile/Proj)
if(Proj.flag == "taser")
- src.stunned = min(stunned+10,20)
+ stunned = min(stunned+10,20)
..()
/obj/machinery/bot/medbot/explode()
- src.on = 0
+ on = 0
visible_message("[src] blows apart!", 1)
var/turf/Tsec = get_turf(src)
@@ -481,9 +514,9 @@
new /obj/item/device/healthanalyzer(Tsec)
- if(src.reagent_glass)
- src.reagent_glass.loc = Tsec
- src.reagent_glass = null
+ if(reagent_glass)
+ reagent_glass.loc = Tsec
+ reagent_glass = null
if (prob(50))
new /obj/item/robot_parts/l_arm(Tsec)
@@ -494,16 +527,15 @@
qdel(src)
return
-/obj/machinery/bot/medbot/Bump(M as mob|obj) //Leave no door unopened!
- 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
+/obj/machinery/bot/medbot/proc/declare(var/crit_patient)
+ if(declare_cooldown)
+ return
+ var/area/location = get_area(src)
+ speak("Medical emergency! [crit_patient ? "[crit_patient]" : "A patient"] is in critical condition at [location]!",radio_frequency)
+ declare_cooldown = 1
+ spawn(200) //Twenty seconds
+ declare_cooldown = 0
+
/* terrible
/obj/machinery/bot/medbot/Bumped(atom/movable/M as mob|obj)
@@ -554,7 +586,7 @@
return
//Making a medibot!
- if(src.contents.len >= 1)
+ if(contents.len >= 1)
user << "You need to empty [src] out first."
return
@@ -576,33 +608,33 @@
/obj/item/weapon/firstaid_arm_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob)
..()
if(istype(W, /obj/item/weapon/pen))
- var/t = copytext(stripped_input(user, "Enter new robot name", src.name, src.created_name),1,MAX_NAME_LEN)
+ var/t = copytext(stripped_input(user, "Enter new robot name", name, created_name),1,MAX_NAME_LEN)
if (!t)
return
- if (!in_range(src, usr) && src.loc != usr)
+ if (!in_range(src, usr) && loc != usr)
return
- src.created_name = t
+ created_name = t
else
switch(build_step)
if(0)
if(istype(W, /obj/item/device/healthanalyzer))
user.drop_item()
qdel(W)
- src.build_step++
+ build_step++
user << "You add the health sensor to [src]."
- src.name = "First aid/robot arm/health analyzer assembly"
- src.overlays += image('icons/obj/aibots.dmi', "na_scanner")
+ name = "First aid/robot arm/health analyzer assembly"
+ overlays += image('icons/obj/aibots.dmi', "na_scanner")
if(1)
if(isprox(W))
user.drop_item()
qdel(W)
- src.build_step++
+ build_step++
user << "You complete the Medibot! Beep boop."
var/turf/T = get_turf(src)
var/obj/machinery/bot/medbot/S = new /obj/machinery/bot/medbot(T)
- S.skin = src.skin
- S.name = src.created_name
+ S.skin = skin
+ S.name = created_name
user.unEquip(src, 1)
qdel(src)
diff --git a/code/game/machinery/bots/mulebot.dm b/code/game/machinery/bots/mulebot.dm
index 696da1238b4..9863cf785fb 100644
--- a/code/game/machinery/bots/mulebot.dm
+++ b/code/game/machinery/bots/mulebot.dm
@@ -19,34 +19,30 @@ var/global/mulebot_count = 0
fire_dam_coeff = 0.7
brute_dam_coeff = 0.5
var/atom/movable/load = null // the loaded crate (usually)
- var/beacon_freq = 1400
- var/control_freq = 1447
+ var/list/delivery_beacons = list() //List of beacons that serve as delivery locations.
+ beacon_freq = 1400
+ control_freq = 1447
+ bot_type = MULE_BOT
+ bot_filter = RADIO_MULEBOT
suffix = ""
var/turf/target // this is turf to navigate to (location of beacon)
var/loaddir = 0 // this the direction to unload onto/load from
- var/new_destination = "" // pending new destination (waiting for beacon response)
- var/destination = "" // destination description
+ new_destination = "" // pending new destination (waiting for beacon response)
+ destination = "" // destination description
var/home_destination = "" // tag of home beacon
req_access = list(access_cargo) // added robotics access so assembly line drop-off works properly -veyveyr //I don't think so, Tim. You need to add it to the MULE's hidden robot ID card. -NEO
- var/path[] = new()
- var/mode = 0 //0 = idle/ready
- //1 = loading/unloading
- //2 = moving to deliver
- //3 = returning to home
- //4 = blocked
- //5 = computing navigation
- //6 = waiting for nav computation
- //7 = no destination beacon found (or no route)
+ mode = BOT_IDLE
- var/blockcount = 0 //number of times retried a blocked path
+ blockcount = 0 //number of times retried a blocked path
var/reached_target = 1 //true if already reached the target
- var/refresh = 1 // true to refresh dialogue
- var/auto_return = 1 // true if auto return to home beacon after unload
- var/auto_pickup = 1 // true if auto-pickup at beacon
+ var/refresh = 1 // true to refresh dialogue
+ var/auto_return = 1 // true if auto return to home beacon after unload
+ var/auto_pickup = 1 // true if auto-pickup at beacon
+ var/report_delivery = 1 // true if bot will announce an arrival to a location.
var/obj/item/weapon/stock_parts/cell/cell
var/datum/wires/mulebot/wires = null
@@ -67,18 +63,16 @@ var/global/mulebot_count = 0
/obj/machinery/bot/mulebot/New()
..()
wires = new(src)
- botcard = new(src)
var/datum/job/cargo_tech/J = new/datum/job/cargo_tech
botcard.access = J.get_access()
+ prev_access = botcard.access
// botcard.access += access_robotics //Why --Ikki
cell = new(src)
cell.charge = 2000
cell.maxcharge = 2000
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)
+ add_to_beacons(bot_filter)
mulebot_count += 1
if(!suffix)
@@ -100,8 +94,8 @@ var/global/mulebot_count = 0
locked = !locked
user << "You [locked ? "lock" : "unlock"] the mulebot's controls!"
flick("mulebot-emagged", src)
- playsound(src.loc, 'sound/effects/sparks1.ogg', 100, 0)
- else if(istype(I, /obj/item/weapon/card/id))
+ playsound(loc, 'sound/effects/sparks1.ogg', 100, 0)
+ else if(istype(I, /obj/item/weapon/card/id) || istype(I, /obj/item/device/pda))
if(toggle_lock(user))
user << "Controls [(locked ? "locked" : "unlocked")]."
@@ -118,30 +112,30 @@ var/global/mulebot_count = 0
open = !open
if(open)
- src.visible_message("[user] opens the maintenance hatch of [src]", "You open [src]'s maintenance hatch.")
+ visible_message("[user] opens the maintenance hatch of [src]", "You open [src]'s maintenance hatch.")
on = 0
icon_state="mulebot-hatch"
else
- src.visible_message("[user] closes the maintenance hatch of [src]", "You close [src]'s maintenance hatch.")
+ visible_message("[user] closes the maintenance hatch of [src]", "You close [src]'s maintenance hatch.")
icon_state = "mulebot0"
updateDialog()
else if (istype(I, /obj/item/weapon/wrench))
- if (src.health < maxhealth)
- src.health = min(maxhealth, src.health+25)
+ if (health < maxhealth)
+ health = min(maxhealth, health+25)
user.visible_message(
- "[user] repairs [src]!",
+ "[user] repairs [src]!",
"You repair [src]!"
)
else
- user << "[src] does not need a repair!"
+ user << " [src] does not need a repair!"
else if(istype(I, /obj/item/device/multitool) || istype(I, /obj/item/weapon/wirecutters))
if(open)
attack_hand(usr)
else if(load && ismob(load)) // chance to knock off rider
if(prob(1+I.force * 2))
unload(0)
- user.visible_message("[user] knocks [load] off [src] with \the [I]!", "You knock [load] off [src] with \the [I]!")
+ user.visible_message(" [user] knocks [load] off [src] with \the [I]!", " You knock [load] off [src] with \the [I]!")
else
user << "You hit [src] with \the [I] but to no effect."
else
@@ -164,7 +158,7 @@ var/global/mulebot_count = 0
if(prob(50) && !isnull(load))
unload(0)
if(prob(25))
- src.visible_message("Something shorts out inside [src]!")
+ visible_message(" Something shorts out inside [src]!")
wires.RandomCut()
..()
@@ -182,29 +176,30 @@ var/global/mulebot_count = 0
/obj/machinery/bot/mulebot/interact(var/mob/user, var/ai=0)
var/dat
- dat += "Multiple Utility Load Effector Mk. IV
"
+ dat += "Multiple Utility Load Effector Mk. V
"
dat += "ID: [suffix]
"
dat += "Power: [on ? "On" : "Off"]
"
if(!open)
dat += "Status
"
+
dat += ""
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 reach destination"
+ if(BOT_IDLE)
+ dat += "Ready"
+ if(BOT_LOADING)
+ dat += "[mode_name[BOT_LOADING]]"
+ if(BOT_DELIVER)
+ dat += "[mode_name[BOT_DELIVER]]"
+ if(BOT_GO_HOME)
+ dat += "[mode_name[BOT_GO_HOME]]"
+ if(BOT_BLOCKED)
+ dat += "[mode_name[BOT_BLOCKED]]"
+ if(BOT_NAV,BOT_WAIT_FOR_NAV)
+ dat += "[mode_name[BOT_NAV]]"
+ if(BOT_NO_ROUTE)
+ dat += "[mode_name[BOT_NO_ROUTE]]"
dat += "
"
dat += "Current Load: [load ? load.name : "none"]
"
@@ -225,6 +220,7 @@ var/global/mulebot_count = 0
dat += "Set Home
"
dat += "Toggle Auto Return Home ([auto_return ? "On":"Off"])
"
dat += "Toggle Auto Pickup Crate ([auto_pickup ? "On":"Off"])
"
+ dat += "Toggle Delivery Reporting ([report_delivery ? "On" : "Off"])
"
if(load)
dat += "Unload Now
"
@@ -247,7 +243,7 @@ var/global/mulebot_count = 0
//onclose(user, "mulebot")
var/datum/browser/popup = new(user, "mulebot", "M.U.L.E. Mk. III [suffix ? "([suffix])" : ""]", 350, 500)
popup.set_content(dat)
- popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
+ popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()
return
@@ -261,7 +257,7 @@ var/global/mulebot_count = 0
return
if (usr.stat)
return
- if ((in_range(src, usr) && istype(src.loc, /turf)) || (istype(usr, /mob/living/silicon)))
+ if ((in_range(src, usr) && istype(loc, /turf)) || (istype(usr, /mob/living/silicon)))
usr.set_machine(src)
switch(href_list["op"])
@@ -269,7 +265,7 @@ var/global/mulebot_count = 0
toggle_lock(usr)
if("power")
- if (src.on)
+ if (on)
turn_off()
else if (cell && !open)
if (!turn_on())
@@ -305,23 +301,23 @@ var/global/mulebot_count = 0
if("stop")
- if(mode >=2)
- mode = 0
+ if(mode >= BOT_DELIVER)
+ bot_reset()
updateDialog()
if("go")
- if(mode == 0)
+ if(mode == BOT_IDLE)
start()
updateDialog()
if("home")
- if(mode == 0 || mode == 2)
+ if(mode == BOT_IDLE || mode == BOT_DELIVER)
start_home()
updateDialog()
if("destination")
refresh=0
- var/new_dest = input("Enter new destination tag", "Mulebot [suffix ? "([suffix])" : ""]", destination) as text|null
+ var/new_dest = input("Select M.U.L.E. Destination", "Mulebot [suffix ? "([suffix])" : ""]", destination) as null|anything in delivery_beacons
refresh=1
if(new_dest)
set_destination(new_dest)
@@ -357,12 +353,15 @@ var/global/mulebot_count = 0
if("autopick")
auto_pickup = !auto_pickup
+ if("report")
+ report_delivery = !report_delivery
+
if("close")
usr.unset_machine()
usr << browse(null,"window=mulebot")
updateDialog()
- //src.updateUsrDialog()
+ //updateUsrDialog()
else
usr << browse(null, "window=mulebot")
usr.unset_machine()
@@ -375,7 +374,7 @@ var/global/mulebot_count = 0
return !open && cell && cell.charge > 0 && wires.HasPower()
/obj/machinery/bot/mulebot/proc/toggle_lock(var/mob/user)
- if(src.allowed(user))
+ if(allowed(user))
locked = !locked
updateDialog()
return 1
@@ -403,8 +402,8 @@ var/global/mulebot_count = 0
// called to load a crate
/obj/machinery/bot/mulebot/proc/load(var/atom/movable/C)
if(wires.LoadCheck() && !istype(C,/obj/structure/closet/crate))
- src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
- playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
+ playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
return // if not emagged, only allow crates to be loaded
//I'm sure someone will come along and ask why this is here... well people were dragging screen items onto the mule, and that was not cool.
@@ -416,16 +415,16 @@ var/global/mulebot_count = 0
if(get_dist(C, src) > 1 || load || !on)
return
- mode = 1
+ mode = BOT_LOADING
// if a create, close before loading
var/obj/structure/closet/crate/crate = C
if(istype(crate))
crate.close()
- C.loc = src.loc
+ C.loc = loc
sleep(2)
- if(C.loc != src.loc) //To prevent you from going onto more thano ne bot.
+ if(C.loc != loc) //To prevent you from going onto more thano ne bot.
return
C.loc = src
load = C
@@ -441,7 +440,7 @@ var/global/mulebot_count = 0
M.client.perspective = EYE_PERSPECTIVE
M.client.eye = src
- mode = 0
+ mode = BOT_IDLE
send_status()
// called to unload the bot
@@ -451,7 +450,7 @@ var/global/mulebot_count = 0
if(!load)
return
- mode = 1
+ mode = BOT_LOADING
overlays.Cut()
if(ismob(load))
@@ -461,11 +460,11 @@ var/global/mulebot_count = 0
M.client.eye = src
- load.loc = src.loc
+ load.loc = loc
load.pixel_y -= 9
load.layer = initial(load.layer)
if(dirn)
- var/turf/T = src.loc
+ var/turf/T = loc
var/turf/newT = get_step(T,dirn)
if(load.CanPass(load,newT)) //Can't get off onto anything that wouldn't let you pass normally
step(load, dirn)
@@ -477,9 +476,9 @@ var/global/mulebot_count = 0
// with items dropping as mobs are loaded
for(var/atom/movable/AM in src)
- if(AM == cell || AM == botcard) continue
+ if(AM == cell || istype(AM , botcard) || AM == Radio) continue
- AM.loc = src.loc
+ AM.loc = loc
AM.layer = initial(AM.layer)
AM.pixel_y = initial(AM.pixel_y)
if(ismob(AM))
@@ -487,8 +486,19 @@ var/global/mulebot_count = 0
if(M.client)
M.client.perspective = MOB_PERSPECTIVE
M.client.eye = src
- mode = 0
+ mode = BOT_IDLE
+/obj/machinery/bot/mulebot/call_bot()
+ ..()
+ var/area/dest_area
+ if (call_path && call_path.len)
+ target = call_path[call_path.len] //Target is the end point of the path, the waypoint set by the AI.
+ dest_area = get_area(target)
+ destination = format_text(dest_area.name)
+ path = call_path
+ call_path = null //Once the MULE is commanded, follow normal procedures to reach the waypoint.
+ pathset = 1 //Indicates the AI's custom path is initialized.
+ start()
/obj/machinery/bot/mulebot/process()
if(!has_power())
@@ -520,13 +530,14 @@ var/global/mulebot_count = 0
/obj/machinery/bot/mulebot/proc/process_bot()
//if(mode) world << "Mode: [mode]"
+
switch(mode)
- if(0) // idle
+ if(BOT_IDLE) // idle
icon_state = "mulebot0"
return
- if(1) // loading/unloading
+ if(BOT_LOADING) // loading/unloading
return
- if(2,3,4) // navigating to deliver,home, or blocked
+ if(BOT_DELIVER,BOT_GO_HOME,BOT_BLOCKED) // navigating to deliver,home, or blocked
if(loc == target) // reached target
at_target()
@@ -569,14 +580,14 @@ var/global/mulebot_count = 0
path -= loc
- if(mode==4)
+ if(mode == BOT_BLOCKED)
spawn(1)
send_status()
if(destination == home_destination)
- mode = 3
+ mode = BOT_GO_HOME
else
- mode = 2
+ mode = BOT_DELIVER
else // failed to move
@@ -585,73 +596,74 @@ var/global/mulebot_count = 0
blockcount++
- mode = 4
+ mode = BOT_BLOCKED
if(blockcount == 3)
- src.visible_message("[src] makes an annoyed buzzing sound.", "You hear an electronic buzzing sound.")
- playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0)
+ visible_message("[src] makes an annoyed buzzing sound.", "You hear an electronic buzzing sound.")
+ playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
if(blockcount > 10) // attempt 10 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, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
+ playsound(loc, 'sound/machines/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, 'sound/machines/ping.ogg', 50, 0)
- mode = 4
- mode =6
+ visible_message("[src] makes a delighted ping!", "You hear a ping.")
+ playsound(loc, 'sound/machines/ping.ogg', 50, 0)
+ mode = BOT_BLOCKED
+ mode = BOT_WAIT_FOR_NAV
return
return
else
- src.visible_message("[src] makes an annoyed buzzing sound.", "You hear an electronic buzzing sound.")
- playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0)
+ visible_message("[src] makes an annoyed buzzing sound.", "You hear an electronic buzzing sound.")
+ playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
//world << "Bad turf."
- mode = 5
+ mode = BOT_NAV
return
else
//world << "No path."
- mode = 5
+ mode = BOT_NAV
return
- if(5) // calculate new path
+ if(BOT_NAV) // calculate new path
//world << "Calc new path."
- mode = 6
+ mode = BOT_WAIT_FOR_NAV
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, 'sound/machines/ping.ogg', 50, 0)
+ mode = BOT_BLOCKED
+ visible_message("[src] makes a delighted ping!", "You hear a ping.")
+ playsound(loc, 'sound/machines/ping.ogg', 50, 0)
else
- src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
- playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
+ playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
- mode = 7
+ mode = BOT_NO_ROUTE
//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_cardinal, 0, 250, id=botcard, exclude=avoid)
- if(!src.path)
- src.path = list()
+/obj/machinery/bot/mulebot/calc_path(var/turf/avoid = null)
+ path = AStar(loc, target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 250, id=botcard, exclude=avoid)
+ if(!path)
+ path = list()
// 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)
+/obj/machinery/bot/mulebot/set_destination(var/new_dest)
spawn(0)
new_destination = new_dest
post_signal(beacon_freq, "findbeacon", "delivery")
@@ -660,9 +672,9 @@ var/global/mulebot_count = 0
// starts bot moving to current destination
/obj/machinery/bot/mulebot/proc/start()
if(destination == home_destination)
- mode = 3
+ mode = BOT_GO_HOME
else
- mode = 2
+ mode = BOT_DELIVER
icon_state = "mulebot[(wires.MobAvoid() != 0)]"
// starts bot moving to home
@@ -670,17 +682,28 @@ var/global/mulebot_count = 0
/obj/machinery/bot/mulebot/proc/start_home()
spawn(0)
set_destination(home_destination)
- mode = 4
+ mode = BOT_BLOCKED
icon_state = "mulebot[(wires.MobAvoid() != 0)]"
// 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, 'sound/machines/chime.ogg', 50, 0)
+ radio_frequency = 1347 //Supply channel
+ visible_message("[src] makes a chiming sound!", "You hear a chime.")
+ playsound(loc, 'sound/machines/chime.ogg', 50, 0)
reached_target = 1
+ if(pathset) //The AI called us here, so notify it of our arrival.
+ loaddir = dir //The MULE will attempt to load a crate in whatever direction the MULE is "facing".
+ if(calling_ai)
+ calling_ai << "\icon[src] [src] wirelessly plays a chiming sound!"
+ playsound(calling_ai, 'sound/machines/chime.ogg',40, 0)
+ calling_ai = null
+ radio_frequency = 1447 //Report on AI Private instead if the AI is controlling us.
+ //bot_reset()
+
if(load) // if loaded, unload at target
+ speak("Destination [destination] reached. Unloading [load].",radio_frequency)
unload(loaddir)
else
// not loaded
@@ -695,14 +718,16 @@ var/global/mulebot_count = 0
AM = locate(/obj/structure/closet/crate) in get_step(loc,loaddir)
if(AM)
load(AM)
+ if(report_delivery)
+ speak("Now loading [load] at [get_area(src)].", radio_frequency)
// 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
+ mode = BOT_BLOCKED
else
- mode = 0 // otherwise go idle
+ bot_reset() // otherwise go idle
send_status() // report status to anyone listening
@@ -714,13 +739,12 @@ var/global/mulebot_count = 0
var/mob/M = obs
if(ismob(M))
if(istype(M,/mob/living/silicon/robot))
- src.visible_message("[src] bumps into [M]!")
+ visible_message("[src] bumps into [M]!")
else
- src.visible_message("[src] knocks over [M]!")
+ visible_message("[src] knocks over [M]!")
M.stop_pulling()
M.Stun(8)
M.Weaken(5)
- M.lying = 1
..()
/obj/machinery/bot/mulebot/alter_health()
@@ -730,8 +754,8 @@ var/global/mulebot_count = 0
// called from mob/living/carbon/human/Crossed()
// when mulebot is in the same loc
/obj/machinery/bot/mulebot/proc/RunOver(var/mob/living/carbon/human/H)
- src.visible_message("[src] drives over [H]!")
- playsound(src.loc, 'sound/effects/splat.ogg', 50, 1)
+ visible_message("[src] drives over [H]!")
+ playsound(loc, 'sound/effects/splat.ogg', 50, 1)
var/damage = rand(5,15)
H.apply_damage(2*damage, BRUTE, "head")
@@ -741,7 +765,7 @@ var/global/mulebot_count = 0
H.apply_damage(0.5*damage, BRUTE, "l_arm")
H.apply_damage(0.5*damage, BRUTE, "r_arm")
- var/obj/effect/decal/cleanable/blood/B = new(src.loc)
+ var/obj/effect/decal/cleanable/blood/B = new(loc)
B.blood_DNA = list()
B.blood_DNA[H.dna.unique_enzymes] = H.dna.blood_type
@@ -779,7 +803,7 @@ var/global/mulebot_count = 0
// process control input
switch(recv)
if("stop")
- mode = 0
+ bot_reset()
return
if("go")
@@ -815,6 +839,7 @@ var/global/mulebot_count = 0
// receive response from beacon
recv = signal.data["beacon"]
+
if(wires.BeaconRX())
if(recv == new_destination) // if the recvd beacon location matches the set destination
// the we will navigate there
@@ -829,12 +854,18 @@ var/global/mulebot_count = 0
calc_path()
updateDialog()
+ //Detects and stores current active delivery beacons.
+ if(signal.data["beacon"])
+ if(!delivery_beacons)
+ delivery_beacons = new()
+ delivery_beacons[signal.data["beacon"] ] = signal.source
+
// send a radio signal with a single data key/value pair
-/obj/machinery/bot/mulebot/proc/post_signal(var/freq, var/key, var/value)
+/obj/machinery/bot/mulebot/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)
+/obj/machinery/bot/mulebot/post_signal_multiple(var/freq, var/list/keyval)
if(freq == beacon_freq && !(wires.BeaconRX()))
return
@@ -856,17 +887,17 @@ var/global/mulebot_count = 0
//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")
+ else if (signal.data["type"] == MULE_BOT)
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()
+/obj/machinery/bot/mulebot/send_status()
var/list/kv = list(
- "type" = "mulebot",
+ "type" = MULE_BOT,
"name" = suffix,
- "loca" = (loc ? loc.loc : "Unknown"), // somehow loc can be null and cause a runtime - Quarxink
+ "loca" = get_area(src),
"mode" = mode,
"powr" = (cell ? cell.percent() : 0),
"dest" = destination,
@@ -886,7 +917,7 @@ var/global/mulebot_count = 0
/obj/machinery/bot/mulebot/explode()
- src.visible_message("[src] blows apart!", 1)
+ visible_message(" [src] blows apart!", 1)
var/turf/Tsec = get_turf(src)
new /obj/item/device/assembly/prox_sensor(Tsec)
@@ -902,6 +933,6 @@ var/global/mulebot_count = 0
s.set_up(3, 1, src)
s.start()
- new /obj/effect/decal/cleanable/oil(src.loc)
+ new /obj/effect/decal/cleanable/oil(loc)
unload(0)
qdel(src)
diff --git a/code/game/machinery/bots/secbot.dm b/code/game/machinery/bots/secbot.dm
index ae8f5927db7..406245fea17 100644
--- a/code/game/machinery/bots/secbot.dm
+++ b/code/game/machinery/bots/secbot.dm
@@ -17,27 +17,15 @@
var/threatlevel = 0
var/target_lastloc //Loc of target when arrested.
var/last_found //There's a delay
- var/frustration = 0
// var/emagged = 0 //Emagged Secbots view everyone as a criminal
var/declare_arrests = 1 //When making an arrest, should it notify everyone wearing sechuds?
var/idcheck = 0 //If true, arrest people with no IDs
- var/weaponscheck = 0 //If true, arrest people for weapons if they don't have access
+ var/weaponscheck = 0 //If true, arrest people for weapons if they lack access
var/check_records = 1 //Does it check security records?
var/arrest_type = 0 //If true, don't handcuff
-
- var/mode = 0
-#define SECBOT_IDLE 0 // idle
-#define SECBOT_HUNT 1 // found target, hunting
-#define SECBOT_PREP_ARREST 2 // at target, preparing to arrest
-#define SECBOT_ARREST 3 // arresting target
-#define SECBOT_START_PATROL 4 // start patrol
-#define SECBOT_PATROL 5 // patrolling
-#define SECBOT_SUMMON 6 // summoned by PDA
-
- var/auto_patrol = 0 // set to make bot automatically patrol
-
- var/beacon_freq = 1445 // navigation beacon frequency
- var/control_freq = 1447 // bot control frequency
+ radio_frequency = 1359 //Security channel
+ bot_type = SEC_BOT
+ bot_filter = RADIO_SECBOT
//List of weapons that secbots will not arrest for
var/safe_weapons = list(\
@@ -45,18 +33,6 @@
/obj/item/weapon/gun/energy/laser/redtag,\
/obj/item/weapon/gun/energy/laser/practice)
- var/turf/patrol_target // this is turf to navigate to (location of beacon)
- var/new_destination // pending new destination (waiting for beacon response)
- var/destination // destination description tag
- var/next_destination // the next destination in the patrol route
- var/list/path = new // list of path turfs
-
- var/blockcount = 0 //number of times retried a blocked path
- var/awaiting_beacon = 0 // count of pticks awaiting a beacon response
-
- var/nearest_beacon // the nearest beacon's tag
- var/turf/nearest_beacon_loc // the nearest beacon's location
-
/obj/machinery/bot/secbot/beepsky
name = "Officer Beep O'sky"
@@ -83,30 +59,38 @@
/obj/machinery/bot/secbot/New()
..()
- src.icon_state = "secbot[src.on]"
+ icon_state = "secbot[on]"
spawn(3)
- src.botcard = new /obj/item/weapon/card/id(src)
- var/datum/job/detective/J = new /datum/job/detective
- src.botcard.access = J.get_access()
- if(radio_controller)
- radio_controller.add_object(src, control_freq, filter = RADIO_SECBOT)
- radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
+
+ var/datum/job/detective/J = new/datum/job/detective
+ botcard.access = J.get_access()
+ prev_access = botcard.access
+ add_to_beacons(bot_filter)
/obj/machinery/bot/secbot/turn_on()
..()
- src.icon_state = "secbot[src.on]"
- src.updateUsrDialog()
+ icon_state = "secbot[on]"
+ updateUsrDialog()
/obj/machinery/bot/secbot/turn_off()
..()
- src.target = null
- src.oldtarget_name = null
- src.anchored = 0
- src.mode = SECBOT_IDLE
+ icon_state = "secbot[on]"
+ updateUsrDialog()
+
+/obj/machinery/bot/secbot/bot_reset()
+ ..()
+ target = null
+ oldtarget_name = null
+ anchored = 0
walk_to(src,0)
- src.icon_state = "secbot[src.on]"
- src.updateUsrDialog()
+ last_found = world.time
+
+/obj/machinery/bot/secbot/set_custom_texts()
+
+ text_hack = "You overload [name]'s target identification system."
+ text_dehack = "You reboot [name] and restore the target identification."
+ text_dehack_fail = "[name] refuses to accept your authority!"
/obj/machinery/bot/secbot/attack_hand(mob/user as mob)
. = ..()
@@ -119,13 +103,14 @@
var/dat
dat += hack(user)
dat += text({"
+Securitron v1.6 controls
Status: []
-Behaviour controls are [src.locked ? "locked" : "unlocked"]
-Maintenance panel panel is [src.open ? "opened" : "closed"]
"},
+Behaviour controls are [locked ? "locked" : "unlocked"]
+Maintenance panel panel is [open ? "opened" : "closed"]"},
-"[src.on ? "On" : "Off"]" )
+"[on ? "On" : "Off"]" )
- if(!src.locked || issilicon(user))
+ if(!locked || issilicon(user))
dat += text({"
Arrest Unidentifiable Persons: []
Arrest for Unauthorized Weapons: []
@@ -135,136 +120,107 @@ Operating Mode: []
Report Arrests[]
Auto Patrol: []"},
-"[src.idcheck ? "Yes" : "No"]",
-"[src.weaponscheck ? "Yes" : "No"]",
-"[src.check_records ? "Yes" : "No"]",
-"[src.arrest_type ? "Detain" : "Arrest"]",
-"[src.declare_arrests ? "Yes" : "No"]",
+"[idcheck ? "Yes" : "No"]",
+"[weaponscheck ? "Yes" : "No"]",
+"[check_records ? "Yes" : "No"]",
+"[arrest_type ? "Detain" : "Arrest"]",
+"[declare_arrests ? "Yes" : "No"]",
"[auto_patrol ? "On" : "Off"]" )
- var/datum/browser/popup = new(user, "autosec", "Securitron v1.5.1 controls")
+ var/datum/browser/popup = new(user, "autosec", "Securitron v1.6 controls")
popup.set_content(dat)
popup.open()
return
/obj/machinery/bot/secbot/Topic(href, href_list)
- if(..())
- return
- usr.set_machine(src)
- if((href_list["power"]) && (src.allowed(usr)))
- if (src.on && !src.emagged)
- turn_off()
- else
- turn_on()
- return
+
+ ..()
switch(href_list["operation"])
if("idcheck")
- src.idcheck = !src.idcheck
- src.updateUsrDialog()
+ idcheck = !idcheck
+ updateUsrDialog()
if("weaponscheck")
- src.weaponscheck = !src.weaponscheck
- src.updateUsrDialog()
+ weaponscheck = !weaponscheck
+ updateUsrDialog()
if("ignorerec")
- src.check_records = !src.check_records
- src.updateUsrDialog()
+ check_records = !check_records
+ updateUsrDialog()
if("switchmode")
- src.arrest_type = !src.arrest_type
- src.updateUsrDialog()
- if("patrol")
- auto_patrol = !auto_patrol
- mode = SECBOT_IDLE
+ arrest_type = !arrest_type
updateUsrDialog()
if("declarearrests")
- src.declare_arrests = !src.declare_arrests
- src.updateUsrDialog()
- if("hack")
- if(!src.emagged)
- src.emagged = 2
- src.hacked = 1
- usr << "You overload [src]'s target identification system."
- else if(!src.hacked)
- usr << "[src] refuses to accept your authority!"
- else
- src.emagged = 0
- src.hacked = 0
- usr << "You reboot [src] and restore the target identification."
- src.updateUsrDialog()
+ declare_arrests = !declare_arrests
+ updateUsrDialog()
+
/obj/machinery/bot/secbot/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
- if(src.allowed(user) && !open && !emagged)
- src.locked = !src.locked
- user << "Controls are now [src.locked ? "locked." : "unlocked."]"
+ if(allowed(user) && !open && !emagged)
+ locked = !locked
+ user << "Controls are now [locked ? "locked." : "unlocked."]"
else
if(emagged)
user << "ERROR"
if(open)
user << "Please close the access panel before locking it."
else
- user << "Access denied."
+ user << " Access denied."
else
..()
if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != "harm") // Any intent but harm will heal, so we shouldn't get angry.
return
- if(!istype(W, /obj/item/weapon/screwdriver) && (W.force) && (!src.target) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
+ if(!istype(W, /obj/item/weapon/screwdriver) && (W.force) && (!target) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
threatlevel = user.assess_threat(src)
threatlevel += 6
if(threatlevel >= 4)
- src.target = user
- src.mode = SECBOT_HUNT
+ target = user
+ mode = BOT_HUNT
/obj/machinery/bot/secbot/Emag(mob/user as mob)
..()
- if(open && !locked)
- if(user) user << "You short out [src]'s target assessment circuits."
+ if(emagged == 2)
+ if(user) user << " You short out [src]'s target assessment circuits."
spawn(0)
for(var/mob/O in hearers(src, null))
- O.show_message("[src] buzzes oddly!", 1)
- src.target = null
- if(user) src.oldtarget_name = user.name
- src.last_found = world.time
- src.anchored = 0
- src.declare_arrests = 0
- src.emagged = 2
- src.on = 1
- src.icon_state = "secbot[src.on]"
- mode = SECBOT_IDLE
+ O.show_message("[src] buzzes oddly!", 1)
+ if(user) oldtarget_name = user.name
+ declare_arrests = 0
/obj/machinery/bot/secbot/process()
set background = BACKGROUND_ENABLED
- if(!src.on)
+ if(!on)
+ return
+
+ if(call_path)
+ call_mode()
return
switch(mode)
- if(SECBOT_IDLE) // idle
+ if(BOT_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
+ mode = BOT_START_PATROL // switch to patrol mode
- if(SECBOT_HUNT) // hunting for perp
+ if(BOT_HUNT) // hunting for perp
// if can't reach perp for long enough, go idle
- if(src.frustration >= 8)
+ if(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 = SECBOT_IDLE
- walk_to(src,0)
+ bot_reset()
if(target) // make sure target exists
- if(src.Adjacent(target) && isturf(src.target.loc)) // if right next to perp
- playsound(src.loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
- src.icon_state = "secbot-c"
+ if(Adjacent(target) && isturf(target.loc)) // if right next to perp
+ playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
+ icon_state = "secbot-c"
spawn(2)
- src.icon_state = "secbot[src.on]"
- var/mob/living/carbon/M = src.target
+ icon_state = "secbot[on]"
+ var/mob/living/carbon/M = target
var/maxstuns = 4
if(istype(M, /mob/living/carbon/human))
if(M.stuttering < 5 && (!(HULK in M.mutations)))
@@ -278,7 +234,7 @@ Auto Patrol: []"},
if(declare_arrests)
var/area/location = get_area(src)
- broadcast_hud_message("[src.name] is [arrest_type ? "detaining" : "arresting"] level [threatlevel] scumbag [target] in [location]", src)
+ speak("[arrest_type ? "Detaining" : "Arresting"] level [threatlevel] scumbag [target] in [location].", radio_frequency)
target.visible_message("[src.target] has been stunned by [src]!",\
"[src.target] has been stunned by [src]!")
@@ -286,369 +242,115 @@ Auto Patrol: []"},
if(maxstuns <= 0)
target = null
- mode = SECBOT_PREP_ARREST
- src.anchored = 1
- src.target_lastloc = M.loc
+ mode = BOT_PREP_ARREST
+ anchored = 1
+ 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++
+ var/turf/olddist = get_dist(src, target)
+ walk_to(src, target,1,4)
+ if((get_dist(src, target)) >= (olddist))
+ frustration++
else
- src.frustration = 0
+ frustration = 0
- if(SECBOT_PREP_ARREST) // preparing to arrest target
+ if(BOT_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
+ if((get_dist(src, target) > 1) || ((target.loc != target_lastloc) && target.weakened < 2))
+ anchored = 0
+ mode = BOT_HUNT
return
if(iscarbon(target) && target.canBeHandcuffed())
- if(!src.target.handcuffed && !src.arrest_type)
- playsound(src.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -2)
- mode = SECBOT_ARREST
- target.visible_message("[src] is trying to put handcuffs on [src.target]!",\
+ if(!target.handcuffed && !arrest_type)
+ playsound(loc, 'sound/weapons/handcuffs.ogg', 30, 1, -2)
+ mode = BOT_ARREST
+ target.visible_message("[src] is trying to put handcuffs on [target]!",\
"[src] is trying to put handcuffs on [src.target]!")
spawn(60)
- if(get_dist(src, src.target) <= 1)
- if(src.target.handcuffed)
+ if(get_dist(src, target) <= 1)
+ if(target.handcuffed)
return
- if(istype(src.target,/mob/living/carbon))
+ if(istype(target,/mob/living/carbon))
target.handcuffed = new /obj/item/weapon/handcuffs(target)
target.update_inv_handcuffed(0) //update the handcuffs overlay
- mode = SECBOT_IDLE
- src.target = null
- src.anchored = 0
- src.last_found = world.time
- src.frustration = 0
+ mode = BOT_IDLE
+ target = null
+ anchored = 0
+ last_found = world.time
+ frustration = 0
- playsound(src.loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg'), 50, 0)
+ playsound(loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/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)
+ // speak(arrest_message)
else
- mode = SECBOT_IDLE
- src.target = null
- src.anchored = 0
- src.last_found = world.time
- src.frustration = 0
+ mode = BOT_IDLE
+ target = null
+ anchored = 0
+ last_found = world.time
+ frustration = 0
- if(SECBOT_ARREST) // arresting
+ if(BOT_ARREST) // arresting
if(!target || target.handcuffed)
- src.anchored = 0
- mode = SECBOT_IDLE
+ anchored = 0
+ mode = BOT_IDLE
return
+ else //Try arresting again if the target escapes.
+ mode = BOT_PREP_ARREST
+ anchored = 0
+ if(BOT_START_PATROL)
+ look_for_perp()
+ start_patrol()
- if(SECBOT_START_PATROL) // start a patrol
-
- 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()
+ if(BOT_PATROL)
+ look_for_perp()
+ bot_patrol()
+ if(BOT_SUMMON)
+ bot_summon()
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
-
- 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
-/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
- auto_patrol = 0
- mode = SECBOT_IDLE
- speak("Disengaging patrol mode.")
- send_status()
-
-
-/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 a radio signal
-// used for beacon reception
-
-/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]]"
- */
-
- var/recv = signal.data["command"]
- // process all-bot input
- if(recv=="bot_status")
- 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
-
-
-
- // 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
-/obj/machinery/bot/secbot/proc/calc_path(var/turf/avoid = null)
- src.path = AStar(src.loc, patrol_target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 120, id=botcard, exclude=avoid)
- if(!src.path)
- src.path = list()
-
-
// look for a criminal in view of the bot
/obj/machinery/bot/secbot/proc/look_for_perp()
- src.anchored = 0
+ 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))
+ if((C.name == oldtarget_name) && (world.time < last_found + 100))
continue
- src.threatlevel = C.assess_threat(src)
+ threatlevel = C.assess_threat(src)
- if(!src.threatlevel)
+ if(!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('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg'), 50, 0)
- src.visible_message("[src] points at [C.name]!")
- mode = SECBOT_HUNT
+ else if(threatlevel >= 4)
+ target = C
+ oldtarget_name = C.name
+ speak("Level [threatlevel] infraction alert!")
+ playsound(loc, pick('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg'), 50, 0)
+ visible_message("[src] points at [C.name]!")
+ mode = BOT_HUNT
spawn(0)
process() // ensure bot quickly responds to a perp
break
else
continue
-
/obj/machinery/bot/secbot/proc/check_for_weapons(var/obj/item/slot_item)
if(istype(slot_item, /obj/item/weapon/gun) || istype(slot_item, /obj/item/weapon/melee))
if(!(slot_item.type in safe_weapons))
return 1
return 0
-/obj/machinery/bot/secbot/Bump(M as mob|obj) //Leave no door unopened!
- 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
/* terrible
/obj/machinery/bot/secbot/Bumped(atom/movable/M as mob|obj)
@@ -661,13 +363,13 @@ Auto Patrol: []"},
/obj/machinery/bot/secbot/explode()
walk_to(src,0)
- src.visible_message("[src] blows apart!", 1)
+ visible_message(" [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 += "hs_hole"
- Sa.created_name = src.name
+ Sa.created_name = name
new /obj/item/device/assembly/prox_sensor(Tsec)
new /obj/item/weapon/melee/baton(Tsec)
@@ -678,14 +380,14 @@ Auto Patrol: []"},
s.set_up(3, 1, src)
s.start()
- new /obj/effect/decal/cleanable/oil(src.loc)
+ new /obj/effect/decal/cleanable/oil(loc)
qdel(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
+ target = user
+ mode = BOT_HUNT
//Secbot Construction
@@ -695,7 +397,7 @@ Auto Patrol: []"},
..()
return
- if(src.type != /obj/item/clothing/head/helmet) //Eh, but we don't want people making secbots out of space helmets.
+ if(type != /obj/item/clothing/head/helmet) //Eh, but we don't want people making secbots out of space helmets.
return
if(S.secured)
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index 3f239f3d591..d68d92464a4 100644
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -297,12 +297,18 @@ var/global/list/obj/item/device/pda/PDAs = list()
dat += "Engineering Functions
"
dat += ""
if (cartridge.access_medical)
dat += "Medical Functions
"
dat += ""
+ else
dat += ""
if (cartridge.access_security)
dat += "Security Functions
"
@@ -325,6 +331,8 @@ var/global/list/obj/item/device/pda/PDAs = list()
if (cartridge)
if (cartridge.access_janitor)
dat += "
Custodial Locator"
+ if(istype(cartridge.radio, /obj/item/radio/integrated/cleanbot))
+ dat += "
Cleanbot Access"
if (istype(cartridge.radio, /obj/item/radio/integrated/signal))
dat += "
Signaler System"
if (cartridge.access_reagent_scanner)
@@ -467,9 +475,9 @@ var/global/list/obj/item/device/pda/PDAs = list()
mode = 0
else
mode = round(mode/10)
- if(mode==4)//Fix for cartridges. Redirects to hub.
+ if(mode==4 || mode == 5)//Fix for cartridges. Redirects to hub.
mode = 0
- else if(mode >= 40 && mode <= 49)//Fix for cartridges. Redirects to refresh the menu.
+ else if(mode >= 40 && mode <= 59)//Fix for cartridges. Redirects to refresh the menu.
cartridge.mode = mode
cartridge.unlock()
if ("Authenticate")//Checks for ID
@@ -1085,4 +1093,4 @@ var/global/list/obj/item/device/pda/PDAs = list()
for(var/obj/item/device/pda/P in PDAs)
if(!P.owner || P.toff || P.hidden) continue
. += P
- return .
+ return .
\ No newline at end of file
diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm
index 082db03166a..3c1934f55a2 100644
--- a/code/game/objects/items/devices/PDA/cart.dm
+++ b/code/game/objects/items/devices/PDA/cart.dm
@@ -38,21 +38,37 @@
icon_state = "cart-e"
access_engine = 1
+ /obj/item/weapon/cartridge/engineering/New()
+ ..()
+ radio = new /obj/item/radio/integrated/floorbot(src)
+
/obj/item/weapon/cartridge/atmos
name = "\improper BreatheDeep cartridge"
icon_state = "cart-a"
access_atmos = 1
+ /obj/item/weapon/cartridge/atmos/New()
+ ..()
+ radio = new /obj/item/radio/integrated/floorbot(src)
+
/obj/item/weapon/cartridge/medical
name = "\improper Med-U cartridge"
icon_state = "cart-m"
access_medical = 1
+ /obj/item/weapon/cartridge/medical/New()
+ ..()
+ radio = new /obj/item/radio/integrated/medbot(src)
+
/obj/item/weapon/cartridge/chemistry
name = "\improper ChemWhiz cartridge"
icon_state = "cart-chem"
access_reagent_scanner = 1
+ /obj/item/weapon/cartridge/chemistry/New()
+ ..()
+ radio = new /obj/item/radio/integrated/medbot(src)
+
/obj/item/weapon/cartridge/security
name = "\improper R.O.B.U.S.T. cartridge"
icon_state = "cart-s"
@@ -79,6 +95,10 @@
icon_state = "cart-j"
access_janitor = 1
+/obj/item/weapon/cartridge/janitor/New()
+ ..()
+ radio = new /obj/item/radio/integrated/cleanbot(src)
+
/obj/item/weapon/cartridge/lawyer
name = "\improper P.R.O.V.E. cartridge"
icon_state = "cart-s"
@@ -167,6 +187,10 @@
access_engine = 1
access_atmos = 1
+/obj/item/weapon/cartridge/ce/New()
+ ..()
+ radio = new /obj/item/radio/integrated/floorbot(src)
+
/obj/item/weapon/cartridge/cmo
name = "\improper Med-U DELUXE cartridge"
icon_state = "cart-cmo"
@@ -175,6 +199,10 @@
access_reagent_scanner = 1
access_medical = 1
+/obj/item/weapon/cartridge/cmo/New()
+ ..()
+ radio = new /obj/item/radio/integrated/medbot(src)
+
/obj/item/weapon/cartridge/rd
name = "\improper Signal Ace DELUXE cartridge"
icon_state = "cart-rd"
@@ -249,6 +277,66 @@
frequency.post_signal(src, status_signal)
+/obj/item/weapon/cartridge/proc/bot_control(var/obj/item/radio/integrated/SC)
+
+
+ if(!SC)
+ menu = "Interlink Error - Please reinsert cartridge."
+ return
+
+ if(!SC.active)
+ // list of bots
+ if(!SC.botlist || (SC.botlist && SC.botlist.len==0))
+ menu += "No bots found.
"
+
+ else
+ for(var/obj/machinery/bot/B in SC.botlist)
+ menu += "[B] at [get_area(B)]
"
+
+ menu += "
Scan for active bots
"
+
+ else // bot selected, control it
+
+ menu += "[SC.active]
Status: (
refresh)
"
+
+ if(!SC.botstatus)
+ menu += "Waiting for response...
"
+ else
+
+ menu += "Location: [SC.botstatus["loca"] ]
"
+ menu += "Mode: "
+
+ switch(SC.botstatus["mode"])
+ if(BOT_IDLE)
+ menu += "Ready"
+ if(BOT_HUNT)
+ menu += "Apprehending target"
+ if(BOT_PREP_ARREST,BOT_ARREST)
+ menu += "Arresting target"
+ if(BOT_START_PATROL)
+ menu += "Starting patrol"
+ if(BOT_PATROL)
+ menu += "On patrol"
+ if(BOT_SUMMON)
+ menu += "Responding to summons"
+ if(BOT_CLEANING)
+ menu += "Cleaning"
+ if(BOT_MOVING)
+ menu += "Proceeding to work site"
+ if(BOT_REPAIRING)
+ menu += "Performing repairs"
+ if(BOT_HEALING)
+ menu += "Medicating patient"
+ if(BOT_RESPONDING)
+ menu += "Proceeding to AI waypoint"
+
+ menu += "
\[Stop Patrol\] "
+ menu += "\[Start Patrol\] "
+ menu += "\[Summon Bot\]
"
+ menu += "
Return to bot list"
+ return menu
+
+
/obj/item/weapon/cartridge/proc/generate_menu()
switch(mode)
if(40) //signaller
@@ -457,52 +545,8 @@ Code:
menu += "
"
if (46) //beepsky control
var/obj/item/radio/integrated/beepsky/SC = radio
- if(!SC)
- menu = "Interlink Error - Please reinsert cartridge."
- return
-
menu = "
Securitron Interlink
"
-
- if(!SC.active)
- // list of bots
- if(!SC.botlist || (SC.botlist && SC.botlist.len==0))
- menu += "No bots found.
"
-
- else
- for(var/obj/machinery/bot/secbot/B in SC.botlist)
- menu += "[B] at [B.loc.loc]
"
-
- menu += "
Scan for active bots
"
-
- else // bot selected, control it
-
- menu += "[SC.active]
Status: (
refresh)
"
-
- if(!SC.botstatus)
- menu += "Waiting for response...
"
- else
-
- menu += "Location: [SC.botstatus["loca"] ]
"
- menu += "Mode: "
-
- switch(SC.botstatus["mode"])
- if(0)
- menu += "Ready"
- if(1)
- menu += "Apprehending target"
- if(2,3)
- menu += "Arresting target"
- if(4)
- menu += "Starting patrol"
- if(5)
- menu += "On patrol"
- if(6)
- menu += "Responding to summons"
-
- menu += "
\[Stop Patrol\] "
- menu += "\[Start Patrol\] "
- menu += "\[Summon Bot\]
"
- menu += "
Return to bot list"
+ bot_control(SC)
if (47) //quartermaster order records
menu = "
Supply Record Interlink
"
@@ -526,7 +570,6 @@ Code:
if(!QC)
menu = "Interlink Error - Please reinsert cartridge."
return
-
menu = "
M.U.L.E. bot Interlink V0.8
"
if(!QC.active)
@@ -552,19 +595,19 @@ Code:
menu += "Mode: "
switch(QC.botstatus["mode"])
- if(0)
+ if(BOT_IDLE)
menu += "Ready"
- if(1)
+ if(BOT_LOADING)
menu += "Loading/Unloading"
- if(2)
+ if(BOT_DELIVER)
menu += "Navigating to Delivery Location"
- if(3)
+ if(BOT_GO_HOME)
menu += "Navigating to Home"
- if(4)
+ if(BOT_BLOCKED)
menu += "Waiting for clear path"
- if(5,6)
+ if(BOT_NAV,BOT_WAIT_FOR_NAV)
menu += "Calculating navigation path"
- if(7)
+ if(BOT_NO_ROUTE)
menu += "Unable to locate destination"
var/obj/structure/closet/crate/C = QC.botstatus["load"]
menu += "
Current Load: [ !C ? "none" : "[C.name] (unload)" ]
"
@@ -641,6 +684,20 @@ Code:
menu += "ERROR: Unable to determine current location."
menu += "
Refresh GPS Locator"
+ if (50) //Cleanbot control
+ menu = "
Cleanbot Interlink
"
+ var/obj/item/radio/integrated/cleanbot/SC = radio
+ bot_control(SC)
+
+ if (51) //floorbot control
+ menu = "
Floorbot Interlink
"
+ var/obj/item/radio/integrated/floorbot/SC = radio
+ bot_control(SC)
+
+ if (52) //Medibot control
+ menu = "
Medibot Interlink
"
+ var/obj/item/radio/integrated/medbot/SC = radio
+ bot_control(SC)
/obj/item/weapon/cartridge/Topic(href, href_list)
..()
diff --git a/code/game/objects/items/devices/PDA/radio.dm b/code/game/objects/items/devices/PDA/radio.dm
index e576cc2e109..ca45bc45567 100644
--- a/code/game/objects/items/devices/PDA/radio.dm
+++ b/code/game/objects/items/devices/PDA/radio.dm
@@ -4,6 +4,13 @@
icon = 'icons/obj/module.dmi'
icon_state = "power_mod"
var/obj/item/device/pda/hostpda = null
+ var/list/botlist = null // list of bots
+ var/obj/machinery/bot/active // the active bot; if null, show bot list
+ var/list/botstatus // the status signal sent by the bot
+ var/bot_type //The type of bot it is.
+ var/bot_filter //Determines which radio filter to use.
+
+ var/control_freq = 1447
var/on = 0 //Are we currently active??
var/menu_message = ""
@@ -12,13 +19,17 @@
..()
if (istype(loc.loc, /obj/item/device/pda))
hostpda = loc.loc
+ if (bot_filter)
+ spawn(5)
+ add_to_radio(bot_filter)
-/obj/item/radio/integrated/proc/post_signal(var/freq, var/key, var/value, var/key2, var/value2, var/key3, var/value3, s_filter)
+/obj/item/radio/integrated/proc/post_signal(var/freq, var/key, var/value, var/key2, var/value2, var/key3, var/value3,var/key4, var/value4, s_filter)
//world << "Post: [freq]: [key]=[value], [key2]=[value2]"
var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
- if(!frequency) return
+ if(!frequency)
+ return
var/datum/signal/signal = new()
signal.source = src
@@ -28,6 +39,8 @@
signal.data[key2] = value2
if(key3)
signal.data[key3] = value3
+ if(key4)
+ signal.data[key4] = value4
frequency.post_signal(src, signal, filter = s_filter)
@@ -44,33 +57,18 @@
/obj/item/radio/integrated/proc/generate_menu()
-/obj/item/radio/integrated/beepsky
- var/list/botlist = null // list of bots
- var/obj/machinery/bot/secbot/active // the active bot; if null, show bot list
- var/list/botstatus // the status signal sent by the bot
- var/control_freq = 1447
-// create a new QM cartridge, and register to receive bot control & beacon message
-/obj/item/radio/integrated/beepsky/New()
- ..()
- spawn(5)
- if(radio_controller)
- radio_controller.add_object(src, control_freq, filter = RADIO_SECBOT)
+/obj/item/radio/integrated/receive_signal(datum/signal/signal)
+ /*var/obj/item/device/pda/P = src.loc
-// receive radio signals
-// can detect bot status signals
-// create/populate list as they are recvd
-/obj/item/radio/integrated/beepsky/receive_signal(datum/signal/signal)
-// var/obj/item/device/pda/P = src.loc
-
- /*
world << "recvd:[P] : [signal.source]"
for(var/d in signal.data)
world << "- [d] = [signal.data[d]]"
- */
- if (signal.data["type"] == "secbot")
+ */
+
+ if (signal.data["type"] == bot_type)
if(!botlist)
botlist = new()
@@ -81,9 +79,7 @@
var/list/b = signal.data
botstatus = b.Copy()
-// if (istype(P)) P.updateSelfDialog()
-
-/obj/item/radio/integrated/beepsky/Topic(href, href_list)
+/obj/item/radio/integrated/Topic(href, href_list)
..()
var/obj/item/device/pda/PDA = src.hostpda
@@ -91,32 +87,53 @@
if("control")
active = locate(href_list["bot"])
- post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT)
+ post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter)
if("scanbots") // find all bots
botlist = null
- post_signal(control_freq, "command", "bot_status", s_filter = RADIO_SECBOT)
+ post_signal(control_freq, "command", "bot_status", s_filter = bot_filter)
if("botlist")
active = null
if("stop", "go")
- post_signal(control_freq, "command", href_list["op"], "active", active, s_filter = RADIO_SECBOT)
- post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT)
+ post_signal(control_freq, "command", href_list["op"], "active", active, s_filter = bot_filter)
+ post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter)
if("summon")
- post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(PDA) , s_filter = RADIO_SECBOT)
- post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT)
+ post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(PDA) , "useraccess", PDA.GetAccess(), s_filter = bot_filter)
+ post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter)
PDA.cartridge.unlock()
+/obj/item/radio/integrated/proc/add_to_radio(bot_filter) //Master filter control for bots. Must be placed in the bot's local New() to support map spawned bots.
+ if(radio_controller)
+ radio_controller.add_object(src, control_freq, filter = bot_filter)
+
+
+/obj/item/radio/integrated/beepsky
+ bot_filter = RADIO_SECBOT
+ bot_type = SEC_BOT
+
+/obj/item/radio/integrated/medbot
+ bot_filter = RADIO_MEDBOT
+ bot_type = MED_BOT
+
+/obj/item/radio/integrated/floorbot
+ bot_filter = RADIO_FLOORBOT
+ bot_type = FLOOR_BOT
+
+/obj/item/radio/integrated/cleanbot
+ bot_filter = RADIO_CLEANBOT
+ bot_type = CLEAN_BOT
+
/obj/item/radio/integrated/mule
- var/list/botlist = null // list of bots
- var/obj/machinery/bot/mulebot/active // the active bot; if null, show bot list
- var/list/botstatus // the status signal sent by the bot
+ //var/list/botlist = null // list of bots
+ //var/obj/machinery/bot/mulebot/active // the active bot; if null, show bot list
+ //var/list/botstatus // the status signal sent by the bot
var/list/beacons
var/beacon_freq = 1400
- var/control_freq = 1447
+ control_freq = 1447
// create a new QM cartridge, and register to receive bot control & beacon message
/obj/item/radio/integrated/mule/New()
@@ -141,7 +158,7 @@
for(var/d in signal.data)
world << "- [d] = [signal.data[d]]"
*/
- if(signal.data["type"] == "mulebot")
+ if(signal.data["type"] == MULE_BOT)
if(!botlist)
botlist = new()
@@ -162,52 +179,46 @@
// if(istype(P)) P.updateSelfDialog()
/obj/item/radio/integrated/mule/Topic(href, href_list)
- ..()
+ //..()
var/obj/item/device/pda/PDA = src.hostpda
var/cmd = "command"
- if(active) cmd = "command [active.suffix]"
+ if(active)
+ cmd = "command [active.suffix]"
switch(href_list["op"])
if("control")
active = locate(href_list["bot"])
- post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
if("scanbots") // find all bots
botlist = null
- post_signal(control_freq, "command", "bot_status", s_filter = RADIO_MULEBOT)
if("botlist")
active = null
-
if("unload")
post_signal(control_freq, cmd, "unload", s_filter = RADIO_MULEBOT)
- post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
if("setdest")
if(beacons)
var/dest = input("Select Bot Destination", "Mulebot [active.suffix] Interlink", active.destination) as null|anything in beacons
if(dest)
post_signal(control_freq, cmd, "target", "destination", dest, s_filter = RADIO_MULEBOT)
- post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
if("retoff")
post_signal(control_freq, cmd, "autoret", "value", 0, s_filter = RADIO_MULEBOT)
- post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
if("reton")
post_signal(control_freq, cmd, "autoret", "value", 1, s_filter = RADIO_MULEBOT)
- post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
if("pickoff")
post_signal(control_freq, cmd, "autopick", "value", 0, s_filter = RADIO_MULEBOT)
- post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
+
if("pickon")
post_signal(control_freq, cmd, "autopick", "value", 1, s_filter = RADIO_MULEBOT)
- post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
if("stop", "go", "home")
post_signal(control_freq, cmd, href_list["op"], s_filter = RADIO_MULEBOT)
- post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
+
+ post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
PDA.cartridge.unlock()
@@ -227,10 +238,10 @@
..()
if(radio_controller)
initialize()
-
+
/obj/item/radio/integrated/signal/initialize()
if (src.frequency < 1441 || src.frequency > 1489)
- src.frequency = sanitize_frequency(src.frequency)
+ src.frequency = sanitize_frequency(src.frequency)
set_frequency(frequency)
@@ -256,4 +267,4 @@
radio_connection.post_signal(src, signal)
- return
+ return
\ No newline at end of file
diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm
index 3c597dd443e..dd2aa2b8caf 100644
--- a/code/modules/client/client procs.dm
+++ b/code/modules/client/client procs.dm
@@ -258,6 +258,9 @@ var/next_external_rsc = 0
'icons/pda_icons/pda_blank.png',
'icons/pda_icons/pda_boom.png',
'icons/pda_icons/pda_bucket.png',
+ 'icons/pda_icons/pda_medbot.png',
+ 'icons/pda_icons/pda_floorbot.png',
+ 'icons/pda_icons/pda_cleanbot.png',
'icons/pda_icons/pda_crate.png',
'icons/pda_icons/pda_cuffs.png',
'icons/pda_icons/pda_eject.png',
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index ceea1384d12..66963138eb5 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -31,6 +31,7 @@ var/list/ai_list = list()
var/obj/item/device/pda/ai/aiPDA = null
var/obj/item/device/multitool/aiMulti = null
var/obj/item/device/camera/siliconcam/aicamera = null
+ var/obj/machinery/bot/Bot
//MALFUNCTION
var/datum/module_picker/malf_picker
@@ -54,6 +55,8 @@ var/list/ai_list = list()
var/last_paper_seen = null
var/can_shunt = 1
var/last_announcement = "" // For AI VOX, if enabled
+ var/turf/waypoint //Holds the turf of the currently selected waypoint.
+ var/waypoint_mode = 0 //Waypoint mode is for selecting a turf via clicking.
/mob/living/silicon/ai/New(loc, var/datum/ai_laws/L, var/obj/item/device/mmi/B, var/safety = 0)
var/list/possibleNames = ai_names
@@ -94,7 +97,7 @@ var/list/ai_list = list()
if (istype(loc, /turf))
verbs.Add(/mob/living/silicon/ai/proc/ai_network_change, \
/mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \
- /mob/living/silicon/ai/proc/toggle_camera_light)
+ /mob/living/silicon/ai/proc/toggle_camera_light, /mob/living/silicon/ai/proc/botcall)
if(!safety)//Only used by AIize() to successfully spawn an AI.
if (!B)//If there is no player/brain inside.
@@ -356,6 +359,24 @@ var/list/ai_list = list()
A.ai_actual_track(target)
return
+ if (href_list["callbot"]) //Command a bot to move to a selected location.
+ Bot = locate(href_list["callbot"]) in machines
+ if(!Bot || Bot.remote_disabled || src.control_disabled)
+ return //True if there is no bot found, the bot is manually emagged, or the AI is carded with wireless off.
+ waypoint_mode = 1
+ src << "Set your waypoint by clicking on a valid location free of obstructions."
+ return
+
+ if (href_list["interface"]) //Remotely connect to a bot!
+ Bot = locate(href_list["interface"]) in machines
+ if(!Bot || Bot.remote_disabled || src.control_disabled)
+ return
+ Bot.attack_ai(src)
+
+ if (href_list["botrefresh"]) //Refreshes the bot control panel.
+ botcall()
+ return
+
else if (href_list["faketrack"])
var/mob/target = locate(href_list["track"]) in mob_list
var/mob/living/silicon/ai/A = locate(href_list["track2"]) in mob_list
@@ -451,6 +472,61 @@ var/list/ai_list = list()
return 1
+/mob/living/silicon/ai/proc/botcall()
+ set category = "AI Commands"
+ set name = "Access Robot Control"
+ set desc = "Wirelessly control various automatic robots."
+ if(stat == 2)
+ src << "Critical error. System offline."
+ return
+
+ if(control_disabled)
+ src << "Wireless communication is disabled."
+ return
+ var/turf/ai_current_turf = get_turf(src)
+ var/ai_Zlevel = ai_current_turf.z
+ var/d
+ var/area/bot_area
+ d += "Query network status
"
+ d += "Name | Status | Location | Control |
"
+
+ for (Bot in machines)
+ if(Bot.z == ai_Zlevel && !Bot.remote_disabled) //Only non-emagged bots on the same Z-level are detected!
+ bot_area = get_area(Bot)
+ d += "| [Bot.hacked ? "(!) [Bot.name]" : Bot.name] | "
+ //If the bot is on, it will display the bot's current mode status. If the bot is not mode, it will just report "Idle". "Inactive if it is not on at all.
+ d += "[Bot.on ? "[Bot.mode ? "[ Bot.mode_name[Bot.mode] ]": "Idle"]" : "Inactive"] | "
+ d += "[bot_area.name] | "
+ d += "Interface | "
+ d += "Call | "
+ d += "
"
+ d = format_text(d)
+
+ var/datum/browser/popup = new(src, "botcall", "Remote Robot Control", 700, 400)
+ popup.set_content(d)
+ popup.open()
+
+/mob/living/silicon/ai/proc/set_waypoint(var/atom/A)
+ var/turf/turf_check = get_turf(A)
+ //The target must be in view of a camera or near the core.
+ if(turf_check in range(get_turf(src)))
+ call_bot(turf_check)
+ else if(cameranet && cameranet.checkTurfVis(turf_check))
+ call_bot(turf_check)
+ else
+ src << "Selected location is not visible."
+
+/mob/living/silicon/ai/proc/call_bot(var/turf/waypoint)
+
+ if(!Bot)
+ return
+
+ if(Bot.calling_ai && Bot.calling_ai != src) //Prevents an override if another AI is controlling this bot.
+ src << "Interface error. Unit is already in use."
+ return
+
+ Bot.call_bot(src, waypoint)
+
/mob/living/silicon/ai/triggerAlarm(var/class, area/A, var/O, var/alarmsource)
if (stat == 2)
return 1
diff --git a/icons/obj/aibots.dmi b/icons/obj/aibots.dmi
index 7b559aad634..7039ec43103 100644
Binary files a/icons/obj/aibots.dmi and b/icons/obj/aibots.dmi differ
diff --git a/icons/pda_icons/pda_cleanbot.png b/icons/pda_icons/pda_cleanbot.png
new file mode 100644
index 00000000000..cecbcf40773
Binary files /dev/null and b/icons/pda_icons/pda_cleanbot.png differ
diff --git a/icons/pda_icons/pda_floorbot.png b/icons/pda_icons/pda_floorbot.png
new file mode 100644
index 00000000000..999e45aed25
Binary files /dev/null and b/icons/pda_icons/pda_floorbot.png differ
diff --git a/icons/pda_icons/pda_medbot.png b/icons/pda_icons/pda_medbot.png
new file mode 100644
index 00000000000..24ae212be2e
Binary files /dev/null and b/icons/pda_icons/pda_medbot.png differ