Files
2020-02-19 19:48:29 -08:00

3999 lines
122 KiB
Plaintext

//CONTENTS
//Movement control datum
//Guardbot
//Guardbot tools
//Task datums
//Guardbot parts
//Docking Station
//Old Robuddies (PR-4)
//Robot config constants
#define GUARDBOT_LOWPOWER_ALERT_LEVEL 100
#define GUARDBOT_LOWPOWER_IDLE_LEVEL 10
#define GUARDBOT_POWER_DRAW 1
#define GUARDBOT_RADIO_RANGE 75
#define GUARDBOT_DOCK_RESET_DELAY 40
//movement datum
/datum/guardbot_mover
var/obj/machinery/bot/guardbot/master = null
var/delay = 3
New(var/newmaster)
..()
if(istype(newmaster, /obj/machinery/bot/guardbot))
src.master = newmaster
return
proc/master_move(var/atom/the_target as obj|mob,var/adjacent=0)
if(!master)
return 1
if(!isturf(master.loc))
master.mover = null
master = null
return 1
var/target_turf = null
if(isturf(the_target))
target_turf = the_target
else
target_turf = get_turf(the_target)
//var/compare_movepath = current_movepath
SPAWN_DBG(0)
if (!master)
return 1
// Same distance cap as the MULE because I'm really tired of various pathfinding issues. Buddy time and docking stations are often way more than 150 steps away.
// It's 200 something steps alone to get from research to the bar on COG2 for instance, and that's pretty much in a straight line.
var/list/thePath = AStar(get_turf(master), target_turf, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 500, master.botcard)
if (!master)
return 1
master.path = thePath
if(adjacent && master.path && master.path.len) //Make sure to check it isn't null!!
master.path.len-- //Only go UP to the target, not the same tile.
if(!master.path || !master.path.len || !the_target || (ismob(the_target) && master.path.len >= 21))
if(master.task)
master.task.task_input("path_error")
master.moving = 0
//dispose()
master.mover = null
src.master = null
return 1
while(master && master.path && master.path.len && target_turf && master.moving)
// boutput(world, "[compare_movepath] : [current_movepath]")
//if(compare_movepath != current_movepath)
// break
if(master.frustration >= 10 || master.stunned || master.idle || !master.on)
master.frustration = 0
if(master.task)
master.task.task_input("path_blocked")
break
step_to(master, master.path[1])
if(master.loc != master.path[1])
master.frustration++
sleep(delay+delay)
continue
master.path -= master.path[1]
sleep(delay)
if (src.master)
master.moving = 0
master.mover = null
src.master = null
//dispose()
return 0
return 0
//The Robot.
/obj/machinery/bot/guardbot
name = "Guardbuddy"
desc = "The corporate security model of the popular PR-6 Robuddy."
icon = 'icons/obj/aibots.dmi'
icon_state = "robuddy0"
layer = 5.0 //TODO LAYER
density = 0
anchored = 0
req_access = list(access_heads)
on = 1
var/idle = 0 //Sleeping on the job??
var/stunned = 0 //Are we stunned?
locked = 1 //Behavior Controls lock
var/list/path = null
var/frustration = 0
var/moving = 0 //Are we currently ON THE MOVE?
//var/current_movepath = 0 //If we need to switch movement halfway
var/datum/guardbot_mover/mover = null
var/emotion = null //How are you feeling, buddy?
var/datum/computer/file/guardbot_task/task = null //Our current task.
var/datum/computer/file/guardbot_task/model_task = null
var/list/tasks = list() //All tasks. First one is the current.
var/list/scratchpad = list() //Scratchpad memory for tasks to pass messages.
emagged = 0 //Not sure what this should do yet.
health = 25
var/wakeup_timer = 0 //Are we waiting to exit idle mode?
var/warm_boot = 0 //Have we already done the full startup procedure?
var/obj/item/cell/cell //We have limited power! Immersion!!
var/obj/item/device/guardbot_tool/tool //What weapon do we have?
var/obj/machinery/guardbot_dock/charge_dock
var/last_dock_id = null
var/obj/item/clothing/head/hat = null
var/hat_shown = 0
var/hat_icon = 'icons/obj/aibots.dmi'
var/hat_x_offset = 0
var/hat_y_offset = 0
var/icon_needs_update = 1 //Call update_icon() in process
var/image/costume_icon = null
var/bedsheet = 0
var/flashlight_lum = 2
var/flashlight_red = 0.1
var/flashlight_green = 0.4
var/flashlight_blue = 0.1
var/datum/radio_frequency/radio_connection
var/datum/radio_frequency/beacon_connection
var/control_freq = 1219 // bot control frequency
var/beacon_freq = 1445
var/net_id = null
var/last_comm = 0 //World time of last transmission
var/reply_wait = 0
var/exploding = 0 //So we don't die like five times at once.
var/botcard_access = "Captain" //Job access for doors.
//It's not like they can be pushed into airlocks anymore
var/setup_no_costumes = 0 //no halloween costumes for us!!
var/setup_unique_name = 0 //Name doesn't need random number appended to it.
var/setup_spawn_dock = 0 //Spawn a docking station where we are.
var/setup_charge_maximum = 1500 //Max charge of internal cell. 1500 ~25 minutes
var/setup_charge_percentage = 90 //Percentage charge of internal cell
var/setup_default_tool_path = /obj/item/device/guardbot_tool/flash //Starting tool.
#ifdef HALLOWEEN
var/setup_default_startup_task = /datum/computer/file/guardbot_task/security/halloween
#else
var/setup_default_startup_task = /datum/computer/file/guardbot_task/security //Task to run on startup. Duh.
#endif
disposing()
if (tool)
tool.master = null
if (task)
task.disposing()
if (model_task)
model_task.disposing()
radio_controller.remove_object(src, "[control_freq]")
radio_controller.remove_object(src, "[beacon_freq]")
..()
ranger
#ifndef HALLOWEEN
name = "Ol' Harner"
#else
name = "Halloween Harner"
#endif
desc = "Almost as much the law as Beepsky."
setup_unique_name = 1
setup_default_startup_task = /datum/computer/file/guardbot_task/security/patrol
setup_charge_percentage = 95
New()
..()
src.hat = new /obj/item/clothing/head/mj_hat(src)
src.hat.name = "Eldritch shape-shifting hat."
src.update_icon()
safety
name = "Klaus"
desc = "Safetybuddy Klaus wants you to mind safety regulations."
setup_unique_name = 1
setup_charge_maximum = 4500
setup_charge_percentage = 100
New()
..()
src.hat = new /obj/item/clothing/head/helmet/hardhat
src.hat.name = "Klaus' hardhat"
src.update_icon()
heckler
name = "Hecklebuddy"
desc = "A PR-6S Guardbuddy programmed to be sort of a jerk."
setup_default_startup_task = /datum/computer/file/guardbot_task/bodyguard/heckle
New()
..()
SPAWN_DBG (10)
for (var/mob/living/carbon/human/H in view(7, src))
if (!H.stat)
if (model_task)
model_task:protected_name = ckey(H.name)
if (task)
task:protected_name = ckey(H.name)
break
golden
name = "Goldbuddy"
desc = "A gold plated PR-4 Guardbuddy from a limited time raffle from like, a decade ago."
icon = 'icons/misc/oldbots.dmi'
icon_state = "Goldbuddy0"
update_icon()
var/emotion_image = null
if(!src.on)
src.icon_state = "Goldbuddy0"
else if(src.stunned)
src.icon_state = "Goldbuddya"
else if(src.idle)
src.icon_state = "Goldbuddy_idle"
else
if (src.emotion)
emotion_image = image(src.icon, "face-[src.emotion]")
src.icon_state = "Goldbuddy1"
src.overlays = list( emotion_image, src.bedsheet ? image(src.icon, "bhat-ghost[src.bedsheet]") : null, src.costume_icon ? costume_icon : null)
if (src.hat && !src.hat_shown)
var/image/hat_image = image(src.hat_icon, "bhat-[src.hat.icon_state]",,layer = 9.5) //TODO LAYER
hat_image.pixel_x = hat_x_offset
src.underlays = list(hat_image)
src.hat_shown = 1
src.icon_needs_update = 0
return
gunner
name = "Gunbuddy"
desc = "A PR-6S Guardbuddy, but with a gun."
setup_default_tool_path = /obj/item/device/guardbot_tool/taser
vaquero
name = "El Vaquero"
desc = "The side label reads 'Fabricado en México'"
setup_unique_name = 1
setup_default_startup_task = /datum/computer/file/guardbot_task/security/patrol
setup_charge_percentage = 98
syringe
name = "Wardbuddy"
desc = "Wardbuddy is currently the CEO of a small internet syringe venture with plans to expand once he figures out how to fit a private jet in his dad's garage."
setup_default_tool_path = /obj/item/device/guardbot_tool/medicator
smoke
name = "Snoozebuddy"
desc = "Marketed as a riot control solution and sleep aid, the PR-6S2 Snoozebuddy offers a sophisticated gas-release module and a 5-year warranty."
//setup_default_startup_task = /datum/computer/file/guardbot_task/security/patrol
setup_default_tool_path = /obj/item/device/guardbot_tool/smoker
tesla
name = "Shockbuddy"
desc = "The PR-6MS Shockbuddy was remarketed under the Guardbuddy line following the establishment of stricter electroconvulsive therapy regulations."
setup_default_tool_path = /obj/item/device/guardbot_tool/tesla
bodyguard
setup_charge_percentage = 98
setup_default_startup_task = /datum/computer/file/guardbot_task/bodyguard
//xmas -- See spacemas.dm
mail
name = "Mailbuddy"
desc = "The PR-6PS Mailbuddy is a postal delivery ace. This may seem like an extremely specialized robot application, but that's just because it is exactly that."
icon = 'icons/obj/mailbud.dmi'
New()
..()
src.hat = new /obj/item/clothing/head/mailcap(src)
src.update_icon()
New()
..()
if(src.on)
src.warm_boot = 1
#ifdef HALLOWEEN
if (!setup_no_costumes)
src.costume_icon = image(src.icon, "bcostume-[pick("xcom","clown","horse","moustache","owl","pirate","skull", "wizard", "wizardred","devil")]", , FLY_LAYER)
src.costume_icon.pixel_x = src.hat_x_offset
src.costume_icon.pixel_y = src.hat_y_offset
if (src.costume_icon && src.costume_icon:icon_state == "bcostume-wizard")
src.hat = new /obj/item/clothing/head/wizard
#endif
src.update_icon()
if(!src.cell)
src.cell = new /obj/item/cell(src)
src.cell.maxcharge = setup_charge_maximum
src.cell.charge = ((setup_charge_percentage/100) * src.cell.maxcharge)
if(!setup_unique_name)
src.name += "-[rand(100,999)]"
SPAWN_DBG(5)
if (src.on)
add_simple_light("guardbot", list(src.flashlight_red*255, src.flashlight_green*255, src.flashlight_blue*255, (src.flashlight_lum / 7) * 255))
src.botcard = new /obj/item/card/id(src)
src.botcard.access = get_access(src.botcard_access)
if(setup_default_tool_path && !src.tool)
src.tool = new setup_default_tool_path
src.tool.set_loc(src)
src.tool.master = src
if(radio_controller)
radio_connection = radio_controller.add_object(src, "[control_freq]")
beacon_connection = radio_controller.add_object(src, "[beacon_freq]")
src.net_id = generate_net_id(src)
var/obj/machinery/guardbot_dock/dock = null
if(setup_spawn_dock)
dock = new /obj/machinery/guardbot_dock( get_turf(src) )
dock.frequency = src.control_freq
dock.net_id = generate_net_id(dock)
else
dock = locate() in src.loc
if(dock && istype(dock))
if(!dock.net_id)
dock.net_id = generate_net_id(dock)
if(src.setup_default_startup_task && !src.task)
if(!src.model_task)
src.model_task = new setup_default_startup_task
src.model_task.master = src
if(dock)
dock.connect_robot(src,dock.autoeject)
else
if(src.model_task)
src.task = src.model_task.copy_file()
src.task.master = src
src.tasks.Add(src.task)
emag_act(var/mob/user, var/obj/item/card/emag/E)
if(!user || !E) return 0
if (src.idle || !src.on)
boutput(user, "You show \the [E] to [src]! There is no response.")
else
if (E.icon_state == "gold")
boutput(user, "You show \the [E] to [src]! They are super impressed!")
SPAWN_DBG(1 SECOND)
boutput(user, "Like, really REALLY impressed. They probably think you're some kind of celebrity or something.")
sleep(10)
boutput(user, "Or the president. The president of space.")
else
boutput(user, "You show \the [E] to [src]! They are very impressed.")
return 1
attackby(obj/item/W as obj, mob/user as mob)
if (istype(W, /obj/item/device/pda2) && W:ID_card)
W = W:ID_card
if (istype(W, /obj/item/card/id))
if (src.allowed(user))
src.locked = !src.locked
boutput(user, "Controls are now [src.locked ? "locked." : "unlocked."]")
else
boutput(user, "<span style=\"color:red\">Access denied.</span>")
/*
else if (istype(W, /obj/item/card/emag))
if (src.idle || !src.on)
boutput(user, "You show \the [W] to [src]! There is no response.")
else
if (W.icon_state == "gold")
boutput(user, "You show \the [W] to [src]! They are super impressed!")
SPAWN_DBG(1 SECOND)
boutput(user, "Like, really REALLY impressed. They probably think you're some kind of celebrity or something.")
sleep(10)
boutput(user, "Or the president. The president of space.")
else
boutput(user, "You show \the [W] to [src]! They are very impressed.")
return
*/
else if (isscrewingtool(W))
if (src.health < initial(health))
src.health = initial(health)
src.visible_message("<span style=\"color:blue\">[user] repairs [src]!</span>", "<span style=\"color:blue\">You repair [src].</span>")
else if (istype(W, /obj/item/clothing/head))
if(src.hat)
boutput(user, "<span style=\"color:red\">[src] is already wearing a hat!</span>")
return
if(W.icon_state == "fdora")
boutput(user, "[src] looks [pick("kind of offended","kind of weirded-out","a bit disgusted","mildly bemused")] at your offer and turns it down.")
return
if(!(W.icon_state in BUDDY_HATS))
boutput(user, "<span style=\"color:red\">It doesn't fit!</span>")
return
src.hat = W
user.drop_item()
W.set_loc(src)
src.update_icon()
user.visible_message("<b>[user]</b> puts a hat on [src]!","You put a hat on [src]!")
return
else if (istype(W, /obj/item/clothing/suit/bedsheet))
if (src.bedsheet != 0)
boutput(user, "<span style=\"color:red\">There is already a sheet draped over [src]! Two sheets would be ridiculous!</span>")
return
src.bedsheet = 1
user.drop_item()
qdel(W)
src.overlays.len = 0
src.hat_shown = 0
src.update_icon()
user.visible_message("<b>[user]</b> drapes a sheet over [src]!","You cover [src] with a sheet!")
src.add_task(new /datum/computer/file/guardbot_task/bedsheet_handler, 1, 0)
return
else if (istype(W, /obj/item/reagent_containers/food/snacks/candy))
if (src.idle || !src.on)
boutput(user, "You try to give [src] [W], but there is no response.")
return
user.visible_message("<b>[user]</b> gives [W] to [src]!","You give [W] to [src]!")
user.drop_item()
qdel(W)
if (src.task)
src.task.task_input("treated")
return
else
switch(W.damtype)
if("fire")
src.health -= W.force * 0.6
if("brute")
src.health -= W.force * 0.4
else
if (src.health <= 0)
..()
src.explode()
return
else if (W.force && src.task)
src.task.attack_response(user)
..()
get_desc(dist)
..()
if (src.on && src.idle)
. = "<br><span style=\"color:blue\">[src] appears to be sleeping.</span>"
if (src.health < initial(health))
if (src.health > 10)
. += "<br><span style=\"color:red\">[src]'s parts look loose.</span>"
else
. += "<br><span style=\"color:red\"><B>[src]'s parts look very loose!</B></span>"
attack_ai(mob/user as mob)
src.interact(user)
attack_hand(mob/user as mob)
if(..())
return
if(user.a_intent == "help" && user.machine != src && (get_dist(user,src) <= 1))
var/affection = pick("hug","cuddle","snuggle")
user.visible_message("<span style=\"color:blue\">[user] [affection]s [src]!</span>","<span style=\"color:blue\">You [affection] [src]!</span>")
if(src.task)
src.task.task_input("hugged")
return
if(get_dist(user, src) > 1)
return
src.interact(user)
Topic(href, href_list)
if(..())
return
usr.machine = src
src.add_fingerprint(usr)
if ((href_list["power"]) && (!src.locked || (src.allowed(usr) && (issilicon(usr) || get_dist(usr, src) < 2))))
if(src.on)
turn_off()
else
turn_on()
src.updateUsrDialog()
return
process()
if (icon_needs_update)
src.update_icon()
if(!src.on)
return
if(src.stunned)
src.stunned--
if(src.stunned <= 0)
src.wakeup()
return
if( src.manage_power() ) //Returns true if we need to halt process
return //(ie we are now off or idle)
if(idle) //Are we idling?
if(src.wakeup_timer) //Are we waiting to exit the idle state?
src.wakeup_timer--
if(src.wakeup_timer <= 0)
src.wakeup() //Exit idle state.
return
if(src.charge_dock)
if(charge_dock.loc == src.loc)
if(!src.idle)
src.snooze()
else
src.charge_dock = null
src.wakeup()
return
if(src.reply_wait)
src.reply_wait--
if(!src.tasks.len && (src.model_task || setup_default_startup_task))
if(!src.model_task)
src.model_task = new setup_default_startup_task
src.add_task(src.model_task.copy_file(),1)
if(istype(src.task))
src.task.task_act()
return
receive_signal(datum/signal/signal, receive_method, receive_param)
if(!src.on || src.stunned)
return
if(!signal || signal.encryption)
return
var/targaddress = lowertext(signal.data["address_1"])
if (last_dock_id && targaddress == last_dock_id)
targaddress = src.net_id
last_dock_id = null
var/is_beacon = (receive_param == "[src.beacon_freq]")
if(!is_beacon)
if( ((targaddress != src.net_id) && (signal.data["acc_code"] != netpass_heads) ) || !signal.data["sender"])
if(signal.data["address_1"] == "ping" && signal.data["sender"])
src.post_status(signal.data["sender"],"command","ping_reply","device","PNET_PR6_GUARD","netid",src.net_id)
return
if(signal.data["command"] == "dock_return" && !src.idle) //Return to dock for new instructions.
if(!istype(src.task, /datum/computer/file/guardbot_task/recharge/dock_sync))
src.add_task(/datum/computer/file/guardbot_task/recharge/dock_sync, 0, 1)
speak("Software update requested.")
set_emotion("update")
return
else if (signal.data["command"] == "captain_greet" && !src.idle && istype(src.hat, /obj/item/clothing/head/caphat))
speak(pick("Yes...thank you.", "Hello yes. I'm...the captain.", "Good day to you too. A good day from the captain. Me. The captain."))
return
else if (signal.data["command"] == "wizard_greet" && !src.idle && istype(src.hat, /obj/item/clothing/head/wizard))
var/wizdom = pick("Never eat shredded wheat.", "A stitch in time saves nine.", "The pen is mightier than...a dull thing I guess. Maybe a string?", "Rome wasn't built in a day. Actually, a lot of things aren't. I don't think any city was, to be honest.")
speak("Um...[wizdom].")
speak("SO SAYETH THE WIZARD!")
return
if(src.task)
src.task.receive_signal(signal, is_beacon)
return
bullet_act(var/obj/projectile/P)
var/damage = 0
damage = round(((P.power/6)*P.proj_data.ks_ratio), 1.0)
if(P.proj_data.damage_type == D_KINETIC || P.proj_data.damage_type == D_PIERCING || (P.proj_data.damage_type == D_ENERGY && damage))
src.health -= damage
if (src.hat && prob(10))
src.visible_message("<span style=\"color:red\">[src]'s hat is knocked clean off!</span>")
src.hat.set_loc(get_turf(src))
src.hat = null
src.underlays.len = 0
set_emotion("sad")
else if(P.proj_data.damage_type == D_ENERGY) //if it's an energy shot but does no damage, ie. taser rather than laser
src.stunned += 5
if(src.stunned > 15)
src.stunned = 15
return
if (src.health <= 0)
src.explode()
return
if (ismob(P.shooter))
if(P && src.task)
src.task.attack_response(P.shooter)
return
gib()
return src.explode()
ex_act(severity)
switch(severity)
if(1.0)
src.explode(0)
return
if(2.0)
src.health -= 15
if (src.health <= 0)
src.explode(0)
else if (src.hat && prob(10))
src.visible_message("<span style=\"color:red\">[src]'s hat is knocked clean off!</span>")
src.hat.set_loc(get_turf(src))
src.hat = null
set_emotion("sad")
return
return
meteorhit()
src.explode(0)
return
blob_act(var/power)
if(prob(25 * power / 20))
src.explode()
return
emp_act() //Oh no! We have been hit by an EMP grenade!
if(!src.on || prob(10))
return
src.visible_message("<span style=\"color:red\"><b>[src.name]</b> buzzes oddly!</span>")
qdel(src.model_task)
src.model_task = new /datum/computer/file/guardbot_task/security/crazy
src.model_task.master = src
add_task(src.model_task, 0, 1)
if(src.idle)
if(src.charge_dock)
src.charge_dock.eject_robot()
else
src.wakeup()
return
explode(var/allow_big_explosion=1)
if(src.exploding) return
src.exploding = 1
var/death_message = pick("I regret nothing, but I am sorry I am about to leave my friends.","I had a good run.","Es lebe die Freiheit!","It is now safe to shut off your buddy.","System error.","Now I know why you cry.","Stay gold...","Malfunction!","Rosebud...","No regrets!", "Time to die...")
speak(death_message)
src.visible_message("<span style=\"color:red\"><b>[src] blows apart!</b></span>")
var/turf/T = get_turf(src)
if(src.mover)
src.mover.master = null
//qdel(src.mover)
src.mover = null
if(allow_big_explosion && cell && (cell.charge / cell.maxcharge > 0.85) && prob(25))
src.invisibility = 100
var/obj/overlay/Ov = new/obj/overlay(T)
Ov.anchored = 1
Ov.name = "Explosion"
Ov.layer = NOLIGHT_EFFECTS_LAYER_BASE
Ov.pixel_x = -92
Ov.pixel_y = -96
Ov.icon = 'icons/effects/214x246.dmi'
Ov.icon_state = "explosion"
src.tool.set_loc(get_turf(src))
var/obj/item/guardbot_core/core = new /obj/item/guardbot_core(T)
core.created_name = src.name
core.created_default_task = src.setup_default_startup_task
core.created_model_task = src.model_task
var/list/throwparts = list()
throwparts += new /obj/item/parts/robot_parts/arm/left(T)
throwparts += core
throwparts += src.tool
if(src.hat)
throwparts += src.hat
src.hat.set_loc(T)
throwparts += new /obj/item/guardbot_frame(T)
for(var/obj/O in throwparts) //This is why it is called "throwparts"
var/edge = get_edge_target_turf(src, pick(alldirs))
O.throw_at(edge, 100, 4)
SPAWN_DBG(0) //Delete the overlay when finished with it.
src.on = 0
sleep(15)
qdel(Ov)
qdel(src)
T.hotspot_expose(800,125)
explosion(src, T, -1, -1, 2, 3)
else
if(src.tool)
src.tool.set_loc(T)
if(prob(50))
new /obj/item/parts/robot_parts/arm/left(T)
if(src.hat)
src.hat.set_loc(T)
new /obj/item/guardbot_frame(T)
var/obj/item/guardbot_core/core = new /obj/item/guardbot_core(T)
core.created_name = src.name
core.created_default_task = src.setup_default_startup_task
core.created_model_task = src.model_task
var/datum/effects/system/spark_spread/s = unpool(/datum/effects/system/spark_spread)
s.set_up(3, 1, src)
s.start()
qdel(src)
return
proc
manage_power()
if(!on) return 1
if(!cell || (cell.charge <= 0) )
src.turn_off()
return 1
var/to_draw = GUARDBOT_POWER_DRAW
if(src.idle)
to_draw = (to_draw / 2)
cell.use(to_draw)
if(cell.charge < GUARDBOT_LOWPOWER_IDLE_LEVEL)
speak("Critical battery.")
src.snooze()
return 0
if(cell.charge < GUARDBOT_LOWPOWER_ALERT_LEVEL && !(locate(/datum/computer/file/guardbot_task/recharge) in src.tasks) )
src.add_task(/datum/computer/file/guardbot_task/recharge,1,0)
return 0
return 0
wakeup() //Get out of idle state and prepare anything that needs preparing I guess
if(!src.on) return
src.idle = 0 //Also called after recovery from stunning.
src.stunned = 0
src.moving = 0
src.emotion = null
icon_needs_update = 1
add_simple_light("guardbot", list(src.flashlight_red*255, src.flashlight_green*255, src.flashlight_blue*255, (src.flashlight_lum / 7) * 255))
if(src.bedsheet == 1)
src.add_task(new /datum/computer/file/guardbot_task/bedsheet_handler, 1, 0)
return
if(src.tasks.len)
src.task = src.tasks[1]
return
snooze(var/timer = 0, var/cleartasks = 1)
if(src.idle) return //Already snoozing.
src.idle = 1
set_emotion()
remove_simple_light("guardbot")
src.wakeup_timer = timer
//src.target = null
src.moving = 0
src.reply_wait = 0
icon_needs_update = 1
if(cleartasks)
src.tasks.len = 0
remove_current_task()
//src.secondary_targets.len = 0
else
if(src.task)
src.task.task_input("snooze")
src.task = null
return
turn_on()
if(!src.cell || src.cell.charge <= 0)
return
src.on = 1
src.idle = 0
src.moving = 0
src.task = null
src.wakeup_timer = 0
src.last_dock_id = null
icon_needs_update = 1
if(!warm_boot)
src.scratchpad.len = 0
src.speak("Guardbuddy V1.4 Online.")
if (src.health < initial(src.health))
src.speak("Self-check indicates [src.health < (initial(src.health) / 2) ? "severe" : "moderate"] structural damage!")
if(!src.tasks.len && (src.model_task || src.setup_default_startup_task))
if(!src.model_task)
src.model_task = new src.setup_default_startup_task
src.tasks.Add(src.model_task.copy_file())
src.warm_boot = 1
src.wakeup()
turn_off()
if(!warm_boot) //ugh it's some dude just flicking the switch.
return
src.on = 0
src.moving = 0
src.task = null
//src.target = null
src.wakeup_timer = 0
src.warm_boot = 0
src.reply_wait = 0
src.last_dock_id = null
icon_needs_update = 1
set_emotion()
navigate_to(atom/the_target,var/move_delay=3,var/adjacent=0,var/clear_frustration=1)
if(src.moving)
return 1
src.moving = 1
if (clear_frustration)
src.frustration = 0
if(src.mover)
src.mover.master = null
//qdel(src.mover)
src.mover = null
//boutput(world, "TEST: Navigate to [target]")
//current_movepath = world.time
src.mover = new /datum/guardbot_mover(src)
// drsingh for cannot modify null.delay
if (!isnull(src.mover))
src.mover.delay = max(min(move_delay,5),2)
src.mover.master_move(the_target,adjacent)
return 0
bot_attack(var/atom/target as mob|obj, lethal=0)
if(src.tool)
var/is_ranged = get_dist(src, target) > 1
src.tool.bot_attack(target, src, is_ranged, lethal)
return
post_status(var/target_id, var/key, var/value, var/key2, var/value2, var/key3, var/value3)
if(!radio_connection)
return
var/datum/signal/signal = get_free_signal()
signal.source = src
signal.transmission_method = TRANSMISSION_RADIO
signal.data[key] = value
if(key2)
signal.data[key2] = value2
if(key3)
signal.data[key3] = value3
if(target_id)
signal.data["address_1"] = target_id
signal.data["sender"] = src.net_id
src.last_comm = world.time
if(target_id == "!BEACON!")
beacon_connection.post_signal(src, signal)//, GUARDBOT_RADIO_RANGE)
else
radio_connection.post_signal(src, signal, GUARDBOT_RADIO_RANGE)
add_task(var/datum/computer/file/guardbot_task/newtask, var/high_priority = 0, var/clear_others = 0)
if(clear_others)
src.tasks.len = 0
if(!newtask)
return
if(!istype(newtask))
if(ispath(newtask))
newtask = new newtask
else
return
newtask.master = src
if(clear_others)
qdel(src.task)
src.task = newtask
src.tasks.len = 0
src.tasks += src.task
return
if(high_priority)
src.tasks.Insert(1, newtask)
src.task = newtask
return
src.tasks += newtask
if (src.tasks.len == 1)
src.task = newtask
return
remove_current_task()
if(!src.tasks.len) return
if(!src.tasks)
src.tasks = list()
return
src.tasks.Cut(1,2)
var/old_task = src.task
if(src.tasks.len)
src.task = src.tasks[1]
qdel(old_task)
return
set_emotion(var/new_emotion=null)
if(src.emotion == new_emotion)
return
src.icon_needs_update = 1
src.emotion = new_emotion
if (src.hat || src.costume_icon || src.bedsheet)
src.overlays = list((src.costume_icon ? src.costume_icon : null), (src.bedsheet ? image(src.icon, "bhat-ghost[src.bedsheet]") : null))
/*
else
src.overlays.len = 0 //Clear overlays so it will update on update_icon call
src.hat_shown = 0
*/
interact(mob/user as mob)
var/dat = "<tt><B>PR-6S Guardbuddy v1.4</B></tt><br><br>"
var/power_readout = null
var/readout_color = "#000000"
if(!src.cell)
power_readout = "NO CELL"
else
var/charge_percentage = round((cell.charge/cell.maxcharge)*100)
power_readout = "[charge_percentage]%"
switch(charge_percentage)
if(0 to 10)
readout_color = "#F80000"
if(11 to 25)
readout_color = "#FFCC00"
if(26 to 50)
readout_color = "#CCFF00"
if(51 to 75)
readout_color = "#33CC00"
if(76 to 100)
readout_color = "#33FF00"
dat += {"Power: <table border='1' style='background-color:[readout_color]'>
<tr><td><font color=white>[power_readout]</font></td></tr></table><br>"}
dat += "Current Tool: [src.tool ? src.tool.tool_id : "NONE"]<br>"
if(src.locked)
dat += "Status: [src.on ? "On" : "Off"]<br>"
else
dat += "Status: <a href='?src=\ref[src];power=1'>[src.on ? "On" : "Off"]</a><br>"
dat += "<br>Network ID: <b>\[[uppertext(src.net_id)]]</b><br>"
user.Browse("<head><title>Guardbuddy v1.4 controls</title></head>[dat]", "window=guardbot")
onclose(user, "guardbot")
return
update_icon()
var/emotion_image = null
if(!src.on)
src.icon_state = "robuddy0"
else if(src.stunned)
src.icon_state = "robuddya"
else if(src.idle)
src.icon_state = "robuddy_idle"
else
if (src.emotion)
emotion_image = image(src.icon, "face-[src.emotion]")
src.icon_state = "robuddy1"
src.overlays = list( emotion_image, src.bedsheet ? image(src.icon, "bhat-ghost[src.bedsheet]") : null, src.costume_icon ? costume_icon : null)
if (src.hat && !src.hat_shown)
var/image/hat_image = image(src.hat_icon, "bhat-[src.hat.icon_state]",,layer = 9.5) //TODO LAYER
hat_image.pixel_x = hat_x_offset
hat_image.pixel_y = hat_y_offset
src.underlays = list(hat_image)
src.hat_shown = 1
src.icon_needs_update = 0
return
//Robot tools. Flash boards, batons, etc
/obj/item/device/guardbot_tool
name = "Tool module"
desc = "A generic module for a PR-6S Guardbuddy."
icon = 'icons/obj/module.dmi'
icon_state = "tool_generic"
mats = 6
w_class = 2.0
var/is_stun = 0 //Can it be non-lethal?
var/is_lethal = 0 //Can it be lethal?
var/tool_id = "GENERIC" //Identification ID.
var/is_gun = 0 //1 Is ranged, 0 is melee.
var/last_use = 0 //If we want a use delay.
proc
bot_attack(var/atom/target as mob|obj, obj/machinery/bot/guardbot/user, ranged=0, lethal=0)
if(!user || !user.on || user.getStatusDuration("stunned") || user.idle)
return 1
return 0
//A syringe gun module. Mercy sakes.
medicator
name = "Medicator tool module"
desc = "A 'Medicator' syringe launcher module for PR-6S Guardbuddies. These things are actually outlawed on Earth."
icon_state = "tool_syringe"
tool_id = "SYRNG"
is_gun = 1
is_stun = 1 //Can be both nonlethal and lethal
is_lethal = 1 //Depends on reagent load.
var/datum/projectile/current_projectile = new /datum/projectile/syringe
var/stun_reagent = "haloperidol"
var/kill_reagent = "cyanide"
// Updated for new projectile code (Convair880).
bot_attack(var/atom/target as mob|obj, obj/machinery/bot/guardbot/user, ranged=0, lethal=0)
if (..()) return
if (src.last_use && world.time < src.last_use + 60)
return
if (ranged)
var/obj/projectile/P = shoot_projectile_ST_pixel(master, current_projectile, target)
if (!P)
return
if (!P.reagents)
P.reagents = new /datum/reagents(15)
P.reagents.my_atom = P
if (lethal)
P.reagents.add_reagent(kill_reagent, 10)
else
P.reagents.add_reagent(stun_reagent, 15)
user.visible_message("<span style=\"color:red\"><b>[master] fires a syringe at [target]!</b></span>")
else
var/obj/projectile/P = initialize_projectile_ST(master, current_projectile, target)
if (!P)
return
if (!P.reagents)
P.reagents = new /datum/reagents(15)
P.reagents.my_atom = P
if (lethal)
P.reagents.add_reagent(kill_reagent, 10)
else
P.reagents.add_reagent(stun_reagent, 15)
user.visible_message("<span style=\"color:red\"><b>[master] shoots [target] point-blank with a syringe!</b></span>")
P.was_pointblank = 1
hit_with_existing_projectile(P, target)
src.last_use = world.time
return
//Short-range smoke riot control module
smoker
name = "'Smoker' tool module"
desc = "A riot-control gas module for PR-6S Guardbuddies."
icon_state = "tool_smoke"
tool_id = "SMOKE"
is_stun = 1
is_lethal = 1
var/stun_reagent = "ketamine"
var/kill_reagent = "neurotoxin"
New()
..()
var/datum/reagents/R = new/datum/reagents(500)
reagents = R
R.my_atom = src
return
// Fixed. Was completely non-functional (Convair880).
bot_attack(var/atom/target as mob|obj, obj/machinery/bot/guardbot/user, ranged=0, lethal=0)
if(..() || !reagents || ranged) return
if(src.last_use && world.time < src.last_use + 120)
return
src.reagents.clear_reagents()
if (lethal)
src.reagents.add_reagent(kill_reagent, 15)
else
src.reagents.add_reagent(stun_reagent, 15)
smoke_reaction(src.reagents, 3, get_turf(src))
user.visible_message("<span style=\"color:red\"><b>[master] releases a cloud of gas!</b></span>")
src.last_use = world.time
return
//Taser tool
taser
name = "Taser tool module"
desc = "A taser module for PR-6S Guardbuddies."
icon_state = "tool_taser"
tool_id = "TASER"
is_stun = 1
is_gun = 1
var/datum/projectile/current_projectile = new/datum/projectile/energy_bolt/robust
// Updated for new projectile code (Convair880).
bot_attack(var/atom/target as mob|obj, obj/machinery/bot/guardbot/user, ranged=0, lethal=0)
if (..()) return
if (src.last_use && world.time < src.last_use + 80)
return
if (ranged)
var/obj/projectile/P = shoot_projectile_ST_pixel(master, current_projectile, target)
if (!P)
return
user.visible_message("<span style=\"color:red\"><b>[master] fires the taser at [target]!</b></span>")
else
var/obj/projectile/P = initialize_projectile_ST(master, current_projectile, target)
if (!P)
return
user.visible_message("<span style=\"color:red\"><b>[master] shoots [target] point-blank with the taser!</b></span>")
P.was_pointblank = 1
hit_with_existing_projectile(P, target)
src.last_use = world.time
return
//Flash tool
flash
name = "Flash tool module"
desc = "A flash module for PR-6S Guardbuddies."
icon_state = "tool_flash"
is_stun = 1
tool_id = "FLASH"
bot_attack(var/atom/target as mob|obj, obj/machinery/bot/guardbot/user, ranged=0, lethal=0)
if(..()) return
if(ranged) return
if(iscarbon(target))
var/mob/living/carbon/O = target
if(src.last_use && world.time < src.last_use + 80)
return
playsound(user.loc, "sound/weapons/flash.ogg", 100, 1)
flick("robuddy-c", user)
src.last_use = world.time
// We're flashing somebody directly, hence the 100% chance to disrupt cloaking device at the end.
O.apply_flash(30, 8, 0, 0, 0, rand(0, 2), 0, 0, 100)
return
//Electrobolt tool. Basically, Keelin owns ok
tesla
name = "Elektro-Arc tool module"
desc = "An experimental tesla-coil module for PR-6S Guardbuddies."
icon_state = "tool_tesla"
tool_id = "TESLA"
is_gun = 1
is_stun = 1 //Can be both nonlethal and lethal
is_lethal = 1
bot_attack(var/atom/target as mob|obj, obj/machinery/bot/guardbot/user, ranged=0, lethal=0)
if(..())
return
if (get_dist(user,target) > 4)
return
if(src.last_use && world.time < src.last_use + 80)
return
var/atom/last = user
var/atom/target_r = target
var/list/dummies = new/list()
playsound(src, "sound/effects/elec_bigzap.ogg", 40, 1)
if(isturf(target))
target_r = new/obj/elec_trg_dummy(target)
var/turf/currTurf = get_turf(target_r)
currTurf.hotspot_expose(2000, 400)
for(var/count=0, count<4, count++)
var/list/affected = DrawLine(last, target_r, /obj/line_obj/elec ,'icons/obj/projectiles.dmi',"WholeLghtn",1,1,"HalfStartLghtn","HalfEndLghtn",OBJ_LAYER,1,PreloadedIcon='icons/effects/LghtLine.dmi')
for(var/obj/O in affected)
SPAWN_DBG(6 DECI SECONDS) pool(O)
if(isliving(target_r)) //Probably unsafe.
playsound(target_r:loc, "sound/effects/electric_shock.ogg", 50, 1)
if (lethal)
var/mob/living/carbon/human/H = target_r
random_burn_damage(target_r, rand(45,60))
H.do_disorient(stamina_damage = 45, weakened = 50, stunned = 40, disorient = 20, remove_stamina_below_zero = 0)
boutput(target_r, "<span style=\"color:red\"><B>You feel a powerful shock course through your body!</B></span>")
target_r:unlock_medal("HIGH VOLTAGE", 1)
target_r:Virus_ShockCure(target_r, 100)
target_r:shock_cyberheart(33)
if (ishuman(target_r))
target_r:changeStatus("weakened", lethal ? (3 SECONDS): (8 SECONDS))
break
var/list/next = new/list()
for(var/atom/movable/AM in orange(3, target_r))
if(istype(AM, /obj/line_obj/elec) || istype(AM, /obj/elec_trg_dummy) || istype(AM, /obj/overlay/tile_effect) || AM.invisibility)
continue
next.Add(AM)
if(istype(target_r, /obj/elec_trg_dummy))
dummies.Add(target_r)
last = target_r
target_r = pick(next)
target = target_r
for(var/d in dummies)
qdel(d)
src.last_use = world.time
return
//xmas -- See spacemas.dm
//Task Datums
/datum/computer/file/guardbot_task //Computer datum so it can be transmitted over radio
name = "idle"
var/task_id = "IDLE" //Small allcaps id for task
var/tmp/obj/machinery/bot/guardbot/master = null
var/tmp/atom/target = null
var/tmp/list/secondary_targets = list()
var/oldtarget_name
var/last_found = 0
var/handle_beacons = 0 //Can we handle beacon signals?
disposing()
master = null
target = null
secondary_targets = null
..()
proc
task_act()
if(!master || master.task != src)
return 1
if(!master.on || master.stunned)
return 1
return 0
attack_response(mob/attacker as mob)
if(!master || master.task != src)
return 1
if(!master.on || master.stunned || master.idle)
return 1
if(!istype(attacker))
return 1
return 0
task_input(var/input)
if(!master || !input || !master.on) return 1
if(input == "hugged")
switch(master.emotion)
if(null)
master.set_emotion("happy")
if("happy","smug")
master.set_emotion("love")
if("joy","love")
if (prob(25))
master.visible_message("<span style=\"color:blue\">[master.name] reciprocates the hug!</span>")
return 1
return 0
next_target() //Return true if there is a new target, false otherwise
src.target = null
if (src.secondary_targets.len)
src.target = src.secondary_targets[1]
src.secondary_targets -= src.secondary_targets[1]
return 1
return 0
receive_signal(datum/signal/signal, is_beacon=0)
if (!master || !signal)
return 1
if (is_beacon && !src.handle_beacons)
return 1
return 0
configure(var/list/confList)
if (!confList || !confList.len)
return 1
return 0
//Recharge task
recharge
name = "recharge"
task_id = "RECHARGE"
var/tmp/announced = 0
var/dock_return = 0 //If 0: return to recharge, if 1: return for new programming
dock_sync
name = "sync"
task_id = "SYNC"
dock_return = 1
announced = 1
task_input(input)
if(..()) return
switch(input)
if("path_error","path_blocked")
if(src.target)
src.oldtarget_name = src.target.name
src.next_target()
src.last_found = world.time
if("snooze")
src.target = null
src.secondary_targets.len = 0
return
task_act()
if(..()) return
if(!dock_return && master.cell.charge >= (GUARDBOT_LOWPOWER_ALERT_LEVEL * 2))
master.remove_current_task()
return
if(istype(src.target, /turf/simulated))
var/obj/machinery/guardbot_dock/dock = locate() in src.target
if(dock && dock.loc == master.loc)
if(!isnull(dock.current) && dock.current != src)
src.next_target()
else
var/auto_eject = 0
if(!dock_return && master.tasks.len >= 2)
auto_eject = 1
dock.connect_robot(master,auto_eject)
//master.snooze() //Connect autosnoozes the bot.
return
else if (src.target == master.loc)
src.target = null
src.last_found = world.time
src.next_target()
if(!master.moving)
master.navigate_to(src.target)
else
if(!master.last_comm || (world.time >= master.last_comm + 100) )
master.post_status("recharge","data","[master.cell.charge]")
master.reply_wait = 2
if(!announced)
announced++
master.speak("Low battery.")
master.set_emotion("battery")
else
announced = 1
return
receive_signal(datum/signal/signal)
if(..()) return
if(signal.data["command"] == "recharge_src")
if(!master.reply_wait)
return
var/list/L = params2list(signal.data["data"])
if(!L || !L["x"] || !L["y"]) return
var/search_x = text2num(L["x"])
var/search_y = text2num(L["y"])
var/turf/simulated/new_target = locate(search_x,search_y,master.z)
if(!new_target)
return
if (announced != 2)
announced = 2
src.secondary_targets = list()
SPAWN_DBG (10)
if (src.secondary_targets.len)
master.reply_wait = 0
. = INFINITY
for (var/turf/T in src.secondary_targets)
if (!src.target || (. > get_dist(src.master, T)))
src.target = T
. = get_dist(src.master, src.target)
continue
src.secondary_targets -= src.target
src.secondary_targets += new_target
//master.reply_wait = 0
return
attack_response(mob/attacker as mob)
if(..())
return
var/datum/computer/file/guardbot_task/security/single_use/beatdown = new
beatdown.arrest_target = attacker
beatdown.mode = 1
src.master.add_task(beatdown, 1, 0)
return
//Buddytime task -- Even buddies need to relax sometimes!
buddy_time
name = "rumpus"
handle_beacons = 1
task_id = "RUMPUS"
var/tmp/turf/simulated/bar_beacon_turf //Location of bar beacon
var/tmp/obj/stool/our_seat = null
var/tmp/awaiting_beacon = 0
var/tmp/nav_delay = 0
var/tmp/beepsky_check_delay = 0
var/tmp/state = 0
var/tmp/party_counter = 90
var/tmp/party_idle_counter = 0
var/tmp/obj/machinery/bot/secbot/its_beepsky = null
var/rumpus_emotion = "joy" //Emotion to express during buddytime.
var/rumpus_location_tag = "buddytime" //Tag of the bar beacon
task_act()
if(..()) return
switch (state)
if (0)
master.speak("Break time. Rumpus protocol initiated.")
src.state = 1
if (1) //Seeking the bar.
if (src.awaiting_beacon)
src.awaiting_beacon--
if (src.awaiting_beacon <= 0)
src.master.speak("Error: Bar not found. Break canceled.")
src.master.set_emotion("sad")
src.master.remove_current_task()
return
if(istype(src.bar_beacon_turf, /turf/simulated))
if (get_area(src.master) == get_area(bar_beacon_turf))
src.state = 2
master.moving = 0
//master.current_movepath = "HEH"
return
if (!master.moving)
if (nav_delay > 0)
nav_delay--
return
master.navigate_to(src.bar_beacon_turf)
nav_delay = 5
else
if(!master.last_comm || (world.time >= master.last_comm + 100) )
src.awaiting_beacon = 10
master.post_status("!BEACON!", "findbeacon", "patrol")
master.reply_wait = 2
if (2) //Seeking a seat.
if (!istype(src.target, /obj/stool))
src.secondary_targets.len = 0
for (var/obj/stool/S in view(7, master))
secondary_targets += S
if (secondary_targets.len)
src.target = pick(secondary_targets)
else
master.speak("Error: No seating available. Break canceled.")
src.master.set_emotion("sad")
src.master.remove_current_task()
return
else
if(src.target.loc == src.master.loc)
src.master.set_emotion(rumpus_emotion)
src.state = 3
src.our_seat = src.target
src.party_idle_counter = rand(4,14)
if (!its_beepsky)
src.locate_beepsky()
return
if(!master.moving)
master.navigate_to(src.target, 2.5)
return
if (3) //IT IS RUMPUS TIME
if (its_beepsky && (get_area(master) == get_area(its_beepsky)))
beepsky_check_delay = 8
src.state = 4
src.master.set_emotion("ugh")
if (its_beepsky.emagged == 2)
src.master.speak(pick("Oh, look at the time.", "I need to go. I have a...dentist appointment. Yes", "Oh, is the break over already? I better be off.", "I'd best be leaving."))
src.master.remove_current_task()
return
if (party_counter-- <= 0)
src.master.set_emotion()
src.master.speak("Break complete.")
src.master.remove_current_task()
return
if (our_seat && our_seat.loc != src.master.loc)
our_seat = null
src.state = 2
if (src.master.emotion != rumpus_emotion)
src.master.set_emotion(rumpus_emotion)
if (party_idle_counter-- <= 0)
party_idle_counter = rand(4,14)
if (prob(50))
src.master.speak(pick("Yay!", "Woo-hoo!", "Yee-haw!", "Oh boy!", "Oh yeah!", "My favorite color is probably [pick("red","green","mauve","anti-flash white", "aureolin", "coquelicot")].", "I'm glad we have the opportunity to relax like this.", "Imagine if I had two arms. I could hug twice as much!", "I like [pick("tea","coffee","hot chocolate","soda", "diet soda", "milk", "almond milk", "soy milk", "horchata", "hot cocoa with honey mixed in", "green tea", "black tea")]. I have no digestive system or even a mouth, but I'm pretty sure I would like it.", "Sometimes I wonder what it would be like if I could fly."))
else
var/actiontext = pick("does a little dance. It's not very good but there's good effort there.", "slowly rotates around in a circle.", "attempts to do a flip, but is unable to jump.", "hugs an invisible being only it can see.", "rocks back and forth repeatedly.", "tilts side to side.", "claps. Whaaat.", prob(1);"looks directly at you, the viewer.")
if (src.master.hat && prob(8))
actiontext = "adjusts its hat."
src.master.visible_message("<b>[src.master.name]</b> [actiontext]")
if (4)
if (beepsky_check_delay-- > 0)
return
if (!its_beepsky || get_area(master) != get_area(its_beepsky))
if (prob(10))
src.master.speak(pick("Took long enough.", "Thought he'd never leave.", "Thought he'd never leave. Too bad it smells like him in here now."))
src.master.set_emotion(rumpus_emotion)
src.state = 3
return
beepsky_check_delay = 8
return
task_input(var/input)
if (..())
return
if (input == "path_error")
src.master.speak("Error: Destination unreachable. Break canceled.")
src.master.set_emotion("sad")
src.master.remove_current_task()
return
receive_signal(datum/signal/signal)
if(..())
return
var/recv = signal.data["beacon"]
var/valid = signal.data["patrol"]
if(!awaiting_beacon || !recv || !valid || nav_delay)
return
//boutput(world, "patrol task received")
if(recv == rumpus_location_tag) // if the recvd beacon location matches the set destination
// then we will navigate there
bar_beacon_turf = get_turf(signal.source)
awaiting_beacon = 0
nav_delay = rand(3,5)
attack_response(mob/attacker as mob)
if(..())
return
var/datum/computer/file/guardbot_task/security/single_use/beatdown = new
beatdown.arrest_target = attacker
beatdown.mode = 1
src.master.add_task(beatdown, 1, 0)
return
proc/locate_beepsky() //Guardbots don't like beepsky. They think he's a jerk. They are right.
if (src.its_beepsky) //Huh? We haven't lost him.
return
for (var/obj/machinery/bot/secbot/possibly_beepsky in machines)
if (ckey(possibly_beepsky.name) == "officerbeepsky")
src.its_beepsky = possibly_beepsky //Definitely beepsky in this case.
break
return
//Security/Patrol task -- Essentially secbot emulation.
security
name = "secure"
handle_beacons = 1
task_id = "SECURE"
var/tmp/new_destination // pending new destination (waiting for beacon response)
var/tmp/destination // destination description tag
var/tmp/next_destination // the next destination in the patrol route
var/tmp/nearest_beacon // the nearest beacon's tag
var/tmp/turf/nearest_beacon_loc // the nearest beacon's location
var/tmp/awaiting_beacon = 0
var/tmp/patrol_delay = 0
var/tmp/mob/living/carbon/arrest_target = null
var/tmp/mob/living/carbon/hug_target = null
var/list/target_names = list() //Dudes we are preprogrammed to arrest.
var/tmp/mode = 0 //0: Patrol, 1: Arresting somebody
var/tmp/arrest_attempts = 0
var/tmp/cuffing = 0
var/tmp/last_cute_action = 0
var/weapon_access = access_carrypermit //These guys can use guns, ok!
var/lethal = 0 //Do we use lethal force (if possible) ?
var/panic = 0 //Martial law! Arrest all kinds!!
var/no_patrol = 1 //Don't patrol.
var/tmp/list/arrested_messages = list("Have a secure day!","Your move, creep.", "God made tomorrow for the crooks we don't catch today.","One riot, one ranger.")
#define ARREST_DELAY 2.5 //Delay between movements when chasing a criminal, slightly faster than usual. (2.5 vs 3)
#define TIME_BETWEEN_CUTE_ACTIONS 1800 //Tenths of a second between cute actions
patrol
name = "patrol"
task_id = "PATROL"
no_patrol = 0
crazy
name = "patr#(003~"
task_id = "ERR0xF00F"
lethal = 1
panic = 1
no_patrol = 0
single_use
no_patrol = 1
drop_arrest_target()
src.master.remove_current_task()
return
drop_hug_target()
src.master.remove_current_task()
return
seek
no_patrol = 0
look_for_perp()
if(src.arrest_target) return //Already chasing somebody
for (var/mob/living/carbon/C in view(7,master)) //Let's find us a criminal
if ((C.stat) || (C.handcuffed))
continue
if (src.assess_perp(C))
src.master.remove_current_task()
return
assess_perp(mob/living/carbon/human/perp as mob)
if(ckey(perp.name) == master.scratchpad["targetname"])
return 1
var/obj/item/card/id/perp_id = perp.equipped()
if (!istype(perp_id))
perp_id = perp.wear_id
if(perp_id && ckey(perp_id.registered) == master.scratchpad["targetname"])
return 1
return 0
task_act()
if(..()) return
look_for_perp()
switch(mode)
if(0)
if (hug_target)
if ((istype(hug_target) && isdead(hug_target)) || (istype(hug_target, /obj/critter) && hug_target.health <= 0))
hug_target = null
master.set_emotion("sad")
return
if(get_dist(master, hug_target) <= 1)
master.visible_message("<b>[master]</b> hugs [hug_target]!")
if (hug_target.reagents)
hug_target.reagents.add_reagent("hugs", 10)
if (prob(1) && istype(hug_target) && hug_target.client && hug_target.client.IsByondMember())
master.speak("You might want a breath mint.")
drop_hug_target()
master.set_emotion("love")
master.moving = 0
//master.current_movepath = "HEH"
return
if((!(hug_target in view(7,master)) && (!master.mover || !master.moving)) || !master.path || !master.path.len || (4 < get_dist(hug_target,master.path[master.path.len])) )
//qdel(master.mover)
if (master.mover)
master.mover.master = null
master.mover = null
master.moving = 0
master.navigate_to(hug_target,ARREST_DELAY)
return
return
if(patrol_delay)
patrol_delay--
return
if(master.moving || no_patrol)
return
if(!master.moving)
find_patrol_target()
if(1)
if(!arrest_target || !master.tool)
src.mode = 0
return
if(arrest_target)
if(!arrest_target in view(7,master) && !master.moving)
//qdel(master.mover)
master.frustration += 2
if (master.mover)
master.mover.master = null
master.mover = null
master.navigate_to(arrest_target,ARREST_DELAY, 0, 0)
return
else
var/targdist = get_dist(master, arrest_target)
if((targdist <= 1) || (master.tool && master.tool.is_gun))
if (!isliving(arrest_target) || isdead(arrest_target))
mode = 0
drop_arrest_target()
return
master.bot_attack(arrest_target, src.lethal)
if(targdist <= 1 && !cuffing && (arrest_target.getStatusDuration("weakened") || arrest_target.getStatusDuration("stunned")))
cuffing = 1
src.arrest_attempts = 0 //Put in here instead of right after attack so gun robuddies don't get confused
playsound(master.loc, "sound/weapons/handcuffs.ogg", 30, 1, -2)
master.visible_message("<span style=\"color:red\"><b>[master] is trying to put handcuffs on [arrest_target]!</b></span>")
var/cuffloc = arrest_target.loc
SPAWN_DBG(6 SECONDS)
if (!master)
return
if (get_dist(master, arrest_target) <= 1 && arrest_target.loc == cuffloc)
if (!cuffing)
return
if (!master || !master.on || master.idle || master.stunned)
src.cuffing = 0
return
if (arrest_target.handcuffed || !isturf(arrest_target.loc))
drop_arrest_target()
return
if (ishuman(arrest_target))
var/mob/living/carbon/human/H = arrest_target
//if(H.bioHolder.HasEffect("lost_left_arm") || H.bioHolder.HasEffect("lost_right_arm"))
if(!H.limbs.l_arm || !H.limbs.r_arm)
drop_arrest_target()
master.set_emotion("sad")
return
if(iscarbon(arrest_target))
arrest_target.handcuffed = new /obj/item/handcuffs/guardbot(arrest_target)
arrest_target.setStatus("handcuffed", duration = null)
boutput(arrest_target, "<span style=\"color:red\">[master] gently handcuffs you! It's like the cuffs are hugging your wrists.</span>")
arrest_target:set_clothing_icon_dirty()
mode = 0
src.drop_arrest_target()
master.set_emotion("smug")
if (arrested_messages && arrested_messages.len)
var/arrest_message = pick(arrested_messages)
master.speak(arrest_message)
else
src.cuffing = 0
return
if(!master.path || !master.path.len || (4 < get_dist(arrest_target,master.path[master.path.len])) )
master.moving = 0
//master.current_movepath = "HEH" //Stop any current movement.
master.navigate_to(arrest_target,ARREST_DELAY, 0,0)
return
return
task_input(input)
if(..()) return 1
switch(input)
if("snooze")
src.patrol_delay = 0
src.awaiting_beacon = 0
src.next_destination = null
src.target = null
src.secondary_targets.len = 0
if(arrest_target)
src.arrest_target = null
src.last_found = world.time
src.arrest_attempts = 0
src.cuffing = 0
return 1
if("path_error","path_blocked")
src.arrest_attempts++
if(src.arrest_attempts >= 2)
src.cuffing = 0
src.target = null
if(arrest_target)
src.arrest_target = null
src.last_found = world.time
src.mode = 0
src.arrest_attempts = 0
master.set_emotion()
return 1
if ("treated")
return ..("hugged")
return 0
receive_signal(datum/signal/signal)
if(..())
return
if(signal.data["command"] == "configure")
if (signal.data["command2"])
signal.data["command"] = signal.data["command2"]
src.configure(signal.data)
return
var/recv = signal.data["beacon"]
var/valid = signal.data["patrol"]
if(!awaiting_beacon || !recv || !valid || patrol_delay)
return
//boutput(world, "patrol task received")
if(recv == new_destination) // if the recvd beacon location matches the set destination
// then we will navigate there
destination = new_destination
target = signal.source.loc
next_destination = signal.data["next_patrol"]
awaiting_beacon = 0
patrol_delay = rand(3,5) //So a patrol group doesn't bunch up on a single tile.
// if looking for nearest beacon
else if(new_destination == "__nearest__")
var/dist = get_dist(master,signal.source.loc)
if(nearest_beacon)
// note we ignore the beacon we are located at
if(dist>1 && dist<get_dist(master,nearest_beacon_loc))
nearest_beacon = recv
nearest_beacon_loc = signal.source.loc
next_destination = signal.data["next_patrol"]
target = signal.source.loc
destination = recv
awaiting_beacon = 0
patrol_delay = 5
return
else
return
else if(dist > 1)
nearest_beacon = recv
nearest_beacon_loc = signal.source.loc
next_destination = signal.data["next_patrol"]
target = signal.source.loc
destination = recv
awaiting_beacon = 0
patrol_delay = 5
return
attack_response(mob/attacker as mob)
if(..())
return
if(!src.arrest_target)
src.arrest_target = attacker
src.mode = 1
src.oldtarget_name = attacker.name
master.set_emotion("angry")
return
configure(var/list/confList)
if (..())
return 1
if (confList["patrol"])
var/patrol_stat = text2num(confList["patrol"])
if (!isnull(patrol_stat))
if (patrol_stat)
src.no_patrol = 0
else
src.no_patrol = 1
if (confList["lethal"] && (confList["acc_code"] == netpass_heads))
var/lethal_stat = text2num(confList["lethal"])
if (!isnull(lethal_stat))
if (lethal_stat && !src.lethal)
src.lethal = 1
if (src.master)
master.speak("Notice: Lethal force authorized.")
else if (src.lethal)
src.lethal = 0
if (src.master)
master.speak("Notice: Lethal force is no longer authorized.")
if (confList["name"] && !src.master)
var/target_name = ckey(confList["name"])
if (target_name && target_name != "")
src.target_names = list(target_name)
if (confList["command"])
switch(lowertext(confList["command"]))
if ("add_target")
if(confList["acc_code"] != netpass_heads)
return 0
var/newtarget_name = ckey(confList["data"])
if(!newtarget_name || newtarget_name == "")
return 0
if(!(newtarget_name in src.target_names))
src.target_names += newtarget_name
if (src.master)
master.speak("Notice: Criminal database updated.")
return 0
if ("remove_target")
if(confList["acc_code"] != netpass_heads)
return 0
var/seltarget_name = ckey(confList["data"])
if(!seltarget_name || seltarget_name == "")
return 0
if(seltarget_name in src.target_names)
src.target_names -= seltarget_name
if (src.master)
if(src.target_names.len)
master.speak("Notice: Criminal database updated.")
else
master.speak("Notice: Criminal database cleared.")
return 0
if("clear_targets")
if(confList["acc_code"] != netpass_heads)
return 0
if(src.target_names.len)
src.target_names = list()
if (src.master)
master.speak("Notice: Criminal database cleared.")
return 0
return 0
proc
look_for_perp()
if(src.arrest_target) return //Already chasing somebody
for (var/mob/living/carbon/C in view(7,master)) //Let's find us a criminal
if ((C.stat) || (C.handcuffed))
continue
if ((C.name == src.oldtarget_name) && (world.time < src.last_found + 60))
continue
var/threat = 0
if(ishuman(C))
threat = src.assess_perp(C)
// else
// if(isalien(C))
// threat = 9
if(threat >= 4)
src.arrest_target = C
src.oldtarget_name = C.name
src.mode = 1
src.master.frustration = 0
master.set_emotion("angry")
SPAWN_DBG(0)
master.speak("Level [threat] infraction alert!")
master.visible_message("<b>[master]</b> points at [C.name]!")
else if (!last_cute_action || ((last_cute_action + TIME_BETWEEN_CUTE_ACTIONS) < world.time))
if (prob(10))
last_cute_action = world.time
switch(rand(1,5))
if (1)
master.visible_message("<b>[master]</b> waves at [C.name].")
if (2)
master.visible_message("<b>[master]</b> rotates slowly around in a circle.")
if (3,4)
//hugs!!
master.visible_message("<b>[master]</b> points at [C.name]!")
master.speak( pick("Level [rand(1,32)] hug deficiency alert!", "Somebody needs a hug!", "Cheer up!") )
src.hug_target = C
if (5)
master.visible_message("<b>[master]</b> appears to be having a [pick("great","swell","rad","wonderful")] day!")
if (prob(50))
master.speak("Woo!")
return
drop_arrest_target()
src.arrest_target = null
src.last_found = world.time
src.cuffing = 0
src.master.frustration = 0
master.set_emotion()
return
drop_hug_target()
src.hug_target = null
return
find_patrol_target()
if(awaiting_beacon) // awaiting beacon response
awaiting_beacon--
if(awaiting_beacon <= 0)
find_nearest_beacon()
return
if(next_destination)
set_destination(next_destination)
if(!master.moving && target && (target != master.loc))
master.navigate_to(target)
return
else
find_nearest_beacon()
return
find_nearest_beacon()
nearest_beacon = null
new_destination = "__nearest__"
master.post_status("!BEACON!", "findbeacon", "patrol")
awaiting_beacon = 5
SPAWN_DBG(1 SECOND)
if(!master || !master.on || master.stunned || master.idle) return
if(master.task != src) return
awaiting_beacon = 0
if(nearest_beacon && !master.moving)
master.navigate_to(nearest_beacon_loc)
else
patrol_delay = 8
target = null
return
set_destination(var/new_dest)
new_destination = new_dest
master.post_status("!BEACON!", "findbeacon", "patrol")
awaiting_beacon = 5
assess_perp(mob/living/carbon/human/perp as mob)
. = 0
if(src.panic)
return 9
if(ckey(perp.name) in target_names)
return 7
var/obj/item/card/id/perp_id = perp.equipped()
if (!istype(perp_id))
perp_id = perp.wear_id
if(perp_id)
if(ckey(perp_id.registered) in target_names)
return 7
if(weapon_access in perp_id.access)
return 0
if (istype(perp.l_hand))
. += perp.l_hand.contraband
if (istype(perp.r_hand))
. += perp.r_hand.contraband
if (istype(perp:belt))
. += perp:belt.contraband * 0.5
if (istype(perp:wear_suit))
. += perp:wear_suit.contraband
if(perp.mutantrace && perp.mutantrace.jerk)
// if(istype(perp.mutantrace, /datum/mutantrace/zombie))
// return 5 //Zombies are bad news!
// threatcount += 2
return 5
halloween //Go trick or treating!
name = "candy"
task_id = "CANDY"
no_patrol = 0
look_for_perp()
if(src.hug_target)
return
for (var/mob/living/carbon/C in view(7,master)) //Let's get some candy!
if ((C.stat) || (C.handcuffed))
continue
if ((C.name == src.oldtarget_name) && (world.time < src.last_found + 60))
continue
var/threat = 0
if(ishuman(C))
threat = src.assess_perp(C)
// else
// if(isalien(C))
// threat = 9
if(threat < 4 && (!last_cute_action || ((last_cute_action + TIME_BETWEEN_CUTE_ACTIONS) < world.time)))
src.oldtarget_name = C.name
if (prob(10))
src.hug_target = C
return
task_input(var/input)
if (input == "treated")
if (..("filler"))
return 1
src.master.speak( pick("Yayyy! Thank you!", "Whoohoo, candy!", "Thank you! I can't actually eat candy, but I enjoy the aesthetic aspect of it.") )
src.master.set_emotion("happy")
else
if (..())
return 1
task_act()
if (master && mode == 0 && hug_target)
if (isdead(hug_target))
hug_target = null
master.set_emotion("sad")
return
if(get_dist(master, hug_target) <= 1)
if (prob(2))
master.speak("Merry Spacemas!")
SPAWN_DBG(1 SECOND)
if (master)
master.speak("Warning: Real-time clock battery low or missing.")
else
master.speak("Trick or treat!")
if (prob(50) && hug_target.client && hug_target.client.IsByondMember())
master.speak("Oh wait, you're the one who just hands out [pick("religious tracts","pennies", "toothbrushes")].")
master.set_emotion("love")
hug_target = null
master.moving = 0
//master.current_movepath = "HEH"
return
if((!(hug_target in view(7,master)) && (!master.mover || !master.moving)) || !master.path || !master.path.len || (4 < get_dist(hug_target,master.path[master.path.len])) )
//qdel(master.mover)
if (master.mover)
master.mover.master = null
master.mover = null
master.moving = 0
master.navigate_to(hug_target,ARREST_DELAY)
return
else
return ..()
purge //Arrest anyone who isn't a DWAINE superuser.
name = "purge"
task_id = "PURGE"
no_patrol = 0
var/accepted_access = access_dwaine_superuser
assess_perp(mob/living/carbon/human/perp as mob)
var/obj/item/card/id/the_id = perp.wear_id
if (!the_id)
the_id = perp.equipped()
if(!istype(the_id) || (the_id && !(accepted_access in the_id.access)) )
return 9
else
return ..()
/*
klaus //todo
name = "klaus"
task_id = "KLAUS"
look_for_perp()
. = ..()
if (src.arrest_target)
return
*/
area_guard
name = "areaguard"
task_id = "AREAG"
no_patrol = 1
var/area/current_area = null
look_for_perp()
current_area = get_area(src.master)
return ..()
assess_perp(mob/living/carbon/human/perp as mob)
var/area/perp_area = get_area(perp)
if (perp_area == current_area)
return ..()
return 0
//Bodyguard Task -- Guard some dude's personal space
bodyguard
name = "bodyguard"
task_id = "GUARD"
var/tmp/mob/living/carbon/protected = null
var/tmp/mob/living/carbon/arrest_target = null
var/tmp/arrest_attempts = 0
var/tmp/follow_attempts = 0
var/tmp/cuffing = 0
var/tmp/mode = 0 //0: Following protectee, 1: Arresting threat
var/lethal = 0 //Do we use lethal force (if possible) ?
var/desired_emotion = "look"
var/tmp/attacked_by_buddy = 0 //Has our buddy hit us? Buddy abuse is a serious problem.
var/tmp/buddy_is_dork = 0 //Our buddy kinda sucks :(
var/tmp/list/arrested_messages = list("Threat neutralized.","Station secure.","Problem resolved.")
var/protected_name = null //Who are we seeking?
#define SEARCH_EMOTION "look"
#define GUARDING_EMOTION "cool"
#define GUARDING_DORK_EMOTION "coolugh"
#define CHASING_EMOTION "angry"
task_act()
if(..())
return 1
if(master.emotion != desired_emotion)
master.set_emotion(desired_emotion)
if(arrest_target) //Priority one: Arrest a jerk who hurt our buddy.
desired_emotion = CHASING_EMOTION
master.set_emotion(CHASING_EMOTION)
handle_arrest_function()
return
if(!protected) //Priority two: Assess status of buddy.
src.desired_emotion = SEARCH_EMOTION
src.look_for_protected()
return
else
src.desired_emotion = buddy_is_dork ? GUARDING_DORK_EMOTION : GUARDING_EMOTION
if(src.check_buddy()) //Should ONLY return true when we pick up a new arrest target.
master.set_emotion(CHASING_EMOTION)
handle_arrest_function() //So we don't have to wait for the next process. LIVES ARE ON THE LINE HERE!
return
if(!protected in view(7,master) && !master.moving)
//qdel(master.mover)
master.frustration++
if (master.mover)
master.mover.master = null
master.mover = null
master.navigate_to(protected,3,1,1)
return
else
if(isdead(protected))
protected = null
if (buddy_is_dork && prob(50))
master.speak(pick("Rest in peace. I guess", "At least that's over.", "I didn't have the courage to tell you this, but you smelled like rotten ham."))
else
master.speak(pick("Rest in peace.","Guard protocol...inactive.","I'm sorry it had to end this way.","It was an honor to serve alongside you."))
return
if(!master.path || !master.path.len || (3 < get_dist(protected,master.path[master.path.len])) )
master.moving = 0
//qdel(master.mover)
if (master.mover)
master.mover.master = null
master.mover = null
master.navigate_to(protected,3,1,1)
return
task_input(input)
if(..()) return
switch(input)
if("snooze")
// src.arrest_target = null
src.protected = null
src.arrest_attempts = 0
src.follow_attempts = 0
src.cuffing = 0
if("path_error","path_blocked")
if (src.protected)
if(!(src.protected in view(7,master)))
src.follow_attempts++
if(src.follow_attempts >= 2)
src.follow_attempts = 0
src.protected = null
return
return
attack_response(mob/attacker as mob)
if(..())
return
if(attacker == src.protected && !attacked_by_buddy)
attacked_by_buddy = 1
master.speak(pick("Check your fire!","Watch it!","Friendly fire will not be tolerated!"))
return
if(!src.arrest_target)
src.arrest_target = attacker
if(attacker == src.protected)
src.protected = null
return
configure(var/list/confList)
if (..())
return 1
if (confList["name"])
src.protected_name = ckey(confList["name"])
return 0
proc
look_for_protected() //Search for a mob in view with the name we are programmed to guard.
if(src.protected) return //We have someone to protect!
for (var/mob/living/C in view(7,master))
if (isdead(C)) //We were too late!
continue
var/check_name = C.name
if(ishuman(C) && C:wear_id)
check_name = C:wear_id:registered
if (ckey(check_name) == ckey(src.protected_name))
src.protected = C
src.desired_emotion = GUARDING_EMOTION
C.unlock_medal("Ol' buddy ol' pal", 1)
src.buddy_is_dork = (C.client && C.client.IsByondMember())
SPAWN_DBG(0)
//if (buddy_is_dork && prob(50))
//master.speak(pick("I am here to protect...Oh, it's <i>you</i>.", "I have been instructed to guard you. Welp.", "You are now under guard. I guess."))
master.speak(pick("I am here to protect you.","I have been instructed to guard you.","You are now under guard.","Come with me if you want to live!"))
master.visible_message("<b>[master]</b> points at [C.name]!")
break
return
drop_arrest_target()
src.arrest_target = null
src.cuffing = 0
return
check_buddy()
//Out of sight, out of mind.
if(!(protected in view(7,master)))
return 0
//Has our buddy been attacked??
if(protected.lastattacker && (protected.lastattackertime + 40) >= world.time)
if(protected.lastattacker != protected)
master.moving = 0
//qdel(master.mover)
if (master.mover)
master.mover.master = null
master.mover = null
src.arrest_target = protected.lastattacker
src.follow_attempts = 0
src.arrest_attempts = 0
return 1
return 0
handle_arrest_function()
var/datum/computer/file/guardbot_task/security/single_use/beatdown = new
beatdown.arrest_target = src.arrest_target
beatdown.mode = 1
beatdown.arrested_messages = src.arrested_messages
src.arrest_target = null
src.master.add_task(beatdown, 1, 0)
return
bodyguard/heckle
name = "heckle"
task_id = "HECKLE"
var/global/list/buddy_heckle_phrases = list( "Neeerrd!", "Dork!", "Hey! Hey! You smell...bad! Really bad!", "Hey! You have an odor! A grody one! GRODY NERD ALERT!", "Did you get lost on the way to your anime club?", "Are you as bad at your job as you are at dressing yourself?", "You should probably eat something other than fatty beef jerky for every meal. Your family is getting worried about you.","I'm sorry they didn't let you wear your fedora to work today.", "CAUTION: Poor impulse control!","That's a, um, really unfortunate choice of uniform. Maybe you should try something with vertical stripes to de-emphasize the...you know.", "You, uh, should probably wash your hair. I think if you took a swim, all the seals would die.")
var/tmp/initial_seek_complete = 0
task_act()
if (..())
return
if (src.protected && prob(10))
master.speak( pick(buddy_heckle_phrases) )
master.visible_message("<b>[master]</b> points at [src.protected.name]!")
look_for_protected() //Search for a mob in view with the name we are programmed to guard.
if(src.protected) return //We have someone to protect!
for (var/mob/living/C in view(7,master))
if (isdead(C)) //We were too late!
continue
var/check_name = C.name
if(ishuman(C) && C:wear_id)
check_name = C:wear_id:registered
if (ckey(check_name) == ckey(src.protected_name))
src.protected = C
buddy_is_dork = 1
//src.desired_emotion = GUARDING_EMOTION
SPAWN_DBG(0)
master.speak("Level 9F [pick("dork","nerd","weenie","doofus","loser","dingus","dorkus")] detected!")
master.visible_message("<b>[master]</b> points at [C.name]!")
return
if (!initial_seek_complete)
initial_seek_complete = 1
master.scratchpad["targetname"] = ckey(src.protected_name)
src.master.add_task(/datum/computer/file/guardbot_task/security/seek, 1, 0)
return
check_buddy()
return 0
#undef SEARCH_EMOTION
#undef GUARDING_EMOTION
#undef GUARDING_DORK_EMOTION
#undef CHASING_EMOTION
#define STATE_FINDING_BEACON 0//Byond, enums, lack thereof, etc
#define STATE_PATHING_TO_BEACON 1
#define STATE_AT_BEACON 2
#define STATE_POST_TOUR_IDLE 3
//Neat things we've seen on this trip
#define NT_WIZARD 1
#define NT_CAPTAIN 2
#define NT_JONES 4
#define NT_BEE 8
#define NT_SECBOT 16
#define NT_BEEPSKY 32
#define NT_OTHERBUDDY 64
#define NT_SPACE 128
#define NT_DORK 256
#define NT_CLOAKER 1024
#define NT_GEORGE 2048
#define NT_DRONE 4096
#define NT_AUTOMATON 8192
#define NT_CHEGET 16384
#define NT_GAFFE 32768 //Note: this is the last one the bitfield can fit. Thanks, byond!!
tourguide
name = "tourguide"
task_id = "TOUR"
handle_beacons = 1
var/wait_for_guests = 0 //Wait for people to be around before giving tour dialog?
var/tmp/state = STATE_FINDING_BEACON
var/tmp/desired_emotion = "happy"
var/tmp/list/visited_beacons = list()
var/tmp/next_beacon_id = "tour0"
var/tmp/current_beacon_id = null
var/tmp/turf/current_beacon_loc = null
var/tmp/awaiting_beacon = 0
var/tmp/current_tour_text = null
var/tmp/tour_delay = 0
var/tmp/neat_things = 0 //Bitfield to mark neat things seen on a tour.
var/tmp/recent_nav_attempts = 0
New()
..()
tourguides += src
disposing()
..()
tourguides -= src
#define TOUR_FACE "happy"
#define ANGRY_FACE "angry"
//Method of operation:
//Locate starting beacon or last beacon
//Check name of beacon against list of visited beacons.
//Interrogate beacon for information string, if any
//Say information string once our tourgroup (or some random doofus, it doesn't really matter) has arrived.
//Locate next beacon OR finish if none defined.
task_act()
if (..())
return
if(master.emotion != desired_emotion)
master.set_emotion(desired_emotion)
switch (state)
if (STATE_FINDING_BEACON)
if (awaiting_beacon)
awaiting_beacon--
return
if (!next_beacon_id)
next_beacon_id = initial(next_beacon_id)
awaiting_beacon = 10
master.post_status("!BEACON!", "findbeacon", "tour")
return
if (STATE_PATHING_TO_BEACON)
if (!isturf(current_beacon_loc))
state = STATE_FINDING_BEACON
return
if (prob(20))
src.look_for_neat_thing()
if (!master.moving)
if (awaiting_beacon > 0)
awaiting_beacon--
return
if (current_beacon_loc != master.loc)
master.navigate_to(current_beacon_loc)
else
state = STATE_AT_BEACON
return
if (STATE_AT_BEACON)
if (wait_for_guests && !locate(/mob/living/carbon) in view(src.master)) //Maybe we shouldn't speak to no-one??
return //I realize this doesn't check if they're dead. Buddies can't always tell, ok!! Maybe if people had helpful power lights too
if (ckey(current_tour_text))
if (findtext(current_tour_text, "|p")) //There are pauses present! So, um, pause.
var/list/tour_text_with_pauses = splittext(current_tour_text, "|p")
SPAWN_DBG (0)
sleep(10)
for (var/tour_line in tour_text_with_pauses)
if (!ckey(tour_line) || !master)
break
master.speak( copytext( html_encode(tour_line), 1, MAX_MESSAGE_LEN ) )
sleep(10)
else
master.speak( copytext(html_encode(current_tour_text), 1, MAX_MESSAGE_LEN))
if (next_beacon_id)
state = STATE_FINDING_BEACON
awaiting_beacon = 3 //This will just serve as a delay so the buddy isn't zipping around at light speed between stops.
else
state = STATE_POST_TOUR_IDLE
tour_delay = 30
master.speak("And that concludes the tour session. Please visit the gift shop on your way out.")
return
if (STATE_POST_TOUR_IDLE)
if (tour_delay-- > 0)
return
next_beacon_id = initial(next_beacon_id)
state = STATE_FINDING_BEACON
neat_things = 0
return
attack_response(mob/attacker as mob)
if(..())
return
src.master.set_emotion(ANGRY_FACE)
src.master.speak(pick("Rude!","That is not acceptable behavior!","This is a tour, not a fight factory!","You have been ejected from the tourgroup for: Roughhousing. Please be aware that tour sessions are non-refundable."))
var/datum/computer/file/guardbot_task/security/single_use/beatdown = new
beatdown.arrest_target = attacker
beatdown.mode = 1
src.master.add_task(beatdown, 1, 0)
return
task_input(input)
if(..()) return
switch(input)
if("snooze")
src.awaiting_beacon = 0
src.next_beacon_id = null
if("path_error","path_blocked")
if (recent_nav_attempts++ > 10)
recent_nav_attempts = 0
awaiting_beacon = 10
return
receive_signal(datum/signal/signal)
if(..())
return
var/recv = signal.data["beacon"]
var/valid = signal.data["tour"]
if(!awaiting_beacon || !recv || !valid || state != STATE_FINDING_BEACON)
return
if(recv == next_beacon_id) // if the recvd beacon location matches the set destination
// then we will navigate there
current_beacon_id = next_beacon_id
current_beacon_loc = signal.source.loc
next_beacon_id = signal.data["next_tour"]
awaiting_beacon = 0
src.state = STATE_PATHING_TO_BEACON
if (ckey(signal.data["desc"]))
current_tour_text = signal.data["desc"]
else
current_tour_text = null
return
proc/look_for_neat_thing()
var/area/spaceArea = get_area(src.master)
if (!(src.neat_things & NT_SPACE) && spaceArea && spaceArea.name == "Space" && !istype(get_turf(src.master), /turf/simulated/shuttle))
src.neat_things |= NT_SPACE
src.master.speak(pick("While you find yourself surrounded by space, please try to avoid the temptation to inhale any of it. That doesn't work.",\
"Space: the final frontier. Oh, except for time travel and any other dimensions. And frontiers on other planets, including other planets in those other dimensions and times. Maybe I should stick with \"space: a frontier.\"",\
"Those worlds in space are as countless as all the grains of sand on all the beaches of the earth. Each of those worlds is as real as ours and every one of them is a succession of incidents, events, occurrences which influence its future. Countless worlds, numberless moments, an immensity of space and time. This Sagan quote and others like it are available on mugs at the gift shop.",\
"Please keep hold of the station at all times while in an exposed area. The same principle does not apply to your breath without a mask. Your lungs will pop like bubblegum. Just a heads up."))
return
for (var/atom/movable/AM in view(7, master))
if (ishuman(AM))
var/mob/living/carbon/human/H = AM
if (!(src.neat_things & NT_GAFFE) && !isdead(H) && !H.sight_check(1))
src.neat_things |= NT_GAFFE
src.master.speak("Ah! As you can see here--")
SPAWN_DBG (10)
. = desired_emotion //We're going to make him sad until the end of this spawn, ok.
desired_emotion = "sad"
master.set_emotion(desired_emotion)
src.master.speak("OH! Sorry! Sorry, [H.name]! I didn't mean it that way!")
sleep(5)
var/mob/living/carbon/human/deaf_person = null
for (var/mob/living/carbon/human/maybe_deaf in view(7, master))
if (!isdead(maybe_deaf) && !maybe_deaf.hearing_check(1))
deaf_person = maybe_deaf
break
if (deaf_person)
src.master.speak("I'll just narrate things so you can all hear it--")
sleep(10)
if (deaf_person == H)
src.master.speak("SORRY [H] I DIDN'T MEAN THAT EITHER AAAA")
else
src.master.speak("Oh! Sorry! Sorry, [deaf_person.name]!! I didn't mean that that way eith-wait um.")
sleep(10)
src.master.visible_message("<b>[src.master]</b> begins signing frantically! Despite, um, robot hands not really being equipped for sign language.")
sleep(100)
desired_emotion = .
master.set_emotion(desired_emotion)
if (!(src.neat_things & NT_CLOAKER) && H.invisibility > 0)
src.master.speak("As a courtesy to other tourgroup members, you are requested, though not required, to deactivate any cloaking devices, stealth suits, light redirection field packs, and/or unholy blood magic.")
src.neat_things |= NT_CLOAKER
return
if (!(src.neat_things & NT_WIZARD) && istype(H.wear_suit, /obj/item/clothing/suit/wizrobe) )
src.master.speak( pick("Look, group, a wizard! Please be careful, space wizards can be dangerous.","Ooh, a real space wizard! Look but don't touch, folks!","Space wizards are highly secretive, especially regarding the nature of their abilities. Current speculation is that their \"magic\" is really the application of advanced technologies or artifacts.") )
src.neat_things |= NT_WIZARD
return
if (!(src.neat_things & NT_CAPTAIN) && istype(H.head, /obj/item/clothing/head/caphat))
src.neat_things |= NT_CAPTAIN
src.master.speak("Good day, Captain! You're looking [pick("spiffy","good","swell","proper","professional","prim and proper", "spiffy", "ultra-spiffy")] today.")
return
if (!(src.neat_things & NT_DORK) && (H.client && H.client.IsByondMember() && prob(5)))// || (H.ckey in Dorks))) //If this is too mean to clarks, remove that part I guess
src.neat_things |= NT_DORK
var/insult = pick("dork","nerd","weenie","doofus","loser","dingus","dorkus")
var/insultphrase = "And if you look to--[insult] alert! [pick("Huge","Total","Mega","Complete")] [insult] detected! Alert! Alert! [capitalize(insult)]! "
insultphrase += copytext(insult,1,2)
var/i = rand(3,7)
while (i-- > 0)
insultphrase += copytext(insult,2,3)
insultphrase += "[copytext(insult,3)]!!"
src.master.speak(insultphrase)
var/P = new /obj/decal/point(get_turf(H))
SPAWN_DBG (40)
qdel(P)
src.master.visible_message("<b>[src.master]</b> points to [H]")
return
else if (!(src.neat_things & NT_JONES) && istype(AM, /obj/critter/cat) && AM.name == "Jones")
src.neat_things |= NT_JONES
var/obj/critter/cat/jones = AM
src.master.speak("And over here is the ship's cat, J[jones.alive ? "ones! No spacecraft is complete without a cat!" : "-oh mercy, MOVING ON, MOVING ON"]")
return
else if (istype(AM, /obj/critter/domestic_bee) && AM:alive && !(src.neat_things & NT_BEE))
src.neat_things |= NT_BEE
if (istype(AM, /obj/critter/domestic_bee/trauma))
src.master.speak("Look, team, a domestic space bee! This happy creature--oh dear. Hold on, please.")
var/datum/computer/file/guardbot_task/security/single_use/emergency_hug = new
emergency_hug.hug_target = AM
src.master.add_task(emergency_hug, 1, 0)
return
src.master.speak("Look, team, a domestic space bee! This happy creature is the result of decades of genetic research!")
switch (rand(1,5))
if (1)
src.master.speak("Fun fact: Domestic space bee DNA is [rand(1,17)]% [pick("dog", "human", "cat", "honeybee")]")
if (2)
src.master.speak("Fun fact: Domestic space bees are responsible for over [rand(45,67)]% of all honey production outside of Earth!")
if (3)
src.master.speak("Fun fact: Domestic space bees are very well adapted to accidental space exposure, and can survive in that environment for upwards of [pick("ten hours", "two days", "42 minutes", "three-score ke", "one-and-one-half nychthemeron")].")
if (4)
src.master.speak("Fun fact: Domestic space bee DNA is protected by U.S. patent number [rand(111,999)],[rand(111,999)],[rand(555,789)].")
if (5)
src.master.speak("Fun fact: The average weight of a domestic space bee is about [pick("10 pounds","4.54 kilograms", "25600 drams", "1.42857143 cloves", "145.833333 troy ounces")].")
return
else if (istype(AM, /obj/critter/dog/george) && !(src.neat_things & NT_GEORGE))
src.neat_things |= NT_GEORGE
src.master.speak("Why, if it isn't beloved station canine, George! Who's a good doggy? You are! Yes, you!")
else if (istype(AM, /obj/critter/gunbot/drone) && !(src.neat_things & NT_DRONE))
src.neat_things |= NT_DRONE
src.master.speak( pick("Oh dear, a syndicate autonomous drone! These nasty things have been shooting up innocent space-folk for a couple of years now.", "Watch out, folks! That's a syndicate drone, they're nasty buggers!", "Ah, a syhndicate drone! They're made in a secret factory, one located at--oh dear, we better get hurrying before it becomes upset.", "Watch out, that's a syndicate drone! They're made in a secret factory. There was a guy who knew where it was on my first tour, but he took the secret...to his grave!! Literally. It's with him. In his crypt.") )
else if (!(src.neat_things & NT_AUTOMATON) && istype(AM, /obj/critter/automaton))
src.neat_things |= NT_AUTOMATON
src.master.speak("This here is some kind of automaton. This, uh, porcelain-faced, click-clackity metal man.")
. = "Why [istype(get_area(AM), /area/solarium) ? "am I" : "is this"] here?"
SPAWN_DBG (20)
src.master.speak(.)
else if (istype(AM, /obj/machinery/bot))
if (istype(AM, /obj/machinery/bot/secbot))
if (AM.name == "Officer Beepsky" && !(src.neat_things & NT_BEEPSKY))
src.neat_things |= NT_BEEPSKY
src.master.speak("And here comes Officer Beepsky, the proud guard of this station. Proud.")
src.master.speak("Not at all terrible. No Sir. Not at all.")
if (prob(10))
SPAWN_DBG(1.5 SECONDS)
src.master.speak("Well okay, maybe a little.")
return
else if (!(src.neat_things & NT_SECBOT))
src.neat_things |= NT_SECBOT
src.master.speak("And if you look over now, you'll see a securitron, an ace security robot originally developed \"in the field\" from spare parts in a security office!")
return
else if (istype(AM, /obj/machinery/bot/guardbot) && AM != src.master)
var/obj/machinery/bot/guardbot/otherBuddy = AM
if (!(src.neat_things & NT_CAPTAIN) && istype(otherBuddy.hat, /obj/item/clothing/head/caphat))
src.neat_things |= NT_CAPTAIN
src.master.speak("Good day, Captain! You look a little different today, did you get a haircut?")
var/otherBuddyID = otherBuddy.net_id
//Notify other buddy
SPAWN_DBG(1 SECOND)
if (src.master)
src.master.post_status("[otherBuddyID]", "command", "captain_greet")
return
else if (!(src.neat_things & NT_WIZARD) && istype(otherBuddy.hat, /obj/item/clothing/head/wizard))
src.neat_things |= NT_WIZARD
src.master.speak("Look, a space wizard! Please stand back, I am going to attempt to communicate with it.")
src.master.speak("Hello, Mage, Seer, Wizard, Wizzard, or other magic-user. We mean you no harm! We ask you humbly for your WIZARDLY WIZ-DOM.")
if (prob(25))
src.master.speak("We hope that we aren't disrupting any sort of wiz-biz or wizness deal.")
//As before, notify the other buddy
var/otherBuddyID = otherBuddy.net_id
SPAWN_DBG(1 SECOND)
if (src.master)
src.master.post_status("[otherBuddyID]", "command", "wizard_greet")
else if (!(src.neat_things & NT_OTHERBUDDY))
src.neat_things |= NT_OTHERBUDDY
if (istype(otherBuddy, /obj/machinery/bot/guardbot/future))
src.master.speak("The PR line of personal robot has been--wait! Hold the phone! Is that a PR-7? Oh man, I feel old!")
return
if (istype(otherBuddy, /obj/machinery/bot/guardbot/old/tourguide/lunar))
src.master.visible_message("<b>[master]</b> waves at [otherBuddy].")
return
if (istype(otherBuddy, /obj/machinery/bot/guardbot/soviet))
src.master.speak("That's...that's one of those eastern bloc robuddies. Um...hello?")
src.master.visible_message("<b>[master]</b> gives [otherBuddy] a slow, confused wave.")
return
src.master.speak("The PR line of personal robot has been Thinktronic Data Systems' flagship robot line for over 15 years. It's easy to see their appeal!")
switch (rand(1,4))
if (1)
src.master.speak("Buddy Fact: In 2051, Robuddies were conclusively determined to have a[prob(40) ? "t least three-fourths of a" : ""] soul.")
if (2)
src.master.speak("Buddy Fact: Robuddies cannot jump. We just can't, sorry!")
if (3)
src.master.speak("Buddy Fact: Our hug protocols have been extensively revised through thousands of rounds of testing and simulation to deliver Peak Cuddle.")
if (4)
src.master.speak("Buddy Fact: Robuddies are programmed to be avid fans of hats and similar headgear.")
else if ((istype(AM, /obj/item/luggable_computer/cheget) || istype(AM, /obj/machinery/computer3/luggable/cheget)) && !(src.neat_things & NT_CHEGET))
src.neat_things |= NT_CHEGET
src.master.speak( pick("And over there is--NOTHING. Not a thing. Let's continue on with the tour.", "Please ignore the strange briefcase, is what I would say, were there a strange briefcase. But there is not, and even if there was you should ignore it.","This is just a reminder that station crew are not to handle Soviet materials, per a whole bunch of treaties and negotiations.") )
AM.visible_message("<b>[AM]</b> bloops sadly.")
playsound(AM.loc, prob(50) ? 'sound/machines/cheget_sadbloop.ogg' : 'sound/machines/cheget_somberbloop.ogg', 50, 1)
return
//Be kind, undefine...d
#undef STATE_FINDING_BEACON
#undef STATE_PATHING_TO_BEACON
#undef STATE_AT_BEACON
#undef STATE_POST_TOUR_IDLE
#undef TOUR_FACE
#undef ANGRY_FACE
#undef NT_WIZARD
#undef NT_CAPTAIN
#undef NT_JONES
#undef NT_BEE
#undef NT_SECBOT
#undef NT_BEEPSKY
#undef NT_OTHERBUDDY
#undef NT_SPACE
#undef NT_DORK
#undef NT_CLOAKER
#undef NT_GEORGE
#undef NT_DRONE
#undef NT_AUTOMATON
#undef NT_CHEGET
#undef NT_GAFFE
bedsheet_handler
name = "confusion"
task_id = "HUH"
var/announced = 0
var/escape_counter = 4
task_act()
if (..())
return
if (master.bedsheet != 1)
src.master.remove_current_task()
return
if (!announced)
announced = 1
master.speak(pick("Hey, who turned out the lights?","Error: Visual sensor impaired!","Whoa hey, what's the big deal?","Where did everyone go?"))
if (escape_counter-- > 0)
flick("robuddy-ghostfumble", master)
master.visible_message("<span style=\"color:red\">[master] fumbles around in the sheet!</span>")
else
master.visible_message("[master] cuts a hole in the sheet!")
master.speak(pick("Problem solved.","Oh, alright","There we go!"))
master.bedsheet = 2
master.overlays.len = 0
master.hat_shown = 0
master.update_icon()
src.master.remove_current_task()
return
threat_scan
name = "threatscan"
task_id = "SCAN"
var/weapon_access = access_carrypermit
task_act()
if (..())
return
var/mob/living/newThreat = look_for_threat()
if (istype(newThreat))
master.scratchpad["threat"] = newThreat
master.scratchpad["threat_time"] = "[time2text(world.timeofday, "hh:mm:ss")]"
src.master.remove_current_task()
return
return
proc
look_for_threat()
for (var/mob/living/carbon/C in view(7,master)) //Let's find us a criminal
if ((C.stat) || (C.handcuffed))
continue
var/threat = 0
if(ishuman(C))
threat = src.assess_threat_potential(C)
// else
// if(isalien(C))
// threat = 9
if(threat >= 4)
master.scratchpad["threat_level"] = threat
return C
return null
assess_threat_potential(mob/living/carbon/human/potentialThreat as mob)
var/threatcount = 0
var/obj/item/card/id/worn_id = potentialThreat.equipped()
if (!istype(worn_id))
worn_id = potentialThreat.wear_id
if(worn_id)
if(weapon_access in worn_id.access)
return 0
if(istype(potentialThreat.l_hand, /obj/item/gun) || istype(potentialThreat.l_hand, /obj/item/baton) || istype(potentialThreat.l_hand, /obj/item/sword))
threatcount += 4
if(istype(potentialThreat.r_hand, /obj/item/gun) || istype(potentialThreat.r_hand, /obj/item/baton) || istype(potentialThreat.r_hand, /obj/item/sword))
threatcount += 4
if (ishuman(potentialThreat))
if(istype(potentialThreat:belt, /obj/item/gun) || istype(potentialThreat:belt, /obj/item/baton) || istype(potentialThreat:belt, /obj/item/sword))
threatcount += 2
if(istype(potentialThreat:wear_suit, /obj/item/clothing/suit/wizrobe))
threatcount += 4
if(istype(potentialThreat.mutantrace, /datum/mutantrace/abomination))
return 5
return threatcount
/*
* Guardbot Parts
*/
/obj/item/guardbot_core
name = "Guardbuddy mainboard"
desc = "The primary circuitry of a PR-6S Guardbuddy."
icon = 'icons/obj/aibots.dmi'
icon_state = "robuddy_core-6"
mats = 6
w_class = 2.0
var/created_default_task = null //Default task path of result
var/datum/computer/file/guardbot_task/created_model_task = null
var/created_name = "Guardbuddy" //Name of resulting guardbot
var/buddy_model = 6 //What type of guardbot does this belong to (Default is PR-6, but Murray and Marty are PR-4s)
attackby(obj/item/W as obj, mob/user as mob)
if (istype(W, /obj/item/pen))
if (created_name != initial(created_name))
boutput(user, "<span style=\"color:red\">This robot has already been named!</span>")
return
var/t = input(user, "Enter new robot name", src.name, src.created_name) as text
t = copytext(html_encode(t), 1, MAX_MESSAGE_LEN)
if (!t)
return
if (!in_range(src, usr) && src.loc != usr)
return
src.created_name = t
else
..()
/obj/item/guardbot_frame
name = "Guardbuddy frame"
desc = "The external casing of a PR-6S Guardbuddy."
icon = 'icons/obj/aibots.dmi'
icon_state = "robuddy_frame-6-1"
mats = 5
var/stage = 1
var/created_name = "Guardbuddy" //Still the name of resulting guardbot
var/created_default_task = null //Default task path of result
var/datum/computer/file/guardbot_task/created_model_task = null //Initial model task of result.
var/obj/created_module = null //Tool module of result.
var/obj/item/cell/created_cell = null //Energy cell of result.
var/buddy_model = 6 //What type of guardbot does this belong to (Default is PR-6, but Murray and Marty are PR-4s)
var/spawned_bot_type = /obj/machinery/bot/guardbot
New()
..()
SPAWN_DBG(6 DECI SECONDS)
src.icon_state = "robuddy_frame-[buddy_model]-[stage]"
if(src.stage >= 2)
src.created_cell = new
src.created_cell.charge = 0.9 * src.created_cell.maxcharge
return
//Frame -> Add cell -> Add tool -> Add core -> Add arm -> Done
attackby(obj/item/W as obj, mob/user as mob)
if ((istype(W, /obj/item/guardbot_core)))
if(W:buddy_model != src.buddy_model)
boutput(user, "<span style=\"color:red\">That core board is for a different model of robot!</span>")
return
if(!created_cell || stage != 2)
boutput(user, "<span style=\"color:red\">You need to add a power cell first!</span>")
return
if(!created_module)
boutput(user, "<span style=\"color:red\">You need to add a tool module first!</span>")
return
src.stage = 3
src.icon_state = "robuddy_frame-[buddy_model]-3"
if(W:created_name)
src.created_name = W:created_name
if(W:created_default_task)
src.created_default_task = W:created_default_task
if(W:created_model_task)
src.created_model_task = W:created_model_task
boutput(user, "You add the core board to [src]!")
qdel(W)
else if((istype(W, /obj/item/cell)) && stage == 1 && !created_cell)
user.drop_item()
W.set_loc(src)
src.created_cell = W
src.stage = 2
src.icon_state = "robuddy_frame-[buddy_model]-2"
boutput(user, "You add the power cell to [src]!")
else if((istype(W, /obj/item/device/guardbot_tool)) && stage == 2 && !created_module)
user.drop_item()
W.set_loc(src)
src.created_module = W
boutput(user, "You add the [W.name] to [src]!")
else if (istype(W, /obj/item/parts/robot_parts/arm/) && src.stage == 3)
src.stage++
boutput(user, "You add the robot arm to [src]!")
qdel(W)
var/obj/machinery/bot/guardbot/newbot = new src.spawned_bot_type (get_turf(src))
if(newbot.cell)
qdel(newbot.cell)
newbot.cell = src.created_cell
newbot.setup_default_tool_path = null
newbot.cell.set_loc(newbot)
if(src.created_default_task)
newbot.setup_default_startup_task = src.created_default_task
if(src.created_module)
newbot.tool = src.created_module
newbot.tool.set_loc(newbot)
newbot.tool.master = newbot
if(src.created_model_task)
newbot.model_task = src.created_model_task
newbot.model_task.master = newbot
newbot.name = src.created_name
qdel(src)
return
else
..()
return
//The Docking Station. Recharge here!
/obj/machinery/guardbot_dock
name = "docking station"
desc = "A recharging and command station for PR-6S Guardbuddies."
icon = 'icons/obj/aibots.dmi'
icon_state = "robuddycharger0"
mats = 8
anchored = 1
var/panel_open = 0
var/autoeject = 0 //1: Eject fully charged robots automatically. 2: Eject robot when living carbon mob is in view.
var/frequency = 1219
var/net_id = null //What is our network id???
var/net_number = 0
var/host_id = null //Who is linked to us?
var/timeout = 45
var/timeout_alert = 0
var/obj/machinery/bot/guardbot/current = null
var/datum/radio_frequency/radio_connection
var/obj/machinery/power/data_terminal/link = null
//A reset button is useful for when the system gets all confused.
var/last_reset = 0 //Last world.time we were manually reset.
New()
..()
SPAWN_DBG(8 DECI SECONDS)
if(radio_controller)
radio_connection = radio_controller.add_object(src, "[frequency]")
if(!src.net_id)
src.net_id = generate_net_id(src)
if(!src.link)
var/turf/T = get_turf(src)
var/obj/machinery/power/data_terminal/test_link = locate() in T
if(test_link && !test_link.is_valid_master(test_link.master))
src.link = test_link
src.link.master = src
return
attack_hand(mob/user as mob)
if(..() || status & NOPOWER)
return
user.machine = src
var/dat = "<html><head><title>PR-6S Docking Station</title></head><body>"
var/readout_color = "#000000"
var/readout = "ERROR"
if(src.host_id)
readout_color = "#33FF00"
readout = "OK CONNECTION"
else
readout_color = "#F80000"
readout = "NO CONNECTION"
dat += "Host Connection: "
dat += "<table border='1' style='background-color:[readout_color]'><tr><td><font color=white>[readout]</font></td></tr></table><br>"
dat += "<a href='?src=\ref[src];reset=1'>Reset Connection</a><br>"
if (src.panel_open)
dat += "<br>Configuration Switches:<br><table border='1' style='background-color:#7A7A7A'><tr>"
for (var/i = 8, i >= 1, i >>= 1)
var/styleColor = (net_number & i) ? "#60B54A" : "#CD1818"
dat += "<td style='background-color:[styleColor]'><a href='?src=\ref[src];dipsw=[i]' style='color:[styleColor]'>##</a></td>"
dat += "</tr></table>"
user.Browse(dat,"window=guarddock;size=245x282")
onclose(user,"guarddock")
return
Topic(href, href_list)
if(..())
return
usr.machine = src
if (href_list["reset"])
if(last_reset && (last_reset + GUARDBOT_DOCK_RESET_DELAY >= world.time))
return
if(!host_id)
return
src.last_reset = world.time
var/rem_host = src.host_id
src.host_id = null
src.post_wire_status(rem_host, "command","term_disconnect")
SPAWN_DBG(5 DECI SECONDS)
src.post_wire_status(rem_host, "command","term_connect","device","PNET_PR6_CHARG")
src.updateUsrDialog()
return
src.add_fingerprint(usr)
return
receive_signal(datum/signal/signal)
if(status & NOPOWER)
return
if(!signal || signal.encryption || !signal.data["sender"])
return
var/target = signal.data["sender"]
if(signal.transmission_method == TRANSMISSION_WIRE)
if((signal.data["address_1"] == "ping") && ((signal.data["net"] == null) || ("[signal.data["net"]]" == "[src.net_number]")) && target)
SPAWN_DBG(5 DECI SECONDS) //Send a reply for those curious jerks
src.post_wire_status(target, "command", "ping_reply", "device", "PNET_PR6_CHARG", "netid", src.net_id, "net", src.net_number)
return
if(signal.data["address_1"] != src.net_id || !target)
return
var/sigcommand = lowertext(signal.data["command"])
if(!sigcommand || !signal.data["sender"])
return
switch(sigcommand)
if("term_connect") //Terminal interface stuff.
if(target == src.host_id)
src.host_id = null
src.post_wire_status(target, "command","term_disconnect")
return
src.timeout = initial(src.timeout)
src.timeout_alert = 0
src.host_id = target
if(signal.data["data"] != "noreply")
src.post_wire_status(target, "command","term_connect","data","noreply","device","PNET_PR6_CHARG")
SPAWN_DBG(2 DECI SECONDS) //Sign up with the driver (if a mainframe contacted us)
src.post_wire_status(target,"command","term_message","data","command=register&status=[current ? current.net_id : "nobot"]")
src.updateUsrDialog()
return
if("term_message","term_file")
if(target != src.host_id) //Huh, who is this?
return
var/list/data = params2list(signal.data["data"])
if(!data)
return
switch(data["command"])
if("status") //Status of connected bot.
var/status = "command=reply"
if(!src.current)
status += "&status=nobot"
else
status += "&status=[current.net_id]"
var/botcharge = null
if(src.current.cell)
botcharge = "[round((src.current.cell.charge/src.current.cell.maxcharge)*100)]"
else
botcharge = "nocell"
status += "&charge=[botcharge]"
var/bottool = null
if(src.current.tool)
bottool = src.current.tool.tool_id
else
bottool = "NONE"
status += "&tool=[bottool]"
if(current.model_task)
status += "&deftask=[current.model_task.task_id]"
else
status += "&deftask=NONE"
if(current.task)
status += "&curtask=[current.task.task_id]"
else
status += "&curtask=NONE"
//status += "&botid=[current.net_id]"
src.post_wire_status(target,"command","term_message","data",status)
return
if("eject") //Eject current bot
if(!src.current)
src.post_wire_status(target,"command","term_message","data","command=status&status=nobot")
return
src.eject_robot() //eject_robot alerts the host on its own
return
if("upload")
if(!src.current)
src.post_wire_status(target,"command","term_message","data","command=status&status=nobot")
return
var/datum/computer/file/guardbot_task/newtask = signal.data_file
if(!istype(newtask))
src.post_wire_status(target,"command","term_message","data","command=status&status=badtask")
return
newtask = newtask.copy_file() //Original one will be deleted with the signal.
//Clear other tasks?
var/overwrite = text2num(data["overwrite"])
if(isnull(overwrite))
overwrite = 0
//Replace model (default task)?
var/model = text2num(data["newmodel"])
if(isnull(model))
model = 0
var/result = upload_task(newtask, overwrite, model)
if(result)
src.post_wire_status(target,"command","term_message","data","command=status&status=upload_success")
else
src.post_wire_status(target,"command","term_message","data","command=status&status=badtask")
qdel(newtask)
return
if("download")
if(!src.current)
src.post_wire_status(target,"command","term_message","data","command=status&status=nobot")
return
var/datum/computer/file/guardbot_task/task_copy
if (text2num(data["model"]) != null)
if (src.current.model_task)
task_copy = src.current.model_task.copy_file()
else
if (src.current.task)
task_copy = src.current.task.copy_file()
if (task_copy)
var/datum/signal/newsignal = get_free_signal()
newsignal.source = src
newsignal.transmission_method = TRANSMISSION_WIRE
newsignal.data = list("address_1" = target, "command"="term_file", "data", "command=taskfile", "sender" = src.net_id)
newsignal.data_file = task_copy
SPAWN_DBG(2 DECI SECONDS)
src.link.post_signal(src, newsignal)
else
src.post_wire_status(target, "command", "term_message", "data", "command=status&status=notask")
return
if("taskinq") //Task inquiry.
if(!src.current)
src.post_wire_status(target,"command","term_message","data","command=status&status=nobot")
return
var/task_reply = "command=trep"
if(current.model_task)
task_reply += "&deftask=[current.model_task.task_id]"
else
task_reply += "&deftask=NONE"
if(current.task)
task_reply += "&curtask=[current.task.task_id]"
else
task_reply += "&curtask=NONE"
src.post_wire_status(target,"command","term_message","data",task_reply)
return
if("wipe") //Clear tasks of current bot
if(!src.current)
src.post_wire_status(target,"command","term_message","data","command=status&status=nobot")
return
src.current.add_task(null, 0, 1) //No new task, normal priority, wipe all others.
if(src.current.model_task)
qdel(src.current.model_task)
if(src.current.task)
qdel(src.current.task)
src.post_wire_status(target,"command","term_message","data","command=status&status=wipe_success")
return
return
if("term_ping")
if(target != src.host_id)
return
if(signal.data["data"] == "reply")
src.post_wire_status(target, "command","term_ping")
src.timeout = initial(src.timeout)
src.timeout_alert = 0
return
if("term_disconnect")
if(target == src.host_id)
src.host_id = null
src.timeout = initial(src.timeout)
src.timeout_alert = 0
return
return
else
if( (signal.data["address_1"] == "recharge") && !src.current)
var/turf/T = get_turf(src)
if(!T) return
var/to_send = signal.data["sender"]
SPAWN_DBG(rand(4,6)) //So robots don't swarm one of the stations.
src.post_status(to_send, "command","recharge_src", "data", "x=[T.x]&y=[T.y]")
return
MouseDrop_T(obj/O as obj, mob/user as mob)
if(user.stat || get_dist(user,src)>1)
return
if(istype(O, /obj/machinery/bot/guardbot) && !src.current && !O:charge_dock)
if(O.loc != src.loc) return
src.connect_robot(O)
user.visible_message("[user] plugs [O] into the docking station!","You plug [O] into the docking station!")
//if(!O:idle)
// O:snooze()
return
process()
if(current)
if((status & NOPOWER) || !current.cell || (current.loc != src.loc))
eject_robot()
return
current.cell.give(200 + (current.cell.percent() < 25) ? 50 : 0)
use_power(275)
src.icon_state = "robuddycharger1"
if((src.autoeject == 1) && (current.cell.charge >= current.cell.maxcharge) )
eject_robot()
else if ((src.autoeject == 2 || src.autoeject == 3) && (current.cell.charge >= current.cell.maxcharge) )
for (var/mob/living/carbon/M in view(7, src))
if (M.stat) continue
eject_robot()
break
if(src.host_id)
if(src.timeout == 0)
src.post_wire_status(host_id, "command","term_disconnect","data","timeout")
src.host_id = null
src.updateUsrDialog()
src.timeout = initial(src.timeout)
src.timeout_alert = 0
else
src.timeout--
if(src.timeout <= 5 && !src.timeout_alert)
src.timeout_alert = 1
src.post_wire_status(src.host_id, "command","term_ping","data","reply")
return
attackby(obj/item/W as obj, mob/user as mob)
if (isscrewingtool(W))
playsound(src.loc, "sound/items/Screwdriver.ogg", 50, 1)
boutput(user, "You [src.panel_open ? "secure" : "unscrew"] the maintenance panel.")
src.panel_open = !src.panel_open
src.updateUsrDialog()
return
else
..()
return
disposing()
if(src.current)
src.current.wakeup()
current = null
if(radio_controller)
radio_controller.remove_object(src, "[frequency]")
radio_connection = null
if (link)
link.master = null
link = null
..()
return
proc
eject_robot()
if(!current) return
src.icon_state = "robuddycharger0"
src.current.charge_dock = null
src.current.last_dock_id = src.net_id
if (src.autoeject == 3)
src.current.turn_off()
src.current.warm_boot = 0
src.current.turn_on()
else
src.current.wakeup()
src.autoeject = 0
if(src.host_id) //Alert system host of this development!!
src.post_wire_status(src.host_id,"command","term_message","data","command=status&status=ejected&botid=[current.net_id]")
src.current = null
return
connect_robot(obj/machinery/bot/guardbot/robot,aeject=0)
if(!istype(robot))
return 0
src.current = robot
robot.charge_dock = src
src.autoeject = aeject
if(!robot.idle)
robot.snooze()
if(src.host_id)
src.post_wire_status(src.host_id,"command","term_message","data","command=status&status=connect&botid=[current.net_id]")
return 1
upload_task(var/datum/computer/file/guardbot_task/task, clear_others=0, new_model=0)
if(!current || !current.on || !istype(task))
return 0
if(new_model)
if(current.model_task)
qdel(current.model_task)
var/datum/computer/file/guardbot_task/model = task.copy_file()
model.master = current
current.model_task = model
current.add_task(task, 0, clear_others)
if(!current.task)
current.task = task
return 1
post_status(var/target_id, var/key, var/value, var/key2, var/value2, var/key3, var/value3)
if(!radio_connection)
return
var/datum/signal/signal = get_free_signal()
signal.source = src
signal.transmission_method = TRANSMISSION_RADIO
signal.data[key] = value
if(key2)
signal.data[key2] = value2
if(key3)
signal.data[key3] = value3
if(target_id)
signal.data["address_1"] = target_id
signal.data["sender"] = src.net_id
radio_connection.post_signal(src, signal, GUARDBOT_RADIO_RANGE)
post_wire_status(var/target_id, var/key, var/value, var/key2, var/value2, var/key3, var/value3)
if(!src.link || !target_id)
return
var/datum/signal/signal = get_free_signal()
signal.source = src
signal.transmission_method = TRANSMISSION_WIRE
signal.data[key] = value
if(key2)
signal.data[key2] = value2
if(key3)
signal.data[key3] = value3
signal.data["address_1"] = target_id
signal.data["sender"] = src.net_id
SPAWN_DBG(2 DECI SECONDS)
if (src.link) //ZeWaka: Fix for null.post_signal
src.link.post_signal(src, signal)
/obj/machinery/computer/tour_console
name = "Tour Console"
desc = "A computer console, presumably one relating to tours."
icon_state = "old2"
pixel_y = 8
var/obj/machinery/bot/guardbot/linked_bot = null
New()
..()
SPAWN_DBG (8)
linked_bot = locate() in orange(1, src)
attack_ai(mob/user as mob)
return src.attack_hand(user)
attack_hand(mob/user as mob)
if (..() || (status & (NOPOWER|BROKEN)))
return
user.machine = src
add_fingerprint(user)
var/dat = "<center><h4>Tour Monitor</h4></center>"
if (!linked_bot)
dat += "<font color=red>No tour guide detected!</font>"
else
dat += "<b>Guide:</b> <center>\[[linked_bot.name]]</center><br>"
if ((linked_bot in orange(1, src)) && linked_bot.charge_dock)
dat += "<center><a href='?src=\ref[src];start_tour=1'>Begin Tour</a></center>"
else
var/area/guideArea = get_area(linked_bot)
dat += "<b>Current Location:</b> [istype(guideArea) ? guideArea.name : "<font color=red>Unknown</font>"]"
user.Browse("<head><title>Tour Monitor</title></head>[dat]", "window=tourconsole;size=302x245")
onclose(user, "tourconsole")
return
Topic(href, href_list)
if(..())
return
usr.machine = src
src.add_fingerprint(usr)
if (href_list["start_tour"] && linked_bot && (linked_bot in orange(1, src)) && linked_bot.charge_dock)
linked_bot.charge_dock.eject_robot()
src.updateUsrDialog()
return
/obj/machinery/bot/guardbot/old
name = "Robuddy"
desc = "A PR-4 Robuddy. That's two models back by now! You didn't know any of these were still around."
icon = 'icons/misc/oldbots.dmi'
setup_no_costumes = 1
no_camera = 1
setup_charge_maximum = 800
setup_default_tool_path = /obj/item/device/guardbot_tool/flash
speak(var/message)
return ..("<font face=Consolas>[uppertext(message)]</font>")
interact(mob/user as mob)
var/dat = "<tt><B>PR-4 Robuddy v0.8</B></tt><br><br>"
var/power_readout = null
var/readout_color = "#000000"
if(!src.cell)
power_readout = "NO CELL"
else
var/charge_percentage = round((cell.charge/cell.maxcharge)*100)
power_readout = "[charge_percentage]%"
switch(charge_percentage)
if(0 to 10)
readout_color = "#F80000"
if(11 to 25)
readout_color = "#FFCC00"
if(26 to 50)
readout_color = "#CCFF00"
if(51 to 75)
readout_color = "#33CC00"
if(76 to 100)
readout_color = "#33FF00"
dat += {"Power: <table border='1' style='background-color:[readout_color]'>
<tr><td><font color=white>[power_readout]</font></td></tr></table><br>"}
dat += "Current Tool: [src.tool ? src.tool.tool_id : "NONE"]<br>"
if(src.locked)
dat += "Status: [src.on ? "On" : "Off"]<br>"
else
dat += "Status: <a href='?src=\ref[src];power=1'>[src.on ? "On" : "Off"]</a><br>"
dat += "<br>Network ID: <b>\[[uppertext(src.net_id)]]</b><br>"
user.Browse("<head><title>Robuddy v0.8 controls</title></head>[dat]", "window=guardbot")
onclose(user, "guardbot")
return
explode()
if(src.exploding) return
src.exploding = 1
var/death_message = pick("It is now safe to shut off your buddy.","I regret nothing, but I am sorry I am about to leave my friends.","Malfunction!","I had a good run.","Es lebe die Freiheit!","Life was worth living.","Time to die...")
speak(death_message)
src.visible_message("<span style=\"color:red\"><b>[src] blows apart!</b></span>")
var/turf/T = get_turf(src)
if(src.mover)
src.mover.master = null
qdel(src.mover)
src.invisibility = 100
var/obj/overlay/Ov = new/obj/overlay(T)
Ov.anchored = 1
Ov.name = "Explosion"
Ov.layer = NOLIGHT_EFFECTS_LAYER_BASE
Ov.pixel_x = -92
Ov.pixel_y = -96
Ov.icon = 'icons/effects/214x246.dmi'
Ov.icon_state = "explosion"
src.tool.set_loc(get_turf(src))
var/obj/item/guardbot_core/old/core = new /obj/item/guardbot_core/old(T)
core.created_name = src.name
core.created_default_task = src.setup_default_startup_task
core.created_model_task = src.model_task
var/list/throwparts = list()
throwparts += new /obj/item/parts/robot_parts/arm/left(T)
throwparts += new /obj/item/device/flash(T)
throwparts += core
throwparts += src.tool
if(src.hat)
throwparts += src.hat
src.hat.set_loc(T)
throwparts += new /obj/item/guardbot_frame/old(T)
for(var/obj/O in throwparts) //This is why it is called "throwparts"
var/edge = get_edge_target_turf(src, pick(alldirs))
O.throw_at(edge, 100, 4)
SPAWN_DBG(0) //Delete the overlay when finished with it.
src.on = 0
sleep(15)
qdel(Ov)
qdel(src)
T.hotspot_expose(800,125)
explosion(src, T, -1, -1, 2, 3)
return
/obj/item/guardbot_frame/old
name = "Robuddy frame"
desc = "The external casing of a PR-4 Robuddy."
icon_state = "robuddy_frame-4-1"
spawned_bot_type = /obj/machinery/bot/guardbot/old
buddy_model = 4
/obj/item/guardbot_frame/old/golden
desc = "The external casing of a PR-4 Robuddy. This one is gold plated."
icon = 'icons/obj/aibots.dmi'
icon_state = "goldbuddy_frame-4-1"
spawned_bot_type = /obj/machinery/bot/guardbot/golden
created_name = "Goldbuddy"
buddy_model = 4
New()
..()
SPAWN_DBG(6 DECI SECONDS)
src.icon_state = "goldbuddy_frame-[buddy_model]-[stage]"
if(src.stage >= 2)
src.created_cell = new
src.created_cell.charge = 0.9 * src.created_cell.maxcharge
return
attackby(obj/item/W as obj, mob/user as mob)
if ((istype(W, /obj/item/guardbot_core)))
if(W:buddy_model != src.buddy_model)
boutput(user, "<span style=\"color:red\">That core board is for a different model of robot!</span>")
return
if(!created_cell || stage != 2)
boutput(user, "<span style=\"color:red\">You need to add a power cell first!</span>")
return
if(!created_module)
boutput(user, "<span style=\"color:red\">You need to add a tool module first!</span>")
return
src.stage = 3
src.icon_state = "goldbuddy_frame-[buddy_model]-3"
if(W:created_name)
src.created_name = W:created_name
if(W:created_default_task)
src.created_default_task = W:created_default_task
if(W:created_model_task)
src.created_model_task = W:created_model_task
boutput(user, "You add the core board to [src]!")
qdel(W)
else if((istype(W, /obj/item/cell)) && stage == 1 && !created_cell)
user.drop_item()
W.set_loc(src)
src.created_cell = W
src.stage = 2
src.icon_state = "goldbuddy_frame-[buddy_model]-2"
boutput(user, "You add the power cell to [src]!")
else if((istype(W, /obj/item/device/guardbot_tool)) && stage == 2 && !created_module)
user.drop_item()
W.set_loc(src)
src.created_module = W
boutput(user, "You add the [W.name] to [src]!")
else if (istype(W, /obj/item/parts/robot_parts/arm/) && src.stage == 3)
src.stage++
boutput(user, "You add the robot arm to [src]!")
qdel(W)
var/obj/machinery/bot/guardbot/newbot = new src.spawned_bot_type (get_turf(src))
if(newbot.cell)
qdel(newbot.cell)
newbot.cell = src.created_cell
newbot.setup_default_tool_path = null
newbot.cell.set_loc(newbot)
if(src.created_default_task)
newbot.setup_default_startup_task = src.created_default_task
if(src.created_module)
newbot.tool = src.created_module
newbot.tool.set_loc(newbot)
newbot.tool.master = newbot
if(src.created_model_task)
newbot.model_task = src.created_model_task
newbot.model_task.master = newbot
newbot.name = src.created_name
qdel(src)
return
/obj/item/guardbot_core/old
name = "Robuddy mainboard"
desc = "The primary circuitry of a PR-4 Robuddy."
icon_state = "robuddy_core-4"
buddy_model = 4
//A tourguide for "the crunch", or a station!
/obj/machinery/bot/guardbot/old/tourguide
name = "Marty"
desc = "A PR-4 Robuddy. These are pretty old, you didn't know there were any still around! This one has a little name tag on the front labeled 'Marty'"
setup_default_startup_task = /datum/computer/file/guardbot_task/tourguide
no_camera = 1
setup_charge_maximum = 3000
setup_charge_percentage = 100
flashlight_lum = 4
var/HatToWear = /obj/item/clothing/head/safari
New()
..()
#ifdef XMAS
src.HatToWear = /obj/item/clothing/head/helmet/space/santahat
#endif
src.hat = new HatToWear(src)
src.update_icon()
/obj/machinery/bot/guardbot/old/tourguide/destiny
name = "Mary"
desc = "A PR-4 Robuddy. These are pretty old, you didn't know there were any still around! This one has a little name tag on the front labeled 'Mary'."
botcard_access = "Staff Assistant"
beacon_freq = 1443
/obj/machinery/bot/guardbot/old/tourguide/linemap
name = "Monty"
desc = "A PR-4 Robuddy. These are pretty old, you didn't know there were any still around! This one has a little name tag on the front labeled 'Monty'."
botcard_access = "Staff Assistant"
beacon_freq = 1443
/obj/machinery/bot/guardbot/old/tourguide/oshan
name = "Moby"
desc = "A PR-4 Robuddy. These are pretty old, you didn't know there were any still around! This one has a little name tag on the front labeled 'Moby'."
botcard_access = "Staff Assistant"
beacon_freq = 1443
HatToWear = /obj/item/clothing/head/sea_captain
New()
..()
src.hat.name = "Moby's ship captain hat"
/obj/machinery/bot/guardbot/old/tourguide/atlas
name = "Mabel"
desc = "A PR-4 Robuddy. These are pretty old, you didn't know there were any still around! This one has a little name tag on the front labeled 'Mabel'."
botcard_access = "Staff Assistant"
beacon_freq = 1443
HatToWear = /obj/item/clothing/head/NTberet
New()
..()
src.hat.name = "Mabel's beret"
/obj/machinery/computer/hug_console
name = "Hug Console"
desc = "A hug console? It has a small opening on the top."
icon = 'icons/obj/stationobjs.dmi'
icon_state = "holo_console0"
attackby(obj/item/W as obj, mob/user as mob)
if (istype(W, /obj/item/token/hug_token))
user.visible_message("<span style=\"color:red\"><b>[user]</b> inserts a [W] into the [src].</span>", "<span style=\"color:red\">You insert a [W] into the [src].</span>")
qdel(W)
for (var/obj/machinery/bot/guardbot/buddy in machines)
if (buddy.z != 1) continue
if (buddy.charge_dock)
buddy.charge_dock.eject_robot()
else if (buddy.idle)
buddy.wakeup()
buddy.add_task(/datum/computer/file/guardbot_task/recharge/dock_sync, 1, 0)
var/datum/computer/file/guardbot_task/security/single_use/tohug = new
tohug.hug_target = user
buddy.add_task(tohug, 1, 0)
buddy.navigate_to(get_turf(user))
/obj/item/token/hug_token
name = "Hug Token"
desc = "A Hug Token. Just looking at it makes you feel better."
icon = 'icons/obj/items.dmi'
icon_state = "coin"
item_state = "coin"
w_class = 1.0
attack_self(var/mob/user as mob)
playsound(src.loc, "sound/items/coindrop.ogg", 100, 1)
user.visible_message("<b>[user]</b> flips the token","You flip the token")
SPAWN_DBG(1 SECOND)
user.visible_message("It came up Hugs.")
#undef GUARDBOT_DOCK_RESET_DELAY
#undef GUARDBOT_LOWPOWER_ALERT_LEVEL
#undef GUARDBOT_LOWPOWER_IDLE_LEVEL
#undef GUARDBOT_POWER_DRAW
#undef GUARDBOT_RADIO_RANGE