mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-12 07:33:34 +01:00
Bot port from /tg/
This commit is contained in:
@@ -66,6 +66,8 @@
|
||||
continue
|
||||
if(!alarm.remote_control)
|
||||
continue
|
||||
if(alarm.hidden)
|
||||
continue
|
||||
var/turf/pos = get_turf(alarm)
|
||||
var/list/alarm_data=list()
|
||||
alarm_data["ID"]="\ref[alarm]"
|
||||
|
||||
@@ -21,6 +21,7 @@ datum/controller/game_controller
|
||||
var/mobs_cost = 0
|
||||
var/diseases_cost = 0
|
||||
var/machines_cost = 0
|
||||
var/aibots_cost = 0
|
||||
var/objects_cost = 0
|
||||
var/networks_cost = 0
|
||||
var/powernets_cost = 0
|
||||
@@ -188,6 +189,13 @@ datum/controller/game_controller/proc/process()
|
||||
processMachines()
|
||||
machines_cost = (world.timeofday - timer) / 10
|
||||
|
||||
sleep(breather_ticks)
|
||||
|
||||
//BOTS
|
||||
timer = world.timeofday
|
||||
process_bots()
|
||||
aibots_cost = (world.timeofday - timer) / 10
|
||||
|
||||
sleep(breather_ticks)
|
||||
|
||||
//OBJECTS
|
||||
@@ -244,7 +252,7 @@ datum/controller/game_controller/proc/process()
|
||||
gc_cost = (world.timeofday - timer) / 10
|
||||
|
||||
//TIMING
|
||||
total_cost = air_cost + sun_cost + mobs_cost + diseases_cost + machines_cost + objects_cost + networks_cost + powernets_cost + nano_cost + events_cost + puddles_cost + ticker_cost + gc_cost
|
||||
total_cost = air_cost + sun_cost + mobs_cost + diseases_cost + machines_cost + aibots_cost + objects_cost + networks_cost + powernets_cost + nano_cost + events_cost + puddles_cost + ticker_cost + gc_cost
|
||||
|
||||
var/end_time = world.timeofday
|
||||
if(end_time < start_time) //why not just use world.time instead?
|
||||
@@ -278,6 +286,15 @@ datum/controller/game_controller/proc/process()
|
||||
|
||||
Machinery.removeAtProcessing()
|
||||
|
||||
/datum/controller/game_controller/proc/process_bots()
|
||||
for(var/obj/machinery/bot/Bot in aibots)
|
||||
if(!Bot.gc_destroyed)
|
||||
last_thing_processed = Bot.type
|
||||
spawn(0)
|
||||
Bot.bot_process()
|
||||
continue
|
||||
aibots -= Bot
|
||||
|
||||
/datum/controller/game_controller/proc/processObjects()
|
||||
for (var/obj/Object in processing_objects)
|
||||
if (Object && Object.loc)
|
||||
|
||||
@@ -172,7 +172,7 @@ proc/AStar(start,end,adjacent,dist,maxnodes,maxnodedepth = 30,mintargetdist,minn
|
||||
//then run the main loop
|
||||
while(!open.IsEmpty() && !path)
|
||||
{
|
||||
//get the lower f node on the open list
|
||||
//get the lower f node on the open list
|
||||
cur = open.Dequeue() //get the lower f turf in the open list
|
||||
closed.Add(cur.source) //and tell we've processed it
|
||||
|
||||
@@ -236,3 +236,10 @@ proc/AStar(start,end,adjacent,dist,maxnodes,maxnodedepth = 30,mintargetdist,minn
|
||||
path.Swap(i,path.len-i+1)
|
||||
|
||||
return path
|
||||
|
||||
//wrapper that returns an empty list if A* failed to find a path
|
||||
/proc/get_path_to(var/start,var/end,var/adjacent,var/dist,var/maxnodes,var/maxnodedepth = 30,var/mintargetdist,var/minnodedist,id=null, var/turf/exclude=null)
|
||||
var/list/path = AStar(start, end, adjacent, dist, maxnodes, maxnodedepth, mintargetdist, minnodedist,id, exclude)
|
||||
if(!path)
|
||||
path = list()
|
||||
return path
|
||||
|
||||
@@ -61,6 +61,33 @@
|
||||
|
||||
*/
|
||||
|
||||
/* the radio controller is a confusing piece of shit and didnt work
|
||||
so i made radios not use the radio controller.
|
||||
*/
|
||||
var/list/all_radios = list()
|
||||
|
||||
/proc/add_radio(var/obj/item/radio, freq)
|
||||
if(!freq || !radio)
|
||||
return
|
||||
if(!all_radios["[freq]"])
|
||||
all_radios["[freq]"] = list(radio)
|
||||
return freq
|
||||
|
||||
all_radios["[freq]"] |= radio
|
||||
return freq
|
||||
|
||||
/proc/remove_radio(var/obj/item/radio, freq)
|
||||
if(!freq || !radio)
|
||||
return
|
||||
if(!all_radios["[freq]"])
|
||||
return
|
||||
|
||||
all_radios["[freq]"] -= radio
|
||||
|
||||
/proc/remove_radio_all(var/obj/item/radio)
|
||||
for(var/freq in all_radios)
|
||||
all_radios["[freq]"] -= radio
|
||||
|
||||
/*
|
||||
Frequency range: 1200 to 1600
|
||||
Radiochat range: 1441 to 1489 (most devices refuse to be tune to other frequency, even during mapmaking)
|
||||
@@ -108,7 +135,8 @@ var/list/radiochannels = list(
|
||||
"Deathsquad" = 1441,
|
||||
"Syndicate" = 1213,
|
||||
"Supply" = 1347,
|
||||
"Service" = 1349
|
||||
"Service" = 1349,
|
||||
"AI Private" = 1447
|
||||
)
|
||||
//depenging helpers
|
||||
var/list/DEPT_FREQS = list(1351, 1355, 1357, 1359, 1213, 1443, 1441, 1347, 1349)
|
||||
@@ -127,6 +155,9 @@ var/const/MED_FREQ = 1355
|
||||
var/const/SUP_FREQ = 1347
|
||||
var/const/SRV_FREQ = 1349
|
||||
|
||||
// other channels
|
||||
var/const/AIPRIV_FREQ = 1447
|
||||
|
||||
#define TRANSMISSION_WIRE 0
|
||||
#define TRANSMISSION_RADIO 1
|
||||
|
||||
@@ -140,6 +171,9 @@ var/const/RADIO_AIRLOCK = "6"
|
||||
var/const/RADIO_SECBOT = "7"
|
||||
var/const/RADIO_MULEBOT = "8"
|
||||
var/const/RADIO_MAGNETS = "9"
|
||||
var/const/RADIO_CLEANBOT = "10"
|
||||
var/const/RADIO_FLOORBOT = "11"
|
||||
var/const/RADIO_MEDBOT = "12"
|
||||
|
||||
var/global/datum/controller/radio/radio_controller
|
||||
|
||||
@@ -150,7 +184,7 @@ var/global/datum/controller/radio/radio_controller
|
||||
datum/controller/radio
|
||||
var/list/datum/radio_frequency/frequencies = list()
|
||||
|
||||
proc/add_object(obj/device as obj, var/new_frequency as num, var/filter = null as text|null)
|
||||
proc/add_object(obj/device as obj, var/new_frequency as num, var/filter = null as text|null)
|
||||
var/f_text = num2text(new_frequency)
|
||||
var/datum/radio_frequency/frequency = frequencies[f_text]
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
var/datum/radio_frequency/radio_connection
|
||||
|
||||
var/list/TLV = list()
|
||||
|
||||
var/hidden = 0
|
||||
|
||||
/obj/machinery/alarm/server
|
||||
preset = AALARM_PRESET_SERVER
|
||||
@@ -626,6 +626,8 @@
|
||||
// Not sent from atmos console AND
|
||||
// Not silicon AND locked.
|
||||
data["locked"]=!fromAtmosConsole && (!(istype(user, /mob/living/silicon)) && locked)
|
||||
if(fromAtmosConsole && remote_control < 2)
|
||||
data["locked"] = 1
|
||||
data["rcon"]=rcon_setting
|
||||
data["target_temp"] = target_temperature - T0C
|
||||
data["atmos_alarm"] = alarm_area.atmosalm
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// AI (i.e. game AI, not the AI player) controlled bots
|
||||
|
||||
/obj/machinery/bot
|
||||
icon = 'icons/obj/aibots.dmi'
|
||||
layer = MOB_LAYER
|
||||
luminosity = 3
|
||||
use_power = 0
|
||||
var/obj/item/weapon/card/id/botcard // the ID card that the bot "holds"
|
||||
var/list/prev_access = list()
|
||||
var/on = 1
|
||||
var/health = 0 //do not forget to set health for your bot!
|
||||
var/maxhealth = 0
|
||||
@@ -14,8 +14,74 @@
|
||||
var/open = 0//Maint panel
|
||||
var/locked = 1
|
||||
var/hacked = 0 //Used to differentiate between being hacked by silicons and emagged by humans.
|
||||
var/text_hack = "" //Custom text returned to a silicon upon hacking a bot.
|
||||
var/text_dehack = "" //Text shown when resetting a bots hacked status to normal.
|
||||
var/text_dehack_fail = "" //Shown when a silicon tries to reset a bot emagged with the emag item, which cannot be reset.
|
||||
var/declare_message = "" //What the bot will display to the HUD user.
|
||||
var/frustration = 0 //Used by some bots for tracking failures to reach their target.
|
||||
var/speed = 2 //The speed at which the bot moves, or the number of times it moves per process() tick.
|
||||
var/turf/ai_waypoint //The end point of a bot's path, or the target location.
|
||||
var/list/path = list() //List of turfs through which a bot 'steps' to reach the waypoint.
|
||||
var/pathset = 0
|
||||
var/list/ignore_list = list() //List of unreachable targets for an ignore-list enabled bot to ignore.
|
||||
var/mode = 0 //Standardizes the vars that indicate the bot is busy with its function.
|
||||
var/tries = 0 //Number of times the bot tried and failed to move.
|
||||
var/remote_disabled = 0 //If enabled, the AI cannot *Remotely* control a bot. It can still control it through cameras.
|
||||
var/mob/living/silicon/ai/calling_ai //Links a bot to the AI calling it.
|
||||
var/obj/item/device/radio/Radio //The bot's radio, for speaking to people.
|
||||
var/radio_frequency //The bot's default radio speaking freqency. Recommended to be on a department frequency.
|
||||
//var/emagged = 0 //Urist: Moving that var to the general /bot tree as it's used by most bots
|
||||
var/auto_patrol = 0// set to make bot automatically patrol
|
||||
var/turf/patrol_target // this is turf to navigate to (location of beacon)
|
||||
var/turf/summon_target // The turf of a user summoning a bot.
|
||||
var/new_destination // pending new destination (waiting for beacon response)
|
||||
var/destination // destination description tag
|
||||
var/next_destination // the next destination in the patrol route
|
||||
|
||||
var/blockcount = 0 //number of times retried a blocked path
|
||||
var/awaiting_beacon = 0 // count of pticks awaiting a beacon response
|
||||
|
||||
var/nearest_beacon // the nearest beacon's tag
|
||||
var/turf/nearest_beacon_loc // the nearest beacon's location
|
||||
|
||||
var/beacon_freq = 1445 // navigation beacon frequency
|
||||
var/control_freq = 1447 // bot control frequency
|
||||
|
||||
var/bot_filter // The radio filter the bot uses to identify itself on the network.
|
||||
|
||||
var/bot_type = 0 //The type of bot it is, for radio control.
|
||||
#define SEC_BOT 1 // Secutritrons (Beepsky) and ED-209s
|
||||
#define MULE_BOT 2 // MULEbots
|
||||
#define FLOOR_BOT 3 // Floorbots
|
||||
#define CLEAN_BOT 4 // Cleanbots
|
||||
#define MED_BOT 5 // Medibots
|
||||
|
||||
#define DEFAULT_SCAN_RANGE 7 //default view range for finding targets.
|
||||
|
||||
//Mode defines
|
||||
#define BOT_IDLE 0 // idle
|
||||
#define BOT_HUNT 1 // found target, hunting
|
||||
#define BOT_PREP_ARREST 2 // at target, preparing to arrest
|
||||
#define BOT_ARREST 3 // arresting target
|
||||
#define BOT_START_PATROL 4 // start patrol
|
||||
#define BOT_PATROL 5 // patrolling
|
||||
#define BOT_SUMMON 6 // summoned by PDA
|
||||
#define BOT_CLEANING 7 // cleaning (cleanbots)
|
||||
#define BOT_REPAIRING 8 // repairing hull breaches (floorbots)
|
||||
#define BOT_MOVING 9 // for clean/floor bots, when moving.
|
||||
#define BOT_HEALING 10 // healing people (medbots)
|
||||
#define BOT_RESPONDING 11 // responding to a call from the AI
|
||||
#define BOT_LOADING 12 // loading/unloading
|
||||
#define BOT_DELIVER 13 // moving to deliver
|
||||
#define BOT_GO_HOME 14 // returning to home
|
||||
#define BOT_BLOCKED 15 // blocked
|
||||
#define BOT_NAV 16 // computing navigation
|
||||
#define BOT_WAIT_FOR_NAV 17 // waiting for nav computation
|
||||
#define BOT_NO_ROUTE 18 // no destination beacon found (or no route)
|
||||
var/list/mode_name = list("In Pursuit","Preparing to Arrest","Arresting","Beginning Patrol","Patrolling","Summoned by PDA", \
|
||||
"Cleaning", "Repairing", "Proceeding to work site","Healing","Responding","Loading/Unloading","Navigating to Delivery Location","Navigating to Home", \
|
||||
"Waiting for clear path","Calculating navigation path","Pinging beacon network","Unable to reach destination")
|
||||
//This holds text for what the bot is mode doing, reported on the AI's bot control interface.
|
||||
|
||||
/obj/machinery/bot/proc/turn_on()
|
||||
if(stat) return 0
|
||||
@@ -26,109 +92,209 @@
|
||||
/obj/machinery/bot/proc/turn_off()
|
||||
on = 0
|
||||
SetLuminosity(0)
|
||||
bot_reset() //Resets an AI's call, should it exist.
|
||||
|
||||
/obj/machinery/bot/New()
|
||||
..()
|
||||
aibots += src //Global bot list
|
||||
botcard = new /obj/item/weapon/card/id(src)
|
||||
set_custom_texts()
|
||||
Radio = new /obj/item/device/radio(src)
|
||||
Radio.listening = 0 //Makes bot radios transmit only so no one hears things while adjacent to one.
|
||||
|
||||
|
||||
/obj/machinery/bot/proc/add_to_beacons(bot_filter) //Master filter control for bots. Must be placed in the bot's local New() to support map spawned bots.
|
||||
spawn(20)
|
||||
if(radio_controller)
|
||||
radio_controller.add_object(src, beacon_freq, RADIO_NAVBEACONS)
|
||||
if(bot_filter)
|
||||
radio_controller.add_object(src, control_freq, bot_filter)
|
||||
|
||||
/obj/machinery/bot/proc/explode()
|
||||
aibots -= src
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/bot/proc/healthcheck()
|
||||
if (src.health <= 0)
|
||||
src.explode()
|
||||
if (health <= 0)
|
||||
explode()
|
||||
|
||||
/obj/machinery/bot/proc/Emag(mob/user as mob)
|
||||
if(locked && user)
|
||||
/obj/machinery/bot/proc/Emag(mob/user as mob) //Master Emag proc. Ensure this is called in your bot before setting unique functions.
|
||||
if(locked) //First emag application unlocks the bot's interface. Apply a screwdriver to use the emag again.
|
||||
locked = 0
|
||||
emagged = 1
|
||||
user << "<span class='warning'>You bypass [src]'s controls.</span>"
|
||||
if((!locked && open) || !user) //Ion storm does not require unlocking for emagging
|
||||
if(!locked && open) //Bot panel is unlocked by ID or emag, and the panel is screwed open. Ready for emagging.
|
||||
emagged = 2
|
||||
remote_disabled = 1 //Manually emagging the bot locks out the AI built in panel.
|
||||
locked = 1 //Access denied forever!
|
||||
bot_reset()
|
||||
turn_on() //The bot automatically turns on when emagged, unless recently hit with EMP.
|
||||
else //Bot is unlocked, but the maint panel has not been opened with a screwdriver yet.
|
||||
user << "<span class='notice'>You need to open maintenance panel first.</span>"
|
||||
|
||||
/obj/machinery/bot/examine()
|
||||
set src in view()
|
||||
/obj/machinery/bot/examine(mob/user)
|
||||
..()
|
||||
if (src.health < maxhealth)
|
||||
if (src.health > maxhealth/3)
|
||||
usr << "<span class='warning'>[src]'s parts look loose.</span>"
|
||||
if (health < maxhealth)
|
||||
if (health > maxhealth/3)
|
||||
user << "<span class='danger'>[src]'s parts look loose.</span>"
|
||||
else
|
||||
usr << "<span class='danger'>[src]'s parts look very loose!</span>"
|
||||
return
|
||||
user << "<span class='danger'>[src]'s parts look very loose.</span>"
|
||||
else
|
||||
user << "[src] is in pristine condition."
|
||||
|
||||
/obj/machinery/bot/attack_alien(var/mob/living/carbon/alien/user as mob)
|
||||
src.health -= rand(15,30)*brute_dam_coeff
|
||||
src.visible_message("\red <B>[user] has slashed [src]!</B>")
|
||||
playsound(src.loc, 'sound/weapons/slice.ogg', 25, 1, -1)
|
||||
health -= rand(15,30)*brute_dam_coeff
|
||||
visible_message("<span class='userdanger'>[user] has slashed [src]!</span>")
|
||||
playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
|
||||
if(prob(10))
|
||||
new /obj/effect/decal/cleanable/oil(src.loc)
|
||||
new /obj/effect/decal/cleanable/oil(loc)
|
||||
healthcheck()
|
||||
|
||||
|
||||
/obj/machinery/bot/attack_animal(var/mob/living/simple_animal/M as mob)
|
||||
if(M.melee_damage_upper == 0) return
|
||||
src.health -= M.melee_damage_upper
|
||||
src.visible_message("\red <B>[M] has [M.attacktext] [src]!</B>")
|
||||
add_logs(M, src, "attacked")
|
||||
if(M.melee_damage_upper == 0)
|
||||
return
|
||||
health -= M.melee_damage_upper
|
||||
visible_message("<span class='userdanger'>[M] has [M.attacktext] [src]!</span>")
|
||||
add_logs(M, src, "attacked", admin=0)
|
||||
if(prob(10))
|
||||
new /obj/effect/decal/cleanable/oil(src.loc)
|
||||
new /obj/effect/decal/cleanable/oil(loc)
|
||||
healthcheck()
|
||||
|
||||
/obj/machinery/bot/Topic(href, href_list) //Master Topic to handle common functions.
|
||||
. = ..()
|
||||
if (.)
|
||||
return
|
||||
if(topic_denied(usr))
|
||||
usr << "<span class='warning'>[src]'s interface is not responding!</span>"
|
||||
href_list = list()
|
||||
return
|
||||
|
||||
usr.set_machine(src)
|
||||
add_fingerprint(usr)
|
||||
if((href_list["power"]) && (allowed(usr) || !locked))
|
||||
if (on)
|
||||
turn_off()
|
||||
else
|
||||
turn_on()
|
||||
|
||||
switch(href_list["operation"])
|
||||
if("patrol")
|
||||
auto_patrol = !auto_patrol
|
||||
mode = BOT_IDLE
|
||||
if("remote")
|
||||
remote_disabled = !remote_disabled
|
||||
if("hack")
|
||||
if(emagged != 2)
|
||||
emagged = 2
|
||||
hacked = 1
|
||||
locked = 1
|
||||
usr << "<span class='warning'>[text_hack]</span>"
|
||||
bot_reset()
|
||||
else if(!hacked)
|
||||
usr << "<span class='userdanger'>[text_dehack_fail]</span>"
|
||||
else
|
||||
emagged = 0
|
||||
hacked = 0
|
||||
usr << "<span class='notice'>[text_dehack]</span>"
|
||||
bot_reset()
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/bot/proc/topic_denied(mob/user) //Access check proc for bot topics! Remember to place in a bot's individual Topic if desired.
|
||||
// 0 for access, 1 for denied.
|
||||
if(emagged == 2) //An emagged bot cannot be controlled by humans, silicons can if one hacked it.
|
||||
if(!hacked) //Manually emagged by a human - access denied to all.
|
||||
return 1
|
||||
else if(!issilicon(user)) //Bot is hacked, so only silicons are allowed access.
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
|
||||
/obj/machinery/bot/proc/bot_process() //Master process which handles code common across most bots.
|
||||
|
||||
set background = BACKGROUND_ENABLED
|
||||
|
||||
if(!on)
|
||||
return
|
||||
|
||||
switch(mode) //High-priority overrides are processed first. Bots can do nothing else while under direct command.
|
||||
if(BOT_RESPONDING) //Called by the AI.
|
||||
call_mode()
|
||||
return
|
||||
if(BOT_SUMMON) //Called by PDA
|
||||
bot_summon()
|
||||
return
|
||||
return 1 //Successful completion. Used to prevent child process() continuing if this one is ended early.
|
||||
|
||||
|
||||
/obj/machinery/bot/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
if(istype(W, /obj/item/weapon/screwdriver))
|
||||
if(!locked)
|
||||
open = !open
|
||||
user << "<span class='notice'>Maintenance panel is now [src.open ? "opened" : "closed"].</span>"
|
||||
else if(istype(W, /obj/item/weapon/weldingtool))
|
||||
if(health < maxhealth)
|
||||
if(open)
|
||||
health = min(maxhealth, health+10)
|
||||
user.visible_message("\red [user] repairs [src]!","\blue You repair [src]!")
|
||||
else
|
||||
user << "<span class='notice'>Unable to repair with the maintenance panel closed.</span>"
|
||||
user << "<span class='notice'>Maintenance panel is now [open ? "opened" : "closed"].</span>"
|
||||
else
|
||||
user << "<span class='notice'>[src] does not need a repair.</span>"
|
||||
user << "<span class='warning'>Maintenance panel is locked.</span>"
|
||||
else if (istype(W, /obj/item/weapon/card/emag) && emagged < 2)
|
||||
Emag(user)
|
||||
else
|
||||
if(hasvar(W,"force") && hasvar(W,"damtype"))
|
||||
switch(W.damtype)
|
||||
if("fire")
|
||||
src.health -= W.force * fire_dam_coeff
|
||||
if("brute")
|
||||
src.health -= W.force * brute_dam_coeff
|
||||
..()
|
||||
healthcheck()
|
||||
if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != "harm")
|
||||
if(health >= maxhealth)
|
||||
user << "<span class='warning'>[src] does not need a repair.</span>"
|
||||
return
|
||||
if(!open)
|
||||
user << "<span class='warning'>Unable to repair with the maintenance panel closed.</span>"
|
||||
return
|
||||
var/obj/item/weapon/weldingtool/WT = W
|
||||
if(WT.remove_fuel(0, user))
|
||||
health = min(maxhealth, health+10)
|
||||
user.visible_message("<span class='notice'>[user] repairs [src]!</span>","<span class='notice'>You repair [src]!</span>")
|
||||
else
|
||||
user << "<span class='warning'>The welder must be on for this task.</span>"
|
||||
else
|
||||
..()
|
||||
if(W.force) //if force is non-zero
|
||||
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
|
||||
s.set_up(5, 1, src)
|
||||
switch(W.damtype)
|
||||
if("fire")
|
||||
health -= W.force * fire_dam_coeff
|
||||
s.start()
|
||||
if("brute")
|
||||
health -= W.force * brute_dam_coeff
|
||||
s.start()
|
||||
..()
|
||||
healthcheck()
|
||||
|
||||
|
||||
/obj/machinery/bot/bullet_act(var/obj/item/projectile/Proj)
|
||||
health -= Proj.damage
|
||||
..()
|
||||
healthcheck()
|
||||
|
||||
/obj/machinery/bot/meteorhit()
|
||||
src.explode()
|
||||
if((Proj.damage_type == BRUTE || Proj.damage_type == BURN))
|
||||
health -= Proj.damage
|
||||
if(prob(75) && Proj.damage > 0)
|
||||
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
|
||||
s.set_up(5, 1, src)
|
||||
s.start()
|
||||
..()
|
||||
healthcheck()
|
||||
return
|
||||
|
||||
/obj/machinery/bot/blob_act()
|
||||
src.health -= rand(20,40)*fire_dam_coeff
|
||||
health -= rand(20,40)*fire_dam_coeff
|
||||
healthcheck()
|
||||
return
|
||||
|
||||
/obj/machinery/bot/ex_act(severity)
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
src.explode()
|
||||
explode()
|
||||
return
|
||||
if(2.0)
|
||||
src.health -= rand(5,10)*fire_dam_coeff
|
||||
src.health -= rand(10,20)*brute_dam_coeff
|
||||
health -= rand(5,10)*fire_dam_coeff
|
||||
health -= rand(10,20)*brute_dam_coeff
|
||||
healthcheck()
|
||||
return
|
||||
if(3.0)
|
||||
if (prob(50))
|
||||
src.health -= rand(1,5)*fire_dam_coeff
|
||||
src.health -= rand(1,5)*brute_dam_coeff
|
||||
health -= rand(1,5)*fire_dam_coeff
|
||||
health -= rand(1,5)*brute_dam_coeff
|
||||
healthcheck()
|
||||
return
|
||||
return
|
||||
@@ -136,7 +302,7 @@
|
||||
/obj/machinery/bot/emp_act(severity)
|
||||
var/was_on = on
|
||||
stat |= EMPED
|
||||
var/obj/effect/overlay/pulse2 = new/obj/effect/overlay ( src.loc )
|
||||
var/obj/effect/overlay/pulse2 = new/obj/effect/overlay ( loc )
|
||||
pulse2.icon = 'icons/effects/effects.dmi'
|
||||
pulse2.icon_state = "empdisable"
|
||||
pulse2.name = "emp sparks"
|
||||
@@ -152,15 +318,471 @@
|
||||
if (was_on)
|
||||
turn_on()
|
||||
|
||||
/obj/machinery/bot/proc/hack(mob/user)
|
||||
var/hack
|
||||
if(issilicon(user)) //Allows silicons to toggle the emag status of a bot.
|
||||
hack += "[emagged == 2 ? "Software compromised! Unit may exhibit dangerous or erratic behavior." : "Unit operating normally. Release safety lock?"]<BR>"
|
||||
hack += "Harm Prevention Safety System: <A href='?src=\ref[src];operation=hack'>[emagged ? "<span class='bad'>DANGER</span>" : "Engaged"]</A><BR>"
|
||||
else if(!locked) //Humans with access can use this option to hide a bot from the AI's remote control panel and PDA control.
|
||||
hack += "Remote network control radio: <A href='?src=\ref[src];operation=remote'>[remote_disabled ? "Disconnected" : "Connected"]</A><BR><BR>"
|
||||
return hack
|
||||
|
||||
/obj/machinery/bot/proc/set_custom_texts() //Superclass for setting hack texts. Appears only if a set is not given to a bot locally.
|
||||
text_hack = "You hack [name]."
|
||||
text_dehack = "You reset [name]."
|
||||
text_dehack_fail = "You fail to reset [name]."
|
||||
|
||||
/obj/machinery/bot/attack_ai(mob/user as mob)
|
||||
src.add_hiddenprint(user)
|
||||
src.attack_hand(user)
|
||||
attack_hand(user)
|
||||
|
||||
/obj/machinery/bot/proc/speak(var/message)
|
||||
if((!src.on) || (!message))
|
||||
/obj/machinery/bot/proc/speak(var/message, freq) //Pass a message to have the bot say() it. Pass a frequency to say it on the radio.
|
||||
if((!on) || (!message))
|
||||
return
|
||||
for(var/mob/O in hearers(src, null))
|
||||
O.show_message("<span class='game say'><span class='name'>[src]</span> beeps, \"[message]\"</span>",2)
|
||||
if(freq)
|
||||
return
|
||||
// Commenting out the radio code until our say code's compatible with /tg/'s
|
||||
/* Radio.set_frequency(radio_frequency)
|
||||
Radio.talk_into_atom(src, message, radio_frequency) */
|
||||
else
|
||||
for(var/mob/O in hearers(src, null))
|
||||
O.show_message("<span class='game say'><span class='name'>[src]</span> beeps, \"[message]\"</span>",2)
|
||||
return
|
||||
|
||||
//Generalized behavior code, override where needed!
|
||||
|
||||
/*
|
||||
scan() will search for a given type (such as turfs, human mobs, or objects) in the bot's view range, and return a single result.
|
||||
Arguments: The object type to be searched (such as "/mob/living/carbon/human"), the old scan result to be ignored, if one exists,
|
||||
and the view range, which defaults to 7 (full screen) if an override is not passed.
|
||||
If the bot maintains an ignore list, it is also checked here.
|
||||
|
||||
Example usage: patient = scan(/mob/living/carbon/human, oldpatient, 1)
|
||||
The proc would return a human next to the bot to be set to the patient var.
|
||||
Pass the desired type path itself, declaring a temporary var beforehand is not required.
|
||||
*/
|
||||
obj/machinery/bot/proc/scan(var/scan_type, var/old_target, var/scan_range)
|
||||
var/final_result
|
||||
for (var/scan in view (scan_range ? scan_range : DEFAULT_SCAN_RANGE, src) ) //Search for something in range!
|
||||
if(!istype(scan, scan_type)) //Check that the thing we found is the type we want!
|
||||
continue //If not, keep searching!
|
||||
if( !(scan in ignore_list) && !(scan in old_target) ) //Filter for blacklisted elements, usually unreachable or previously processed oness
|
||||
var/scan_result = process_scan(scan) //Some bots may require additional processing when a result is selected.
|
||||
if( scan_result )
|
||||
final_result = scan_result
|
||||
else
|
||||
continue //The current element failed assessment, move on to the next.
|
||||
return final_result
|
||||
|
||||
//When the scan finds a target, run bot specific processing to select it for the next step. Empty by default.
|
||||
obj/machinery/bot/proc/process_scan(var/scan_target)
|
||||
return scan_target
|
||||
|
||||
|
||||
/obj/machinery/bot/proc/add_to_ignore(var/subject)
|
||||
if(ignore_list.len < 50) //This will help keep track of them, so the bot is always trying to reach a blocked spot.
|
||||
ignore_list |= subject
|
||||
else if (ignore_list.len >= subject) //If the list is full, insert newest, delete oldest.
|
||||
ignore_list -= ignore_list[1]
|
||||
ignore_list |= subject
|
||||
|
||||
/*
|
||||
Movement proc for stepping a bot through a path generated through A-star.
|
||||
Pass a positive integer as an argument to override a bot's default speed.
|
||||
*/
|
||||
obj/machinery/bot/proc/bot_move(var/dest, var/move_speed)
|
||||
if(!dest || !path || path.len == 0) //A-star failed or a path/destination was not set.
|
||||
path = list()
|
||||
return 0
|
||||
if(get_turf(src) == get_turf(dest)) //We have arrived, no need to move again.
|
||||
return 1
|
||||
var/success
|
||||
var/step_count = move_speed ? move_speed : speed //If a value is passed into move_speed, use that instead of the default speed var.
|
||||
if(step_count >= 1 && tries < 4)
|
||||
for(step_count, step_count >= 1,step_count--)
|
||||
success = bot_step(dest)
|
||||
if (success)
|
||||
tries = 0
|
||||
else
|
||||
tries++
|
||||
break
|
||||
sleep(4)
|
||||
else
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
obj/machinery/bot/proc/bot_step(var/dest)
|
||||
if(path && path.len > 1)
|
||||
step_to(src, path[1])
|
||||
if(get_turf(src) == path[1]) //Successful move
|
||||
path -= path[1]
|
||||
else
|
||||
return 0
|
||||
else if(path.len == 1)
|
||||
step_to(src, dest)
|
||||
path = list()
|
||||
return 1
|
||||
|
||||
|
||||
/obj/machinery/bot/proc/check_bot_access()
|
||||
if(mode != BOT_SUMMON && mode != BOT_RESPONDING)
|
||||
botcard.access = prev_access
|
||||
|
||||
/obj/machinery/bot/proc/call_bot(var/caller, var/turf/waypoint)
|
||||
bot_reset() //Reset a bot before setting it to call mode.
|
||||
var/area/end_area = get_area(waypoint)
|
||||
|
||||
//For giving the bot temporary all-access.
|
||||
var/obj/item/weapon/card/id/all_access = new /obj/item/weapon/card/id
|
||||
var/datum/job/captain/All = new/datum/job/captain
|
||||
all_access.access = All.get_access()
|
||||
|
||||
path = AStar(src, waypoint, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 200, id=all_access)
|
||||
calling_ai = caller //Link the AI to the bot!
|
||||
ai_waypoint = waypoint
|
||||
|
||||
if(path && path.len) //Ensures that a valid path is calculated!
|
||||
if(!on)
|
||||
turn_on() //Saves the AI the hassle of having to activate a bot manually.
|
||||
botcard = all_access //Give the bot all-access while under the AI's command.
|
||||
calling_ai << "<span class='notice'>\icon[src] [name] called to [end_area.name]. [path.len-1] meters to destination.</span>"
|
||||
pathset = 1
|
||||
mode = BOT_RESPONDING
|
||||
tries = 0
|
||||
else
|
||||
calling_ai << "<span class='danger'>Failed to calculate a valid route. Ensure destination is clear of obstructions and within range.</span>"
|
||||
calling_ai = null
|
||||
path = list()
|
||||
|
||||
/obj/machinery/bot/proc/call_mode() //Handles preparing a bot for a call, as well as calling the move proc.
|
||||
//Handles the bot's movement during a call.
|
||||
var/success = bot_move(ai_waypoint, 3)
|
||||
if (!success)
|
||||
if(calling_ai)
|
||||
calling_ai << "\icon[src] [get_turf(src) == ai_waypoint ? "<span class='notice'>[src] successfully arrived to waypoint.</span>" : "<span class='danger'>[src] failed to reach waypoint.</span>"]"
|
||||
calling_ai = null
|
||||
bot_reset()
|
||||
|
||||
obj/machinery/bot/proc/bot_reset()
|
||||
if(calling_ai) //Simple notification to the AI if it called a bot. It will not know the cause or identity of the bot.
|
||||
calling_ai << "<span class='danger'>Call command to a bot has been reset.</span>"
|
||||
calling_ai = null
|
||||
path = list()
|
||||
summon_target = null
|
||||
pathset = 0
|
||||
botcard.access = prev_access
|
||||
tries = 0
|
||||
mode = BOT_IDLE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//Patrol and summon code!
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
/obj/machinery/bot/proc/bot_patrol()
|
||||
patrol_step()
|
||||
spawn(5)
|
||||
if(mode == BOT_PATROL)
|
||||
patrol_step()
|
||||
return
|
||||
|
||||
obj/machinery/bot/proc/start_patrol()
|
||||
|
||||
if(tries >= 4) //Bot is trapped, so stop trying to patrol.
|
||||
auto_patrol = 0
|
||||
tries = 0
|
||||
speak("Unable to start patrol.")
|
||||
|
||||
return
|
||||
|
||||
if(!auto_patrol) //A bot not set to patrol should not be patrolling.
|
||||
mode = BOT_IDLE
|
||||
return
|
||||
|
||||
if(patrol_target) // has patrol target
|
||||
spawn(0)
|
||||
calc_path() // Find a route to it
|
||||
if(path.len == 0)
|
||||
patrol_target = 0
|
||||
return
|
||||
mode = BOT_PATROL
|
||||
else // no patrol target, so need a new one
|
||||
find_patrol_target()
|
||||
speak("Engaging patrol mode.")
|
||||
tries++
|
||||
return
|
||||
|
||||
// perform a single patrol step
|
||||
|
||||
/obj/machinery/bot/proc/patrol_step()
|
||||
|
||||
if(loc == patrol_target) // reached target
|
||||
|
||||
at_patrol_target()
|
||||
return
|
||||
|
||||
else if(path.len > 0 && patrol_target) // valid path
|
||||
var/turf/next = path[1]
|
||||
if(next == loc)
|
||||
path -= next
|
||||
return
|
||||
|
||||
|
||||
var/moved = bot_move(patrol_target)//step_towards(src, next) // attempt to move
|
||||
if(moved) // successful move
|
||||
blockcount = 0
|
||||
|
||||
else // failed to move
|
||||
blockcount++
|
||||
|
||||
if(blockcount > 5) // attempt 5 times before recomputing
|
||||
// find new path excluding blocked turf
|
||||
|
||||
spawn(2)
|
||||
calc_path(next)
|
||||
if(path.len == 0)
|
||||
find_patrol_target()
|
||||
else
|
||||
blockcount = 0
|
||||
tries = 0
|
||||
|
||||
return
|
||||
|
||||
return
|
||||
|
||||
else // no path, so calculate new one
|
||||
mode = BOT_START_PATROL
|
||||
|
||||
return
|
||||
|
||||
// finds a new patrol target
|
||||
/obj/machinery/bot/proc/find_patrol_target()
|
||||
send_status()
|
||||
if(awaiting_beacon) // awaiting beacon response
|
||||
awaiting_beacon++
|
||||
if(awaiting_beacon > 5) // wait 5 secs for beacon response
|
||||
find_nearest_beacon() // then go to nearest instead
|
||||
return
|
||||
if(next_destination)
|
||||
set_destination(next_destination)
|
||||
else
|
||||
|
||||
find_nearest_beacon()
|
||||
return
|
||||
|
||||
|
||||
// finds the nearest beacon to self
|
||||
// signals all beacons matching the patrol code
|
||||
/obj/machinery/bot/proc/find_nearest_beacon()
|
||||
nearest_beacon = null
|
||||
new_destination = "__nearest__"
|
||||
post_signal(beacon_freq, "findbeacon", "patrol")
|
||||
awaiting_beacon = 1
|
||||
spawn(10)
|
||||
awaiting_beacon = 0
|
||||
if(nearest_beacon)
|
||||
set_destination(nearest_beacon)
|
||||
tries = 0
|
||||
else
|
||||
auto_patrol = 0
|
||||
mode = BOT_IDLE
|
||||
speak("Disengaging patrol mode.")
|
||||
send_status()
|
||||
|
||||
|
||||
/obj/machinery/bot/proc/at_patrol_target()
|
||||
|
||||
find_patrol_target()
|
||||
return
|
||||
|
||||
|
||||
// sets the current destination
|
||||
// signals all beacons matching the patrol code
|
||||
// beacons will return a signal giving their locations
|
||||
/obj/machinery/bot/proc/set_destination(var/new_dest)
|
||||
new_destination = new_dest
|
||||
post_signal(beacon_freq, "findbeacon", "patrol")
|
||||
awaiting_beacon = 1
|
||||
|
||||
|
||||
// receive a radio signal
|
||||
// used for beacon reception
|
||||
|
||||
/obj/machinery/bot/receive_signal(datum/signal/signal)
|
||||
//log_admin("DEBUG \[[// world.timeofday]\]: /obj/machinery/bot/receive_signal([signal.debug_print()])")
|
||||
if(!on)
|
||||
return
|
||||
/*
|
||||
if(!signal.data["beacon"])
|
||||
|
||||
for(var/x in signal.data)
|
||||
world << "* [x] = [signal.data[x]]"
|
||||
*/
|
||||
|
||||
var/recv = signal.data["command"]
|
||||
// process all-bot input
|
||||
|
||||
if(recv=="bot_status")
|
||||
send_status()
|
||||
|
||||
// check to see if we are the commanded bot
|
||||
if(signal.data["active"] == src)
|
||||
if(emagged == 2 || remote_disabled) //Emagged bots do not respect anyone's authority! Bots with their remote controls off cannot get commands.
|
||||
return
|
||||
// process control input
|
||||
switch(recv)
|
||||
if("stop")
|
||||
bot_reset() //HOLD IT!!
|
||||
auto_patrol = 0
|
||||
return
|
||||
|
||||
if("go")
|
||||
auto_patrol = 1
|
||||
return
|
||||
|
||||
if("summon")
|
||||
bot_reset()
|
||||
var/list/user_access = signal.data["useraccess"]
|
||||
summon_target = signal.data["target"] //Location of the user
|
||||
if(user_access.len != 0)
|
||||
botcard.access = user_access + prev_access //Adds the user's access, if any.
|
||||
mode = BOT_SUMMON
|
||||
calc_summon_path()
|
||||
speak("Responding."/*, radio_frequency*/)
|
||||
return
|
||||
|
||||
// receive response from beacon
|
||||
recv = signal.data["beacon"]
|
||||
var/valid = signal.data["patrol"]
|
||||
if(!recv || !valid)
|
||||
return
|
||||
if(recv == new_destination) // if the recvd beacon location matches the set destination
|
||||
// the we will navigate there
|
||||
destination = new_destination
|
||||
patrol_target = signal.source.loc
|
||||
next_destination = signal.data["next_patrol"]
|
||||
awaiting_beacon = 0
|
||||
|
||||
// if looking for nearest beacon
|
||||
else if(new_destination == "__nearest__")
|
||||
var/dist = get_dist(src,signal.source.loc)
|
||||
if(nearest_beacon)
|
||||
// note we ignore the beacon we are located at
|
||||
if(dist>1 && dist<get_dist(src,nearest_beacon_loc))
|
||||
nearest_beacon = recv
|
||||
nearest_beacon_loc = signal.source.loc
|
||||
return
|
||||
else
|
||||
return
|
||||
else if(dist > 1)
|
||||
nearest_beacon = recv
|
||||
nearest_beacon_loc = signal.source.loc
|
||||
return
|
||||
|
||||
|
||||
// send a radio signal with a single data key/value pair
|
||||
/obj/machinery/bot/proc/post_signal(var/freq, var/key, var/value)
|
||||
post_signal_multiple(freq, list("[key]" = value) )
|
||||
|
||||
// send a radio signal with multiple data key/values
|
||||
/obj/machinery/bot/proc/post_signal_multiple(var/freq, var/list/keyval)
|
||||
if(!z || z != 1) //Bot control will only work on station.
|
||||
return
|
||||
var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
|
||||
if(!frequency) return
|
||||
|
||||
var/datum/signal/signal = new()
|
||||
signal.source = src
|
||||
signal.transmission_method = 1
|
||||
// for(var/key in keyval)
|
||||
// signal.data[key] = keyval[key]
|
||||
signal.data = keyval
|
||||
// world << "sent [key],[keyval[key]] on [freq]"
|
||||
if(signal.data["findbeacon"])
|
||||
frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
|
||||
else if(signal.data["type"] == bot_type)
|
||||
frequency.post_signal(src, signal, filter = bot_filter)
|
||||
else
|
||||
frequency.post_signal(src, signal)
|
||||
|
||||
// signals bot status etc. to controller
|
||||
/obj/machinery/bot/proc/send_status()
|
||||
if(remote_disabled || emagged == 2)
|
||||
return
|
||||
var/list/kv = list(
|
||||
"type" = bot_type,
|
||||
"name" = name,
|
||||
"loca" = get_area(src), // area
|
||||
"mode" = mode
|
||||
)
|
||||
post_signal_multiple(control_freq, kv)
|
||||
|
||||
|
||||
obj/machinery/bot/proc/bot_summon()
|
||||
// summoned to PDA
|
||||
summon_step()
|
||||
return
|
||||
|
||||
// calculates a path to the current destination
|
||||
// given an optional turf to avoid
|
||||
/obj/machinery/bot/proc/calc_path(var/turf/avoid)
|
||||
check_bot_access()
|
||||
path = AStar(loc, patrol_target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 120, id=botcard, exclude=avoid)
|
||||
if(!path)
|
||||
path = list()
|
||||
|
||||
/obj/machinery/bot/proc/calc_summon_path(var/turf/avoid)
|
||||
check_bot_access()
|
||||
path = AStar(loc, summon_target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 150, id=botcard, exclude=avoid)
|
||||
if(!path || tries >= 5) //Cannot reach target. Give up and announce the issue.
|
||||
speak("Summon command failed, destination unreachable."/*,radio_frequency*/)
|
||||
bot_reset()
|
||||
|
||||
/obj/machinery/bot/proc/summon_step()
|
||||
|
||||
if(loc == summon_target) // Arrived to summon location.
|
||||
bot_reset()
|
||||
return
|
||||
|
||||
else if(path.len > 0 && summon_target) //Proper path acquired!
|
||||
var/turf/next = path[1]
|
||||
if(next == loc)
|
||||
path -= next
|
||||
return
|
||||
|
||||
var/moved = bot_move(summon_target, 3) // Move attempt
|
||||
if(moved)
|
||||
blockcount = 0
|
||||
|
||||
else // failed to move
|
||||
blockcount++
|
||||
|
||||
if(blockcount > 5) // attempt 5 times before recomputing
|
||||
// find new path excluding blocked turf
|
||||
spawn(2)
|
||||
calc_summon_path(next)
|
||||
tries++
|
||||
return
|
||||
|
||||
return
|
||||
|
||||
else // no path, so calculate new one
|
||||
calc_summon_path()
|
||||
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/bot/Bump(M as mob|obj) //Leave no door unopened!
|
||||
if((istype(M, /obj/machinery/door/airlock) || istype(M, /obj/machinery/door/window)) && (!isnull(botcard)))
|
||||
var/obj/machinery/door/D = M
|
||||
if(D.check_access(botcard))
|
||||
D.open()
|
||||
frustration = 0
|
||||
else if((istype(M, /mob/living/)) && (!anchored))
|
||||
var/mob/living/Mb = M
|
||||
loc = Mb.loc
|
||||
frustration = 0
|
||||
return
|
||||
@@ -5,17 +5,16 @@
|
||||
icon = 'icons/obj/aibots.dmi'
|
||||
icon_state = "bucket_proxy"
|
||||
force = 3.0
|
||||
throwforce = 10.0
|
||||
throwforce = 5.0
|
||||
throw_speed = 2
|
||||
throw_range = 5
|
||||
w_class = 3.0
|
||||
flags = TABLEPASS
|
||||
var/created_name = "Cleanbot"
|
||||
|
||||
|
||||
//Cleanbot
|
||||
/obj/machinery/bot/cleanbot
|
||||
name = "Cleanbot"
|
||||
name = "\improper Cleanbot"
|
||||
desc = "A little cleaning robot, he looks so excited!"
|
||||
icon = 'icons/obj/aibots.dmi'
|
||||
icon_state = "cleanbot0"
|
||||
@@ -25,55 +24,57 @@
|
||||
//weight = 1.0E7
|
||||
health = 25
|
||||
maxhealth = 25
|
||||
var/cleaning = 0
|
||||
var/screwloose = 0
|
||||
var/oddbutton = 0
|
||||
var/blood = 1
|
||||
var/list/target_types = list()
|
||||
var/obj/effect/decal/cleanable/target
|
||||
var/obj/effect/decal/cleanable/oldtarget
|
||||
var/max_targets = 50 //Maximum number of targets a cleanbot can ignore.
|
||||
var/oldloc = null
|
||||
req_access = list(access_janitor, access_robotics)
|
||||
var/path[] = new()
|
||||
var/patrol_path[] = null
|
||||
var/beacon_freq = 1445 // navigation beacon frequency
|
||||
req_one_access = list(access_janitor, access_robotics)
|
||||
// var/patrol_path[] = null
|
||||
// var/beacon_freq = 1445 // navigation beacon frequency
|
||||
var/closest_dist
|
||||
var/closest_loc
|
||||
var/failed_steps
|
||||
var/should_patrol
|
||||
var/next_dest
|
||||
var/next_dest_loc
|
||||
radio_frequency = SRV_FREQ //Service
|
||||
bot_type = CLEAN_BOT
|
||||
bot_filter = RADIO_CLEANBOT
|
||||
|
||||
/obj/machinery/bot/cleanbot/New()
|
||||
..()
|
||||
src.get_targets()
|
||||
src.icon_state = "cleanbot[src.on]"
|
||||
get_targets()
|
||||
icon_state = "cleanbot[on]"
|
||||
|
||||
should_patrol = 1
|
||||
|
||||
src.botcard = new /obj/item/weapon/card/id(src)
|
||||
var/datum/job/janitor/J = new/datum/job/janitor
|
||||
src.botcard.access = J.get_access()
|
||||
|
||||
if(radio_controller)
|
||||
radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
|
||||
botcard.access = J.get_access()
|
||||
prev_access = botcard.access
|
||||
|
||||
spawn(5)
|
||||
add_to_beacons(bot_filter)
|
||||
|
||||
/obj/machinery/bot/cleanbot/turn_on()
|
||||
. = ..()
|
||||
src.icon_state = "cleanbot[src.on]"
|
||||
src.updateUsrDialog()
|
||||
..()
|
||||
icon_state = "cleanbot[on]"
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/bot/cleanbot/turn_off()
|
||||
..()
|
||||
if(!isnull(src.target))
|
||||
target.targeted_by = null
|
||||
src.target = null
|
||||
src.oldtarget = null
|
||||
src.oldloc = null
|
||||
src.icon_state = "cleanbot[src.on]"
|
||||
src.path = new()
|
||||
src.updateUsrDialog()
|
||||
icon_state = "cleanbot[on]"
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/bot/cleanbot/bot_reset()
|
||||
..()
|
||||
ignore_list = list() //Allows the bot to clean targets it previously ignored due to being unreachable.
|
||||
target = null
|
||||
oldtarget = null
|
||||
oldloc = null
|
||||
|
||||
/obj/machinery/bot/cleanbot/set_custom_texts()
|
||||
text_hack = "You corrupt [name]'s cleaning software."
|
||||
text_dehack = "[name]'s software has been reset!"
|
||||
text_dehack_fail = "[name] does not seem to respond to your repair code!"
|
||||
|
||||
/obj/machinery/bot/cleanbot/attack_hand(mob/user as mob)
|
||||
. = ..()
|
||||
@@ -84,65 +85,41 @@
|
||||
|
||||
/obj/machinery/bot/cleanbot/interact(mob/user as mob)
|
||||
var/dat
|
||||
dat += hack(user)
|
||||
dat += text({"
|
||||
<TT><B>Automatic Station Cleaner v1.0</B></TT><BR><BR>
|
||||
<TT><B>Cleaner v1.1 controls</B></TT><BR><BR>
|
||||
Status: []<BR>
|
||||
Behaviour controls are [src.locked ? "locked" : "unlocked"]<BR>
|
||||
Maintenance panel is [src.open ? "opened" : "closed"]"},
|
||||
text("<A href='?src=\ref[src];operation=start'>[src.on ? "On" : "Off"]</A>"))
|
||||
if(!src.locked || issilicon(user))
|
||||
dat += text({"<BR>Cleans Blood: []<BR>"}, text("<A href='?src=\ref[src];operation=blood'>[src.blood ? "Yes" : "No"]</A>"))
|
||||
dat += text({"<BR>Patrol station: []<BR>"}, text("<A href='?src=\ref[src];operation=patrol'>[src.should_patrol ? "Yes" : "No"]</A>"))
|
||||
// dat += text({"<BR>Beacon frequency: []<BR>"}, text("<A href='?src=\ref[src];operation=freq'>[src.beacon_freq]</A>"))
|
||||
if(src.open && !src.locked)
|
||||
dat += text({"
|
||||
Odd looking screw twiddled: []<BR>
|
||||
Weird button pressed: []"},
|
||||
text("<A href='?src=\ref[src];operation=screw'>[src.screwloose ? "Yes" : "No"]</A>"),
|
||||
text("<A href='?src=\ref[src];operation=oddbutton'>[src.oddbutton ? "Yes" : "No"]</A>"))
|
||||
Behaviour controls are [locked ? "locked" : "unlocked"]<BR>
|
||||
Maintenance panel panel is [open ? "opened" : "closed"]"},
|
||||
text("<A href='?src=\ref[src];power=1'>[on ? "On" : "Off"]</A>"))
|
||||
if(!locked || issilicon(user))
|
||||
dat += text({"<BR>Cleans Blood: []<BR>"}, text("<A href='?src=\ref[src];operation=blood'>[blood ? "Yes" : "No"]</A>"))
|
||||
dat += text({"<BR>Patrol station: []<BR>"}, text("<A href='?src=\ref[src];operation=patrol'>[auto_patrol ? "Yes" : "No"]</A>"))
|
||||
|
||||
user << browse("<HEAD><TITLE>Cleaner v1.0 controls</TITLE></HEAD>[dat]", "window=autocleaner")
|
||||
onclose(user, "autocleaner")
|
||||
var/datum/browser/popup = new(user, "autoclean", "Automatic Station Cleaner v1.1")
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
return
|
||||
|
||||
/obj/machinery/bot/cleanbot/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
usr.set_machine(src)
|
||||
src.add_fingerprint(usr)
|
||||
|
||||
..()
|
||||
switch(href_list["operation"])
|
||||
if("start")
|
||||
if (src.on)
|
||||
turn_off()
|
||||
else
|
||||
turn_on()
|
||||
if("blood")
|
||||
src.blood =!src.blood
|
||||
src.get_targets()
|
||||
src.updateUsrDialog()
|
||||
if("patrol")
|
||||
src.should_patrol =!src.should_patrol
|
||||
src.patrol_path = null
|
||||
src.updateUsrDialog()
|
||||
blood =!blood
|
||||
get_targets()
|
||||
updateUsrDialog()
|
||||
if("freq")
|
||||
var/freq = text2num(input("Select frequency for navigation beacons", "Frequnecy", num2text(beacon_freq / 10))) * 10
|
||||
var/freq = text2num(input("Select frequency for navigation beacons", "Frequency", num2text(beacon_freq / 10))) * 10
|
||||
if (freq > 0)
|
||||
src.beacon_freq = freq
|
||||
src.updateUsrDialog()
|
||||
if("screw")
|
||||
src.screwloose = !src.screwloose
|
||||
usr << "<span class='notice>You twiddle the screw.</span>"
|
||||
src.updateUsrDialog()
|
||||
if("oddbutton")
|
||||
src.oddbutton = !src.oddbutton
|
||||
usr << "<span class='notice'>You press the weird button.</span>"
|
||||
src.updateUsrDialog()
|
||||
beacon_freq = freq
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/bot/cleanbot/attackby(obj/item/weapon/W, mob/user as mob)
|
||||
if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
|
||||
if(src.allowed(usr) && !open && !emagged)
|
||||
src.locked = !src.locked
|
||||
user << "<span class='notice'>You [ src.locked ? "lock" : "unlock"] the [src] behaviour controls.</span>"
|
||||
if(allowed(usr) && !open && !emagged)
|
||||
locked = !locked
|
||||
user << "<span class='notice'>You [ locked ? "lock" : "unlock"] the [src] behaviour controls.</span>"
|
||||
else
|
||||
if(emagged)
|
||||
user << "<span class='warning'>ERROR</span>"
|
||||
@@ -155,186 +132,113 @@ text("<A href='?src=\ref[src];operation=oddbutton'>[src.oddbutton ? "Yes" : "No"
|
||||
|
||||
/obj/machinery/bot/cleanbot/Emag(mob/user as mob)
|
||||
..()
|
||||
if((!locked && open) || !user)
|
||||
if(user) user << "<span class='notice'>The [src] buzzes and beeps.</span>"
|
||||
src.oddbutton = 1
|
||||
src.screwloose = 1
|
||||
if(emagged == 2)
|
||||
if(user)
|
||||
user << "<span class='danger'>[src] buzzes and beeps.</span>"
|
||||
|
||||
/obj/machinery/bot/cleanbot/process()
|
||||
//set background = 1
|
||||
/obj/machinery/bot/cleanbot/process_scan(var/obj/effect/decal/cleanable/D)
|
||||
for(var/T in target_types)
|
||||
if(istype(D, T))
|
||||
return D
|
||||
|
||||
if(!src.on)
|
||||
return
|
||||
if(src.cleaning)
|
||||
/obj/machinery/bot/cleanbot/bot_process()
|
||||
if (!..())
|
||||
return
|
||||
|
||||
if(!src.screwloose && !src.oddbutton && prob(5))
|
||||
if(mode == BOT_CLEANING)
|
||||
return
|
||||
|
||||
if(emagged == 2) //Emag functions
|
||||
if(istype(loc,/turf/simulated))
|
||||
|
||||
if(prob(10)) //Wets floors randomly
|
||||
var/turf/simulated/T = loc
|
||||
T.MakeSlippery()
|
||||
|
||||
if(prob(5)) //Spawns foam!
|
||||
visible_message("<span class='danger'>[src] whirs and bubbles violently, before releasing a plume of froth!</span>")
|
||||
new /obj/effect/effect/foam(loc)
|
||||
|
||||
else if (prob(5))
|
||||
visible_message("[src] makes an excited beeping booping sound!")
|
||||
|
||||
if(src.screwloose && prob(5))
|
||||
if(istype(loc,/turf/simulated))
|
||||
var/turf/simulated/T = src.loc
|
||||
if(T.wet < 1)
|
||||
T.wet = 1
|
||||
if(T.wet_overlay)
|
||||
T.overlays -= T.wet_overlay
|
||||
T.wet_overlay = null
|
||||
T.wet_overlay = image('icons/effects/water.dmi',T,"wet_floor")
|
||||
T.overlays += T.wet_overlay
|
||||
spawn(800)
|
||||
if (istype(T) && T.wet < 2)
|
||||
T.wet = 0
|
||||
if(T.wet_overlay)
|
||||
T.overlays -= T.wet_overlay
|
||||
T.wet_overlay = null
|
||||
if(src.oddbutton && prob(5))
|
||||
visible_message("Something flies out of [src]. He seems to be acting oddly.")
|
||||
var/obj/effect/decal/cleanable/blood/gibs/gib = new /obj/effect/decal/cleanable/blood/gibs(src.loc)
|
||||
//gib.streak(list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST))
|
||||
src.oldtarget = gib
|
||||
if(!src.target || src.target == null)
|
||||
for (var/obj/effect/decal/cleanable/D in view(7,src))
|
||||
for(var/T in src.target_types)
|
||||
if(isnull(D.targeted_by) && (D.type == T || D.parent_type == T) && D != src.oldtarget) // If the mess isn't targeted
|
||||
src.oldtarget = D // or if it is but the bot is gone.
|
||||
src.target = D // and it's stuff we clean? Clean it.
|
||||
D.targeted_by = src // Claim the mess we are targeting.
|
||||
return
|
||||
if(!target) //Search for cleanables it can see.
|
||||
target = scan(/obj/effect/decal/cleanable/, oldtarget)
|
||||
oldtarget = target
|
||||
|
||||
if(!src.target || src.target == null)
|
||||
if(src.loc != src.oldloc)
|
||||
src.oldtarget = null
|
||||
if(!target)
|
||||
if(loc != oldloc)
|
||||
oldtarget = null
|
||||
|
||||
if (!should_patrol)
|
||||
if(auto_patrol)
|
||||
if(mode == BOT_IDLE || mode == BOT_START_PATROL)
|
||||
start_patrol()
|
||||
|
||||
if(mode == BOT_PATROL)
|
||||
bot_patrol()
|
||||
|
||||
return
|
||||
|
||||
if(target)
|
||||
if(!path || path.len == 0) //No path, need a new one
|
||||
//Try to produce a path to the target, and ignore airlocks to which it has access.
|
||||
path = AStar(loc, target.loc, /turf/proc/AdjacentTurfsWithAccess, /turf/proc/Distance, 0, 30, id=botcard)
|
||||
if (!bot_move(target))
|
||||
add_to_ignore(target)
|
||||
target = null
|
||||
path = list()
|
||||
return
|
||||
mode = BOT_MOVING
|
||||
else if (!bot_move(target))
|
||||
target = null
|
||||
mode = BOT_IDLE
|
||||
return
|
||||
|
||||
if (!patrol_path || patrol_path.len < 1)
|
||||
var/datum/radio_frequency/frequency = radio_controller.return_frequency(beacon_freq)
|
||||
if(target && loc == target.loc)
|
||||
clean(target)
|
||||
path = list()
|
||||
target = null
|
||||
|
||||
if(!frequency) return
|
||||
|
||||
closest_dist = 9999
|
||||
closest_loc = null
|
||||
next_dest_loc = null
|
||||
|
||||
var/datum/signal/signal = new()
|
||||
signal.source = src
|
||||
signal.transmission_method = 1
|
||||
signal.data = list("findbeacon" = "patrol")
|
||||
frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
|
||||
spawn(5)
|
||||
if (!next_dest_loc)
|
||||
next_dest_loc = closest_loc
|
||||
if (next_dest_loc)
|
||||
src.patrol_path = AStar(src.loc, next_dest_loc, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 120, id=botcard, exclude=null)
|
||||
else
|
||||
patrol_move()
|
||||
|
||||
return
|
||||
|
||||
if(!path)
|
||||
path = new()
|
||||
if(target && path.len == 0)
|
||||
spawn(0)
|
||||
if(!src || !target) return
|
||||
src.path = AStar(src.loc, src.target.loc, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 30)
|
||||
if(!src.path)
|
||||
src.path = list()
|
||||
if(src.path.len == 0)
|
||||
src.oldtarget = src.target
|
||||
target.targeted_by = null
|
||||
src.target = null
|
||||
return
|
||||
if(src.path.len > 0 && src.target && (src.target != null))
|
||||
step_to(src, src.path[1])
|
||||
src.path -= src.path[1]
|
||||
else if(src.path.len == 1)
|
||||
step_to(src, target)
|
||||
|
||||
if(src.target && (src.target != null))
|
||||
patrol_path = null
|
||||
if(src.loc == src.target.loc)
|
||||
clean(src.target)
|
||||
src.path = new()
|
||||
src.target = null
|
||||
return
|
||||
|
||||
src.oldloc = src.loc
|
||||
|
||||
/obj/machinery/bot/cleanbot/proc/patrol_move()
|
||||
if (src.patrol_path.len <= 0)
|
||||
return
|
||||
|
||||
var/next = src.patrol_path[1]
|
||||
src.patrol_path -= next
|
||||
if (next == src.loc)
|
||||
return
|
||||
|
||||
var/moved = step_towards(src, next)
|
||||
if (!moved)
|
||||
failed_steps++
|
||||
if (failed_steps > 4)
|
||||
patrol_path = null
|
||||
next_dest = null
|
||||
failed_steps = 0
|
||||
else
|
||||
failed_steps = 0
|
||||
|
||||
/obj/machinery/bot/cleanbot/receive_signal(datum/signal/signal)
|
||||
var/recv = signal.data["beacon"]
|
||||
var/valid = signal.data["patrol"]
|
||||
if(!recv || !valid)
|
||||
return
|
||||
|
||||
var/dist = get_dist(src, signal.source.loc)
|
||||
if (dist < closest_dist && signal.source.loc != src.loc)
|
||||
closest_dist = dist
|
||||
closest_loc = signal.source.loc
|
||||
next_dest = signal.data["next_patrol"]
|
||||
|
||||
if (recv == next_dest)
|
||||
next_dest_loc = signal.source.loc
|
||||
next_dest = signal.data["next_patrol"]
|
||||
oldloc = loc
|
||||
|
||||
/obj/machinery/bot/cleanbot/proc/get_targets()
|
||||
src.target_types = new/list()
|
||||
target_types = new/list()
|
||||
|
||||
target_types += /obj/effect/decal/cleanable/oil
|
||||
target_types += /obj/effect/decal/cleanable/vomit
|
||||
target_types += /obj/effect/decal/cleanable/poop
|
||||
target_types += /obj/effect/decal/cleanable/robot_debris
|
||||
target_types += /obj/effect/decal/cleanable/crayon
|
||||
target_types += /obj/effect/decal/cleanable/liquid_fuel
|
||||
target_types += /obj/effect/decal/cleanable/mucus
|
||||
target_types += /obj/effect/decal/cleanable/molten_item
|
||||
target_types += /obj/effect/decal/cleanable/tomato_smudge
|
||||
target_types += /obj/effect/decal/cleanable/egg_smudge
|
||||
target_types += /obj/effect/decal/cleanable/pie_smudge
|
||||
target_types += /obj/effect/decal/cleanable/flour
|
||||
target_types += /obj/effect/decal/cleanable/ash
|
||||
target_types += /obj/effect/decal/cleanable/greenglow
|
||||
target_types += /obj/effect/decal/cleanable/dirt
|
||||
|
||||
|
||||
if(src.blood)
|
||||
target_types += /obj/effect/decal/cleanable/xenoblood
|
||||
if(blood)
|
||||
target_types += /obj/effect/decal/cleanable/xenoblood/
|
||||
target_types += /obj/effect/decal/cleanable/xenoblood/xgibs
|
||||
target_types += /obj/effect/decal/cleanable/blood/
|
||||
target_types += /obj/effect/decal/cleanable/blood/green
|
||||
target_types += /obj/effect/decal/cleanable/blood/tracks
|
||||
target_types += /obj/effect/decal/cleanable/blood/gibs/
|
||||
target_types += /obj/effect/decal/cleanable/dirt
|
||||
|
||||
/obj/machinery/bot/cleanbot/proc/clean(var/obj/effect/decal/cleanable/target)
|
||||
src.anchored = 1
|
||||
src.icon_state = "cleanbot-c"
|
||||
visible_message("\red [src] begins to clean up the [target]")
|
||||
src.cleaning = 1
|
||||
var/cleantime = 50
|
||||
if(istype(target,/obj/effect/decal/cleanable/dirt)) // Clean Dirt much faster
|
||||
cleantime = 10
|
||||
spawn(cleantime)
|
||||
src.cleaning = 0
|
||||
del(target)
|
||||
src.icon_state = "cleanbot[src.on]"
|
||||
src.anchored = 0
|
||||
src.target = null
|
||||
anchored = 1
|
||||
icon_state = "cleanbot-c"
|
||||
visible_message("<span class='notice'>[src] begins to clean up [target]</span>")
|
||||
mode = BOT_CLEANING
|
||||
spawn(50)
|
||||
if(mode == BOT_CLEANING)
|
||||
qdel(target)
|
||||
anchored = 0
|
||||
target = null
|
||||
mode = BOT_IDLE
|
||||
icon_state = "cleanbot[on]"
|
||||
|
||||
/obj/machinery/bot/cleanbot/explode()
|
||||
src.on = 0
|
||||
src.visible_message("\red <B>[src] blows apart!</B>", 1)
|
||||
on = 0
|
||||
visible_message("<span class='userdanger'>[src] blows apart!</span>")
|
||||
var/turf/Tsec = get_turf(src)
|
||||
|
||||
new /obj/item/weapon/reagent_containers/glass/bucket(Tsec)
|
||||
@@ -347,25 +251,25 @@ text("<A href='?src=\ref[src];operation=oddbutton'>[src.oddbutton ? "Yes" : "No"
|
||||
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
del(src)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/obj/item/weapon/bucket_sensor/attackby(var/obj/item/W, mob/user as mob)
|
||||
..()
|
||||
if(istype(W, /obj/item/robot_parts/l_arm) || istype(W, /obj/item/robot_parts/r_arm))
|
||||
user.drop_item()
|
||||
del(W)
|
||||
var/turf/T = get_turf(src.loc)
|
||||
qdel(W)
|
||||
var/turf/T = get_turf(loc)
|
||||
var/obj/machinery/bot/cleanbot/A = new /obj/machinery/bot/cleanbot(T)
|
||||
A.name = src.created_name
|
||||
A.name = created_name
|
||||
user << "<span class='notice'>You add the robot arm to the bucket and sensor assembly. Beep boop!</span>"
|
||||
user.drop_from_inventory(src)
|
||||
del(src)
|
||||
user.before_take_item(src, 1)
|
||||
qdel(src)
|
||||
|
||||
else if (istype(W, /obj/item/weapon/pen))
|
||||
var/t = copytext(stripped_input(user, "Enter new robot name", src.name, src.created_name),1,MAX_NAME_LEN)
|
||||
var/t = stripped_input(user, "Enter new robot name", name, created_name,MAX_NAME_LEN)
|
||||
if (!t)
|
||||
return
|
||||
if (!in_range(src, usr) && src.loc != usr)
|
||||
if (!in_range(src, usr) && loc != usr)
|
||||
return
|
||||
src.created_name = t
|
||||
created_name = t
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+295
-305
@@ -4,7 +4,7 @@
|
||||
|
||||
|
||||
/obj/machinery/bot/medbot
|
||||
name = "Medibot"
|
||||
name = "\improper Medibot"
|
||||
desc = "A little medical robot. He looks somewhat underwhelmed."
|
||||
icon = 'icons/obj/aibots.dmi'
|
||||
icon_state = "medibot0"
|
||||
@@ -13,30 +13,34 @@
|
||||
anchored = 0
|
||||
health = 20
|
||||
maxhealth = 20
|
||||
req_access =list(access_medical, access_robotics)
|
||||
req_one_access =list(access_medical, access_robotics)
|
||||
var/stunned = 0 //It can be stunned by tasers. Delicate circuits.
|
||||
//var/emagged = 0
|
||||
// var/emagged = 0
|
||||
var/list/botcard_access = list(access_medical)
|
||||
var/obj/item/weapon/reagent_containers/glass/reagent_glass = null //Can be set to draw from this for reagents.
|
||||
var/skin = null //Set to "tox", "ointment" or "o2" for the other two firstaid kits.
|
||||
var/frustration = 0
|
||||
var/path[] = new()
|
||||
var/mob/living/carbon/patient = null
|
||||
var/mob/living/carbon/oldpatient = null
|
||||
var/oldloc = null
|
||||
var/last_found = 0
|
||||
var/last_newpatient_speak = 0 //Don't spam the "HEY I'M COMING" messages
|
||||
var/currently_healing = 0
|
||||
var/injection_amount = 15 //How much reagent do we inject at a time?
|
||||
var/heal_threshold = 10 //Start healing when they have this much damage in a category
|
||||
var/use_beaker = 0 //Use reagents in beaker instead of default treatment agents.
|
||||
var/declare_crit = 1 //If active, the bot will transmit a critical patient alert to MedHUD users.
|
||||
var/declare_cooldown = 0 //Prevents spam of critical patient alerts.
|
||||
var/stationary_mode = 0 //If enabled, the Medibot will not move automatically.
|
||||
radio_frequency = MED_FREQ //Medical frequency
|
||||
//Setting which reagents to use to treat what by default. By id.
|
||||
var/treatment_brute = "tricordrazine"
|
||||
var/treatment_oxy = "tricordrazine"
|
||||
var/treatment_fire = "tricordrazine"
|
||||
var/treatment_tox = "tricordrazine"
|
||||
var/treatment_virus = "spaceacillin"
|
||||
var/treat_virus = 0 //If on, the bot will attempt to treat viral infections, curing them if possible.
|
||||
var/shut_up = 0 //self explanatory :)
|
||||
bot_type = MED_BOT
|
||||
bot_filter = RADIO_MEDBOT
|
||||
|
||||
/obj/machinery/bot/medbot/syndicate
|
||||
name = "Suspicious Medibot"
|
||||
@@ -45,10 +49,19 @@
|
||||
treatment_oxy = "dexalin"
|
||||
treatment_brute = "bicaridine"
|
||||
treatment_fire = "kelotane"
|
||||
treatment_tox = "anti_toxin"
|
||||
|
||||
/obj/machinery/bot/medbot/mysterious
|
||||
name = "\improper Mysterious Medibot"
|
||||
desc = "International Medibot of mystery."
|
||||
skin = "bezerk"
|
||||
treatment_oxy = "dexalinp"
|
||||
treatment_brute = "bicaridine"
|
||||
treatment_fire = "kelotane"
|
||||
treatment_tox = "anti_toxin"
|
||||
|
||||
/obj/item/weapon/firstaid_arm_assembly
|
||||
name = "first aid/robot arm assembly"
|
||||
name = "incomplete medibot assembly."
|
||||
desc = "A first aid kit with a robot arm permanently grafted to it."
|
||||
icon = 'icons/obj/aibots.dmi'
|
||||
icon_state = "firstaid_arm"
|
||||
@@ -57,45 +70,63 @@
|
||||
var/skin = null //Same as medbot, set to tox or ointment for the respective kits.
|
||||
w_class = 3.0
|
||||
|
||||
New()
|
||||
/obj/item/weapon/firstaid_arm_assembly/New()
|
||||
..()
|
||||
spawn(5)
|
||||
if(src.skin)
|
||||
src.overlays += image('icons/obj/aibots.dmi', "kit_skin_[src.skin]")
|
||||
if(src.skin == "bezerk")
|
||||
created_name = "Suspicious Medibot"
|
||||
if(skin)
|
||||
overlays += image('icons/obj/aibots.dmi', "kit_skin_[skin]")
|
||||
|
||||
/obj/machinery/bot/medbot/proc/updateicon()
|
||||
if(!on)
|
||||
icon_state = "medibot0"
|
||||
return
|
||||
if(mode == BOT_HEALING)
|
||||
icon_state = "medibots[stationary_mode]"
|
||||
return
|
||||
else if(stationary_mode) //Bot has yellow light to indicate stationary mode.
|
||||
icon_state = "medibot2"
|
||||
else
|
||||
icon_state = "medibot1"
|
||||
|
||||
/obj/machinery/bot/medbot/New()
|
||||
..()
|
||||
src.icon_state = "medibot[src.on]"
|
||||
updateicon()
|
||||
|
||||
spawn(4)
|
||||
if(src.skin)
|
||||
src.overlays += image('icons/obj/aibots.dmi', "medskin_[src.skin]")
|
||||
if(skin)
|
||||
overlays += image('icons/obj/aibots.dmi', "medskin_[skin]")
|
||||
|
||||
src.botcard = new /obj/item/weapon/card/id(src)
|
||||
if(isnull(src.botcard_access) || (src.botcard_access.len < 1))
|
||||
if(isnull(botcard_access) || (botcard_access.len < 1))
|
||||
var/datum/job/doctor/J = new/datum/job/doctor
|
||||
src.botcard.access = J.get_access()
|
||||
botcard.access = J.get_access()
|
||||
else
|
||||
src.botcard.access = src.botcard_access
|
||||
botcard.access = botcard_access
|
||||
prev_access = botcard.access
|
||||
add_to_beacons(bot_filter)
|
||||
|
||||
/obj/machinery/bot/medbot/turn_on()
|
||||
. = ..()
|
||||
src.icon_state = "medibot[src.on]"
|
||||
src.updateUsrDialog()
|
||||
updateicon()
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/bot/medbot/turn_off()
|
||||
..()
|
||||
src.patient = null
|
||||
src.oldpatient = null
|
||||
src.oldloc = null
|
||||
src.path = new()
|
||||
src.currently_healing = 0
|
||||
src.last_found = world.time
|
||||
src.icon_state = "medibot[src.on]"
|
||||
src.updateUsrDialog()
|
||||
updateicon()
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/bot/medbot/bot_reset()
|
||||
..()
|
||||
patient = null
|
||||
oldpatient = null
|
||||
oldloc = null
|
||||
last_found = world.time
|
||||
declare_cooldown = 0
|
||||
|
||||
/obj/machinery/bot/medbot/set_custom_texts()
|
||||
|
||||
text_hack = "You corrupt [name]'s reagent processor circuits."
|
||||
text_dehack = "You reset [name]'s reagent processor circuits."
|
||||
text_dehack_fail = "[name] seems damaged and does not respond to reprogramming!"
|
||||
|
||||
/obj/machinery/bot/medbot/attack_paw(mob/user as mob)
|
||||
return attack_hand(user)
|
||||
@@ -105,88 +136,94 @@
|
||||
if (.)
|
||||
return
|
||||
var/dat
|
||||
dat += "<TT><B>Automatic Medical Unit v1.0</B></TT><BR><BR>"
|
||||
dat += "Status: <A href='?src=\ref[src];power=1'>[src.on ? "On" : "Off"]</A><BR>"
|
||||
dat += "Maintenance panel panel is [src.open ? "opened" : "closed"]<BR>"
|
||||
dat += hack(user)
|
||||
dat += "<TT><B>Medical Unit Controls v1.1</B></TT><BR><BR>"
|
||||
dat += "Status: <A href='?src=\ref[src];power=1'>[on ? "On" : "Off"]</A><BR>"
|
||||
dat += "Maintenance panel panel is [open ? "opened" : "closed"]<BR>"
|
||||
dat += "Beaker: "
|
||||
if (src.reagent_glass)
|
||||
dat += "<A href='?src=\ref[src];eject=1'>Loaded \[[src.reagent_glass.reagents.total_volume]/[src.reagent_glass.reagents.maximum_volume]\]</a>"
|
||||
if (reagent_glass)
|
||||
dat += "<A href='?src=\ref[src];eject=1'>Loaded \[[reagent_glass.reagents.total_volume]/[reagent_glass.reagents.maximum_volume]\]</a>"
|
||||
else
|
||||
dat += "None Loaded"
|
||||
dat += "<br>Behaviour controls are [src.locked ? "locked" : "unlocked"]<hr>"
|
||||
if(!src.locked || issilicon(user))
|
||||
dat += "<br>Behaviour controls are [locked ? "locked" : "unlocked"]<hr>"
|
||||
if(!locked || issilicon(user))
|
||||
dat += "<TT>Healing Threshold: "
|
||||
dat += "<a href='?src=\ref[src];adj_threshold=-10'>--</a> "
|
||||
dat += "<a href='?src=\ref[src];adj_threshold=-5'>-</a> "
|
||||
dat += "[src.heal_threshold] "
|
||||
dat += "[heal_threshold] "
|
||||
dat += "<a href='?src=\ref[src];adj_threshold=5'>+</a> "
|
||||
dat += "<a href='?src=\ref[src];adj_threshold=10'>++</a>"
|
||||
dat += "</TT><br>"
|
||||
|
||||
dat += "<TT>Injection Level: "
|
||||
dat += "<a href='?src=\ref[src];adj_inject=-5'>-</a> "
|
||||
dat += "[src.injection_amount] "
|
||||
dat += "[injection_amount] "
|
||||
dat += "<a href='?src=\ref[src];adj_inject=5'>+</a> "
|
||||
dat += "</TT><br>"
|
||||
|
||||
dat += "Reagent Source: "
|
||||
dat += "<a href='?src=\ref[src];use_beaker=1'>[src.use_beaker ? "Loaded Beaker (When available)" : "Internal Synthesizer"]</a><br>"
|
||||
dat += "<a href='?src=\ref[src];use_beaker=1'>[use_beaker ? "Loaded Beaker (When available)" : "Internal Synthesizer"]</a><br>"
|
||||
|
||||
dat += "The speaker switch is [src.shut_up ? "off" : "on"]. <a href='?src=\ref[src];togglevoice=[1]'>Toggle</a>"
|
||||
dat += "Treat Viral Infections: <a href='?src=\ref[src];virus=1'>[treat_virus ? "Yes" : "No"]</a><br>"
|
||||
dat += "The speaker switch is [shut_up ? "off" : "on"]. <a href='?src=\ref[src];togglevoice=[1]'>Toggle</a><br>"
|
||||
dat += "Critical Patient Alerts: <a href='?src=\ref[src];critalerts=1'>[declare_crit ? "Yes" : "No"]</a><br>"
|
||||
dat += "Patrol Station: <a href='?src=\ref[src];operation=patrol'>[auto_patrol ? "Yes" : "No"]</a><br>"
|
||||
dat += "Stationary Mode: <a href='?src=\ref[src];stationary=1'>[stationary_mode ? "Yes" : "No"]</a><br>"
|
||||
|
||||
user << browse("<HEAD><TITLE>Medibot v1.0 controls</TITLE></HEAD>[dat]", "window=automed")
|
||||
onclose(user, "automed")
|
||||
var/datum/browser/popup = new(user, "automed", "Automatic Medical Unit v1.1")
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
return
|
||||
|
||||
/obj/machinery/bot/medbot/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
usr.set_machine(src)
|
||||
src.add_fingerprint(usr)
|
||||
if ((href_list["power"]) && (src.allowed(usr)))
|
||||
if (src.on)
|
||||
turn_off()
|
||||
else
|
||||
turn_on()
|
||||
..()
|
||||
|
||||
else if((href_list["adj_threshold"]) && (!src.locked || issilicon(usr)))
|
||||
if(href_list["adj_threshold"])
|
||||
var/adjust_num = text2num(href_list["adj_threshold"])
|
||||
src.heal_threshold += adjust_num
|
||||
if(src.heal_threshold < 5)
|
||||
src.heal_threshold = 5
|
||||
if(src.heal_threshold > 75)
|
||||
src.heal_threshold = 75
|
||||
heal_threshold += adjust_num
|
||||
if(heal_threshold < 5)
|
||||
heal_threshold = 5
|
||||
if(heal_threshold > 75)
|
||||
heal_threshold = 75
|
||||
|
||||
else if((href_list["adj_inject"]) && (!src.locked || issilicon(usr)))
|
||||
else if(href_list["adj_inject"])
|
||||
var/adjust_num = text2num(href_list["adj_inject"])
|
||||
src.injection_amount += adjust_num
|
||||
if(src.injection_amount < 5)
|
||||
src.injection_amount = 5
|
||||
if(src.injection_amount > 15)
|
||||
src.injection_amount = 15
|
||||
injection_amount += adjust_num
|
||||
if(injection_amount < 5)
|
||||
injection_amount = 5
|
||||
if(injection_amount > 15)
|
||||
injection_amount = 15
|
||||
|
||||
else if((href_list["use_beaker"]) && (!src.locked || issilicon(usr)))
|
||||
src.use_beaker = !src.use_beaker
|
||||
else if(href_list["use_beaker"])
|
||||
use_beaker = !use_beaker
|
||||
|
||||
else if (href_list["eject"] && (!isnull(src.reagent_glass)))
|
||||
if(!src.locked)
|
||||
src.reagent_glass.loc = get_turf(src)
|
||||
src.reagent_glass = null
|
||||
else
|
||||
usr << "<span class='notice'>You cannot eject the beaker because the panel is locked.</span>"
|
||||
else if (href_list["eject"] && (!isnull(reagent_glass)))
|
||||
reagent_glass.loc = get_turf(src)
|
||||
reagent_glass = null
|
||||
|
||||
else if ((href_list["togglevoice"]) && (!src.locked || issilicon(usr)))
|
||||
src.shut_up = !src.shut_up
|
||||
else if (href_list["togglevoice"])
|
||||
shut_up = !shut_up
|
||||
|
||||
src.updateUsrDialog()
|
||||
else if (href_list["critalerts"])
|
||||
declare_crit = !declare_crit
|
||||
|
||||
else if (href_list["stationary"])
|
||||
stationary_mode = !stationary_mode
|
||||
path = list()
|
||||
updateicon()
|
||||
|
||||
else if (href_list["virus"])
|
||||
treat_virus = !treat_virus
|
||||
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/bot/medbot/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
|
||||
if (src.allowed(user) && !open && !emagged)
|
||||
src.locked = !src.locked
|
||||
user << "<span class='notice'>Controls are now [src.locked ? "locked." : "unlocked."]</span>"
|
||||
src.updateUsrDialog()
|
||||
if (allowed(user) && !open && !emagged)
|
||||
locked = !locked
|
||||
user << "<span class='notice'>Controls are now [locked ? "locked." : "unlocked."]</span>"
|
||||
updateUsrDialog()
|
||||
else
|
||||
if(emagged)
|
||||
user << "<span class='warning'>ERROR</span>"
|
||||
@@ -196,131 +233,127 @@
|
||||
user << "<span class='warning'>Access denied.</span>"
|
||||
|
||||
else if (istype(W, /obj/item/weapon/reagent_containers/glass))
|
||||
if(src.locked)
|
||||
if(locked)
|
||||
user << "<span class='notice'>You cannot insert a beaker because the panel is locked.</span>"
|
||||
return
|
||||
if(!isnull(src.reagent_glass))
|
||||
if(!isnull(reagent_glass))
|
||||
user << "<span class='notice'>There is already a beaker loaded.</span>"
|
||||
return
|
||||
|
||||
user.drop_item()
|
||||
W.loc = src
|
||||
src.reagent_glass = W
|
||||
reagent_glass = W
|
||||
user << "<span class='notice'>You insert [W].</span>"
|
||||
src.updateUsrDialog()
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
else
|
||||
var/current_health = health
|
||||
..()
|
||||
if (health < maxhealth && !istype(W, /obj/item/weapon/screwdriver) && W.force)
|
||||
if (health < current_health) //if medbot took some damage
|
||||
step_to(src, (get_step_away(src,user)))
|
||||
|
||||
/obj/machinery/bot/medbot/Emag(mob/user as mob)
|
||||
..()
|
||||
if((!locked && open) || !user)
|
||||
if(user) user << "<span class='warning'>You short out [src]'s reagent synthesis circuits.</span>"
|
||||
if(emagged == 2)
|
||||
declare_crit = 0
|
||||
if(user)
|
||||
user << "<span class='warning'>You short out [src]'s reagent synthesis circuits.</span>"
|
||||
spawn(0)
|
||||
for(var/mob/O in hearers(src, null))
|
||||
O.show_message("\red <B>[src] buzzes oddly!</B>", 1)
|
||||
visible_message("<span class='danger'>[src] buzzes oddly!</span>")
|
||||
flick("medibot_spark", src)
|
||||
src.patient = null
|
||||
if(user) src.oldpatient = user
|
||||
src.currently_healing = 0
|
||||
src.last_found = world.time
|
||||
src.anchored = 0
|
||||
src.emagged = 2
|
||||
src.on = 1
|
||||
src.icon_state = "medibot[src.on]"
|
||||
if(user)
|
||||
oldpatient = user
|
||||
|
||||
/obj/machinery/bot/medbot/process()
|
||||
//set background = 1
|
||||
|
||||
if(!src.on)
|
||||
src.stunned = 0
|
||||
/obj/machinery/bot/medbot/process_scan(var/mob/living/carbon/human/H)
|
||||
if (H.stat == 2)
|
||||
return
|
||||
|
||||
if(src.stunned)
|
||||
src.icon_state = "medibota"
|
||||
src.stunned--
|
||||
|
||||
src.oldpatient = src.patient
|
||||
src.patient = null
|
||||
src.currently_healing = 0
|
||||
|
||||
if(src.stunned <= 0)
|
||||
src.icon_state = "medibot[src.on]"
|
||||
src.stunned = 0
|
||||
if ((H == oldpatient) && (world.time < last_found + 100))
|
||||
return
|
||||
|
||||
if(src.frustration > 8)
|
||||
src.oldpatient = src.patient
|
||||
src.patient = null
|
||||
src.currently_healing = 0
|
||||
src.last_found = world.time
|
||||
src.path = new()
|
||||
if(assess_patient(H))
|
||||
last_found = world.time
|
||||
if((last_newpatient_speak + 300) < world.time) //Don't spam these messages!
|
||||
var/message = pick("Hey, [H.name]! Hold on, I'm coming.","Wait [H.name]! I want to help!","[H.name], you appear to be injured!")
|
||||
speak(message)
|
||||
last_newpatient_speak = world.time
|
||||
return H
|
||||
else
|
||||
return
|
||||
|
||||
if(!src.patient)
|
||||
if(!src.shut_up && prob(1))
|
||||
/obj/machinery/bot/medbot/bot_process()
|
||||
if (!..())
|
||||
return
|
||||
|
||||
if(mode == BOT_HEALING)
|
||||
return
|
||||
|
||||
if(stunned)
|
||||
icon_state = "medibota"
|
||||
stunned--
|
||||
|
||||
oldpatient = patient
|
||||
patient = null
|
||||
mode = BOT_IDLE
|
||||
|
||||
if(stunned <= 0)
|
||||
updateicon()
|
||||
stunned = 0
|
||||
return
|
||||
|
||||
if(frustration > 8)
|
||||
oldpatient = patient
|
||||
patient = null
|
||||
mode = BOT_IDLE
|
||||
last_found = world.time
|
||||
path = list()
|
||||
|
||||
if(!patient)
|
||||
if(!shut_up && prob(1))
|
||||
var/message = pick("Radar, put a mask on!","There's always a catch, and it's the best there is.","I knew it, I should've been a plastic surgeon.","What kind of medbay is this? Everyone's dropping like dead flies.","Delicious!")
|
||||
src.speak(message)
|
||||
speak(message)
|
||||
var/scan_range = (stationary_mode ? 1 : DEFAULT_SCAN_RANGE) //If in stationary mode, scan range is limited to adjacent patients.
|
||||
patient = scan(/mob/living/carbon/human, oldpatient, scan_range)
|
||||
oldpatient = patient
|
||||
|
||||
for (var/mob/living/carbon/C in view(7,src)) //Time to find a patient!
|
||||
if ((C.stat == 2) || !istype(C, /mob/living/carbon/human))
|
||||
continue
|
||||
|
||||
if ((C == src.oldpatient) && (world.time < src.last_found + 100))
|
||||
continue
|
||||
|
||||
if(src.assess_patient(C))
|
||||
src.patient = C
|
||||
src.oldpatient = C
|
||||
src.last_found = world.time
|
||||
spawn(0)
|
||||
if((src.last_newpatient_speak + 100) < world.time) //Don't spam these messages!
|
||||
var/message = pick("Hey, you! Hold on, I'm coming.","Wait! I want to help!","You appear to be injured!")
|
||||
src.speak(message)
|
||||
src.last_newpatient_speak = world.time
|
||||
src.visible_message("<b>[src]</b> points at [C.name]!")
|
||||
break
|
||||
else
|
||||
continue
|
||||
|
||||
if(!src.path)
|
||||
src.path = new()
|
||||
|
||||
if(src.patient && Adjacent(patient))
|
||||
if(!src.currently_healing)
|
||||
src.currently_healing = 1
|
||||
src.frustration = 0
|
||||
src.medicate_patient(src.patient)
|
||||
if(patient && (get_dist(src,patient) <= 1)) //Patient is next to us, begin treatment!
|
||||
if(mode != BOT_HEALING)
|
||||
mode = BOT_HEALING
|
||||
updateicon()
|
||||
frustration = 0
|
||||
medicate_patient(patient)
|
||||
return
|
||||
|
||||
else if(src.patient && (src.path.len) && (get_dist(src.patient,src.path[src.path.len]) > 2))
|
||||
src.path = new()
|
||||
src.currently_healing = 0
|
||||
src.last_found = world.time
|
||||
//Patient has moved away from us!
|
||||
else if(patient && path && path.len && (get_dist(patient,path[path.len]) > 2))
|
||||
path = list()
|
||||
mode = BOT_IDLE
|
||||
last_found = world.time
|
||||
|
||||
if(src.patient && src.path.len == 0 && (get_dist(src,src.patient) > 1))
|
||||
if(!stationary_mode && patient && path.len == 0 && (get_dist(src,patient) > 1))
|
||||
spawn(0)
|
||||
src.path = AStar(src.loc, get_turf(src.patient), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 30,id=botcard)
|
||||
if (!path) path = list()
|
||||
if(src.path.len == 0)
|
||||
src.oldpatient = src.patient
|
||||
src.patient = null
|
||||
src.currently_healing = 0
|
||||
src.last_found = world.time
|
||||
path = AStar(loc, get_turf(patient), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 30,id=botcard)
|
||||
if(!path)
|
||||
path = list()
|
||||
|
||||
if(path.len > 0 && patient)
|
||||
if(!bot_move(patient))
|
||||
oldpatient = patient
|
||||
patient = null
|
||||
mode = BOT_IDLE
|
||||
last_found = world.time
|
||||
return
|
||||
|
||||
if(src.path.len > 0 && src.patient)
|
||||
step_to(src, src.path[1])
|
||||
src.path -= src.path[1]
|
||||
spawn(3)
|
||||
if(src.path.len)
|
||||
step_to(src, src.path[1])
|
||||
src.path -= src.path[1]
|
||||
if(path.len > 8 && patient)
|
||||
frustration++
|
||||
|
||||
if(src.path.len > 8 && src.patient)
|
||||
src.frustration++
|
||||
if(auto_patrol && !stationary_mode && !patient)
|
||||
if(mode == BOT_IDLE || mode == BOT_START_PATROL)
|
||||
start_patrol()
|
||||
|
||||
if(mode == BOT_PATROL)
|
||||
bot_patrol()
|
||||
|
||||
return
|
||||
|
||||
@@ -332,121 +365,124 @@
|
||||
if(C.suiciding)
|
||||
return 0 //Kevorkian school of robotic medical assistants.
|
||||
|
||||
if(src.emagged == 2) //Everyone needs our medicine. (Our medicine is toxins)
|
||||
if(emagged == 2) //Everyone needs our medicine. (Our medicine is toxins)
|
||||
return 1
|
||||
|
||||
if((skin == "bezerk") && (!("syndicate" in C.faction))) // No healing non-operatives as a SyndiBot.
|
||||
|
||||
if((skin == "bezerk") && (!("syndicate" in C.faction)))
|
||||
return 0
|
||||
|
||||
if(declare_crit && C.health <= 0) //Critical condition! Call for help!
|
||||
declare(C)
|
||||
|
||||
//If they're injured, we're using a beaker, and don't have one of our WONDERCHEMS.
|
||||
if((src.reagent_glass) && (src.use_beaker) && ((C.getBruteLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getOxyLoss() >= (heal_threshold + 15))))
|
||||
for(var/datum/reagent/R in src.reagent_glass.reagents.reagent_list)
|
||||
if((reagent_glass) && (use_beaker) && ((C.getBruteLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getOxyLoss() >= (heal_threshold + 15))))
|
||||
for(var/datum/reagent/R in reagent_glass.reagents.reagent_list)
|
||||
if(!C.reagents.has_reagent(R.id))
|
||||
return 1
|
||||
|
||||
//They're injured enough for it!
|
||||
if((C.getBruteLoss() >= heal_threshold) && (!C.reagents.has_reagent(src.treatment_brute)))
|
||||
if((C.getBruteLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_brute)))
|
||||
return 1 //If they're already medicated don't bother!
|
||||
|
||||
if((C.getOxyLoss() >= (15 + heal_threshold)) && (!C.reagents.has_reagent(src.treatment_oxy)))
|
||||
if((C.getOxyLoss() >= (15 + heal_threshold)) && (!C.reagents.has_reagent(treatment_oxy)))
|
||||
return 1
|
||||
|
||||
if((C.getFireLoss() >= heal_threshold) && (!C.reagents.has_reagent(src.treatment_fire)))
|
||||
if((C.getFireLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_fire)))
|
||||
return 1
|
||||
|
||||
if((C.getToxLoss() >= heal_threshold) && (!C.reagents.has_reagent(src.treatment_tox)))
|
||||
if((C.getToxLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_tox)))
|
||||
return 1
|
||||
|
||||
|
||||
return 0
|
||||
|
||||
/obj/machinery/bot/medbot/proc/medicate_patient(mob/living/carbon/C as mob)
|
||||
if(!src.on)
|
||||
if(!on)
|
||||
return
|
||||
|
||||
if(!istype(C))
|
||||
src.oldpatient = src.patient
|
||||
src.patient = null
|
||||
src.currently_healing = 0
|
||||
src.last_found = world.time
|
||||
oldpatient = patient
|
||||
patient = null
|
||||
mode = BOT_IDLE
|
||||
last_found = world.time
|
||||
return
|
||||
|
||||
if(C.stat == 2)
|
||||
var/death_message = pick("No! NO!","Live, damnit! LIVE!","I...I've never lost a patient before. Not today, I mean.")
|
||||
src.speak(death_message)
|
||||
src.oldpatient = src.patient
|
||||
src.patient = null
|
||||
src.currently_healing = 0
|
||||
src.last_found = world.time
|
||||
speak(death_message)
|
||||
oldpatient = patient
|
||||
patient = null
|
||||
mode = BOT_IDLE
|
||||
last_found = world.time
|
||||
return
|
||||
|
||||
var/reagent_id = null
|
||||
|
||||
if(src.emagged == 2) //Emagged! Time to poison everybody.
|
||||
if(emagged == 2) //Emagged! Time to poison everybody.
|
||||
reagent_id = "toxin"
|
||||
|
||||
else
|
||||
|
||||
if (!reagent_id && (C.getBruteLoss() >= heal_threshold))
|
||||
if(!C.reagents.has_reagent(src.treatment_brute))
|
||||
reagent_id = src.treatment_brute
|
||||
if(!C.reagents.has_reagent(treatment_brute))
|
||||
reagent_id = treatment_brute
|
||||
|
||||
if (!reagent_id && (C.getOxyLoss() >= (15 + heal_threshold)))
|
||||
if(!C.reagents.has_reagent(src.treatment_oxy))
|
||||
reagent_id = src.treatment_oxy
|
||||
if(!C.reagents.has_reagent(treatment_oxy))
|
||||
reagent_id = treatment_oxy
|
||||
|
||||
if (!reagent_id && (C.getFireLoss() >= heal_threshold))
|
||||
if(!C.reagents.has_reagent(src.treatment_fire))
|
||||
reagent_id = src.treatment_fire
|
||||
if(!C.reagents.has_reagent(treatment_fire))
|
||||
reagent_id = treatment_fire
|
||||
|
||||
if (!reagent_id && (C.getToxLoss() >= heal_threshold))
|
||||
if(!C.reagents.has_reagent(src.treatment_tox))
|
||||
reagent_id = src.treatment_tox
|
||||
if(!C.reagents.has_reagent(treatment_tox))
|
||||
reagent_id = treatment_tox
|
||||
|
||||
//If the patient is injured but doesn't have our special reagent in them then we should give it to them first
|
||||
if(reagent_id && src.use_beaker && src.reagent_glass && src.reagent_glass.reagents.total_volume)
|
||||
for(var/datum/reagent/R in src.reagent_glass.reagents.reagent_list)
|
||||
if(reagent_id && use_beaker && reagent_glass && reagent_glass.reagents.total_volume)
|
||||
for(var/datum/reagent/R in reagent_glass.reagents.reagent_list)
|
||||
if(!C.reagents.has_reagent(R.id))
|
||||
reagent_id = "internal_beaker"
|
||||
break
|
||||
|
||||
if(!reagent_id) //If they don't need any of that they're probably cured!
|
||||
src.oldpatient = src.patient
|
||||
src.patient = null
|
||||
src.currently_healing = 0
|
||||
src.last_found = world.time
|
||||
oldpatient = patient
|
||||
patient = null
|
||||
mode = BOT_IDLE
|
||||
last_found = world.time
|
||||
var/message = pick("All patched up!","An apple a day keeps me away.","Feel better soon!")
|
||||
src.speak(message)
|
||||
speak(message)
|
||||
updateicon()
|
||||
return
|
||||
else
|
||||
src.icon_state = "medibots"
|
||||
visible_message("\red <B>[src] is trying to inject [src.patient]!</B>")
|
||||
spawn(30)
|
||||
if ((get_dist(src, src.patient) <= 1) && (src.on))
|
||||
if((reagent_id == "internal_beaker") && (src.reagent_glass) && (src.reagent_glass.reagents.total_volume))
|
||||
src.reagent_glass.reagents.trans_to(src.patient,src.injection_amount) //Inject from beaker instead.
|
||||
src.reagent_glass.reagents.reaction(src.patient, 2)
|
||||
else
|
||||
src.patient.reagents.add_reagent(reagent_id,src.injection_amount)
|
||||
visible_message("\red <B>[src] injects [src.patient] with the syringe!</B>")
|
||||
C.visible_message("<span class='danger'>[src] is trying to inject [patient]!</span>", \
|
||||
"<span class='userdanger'>[src] is trying to inject [patient]!</span>")
|
||||
|
||||
src.icon_state = "medibot[src.on]"
|
||||
src.currently_healing = 0
|
||||
spawn(30)
|
||||
if ((get_dist(src, patient) <= 1) && (on))
|
||||
if(reagent_id == "internal_beaker")
|
||||
if(use_beaker && reagent_glass && reagent_glass.reagents.total_volume)
|
||||
reagent_glass.reagents.trans_to(patient,injection_amount) //Inject from beaker instead.
|
||||
reagent_glass.reagents.reaction(patient, 2)
|
||||
else
|
||||
patient.reagents.add_reagent(reagent_id,injection_amount)
|
||||
C.visible_message("<span class='danger'>[src] injects [patient] with the syringe!</span>", \
|
||||
"<span class='userdanger'>[src] injects [patient] with the syringe!</span>")
|
||||
|
||||
mode = BOT_IDLE
|
||||
updateicon()
|
||||
return
|
||||
|
||||
reagent_id = null
|
||||
return
|
||||
|
||||
|
||||
|
||||
/obj/machinery/bot/medbot/bullet_act(var/obj/item/projectile/Proj)
|
||||
if(Proj.flag == "taser")
|
||||
src.stunned = min(stunned+10,20)
|
||||
stunned = min(stunned+10,20)
|
||||
..()
|
||||
|
||||
/obj/machinery/bot/medbot/explode()
|
||||
src.on = 0
|
||||
visible_message("\red <B>[src] blows apart!</B>", 1)
|
||||
on = 0
|
||||
visible_message("<span class='userdanger'>[src] blows apart!</span>")
|
||||
var/turf/Tsec = get_turf(src)
|
||||
|
||||
new /obj/item/weapon/storage/firstaid(Tsec)
|
||||
@@ -455,9 +491,9 @@
|
||||
|
||||
new /obj/item/device/healthanalyzer(Tsec)
|
||||
|
||||
if(src.reagent_glass)
|
||||
src.reagent_glass.loc = Tsec
|
||||
src.reagent_glass = null
|
||||
if(reagent_glass)
|
||||
reagent_glass.loc = Tsec
|
||||
reagent_glass = null
|
||||
|
||||
if (prob(50))
|
||||
new /obj/item/robot_parts/l_arm(Tsec)
|
||||
@@ -465,57 +501,17 @@
|
||||
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
del(src)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/obj/machinery/bot/medbot/Bump(M as mob|obj) //Leave no door unopened!
|
||||
if ((istype(M, /obj/machinery/door)) && (!isnull(src.botcard)))
|
||||
var/obj/machinery/door/D = M
|
||||
if (!istype(D, /obj/machinery/door/firedoor) && D.check_access(src.botcard) && !istype(D,/obj/machinery/door/poddoor))
|
||||
D.open()
|
||||
src.frustration = 0
|
||||
else if ((istype(M, /mob/living/)) && (!src.anchored))
|
||||
src.loc = M:loc
|
||||
src.frustration = 0
|
||||
return
|
||||
|
||||
/* terrible
|
||||
/obj/machinery/bot/medbot/Bumped(atom/movable/M as mob|obj)
|
||||
spawn(0)
|
||||
if (M)
|
||||
var/turf/T = get_turf(src)
|
||||
M:loc = T
|
||||
*/
|
||||
|
||||
/*
|
||||
* Pathfinding procs, allow the medibot to path through doors it has access to.
|
||||
*/
|
||||
|
||||
//Pretty ugh
|
||||
/*
|
||||
/turf/proc/AdjacentTurfsAllowMedAccess()
|
||||
var/L[] = new()
|
||||
for(var/turf/t in oview(src,1))
|
||||
if(!t.density)
|
||||
if(!LinkBlocked(src, t) && !TurfBlockedNonWindowNonDoor(t,get_access("Medical Doctor")))
|
||||
L.Add(t)
|
||||
return L
|
||||
|
||||
|
||||
//It isn't blocked if we can open it, man.
|
||||
/proc/TurfBlockedNonWindowNonDoor(turf/loc, var/list/access)
|
||||
for(var/obj/O in loc)
|
||||
if(O.density && !istype(O, /obj/structure/window) && !istype(O, /obj/machinery/door))
|
||||
return 1
|
||||
|
||||
if (O.density && (istype(O, /obj/machinery/door)) && (access.len))
|
||||
var/obj/machinery/door/D = O
|
||||
for(var/req in D.req_access)
|
||||
if(!(req in access)) //doesn't have this access
|
||||
return 1
|
||||
|
||||
return 0
|
||||
*/
|
||||
/obj/machinery/bot/medbot/proc/declare(var/crit_patient)
|
||||
if(declare_cooldown)
|
||||
return
|
||||
//var/area/location = get_area(src)
|
||||
declare_critical(crit_patient)
|
||||
declare_cooldown = 1
|
||||
spawn(200) //Twenty seconds
|
||||
declare_cooldown = 0
|
||||
|
||||
/*
|
||||
* Medbot Assembly -- Can be made out of all three medkits.
|
||||
@@ -528,7 +524,7 @@
|
||||
return
|
||||
|
||||
//Making a medibot!
|
||||
if(src.contents.len >= 1)
|
||||
if(contents.len >= 1)
|
||||
user << "<span class='notice'>You need to empty [src] out first.</span>"
|
||||
return
|
||||
|
||||
@@ -539,55 +535,49 @@
|
||||
A.skin = "tox"
|
||||
else if(istype(src,/obj/item/weapon/storage/firstaid/o2))
|
||||
A.skin = "o2"
|
||||
else if(istype(src,/obj/item/weapon/storage/firstaid/tactical))
|
||||
A.skin = "bezerk"
|
||||
|
||||
del(S)
|
||||
qdel(S)
|
||||
user.put_in_hands(A)
|
||||
user << "<span class='notice'>You add the robot arm to the first aid kit.</span>"
|
||||
user.drop_from_inventory(src)
|
||||
del(src)
|
||||
user.before_take_item(src, 1)
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/item/weapon/firstaid_arm_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
..()
|
||||
if(istype(W, /obj/item/weapon/pen))
|
||||
var/t = copytext(stripped_input(user, "Enter new robot name", src.name, src.created_name),1,MAX_NAME_LEN)
|
||||
var/t = stripped_input(user, "Enter new robot name", name, created_name,MAX_NAME_LEN)
|
||||
if (!t)
|
||||
return
|
||||
if (!in_range(src, usr) && src.loc != usr)
|
||||
if (!in_range(src, usr) && loc != usr)
|
||||
return
|
||||
src.created_name = t
|
||||
created_name = t
|
||||
else
|
||||
switch(build_step)
|
||||
if(0)
|
||||
if(istype(W, /obj/item/device/healthanalyzer))
|
||||
user.drop_item()
|
||||
del(W)
|
||||
src.build_step++
|
||||
qdel(W)
|
||||
build_step++
|
||||
user << "<span class='notice'>You add the health sensor to [src].</span>"
|
||||
src.name = "First aid/robot arm/health analyzer assembly"
|
||||
src.overlays += image('icons/obj/aibots.dmi', "na_scanner")
|
||||
name = "First aid/robot arm/health analyzer assembly"
|
||||
overlays += image('icons/obj/aibots.dmi', "na_scanner")
|
||||
|
||||
if(1)
|
||||
if(isprox(W))
|
||||
user.drop_item()
|
||||
del(W)
|
||||
src.build_step++
|
||||
qdel(W)
|
||||
build_step++
|
||||
user << "<span class='notice'>You complete the Medibot! Beep boop.</span>"
|
||||
var/turf/T = get_turf(src)
|
||||
var/obj/machinery/bot/medbot/S = new /obj/machinery/bot/medbot(T)
|
||||
S.skin = skin
|
||||
S.name = created_name
|
||||
user.before_take_item(src, 1)
|
||||
qdel(src)
|
||||
|
||||
if (src.skin == "bezerk")
|
||||
var/obj/machinery/bot/medbot/syndicate/S = new /obj/machinery/bot/medbot/syndicate(T)
|
||||
S.skin = src.skin
|
||||
S.name = src.created_name
|
||||
S.req_access = list("150")
|
||||
|
||||
else
|
||||
var/obj/machinery/bot/medbot/S = new /obj/machinery/bot/medbot(T)
|
||||
S.skin = src.skin
|
||||
S.name = src.created_name
|
||||
|
||||
user.drop_from_inventory(src)
|
||||
del(src)
|
||||
|
||||
/obj/machinery/bot/medbot/proc/declare_critical(var/crit_patient)
|
||||
var/area/location = get_area(src)
|
||||
for(var/mob/living/carbon/human/human in world)
|
||||
if((human.z == src.z) && istype(human.glasses, /obj/item/clothing/glasses/hud/health) | istype(human.glasses, /obj/item/clothing/glasses/hud/health_advanced) && !human.blinded)
|
||||
human << "<span class='info'>\icon[human.glasses] Medical emergency! [crit_patient ? "<b>[crit_patient]</b>" : "A patient"] is in critical condition at [location]!"
|
||||
+214
-194
@@ -19,34 +19,28 @@ var/global/mulebot_count = 0
|
||||
fire_dam_coeff = 0.7
|
||||
brute_dam_coeff = 0.5
|
||||
var/atom/movable/load = null // the loaded crate (usually)
|
||||
var/beacon_freq = 1400
|
||||
var/control_freq = 1447
|
||||
var/list/delivery_beacons = list() //List of beacons that serve as delivery locations.
|
||||
beacon_freq = 1400
|
||||
control_freq = 1447
|
||||
bot_type = MULE_BOT
|
||||
bot_filter = RADIO_MULEBOT
|
||||
|
||||
suffix = ""
|
||||
|
||||
var/turf/target // this is turf to navigate to (location of beacon)
|
||||
var/loaddir = 0 // this the direction to unload onto/load from
|
||||
var/new_destination = "" // pending new destination (waiting for beacon response)
|
||||
var/destination = "" // destination description
|
||||
var/home_destination = "" // tag of home beacon
|
||||
req_access = list(access_cargo) // added robotics access so assembly line drop-off works properly -veyveyr //I don't think so, Tim. You need to add it to the MULE's hidden robot ID card. -NEO
|
||||
var/path[] = new()
|
||||
|
||||
var/mode = 0 //0 = idle/ready
|
||||
//1 = loading/unloading
|
||||
//2 = moving to deliver
|
||||
//3 = returning to home
|
||||
//4 = blocked
|
||||
//5 = computing navigation
|
||||
//6 = waiting for nav computation
|
||||
//7 = no destination beacon found (or no route)
|
||||
mode = BOT_IDLE
|
||||
|
||||
var/blockcount = 0 //number of times retried a blocked path
|
||||
blockcount = 0 //number of times retried a blocked path
|
||||
var/reached_target = 1 //true if already reached the target
|
||||
|
||||
var/refresh = 1 // true to refresh dialogue
|
||||
var/auto_return = 1 // true if auto return to home beacon after unload
|
||||
var/auto_pickup = 1 // true if auto-pickup at beacon
|
||||
var/refresh = 1 // true to refresh dialogue
|
||||
var/auto_return = 1 // true if auto return to home beacon after unload
|
||||
var/auto_pickup = 1 // true if auto-pickup at beacon
|
||||
var/report_delivery = 1 // true if bot will announce an arrival to a location.
|
||||
|
||||
var/obj/item/weapon/cell/cell
|
||||
var/datum/wires/mulebot/wires = null
|
||||
@@ -68,18 +62,16 @@ var/global/mulebot_count = 0
|
||||
/obj/machinery/bot/mulebot/New()
|
||||
..()
|
||||
wires = new(src)
|
||||
botcard = new(src)
|
||||
var/datum/job/cargo_tech/J = new/datum/job/cargo_tech
|
||||
botcard.access = J.get_access()
|
||||
prev_access = botcard.access
|
||||
// botcard.access += access_robotics //Why --Ikki
|
||||
cell = new(src)
|
||||
cell.charge = 2000
|
||||
cell.maxcharge = 2000
|
||||
|
||||
spawn(5) // must wait for map loading to finish
|
||||
if(radio_controller)
|
||||
radio_controller.add_object(src, control_freq, filter = RADIO_MULEBOT)
|
||||
radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
|
||||
add_to_beacons(bot_filter)
|
||||
|
||||
mulebot_count += 1
|
||||
if(!suffix)
|
||||
@@ -87,9 +79,6 @@ var/global/mulebot_count = 0
|
||||
name = "\improper Mulebot ([suffix])"
|
||||
|
||||
|
||||
verbs -= /atom/movable/verb/pull
|
||||
|
||||
|
||||
|
||||
// attack by item
|
||||
// emag : lock/unlock,
|
||||
@@ -99,12 +88,12 @@ var/global/mulebot_count = 0
|
||||
/obj/machinery/bot/mulebot/attackby(var/obj/item/I, var/mob/user)
|
||||
if(istype(I,/obj/item/weapon/card/emag))
|
||||
locked = !locked
|
||||
user << "\blue You [locked ? "lock" : "unlock"] the mulebot's controls!"
|
||||
user << "<span class='notice'>You [locked ? "lock" : "unlock"] the mulebot's controls!</span>"
|
||||
flick("mulebot-emagged", src)
|
||||
playsound(src.loc, 'sound/effects/sparks1.ogg', 100, 0)
|
||||
else if(istype(I, /obj/item/weapon/card/id))
|
||||
playsound(loc, 'sound/effects/sparks1.ogg', 100, 0)
|
||||
else if(istype(I, /obj/item/weapon/card/id) || istype(I, /obj/item/device/pda))
|
||||
if(toggle_lock(user))
|
||||
user << "\blue Controls [(locked ? "locked" : "unlocked")]."
|
||||
user << "<span class='notice'>Controls [(locked ? "locked" : "unlocked")].</span>"
|
||||
|
||||
else if(istype(I,/obj/item/weapon/cell) && open && !cell)
|
||||
var/obj/item/weapon/cell/C = I
|
||||
@@ -114,32 +103,35 @@ var/global/mulebot_count = 0
|
||||
updateDialog()
|
||||
else if(istype(I,/obj/item/weapon/screwdriver))
|
||||
if(locked)
|
||||
user << "\blue The maintenance hatch cannot be opened or closed while the controls are locked."
|
||||
user << "<span class='notice'>The maintenance hatch cannot be opened or closed while the controls are locked.</span>"
|
||||
return
|
||||
|
||||
open = !open
|
||||
if(open)
|
||||
src.visible_message("[user] opens the maintenance hatch of [src]", "\blue You open [src]'s maintenance hatch.")
|
||||
visible_message("[user] opens the maintenance hatch of [src]", "<span class='notice'>You open [src]'s maintenance hatch.</span>")
|
||||
on = 0
|
||||
icon_state="mulebot-hatch"
|
||||
else
|
||||
src.visible_message("[user] closes the maintenance hatch of [src]", "\blue You close [src]'s maintenance hatch.")
|
||||
visible_message("[user] closes the maintenance hatch of [src]", "<span class='notice'>You close [src]'s maintenance hatch.</span>")
|
||||
icon_state = "mulebot0"
|
||||
|
||||
updateDialog()
|
||||
else if (istype(I, /obj/item/weapon/wrench))
|
||||
if (src.health < maxhealth)
|
||||
src.health = min(maxhealth, src.health+25)
|
||||
if (health < maxhealth)
|
||||
health = min(maxhealth, health+25)
|
||||
user.visible_message(
|
||||
"\red [user] repairs [src]!",
|
||||
"\blue You repair [src]!"
|
||||
"<span class='notice'>[user] repairs [src]!</span>",
|
||||
"<span class='notice'>You repair [src]!</span>"
|
||||
)
|
||||
else
|
||||
user << "\blue [src] does not need a repair!"
|
||||
user << "<span class='notice'> [src] does not need a repair!</span>"
|
||||
else if(istype(I, /obj/item/device/multitool) || istype(I, /obj/item/weapon/wirecutters))
|
||||
if(open)
|
||||
attack_hand(usr)
|
||||
else if(load && ismob(load)) // chance to knock off rider
|
||||
if(prob(1+I.force * 2))
|
||||
unload(0)
|
||||
user.visible_message("\red [user] knocks [load] off [src] with \the [I]!", "\red You knock [load] off [src] with \the [I]!")
|
||||
user.visible_message("<span class='danger'> [user] knocks [load] off [src] with \the [I]!</span>", "<span class='danger'> You knock [load] off [src] with \the [I]!</span>")
|
||||
else
|
||||
user << "You hit [src] with \the [I] but to no effect."
|
||||
else
|
||||
@@ -162,13 +154,12 @@ var/global/mulebot_count = 0
|
||||
if(prob(50) && !isnull(load))
|
||||
unload(0)
|
||||
if(prob(25))
|
||||
src.visible_message("\red Something shorts out inside [src]!")
|
||||
visible_message("<span class='danger'> Something shorts out inside [src]!</span>")
|
||||
wires.RandomCut()
|
||||
..()
|
||||
|
||||
|
||||
/obj/machinery/bot/mulebot/attack_ai(var/mob/user)
|
||||
src.add_hiddenprint(user)
|
||||
user.set_machine(src)
|
||||
interact(user, 1)
|
||||
|
||||
@@ -181,38 +172,40 @@ var/global/mulebot_count = 0
|
||||
|
||||
/obj/machinery/bot/mulebot/interact(var/mob/user, var/ai=0)
|
||||
var/dat
|
||||
dat += "<TT><B>Multiple Utility Load Effector Mk. III</B></TT><BR><BR>"
|
||||
dat += "ID: [suffix]<BR>"
|
||||
dat += "Power: [on ? "On" : "Off"]<BR>"
|
||||
dat += "<h3>Multiple Utility Load Effector Mk. V</h3>"
|
||||
dat += "<b>ID:</b> [suffix]<BR>"
|
||||
dat += "<b>Power:</b> [on ? "On" : "Off"]<BR>"
|
||||
|
||||
if(!open)
|
||||
|
||||
dat += "Status: "
|
||||
dat += "<h3>Status</h3>"
|
||||
|
||||
dat += "<div class='statusDisplay'>"
|
||||
switch(mode)
|
||||
if(0)
|
||||
dat += "Ready"
|
||||
if(1)
|
||||
dat += "Loading/Unloading"
|
||||
if(2)
|
||||
dat += "Navigating to Delivery Location"
|
||||
if(3)
|
||||
dat += "Navigating to Home"
|
||||
if(4)
|
||||
dat += "Waiting for clear path"
|
||||
if(5,6)
|
||||
dat += "Calculating navigation path"
|
||||
if(7)
|
||||
dat += "Unable to locate destination"
|
||||
if(BOT_IDLE)
|
||||
dat += "<span class='good'>Ready</span>"
|
||||
if(BOT_LOADING)
|
||||
dat += "<span class='good'>[mode_name[BOT_LOADING]]</span>"
|
||||
if(BOT_DELIVER)
|
||||
dat += "<span class='good'>[mode_name[BOT_DELIVER]]</span>"
|
||||
if(BOT_GO_HOME)
|
||||
dat += "<span class='good'>[mode_name[BOT_GO_HOME]]</span>"
|
||||
if(BOT_BLOCKED)
|
||||
dat += "<span class='average'>[mode_name[BOT_BLOCKED]]</span>"
|
||||
if(BOT_NAV,BOT_WAIT_FOR_NAV)
|
||||
dat += "<span class='average'>[mode_name[BOT_NAV]]</span>"
|
||||
if(BOT_NO_ROUTE)
|
||||
dat += "<span class='bad'>[mode_name[BOT_NO_ROUTE]]</span>"
|
||||
dat += "</div>"
|
||||
|
||||
|
||||
dat += "<BR>Current Load: [load ? load.name : "<i>none</i>"]<BR>"
|
||||
dat += "Destination: [!destination ? "<i>none</i>" : destination]<BR>"
|
||||
dat += "Power level: [cell ? cell.percent() : 0]%<BR>"
|
||||
dat += "<b>Current Load:</b> [load ? load.name : "<i>none</i>"]<BR>"
|
||||
dat += "<b>Destination:</b> [!destination ? "<i>none</i>" : destination]<BR>"
|
||||
dat += "<b>Power level:</b> [cell ? cell.percent() : 0]%"
|
||||
|
||||
if(locked && !ai)
|
||||
dat += "<HR>Controls are locked <A href='byond://?src=\ref[src];op=unlock'><I>(unlock)</I></A>"
|
||||
dat += " <br /><div class='notice'>Controls are locked</div><A href='byond://?src=\ref[src];op=unlock'>Unlock Controls</A>"
|
||||
else
|
||||
dat += "<HR>Controls are unlocked <A href='byond://?src=\ref[src];op=lock'><I>(lock)</I></A><BR><BR>"
|
||||
dat += " <br /><div class='notice'>Controls are unlocked</div><A href='byond://?src=\ref[src];op=lock'>Lock Controls</A><BR><BR>"
|
||||
|
||||
dat += "<A href='byond://?src=\ref[src];op=power'>Toggle Power</A><BR>"
|
||||
dat += "<A href='byond://?src=\ref[src];op=stop'>Stop</A><BR>"
|
||||
@@ -223,15 +216,16 @@ var/global/mulebot_count = 0
|
||||
dat += "<A href='byond://?src=\ref[src];op=sethome'>Set Home</A><BR>"
|
||||
dat += "<A href='byond://?src=\ref[src];op=autoret'>Toggle Auto Return Home</A> ([auto_return ? "On":"Off"])<BR>"
|
||||
dat += "<A href='byond://?src=\ref[src];op=autopick'>Toggle Auto Pickup Crate</A> ([auto_pickup ? "On":"Off"])<BR>"
|
||||
dat += "<A href='byond://?src=\ref[src];op=report'>Toggle Delivery Reporting</A> ([report_delivery ? "On" : "Off"])<BR>"
|
||||
|
||||
if(load)
|
||||
dat += "<A href='byond://?src=\ref[src];op=unload'>Unload Now</A><BR>"
|
||||
dat += "<HR>The maintenance hatch is closed.<BR>"
|
||||
dat += "<div class='notice'>The maintenance hatch is closed.</div>"
|
||||
|
||||
else
|
||||
if(!ai)
|
||||
dat += "The maintenance hatch is open.<BR><BR>"
|
||||
dat += "Power cell: "
|
||||
dat += "<div class='notice'>The maintenance hatch is open.</div><BR>"
|
||||
dat += "<b>Power cell:</b> "
|
||||
if(cell)
|
||||
dat += "<A href='byond://?src=\ref[src];op=cellremove'>Installed</A><BR>"
|
||||
else
|
||||
@@ -239,10 +233,14 @@ var/global/mulebot_count = 0
|
||||
|
||||
dat += wires()
|
||||
else
|
||||
dat += "The bot is in maintenance mode and cannot be controlled.<BR>"
|
||||
dat += "<div class='notice'>The bot is in maintenance mode and cannot be controlled.</div><BR>"
|
||||
|
||||
user << browse("<HEAD><TITLE>Mulebot [suffix ? "([suffix])" : ""]</TITLE></HEAD>[dat]", "window=mulebot;size=350x500")
|
||||
onclose(user, "mulebot")
|
||||
//user << browse("<HEAD><TITLE>M.U.L.E. Mk. III [suffix ? "([suffix])" : ""]</TITLE></HEAD>[dat]", "window=mulebot;size=350x500")
|
||||
//onclose(user, "mulebot")
|
||||
var/datum/browser/popup = new(user, "mulebot", "M.U.L.E. Mk. V [suffix ? "([suffix])" : ""]", 350, 500)
|
||||
popup.set_content(dat)
|
||||
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
|
||||
popup.open()
|
||||
return
|
||||
|
||||
// returns the wire panel text
|
||||
@@ -255,7 +253,7 @@ var/global/mulebot_count = 0
|
||||
return
|
||||
if (usr.stat)
|
||||
return
|
||||
if ((in_range(src, usr) && istype(src.loc, /turf)) || (istype(usr, /mob/living/silicon)))
|
||||
if ((in_range(src, usr) && istype(loc, /turf)) || (istype(usr, /mob/living/silicon)))
|
||||
usr.set_machine(src)
|
||||
|
||||
switch(href_list["op"])
|
||||
@@ -263,11 +261,11 @@ var/global/mulebot_count = 0
|
||||
toggle_lock(usr)
|
||||
|
||||
if("power")
|
||||
if (src.on)
|
||||
if (on)
|
||||
turn_off()
|
||||
else if (cell && !open)
|
||||
if (!turn_on())
|
||||
usr << "\red You can't switch on [src]."
|
||||
usr << "<span class='danger'>You can't switch on [src].</span>"
|
||||
return
|
||||
else
|
||||
return
|
||||
@@ -282,7 +280,7 @@ var/global/mulebot_count = 0
|
||||
cell.add_fingerprint(usr)
|
||||
cell = null
|
||||
|
||||
usr.visible_message("\blue [usr] removes the power cell from [src].", "\blue You remove the power cell from [src].")
|
||||
usr.visible_message("<span class='notice'>[usr] removes the power cell from [src].</span>", "<span class='notice'>You remove the power cell from [src].</span>")
|
||||
updateDialog()
|
||||
|
||||
if("cellinsert")
|
||||
@@ -294,28 +292,28 @@ var/global/mulebot_count = 0
|
||||
C.loc = src
|
||||
C.add_fingerprint(usr)
|
||||
|
||||
usr.visible_message("\blue [usr] inserts a power cell into [src].", "\blue You insert the power cell into [src].")
|
||||
usr.visible_message("<span class='notice'>[usr] inserts a power cell into [src].</span>", "<span class='notice'>You insert the power cell into [src].</span>")
|
||||
updateDialog()
|
||||
|
||||
|
||||
if("stop")
|
||||
if(mode >=2)
|
||||
mode = 0
|
||||
if(mode >= BOT_DELIVER)
|
||||
bot_reset()
|
||||
updateDialog()
|
||||
|
||||
if("go")
|
||||
if(mode == 0)
|
||||
if(mode == BOT_IDLE)
|
||||
start()
|
||||
updateDialog()
|
||||
|
||||
if("home")
|
||||
if(mode == 0 || mode == 2)
|
||||
if(mode == BOT_IDLE || mode == BOT_DELIVER)
|
||||
start_home()
|
||||
updateDialog()
|
||||
|
||||
if("destination")
|
||||
refresh=0
|
||||
var/new_dest = input("Enter new destination tag", "Mulebot [suffix ? "([suffix])" : ""]", destination) as text|null
|
||||
var/new_dest = input("Select M.U.L.E. Destination", "Mulebot [suffix ? "([suffix])" : ""]", destination) as null|anything in delivery_beacons
|
||||
refresh=1
|
||||
if(new_dest)
|
||||
set_destination(new_dest)
|
||||
@@ -351,12 +349,15 @@ var/global/mulebot_count = 0
|
||||
if("autopick")
|
||||
auto_pickup = !auto_pickup
|
||||
|
||||
if("report")
|
||||
report_delivery = !report_delivery
|
||||
|
||||
if("close")
|
||||
usr.unset_machine()
|
||||
usr << browse(null,"window=mulebot")
|
||||
|
||||
updateDialog()
|
||||
//src.updateUsrDialog()
|
||||
//updateUsrDialog()
|
||||
else
|
||||
usr << browse(null, "window=mulebot")
|
||||
usr.unset_machine()
|
||||
@@ -369,12 +370,12 @@ var/global/mulebot_count = 0
|
||||
return !open && cell && cell.charge > 0 && wires.HasPower()
|
||||
|
||||
/obj/machinery/bot/mulebot/proc/toggle_lock(var/mob/user)
|
||||
if(src.allowed(user))
|
||||
if(allowed(user))
|
||||
locked = !locked
|
||||
updateDialog()
|
||||
return 1
|
||||
else
|
||||
user << "\red Access denied."
|
||||
user << "<span class='danger'>Access denied.</span>"
|
||||
return 0
|
||||
|
||||
// mousedrop a crate to load the bot
|
||||
@@ -397,8 +398,8 @@ var/global/mulebot_count = 0
|
||||
// called to load a crate
|
||||
/obj/machinery/bot/mulebot/proc/load(var/atom/movable/C)
|
||||
if(wires.LoadCheck() && !istype(C,/obj/structure/closet/crate))
|
||||
src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
|
||||
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
|
||||
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
return // if not emagged, only allow crates to be loaded
|
||||
|
||||
//I'm sure someone will come along and ask why this is here... well people were dragging screen items onto the mule, and that was not cool.
|
||||
@@ -410,19 +411,16 @@ var/global/mulebot_count = 0
|
||||
|
||||
if(get_dist(C, src) > 1 || load || !on)
|
||||
return
|
||||
for(var/obj/structure/plasticflaps/P in src.loc)//Takes flaps into account
|
||||
if(!CanPass(C,P))
|
||||
return
|
||||
mode = 1
|
||||
mode = BOT_LOADING
|
||||
|
||||
// if a create, close before loading
|
||||
var/obj/structure/closet/crate/crate = C
|
||||
if(istype(crate))
|
||||
crate.close()
|
||||
|
||||
C.loc = src.loc
|
||||
C.loc = loc
|
||||
sleep(2)
|
||||
if(C.loc != src.loc) //To prevent you from going onto more thano ne bot.
|
||||
if(C.loc != loc) //To prevent you from going onto more thano ne bot.
|
||||
return
|
||||
C.loc = src
|
||||
load = C
|
||||
@@ -438,22 +436,19 @@ var/global/mulebot_count = 0
|
||||
M.client.perspective = EYE_PERSPECTIVE
|
||||
M.client.eye = src
|
||||
|
||||
mode = 0
|
||||
mode = BOT_IDLE
|
||||
send_status()
|
||||
|
||||
// called to unload the bot
|
||||
// argument is optional direction to unload
|
||||
// if zero, unload at bot's location
|
||||
/obj/machinery/bot/mulebot/proc/unload(var/dirn = 0)
|
||||
/obj/machinery/bot/mulebot/proc/unload(var/dirn)
|
||||
if(!load)
|
||||
return
|
||||
|
||||
mode = 1
|
||||
mode = BOT_LOADING
|
||||
overlays.Cut()
|
||||
|
||||
load.loc = src.loc
|
||||
load.pixel_y -= 9
|
||||
load.layer = initial(load.layer)
|
||||
if(ismob(load))
|
||||
var/mob/M = load
|
||||
if(M.client)
|
||||
@@ -461,13 +456,14 @@ var/global/mulebot_count = 0
|
||||
M.client.eye = src
|
||||
|
||||
|
||||
load.loc = loc
|
||||
load.pixel_y -= 9
|
||||
load.layer = initial(load.layer)
|
||||
if(dirn)
|
||||
var/turf/T = src.loc
|
||||
T = get_step(T,dirn)
|
||||
if(CanPass(load,T))//Can't get off onto anything that wouldn't let you pass normally
|
||||
var/turf/T = loc
|
||||
var/turf/newT = get_step(T,dirn)
|
||||
if(load.CanPass(load,newT)) //Can't get off onto anything that wouldn't let you pass normally
|
||||
step(load, dirn)
|
||||
else
|
||||
load.loc = src.loc//Drops you right there, so you shouldn't be able to get yourself stuck
|
||||
|
||||
load = null
|
||||
|
||||
@@ -476,9 +472,9 @@ var/global/mulebot_count = 0
|
||||
// with items dropping as mobs are loaded
|
||||
|
||||
for(var/atom/movable/AM in src)
|
||||
if(AM == cell || AM == botcard) continue
|
||||
if(AM == cell || istype(AM , botcard) || AM == Radio) continue
|
||||
|
||||
AM.loc = src.loc
|
||||
AM.loc = loc
|
||||
AM.layer = initial(AM.layer)
|
||||
AM.pixel_y = initial(AM.pixel_y)
|
||||
if(ismob(AM))
|
||||
@@ -486,47 +482,56 @@ var/global/mulebot_count = 0
|
||||
if(M.client)
|
||||
M.client.perspective = MOB_PERSPECTIVE
|
||||
M.client.eye = src
|
||||
mode = 0
|
||||
mode = BOT_IDLE
|
||||
|
||||
/obj/machinery/bot/mulebot/call_bot()
|
||||
..()
|
||||
var/area/dest_area
|
||||
if (path && path.len)
|
||||
target = ai_waypoint //Target is the end point of the path, the waypoint set by the AI.
|
||||
dest_area = get_area(target)
|
||||
destination = format_text(dest_area.name)
|
||||
pathset = 1 //Indicates the AI's custom path is initialized.
|
||||
start()
|
||||
|
||||
/obj/machinery/bot/mulebot/process()
|
||||
/obj/machinery/bot/mulebot/bot_process()
|
||||
if(!has_power())
|
||||
on = 0
|
||||
return
|
||||
if(on)
|
||||
var/speed = (wires.Motor1() ? 1 : 0) + (wires.Motor2() ? 2 : 0)
|
||||
//world << "speed: [speed]"
|
||||
var/num_steps = 0
|
||||
switch(speed)
|
||||
if(0)
|
||||
// do nothing
|
||||
if(1)
|
||||
process_bot()
|
||||
spawn(2)
|
||||
process_bot()
|
||||
sleep(2)
|
||||
process_bot()
|
||||
sleep(2)
|
||||
process_bot()
|
||||
sleep(2)
|
||||
process_bot()
|
||||
num_steps = 10
|
||||
if(2)
|
||||
process_bot()
|
||||
spawn(4)
|
||||
process_bot()
|
||||
num_steps = 5
|
||||
if(3)
|
||||
process_bot()
|
||||
num_steps = 3
|
||||
|
||||
if(num_steps)
|
||||
process_bot()
|
||||
num_steps--
|
||||
spawn(0)
|
||||
for(var/i=num_steps,i>0,i--)
|
||||
sleep(2)
|
||||
process_bot()
|
||||
|
||||
if(refresh) updateDialog()
|
||||
|
||||
/obj/machinery/bot/mulebot/proc/process_bot()
|
||||
//if(mode) world << "Mode: [mode]"
|
||||
|
||||
switch(mode)
|
||||
if(0) // idle
|
||||
if(BOT_IDLE) // idle
|
||||
icon_state = "mulebot0"
|
||||
return
|
||||
if(1) // loading/unloading
|
||||
if(BOT_LOADING) // loading/unloading
|
||||
return
|
||||
if(2,3,4) // navigating to deliver,home, or blocked
|
||||
if(BOT_DELIVER,BOT_GO_HOME,BOT_BLOCKED) // navigating to deliver,home, or blocked
|
||||
|
||||
if(loc == target) // reached target
|
||||
at_target()
|
||||
@@ -539,26 +544,28 @@ var/global/mulebot_count = 0
|
||||
if(next == loc)
|
||||
path -= next
|
||||
return
|
||||
|
||||
|
||||
if(istype( next, /turf/simulated))
|
||||
//world << "at ([x],[y]) moving to ([next.x],[next.y])"
|
||||
if(bloodiness)
|
||||
var/turf/simulated/T=loc
|
||||
if(istype(T))
|
||||
var/goingdir=0
|
||||
|
||||
var/newdir = get_dir(next, loc)
|
||||
if(newdir == dir)
|
||||
goingdir = newdir
|
||||
else
|
||||
newdir = newdir | dir
|
||||
if(newdir == 3)
|
||||
newdir = 1
|
||||
else if(newdir == 12)
|
||||
newdir = 4
|
||||
goingdir = newdir
|
||||
T.AddTracks(/obj/effect/decal/cleanable/blood/tracks/wheels,list(),0,goingdir,currentBloodColor)
|
||||
|
||||
if(bloodiness)
|
||||
var/obj/effect/decal/cleanable/blood/tracks/B = new(loc)
|
||||
var/newdir = get_dir(next, loc)
|
||||
if(newdir == dir)
|
||||
B.dir = newdir
|
||||
else
|
||||
newdir = newdir | dir
|
||||
if(newdir == 3)
|
||||
newdir = 1
|
||||
else if(newdir == 12)
|
||||
newdir = 4
|
||||
B.dir = newdir
|
||||
bloodiness--
|
||||
|
||||
|
||||
|
||||
var/moved = step_towards(src, next) // attempt to move
|
||||
if(cell) cell.use(1)
|
||||
if(moved) // successful move
|
||||
@@ -567,14 +574,14 @@ var/global/mulebot_count = 0
|
||||
path -= loc
|
||||
|
||||
|
||||
if(mode==4)
|
||||
if(mode == BOT_BLOCKED)
|
||||
spawn(1)
|
||||
send_status()
|
||||
|
||||
if(destination == home_destination)
|
||||
mode = 3
|
||||
mode = BOT_GO_HOME
|
||||
else
|
||||
mode = 2
|
||||
mode = BOT_DELIVER
|
||||
|
||||
else // failed to move
|
||||
|
||||
@@ -583,73 +590,74 @@ var/global/mulebot_count = 0
|
||||
|
||||
|
||||
blockcount++
|
||||
mode = 4
|
||||
mode = BOT_BLOCKED
|
||||
if(blockcount == 3)
|
||||
src.visible_message("[src] makes an annoyed buzzing sound.", "You hear an electronic buzzing sound.")
|
||||
playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0)
|
||||
visible_message("[src] makes an annoyed buzzing sound.", "You hear an electronic buzzing sound.")
|
||||
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
|
||||
|
||||
if(blockcount > 5) // attempt 5 times before recomputing
|
||||
if(blockcount > 10) // attempt 10 times before recomputing
|
||||
// find new path excluding blocked turf
|
||||
src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
|
||||
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
|
||||
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
|
||||
spawn(2)
|
||||
calc_path(next)
|
||||
if(path.len > 0)
|
||||
src.visible_message("[src] makes a delighted ping!", "You hear a ping.")
|
||||
playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
|
||||
mode = 4
|
||||
mode =6
|
||||
visible_message("[src] makes a delighted ping!", "You hear a ping.")
|
||||
playsound(loc, 'sound/machines/ping.ogg', 50, 0)
|
||||
mode = BOT_BLOCKED
|
||||
mode = BOT_WAIT_FOR_NAV
|
||||
return
|
||||
return
|
||||
else
|
||||
src.visible_message("[src] makes an annoyed buzzing sound.", "You hear an electronic buzzing sound.")
|
||||
playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0)
|
||||
visible_message("[src] makes an annoyed buzzing sound.", "You hear an electronic buzzing sound.")
|
||||
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
|
||||
//world << "Bad turf."
|
||||
mode = 5
|
||||
mode = BOT_NAV
|
||||
return
|
||||
else
|
||||
//world << "No path."
|
||||
mode = 5
|
||||
mode = BOT_NAV
|
||||
return
|
||||
|
||||
if(5) // calculate new path
|
||||
if(BOT_NAV) // calculate new path
|
||||
//world << "Calc new path."
|
||||
mode = 6
|
||||
mode = BOT_WAIT_FOR_NAV
|
||||
spawn(0)
|
||||
|
||||
calc_path()
|
||||
|
||||
if(path.len > 0)
|
||||
blockcount = 0
|
||||
mode = 4
|
||||
src.visible_message("[src] makes a delighted ping!", "You hear a ping.")
|
||||
playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
|
||||
mode = BOT_BLOCKED
|
||||
visible_message("[src] makes a delighted ping!", "You hear a ping.")
|
||||
playsound(loc, 'sound/machines/ping.ogg', 50, 0)
|
||||
|
||||
else
|
||||
src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
|
||||
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
|
||||
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
|
||||
mode = 7
|
||||
mode = BOT_NO_ROUTE
|
||||
//if(6)
|
||||
//world << "Pending path calc."
|
||||
//if(7)
|
||||
//world << "No dest / no route."
|
||||
|
||||
return
|
||||
|
||||
|
||||
// calculates a path to the current destination
|
||||
// given an optional turf to avoid
|
||||
/obj/machinery/bot/mulebot/proc/calc_path(var/turf/avoid = null)
|
||||
src.path = AStar(src.loc, src.target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 250, id=botcard, exclude=avoid)
|
||||
if(!src.path)
|
||||
src.path = list()
|
||||
/obj/machinery/bot/mulebot/calc_path(var/turf/avoid = null)
|
||||
path = AStar(loc, target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 250, id=botcard, exclude=avoid)
|
||||
if(!path)
|
||||
path = list()
|
||||
|
||||
|
||||
// sets the current destination
|
||||
// signals all beacons matching the delivery code
|
||||
// beacons will return a signal giving their locations
|
||||
/obj/machinery/bot/mulebot/proc/set_destination(var/new_dest)
|
||||
/obj/machinery/bot/mulebot/set_destination(var/new_dest)
|
||||
spawn(0)
|
||||
new_destination = new_dest
|
||||
post_signal(beacon_freq, "findbeacon", "delivery")
|
||||
@@ -658,9 +666,9 @@ var/global/mulebot_count = 0
|
||||
// starts bot moving to current destination
|
||||
/obj/machinery/bot/mulebot/proc/start()
|
||||
if(destination == home_destination)
|
||||
mode = 3
|
||||
mode = BOT_GO_HOME
|
||||
else
|
||||
mode = 2
|
||||
mode = BOT_DELIVER
|
||||
icon_state = "mulebot[(wires.MobAvoid() != 0)]"
|
||||
|
||||
// starts bot moving to home
|
||||
@@ -668,17 +676,27 @@ var/global/mulebot_count = 0
|
||||
/obj/machinery/bot/mulebot/proc/start_home()
|
||||
spawn(0)
|
||||
set_destination(home_destination)
|
||||
mode = 4
|
||||
mode = BOT_BLOCKED
|
||||
icon_state = "mulebot[(wires.MobAvoid() != 0)]"
|
||||
|
||||
// called when bot reaches current target
|
||||
/obj/machinery/bot/mulebot/proc/at_target()
|
||||
if(!reached_target)
|
||||
src.visible_message("[src] makes a chiming sound!", "You hear a chime.")
|
||||
playsound(src.loc, 'sound/machines/chime.ogg', 50, 0)
|
||||
radio_frequency = SUP_FREQ //Supply channel
|
||||
visible_message("[src] makes a chiming sound!", "You hear a chime.")
|
||||
playsound(loc, 'sound/machines/chime.ogg', 50, 0)
|
||||
reached_target = 1
|
||||
|
||||
if(pathset) //The AI called us here, so notify it of our arrival.
|
||||
loaddir = dir //The MULE will attempt to load a crate in whatever direction the MULE is "facing".
|
||||
if(calling_ai)
|
||||
calling_ai << "<span class='notice'>\icon[src] [src] wirelessly plays a chiming sound!</span>"
|
||||
playsound(calling_ai, 'sound/machines/chime.ogg',40, 0)
|
||||
calling_ai = null
|
||||
radio_frequency = AIPRIV_FREQ //Report on AI Private instead if the AI is controlling us.
|
||||
|
||||
if(load) // if loaded, unload at target
|
||||
speak("Destination <b>[destination]</b> reached. Unloading [load]."/*,radio_frequency*/)
|
||||
unload(loaddir)
|
||||
else
|
||||
// not loaded
|
||||
@@ -693,14 +711,16 @@ var/global/mulebot_count = 0
|
||||
AM = locate(/obj/structure/closet/crate) in get_step(loc,loaddir)
|
||||
if(AM)
|
||||
load(AM)
|
||||
if(report_delivery)
|
||||
speak("Now loading [load] at <b>[get_area(src)]</b>."/*,radio_frequency*/)
|
||||
// whatever happened, check to see if we return home
|
||||
|
||||
if(auto_return && destination != home_destination)
|
||||
// auto return set and not at home already
|
||||
start_home()
|
||||
mode = 4
|
||||
mode = BOT_BLOCKED
|
||||
else
|
||||
mode = 0 // otherwise go idle
|
||||
bot_reset() // otherwise go idle
|
||||
|
||||
send_status() // report status to anyone listening
|
||||
|
||||
@@ -712,23 +732,22 @@ var/global/mulebot_count = 0
|
||||
var/mob/M = obs
|
||||
if(ismob(M))
|
||||
if(istype(M,/mob/living/silicon/robot))
|
||||
src.visible_message("\red [src] bumps into [M]!")
|
||||
visible_message("<span class='danger'>[src] bumps into [M]!</span>")
|
||||
else
|
||||
src.visible_message("\red [src] knocks over [M]!")
|
||||
visible_message("<span class='danger'>[src] knocks over [M]!</span>")
|
||||
M.stop_pulling()
|
||||
M.Stun(8)
|
||||
M.Weaken(5)
|
||||
M.lying = 1
|
||||
..()
|
||||
|
||||
/obj/machinery/bot/mulebot/alter_health()
|
||||
return get_turf(src)
|
||||
|
||||
|
||||
// called from mob/living/carbon/human/HasEntered()
|
||||
// called from mob/living/carbon/human/Crossed()
|
||||
// when mulebot is in the same loc
|
||||
/obj/machinery/bot/mulebot/proc/RunOver(var/mob/living/carbon/human/H)
|
||||
src.visible_message("\red [src] drives over [H]!")
|
||||
visible_message("\red [src] drives over [H]!")
|
||||
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1)
|
||||
|
||||
var/damage = rand(5,15)
|
||||
@@ -746,12 +765,6 @@ var/global/mulebot_count = 0
|
||||
bloodiness += 4
|
||||
currentBloodColor="#A10808" // For if species get different blood colors.
|
||||
|
||||
/obj/machinery/bot/mulebot/proc/RunOverCreature(var/mob/living/H,var/bloodcolor)
|
||||
src.visible_message("\red [src] drives over [H]!")
|
||||
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1)
|
||||
bloodiness += 4
|
||||
currentBloodColor=bloodcolor // For if species get different blood colors.
|
||||
|
||||
// player on mulebot attempted to move
|
||||
/obj/machinery/bot/mulebot/relaymove(var/mob/user)
|
||||
if(user.stat)
|
||||
@@ -784,7 +797,7 @@ var/global/mulebot_count = 0
|
||||
// process control input
|
||||
switch(recv)
|
||||
if("stop")
|
||||
mode = 0
|
||||
bot_reset()
|
||||
return
|
||||
|
||||
if("go")
|
||||
@@ -820,6 +833,7 @@ var/global/mulebot_count = 0
|
||||
|
||||
// receive response from beacon
|
||||
recv = signal.data["beacon"]
|
||||
|
||||
if(wires.BeaconRX())
|
||||
if(recv == new_destination) // if the recvd beacon location matches the set destination
|
||||
// the we will navigate there
|
||||
@@ -834,12 +848,18 @@ var/global/mulebot_count = 0
|
||||
calc_path()
|
||||
updateDialog()
|
||||
|
||||
//Detects and stores current active delivery beacons.
|
||||
if(signal.data["beacon"])
|
||||
if(!delivery_beacons)
|
||||
delivery_beacons = new()
|
||||
delivery_beacons[signal.data["beacon"] ] = signal.source
|
||||
|
||||
// send a radio signal with a single data key/value pair
|
||||
/obj/machinery/bot/mulebot/proc/post_signal(var/freq, var/key, var/value)
|
||||
/obj/machinery/bot/mulebot/post_signal(var/freq, var/key, var/value)
|
||||
post_signal_multiple(freq, list("[key]" = value) )
|
||||
|
||||
// send a radio signal with multiple data key/values
|
||||
/obj/machinery/bot/mulebot/proc/post_signal_multiple(var/freq, var/list/keyval)
|
||||
/obj/machinery/bot/mulebot/post_signal_multiple(var/freq, var/list/keyval)
|
||||
|
||||
if(freq == beacon_freq && !(wires.BeaconRX()))
|
||||
return
|
||||
@@ -861,17 +881,17 @@ var/global/mulebot_count = 0
|
||||
//world << "sent [key],[keyval[key]] on [freq]"
|
||||
if (signal.data["findbeacon"])
|
||||
frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
|
||||
else if (signal.data["type"] == "mulebot")
|
||||
else if (signal.data["type"] == MULE_BOT)
|
||||
frequency.post_signal(src, signal, filter = RADIO_MULEBOT)
|
||||
else
|
||||
frequency.post_signal(src, signal)
|
||||
|
||||
// signals bot status etc. to controller
|
||||
/obj/machinery/bot/mulebot/proc/send_status()
|
||||
/obj/machinery/bot/mulebot/send_status()
|
||||
var/list/kv = list(
|
||||
"type" = "mulebot",
|
||||
"type" = MULE_BOT,
|
||||
"name" = suffix,
|
||||
"loca" = (loc ? loc.loc : "Unknown"), // somehow loc can be null and cause a runtime - Quarxink
|
||||
"loca" = get_area(src),
|
||||
"mode" = mode,
|
||||
"powr" = (cell ? cell.percent() : 0),
|
||||
"dest" = destination,
|
||||
@@ -891,7 +911,7 @@ var/global/mulebot_count = 0
|
||||
|
||||
|
||||
/obj/machinery/bot/mulebot/explode()
|
||||
src.visible_message("\red <B>[src] blows apart!</B>", 1)
|
||||
visible_message("<span class='userdanger'>[src] blows apart!</span>")
|
||||
var/turf/Tsec = get_turf(src)
|
||||
|
||||
new /obj/item/device/assembly/prox_sensor(Tsec)
|
||||
@@ -907,6 +927,6 @@ var/global/mulebot_count = 0
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
|
||||
new /obj/effect/decal/cleanable/oil(src.loc)
|
||||
new /obj/effect/decal/cleanable/oil(loc)
|
||||
unload(0)
|
||||
del(src)
|
||||
qdel(src)
|
||||
|
||||
+229
-534
@@ -1,5 +1,5 @@
|
||||
/obj/machinery/bot/secbot
|
||||
name = "Securitron"
|
||||
name = "\improper Securitron"
|
||||
desc = "A little security robot. He looks less than thrilled."
|
||||
icon = 'icons/obj/aibots.dmi'
|
||||
icon_state = "secbot0"
|
||||
@@ -17,41 +17,15 @@
|
||||
var/threatlevel = 0
|
||||
var/target_lastloc //Loc of target when arrested.
|
||||
var/last_found //There's a delay
|
||||
var/frustration = 0
|
||||
// var/emagged = 0 //Emagged Secbots view everyone as a criminal
|
||||
var/declare_arrests = 1 //When making an arrest, should it notify everyone wearing sechuds?
|
||||
var/declare_arrests = 1 //When making an arrest, should it notify everyone on the security channel?
|
||||
var/idcheck = 0 //If true, arrest people with no IDs
|
||||
var/weaponscheck = 1 //If true, arrest people for weapons if they don't have access
|
||||
var/weaponscheck = 1 //If true, arrest people for weapons if they lack access
|
||||
var/check_records = 1 //Does it check security records?
|
||||
var/arrest_type = 0 //If true, don't handcuff
|
||||
var/next_harm_time = 0
|
||||
|
||||
var/mode = 0
|
||||
#define SECBOT_IDLE 0 // idle
|
||||
#define SECBOT_HUNT 1 // found target, hunting
|
||||
#define SECBOT_PREP_ARREST 2 // at target, preparing to arrest
|
||||
#define SECBOT_ARREST 3 // arresting target
|
||||
#define SECBOT_START_PATROL 4 // start patrol
|
||||
#define SECBOT_PATROL 5 // patrolling
|
||||
#define SECBOT_SUMMON 6 // summoned by PDA
|
||||
|
||||
var/auto_patrol = 0 // set to make bot automatically patrol
|
||||
|
||||
var/beacon_freq = 1445 // navigation beacon frequency
|
||||
var/control_freq = 1447 // bot control frequency
|
||||
|
||||
|
||||
var/turf/patrol_target // this is turf to navigate to (location of beacon)
|
||||
var/new_destination // pending new destination (waiting for beacon response)
|
||||
var/destination // destination description tag
|
||||
var/next_destination // the next destination in the patrol route
|
||||
var/list/path = new // list of path turfs
|
||||
|
||||
var/blockcount = 0 //number of times retried a blocked path
|
||||
var/awaiting_beacon = 0 // count of pticks awaiting a beacon response
|
||||
|
||||
var/nearest_beacon // the nearest beacon's tag
|
||||
var/turf/nearest_beacon_loc // the nearest beacon's location
|
||||
radio_frequency = SEC_FREQ //Security channel
|
||||
bot_type = SEC_BOT
|
||||
bot_filter = RADIO_SECBOT
|
||||
|
||||
//List of weapons that secbots will not arrest for
|
||||
var/safe_weapons = list(\
|
||||
@@ -59,24 +33,24 @@
|
||||
/obj/item/weapon/gun/energy/laser/redtag,\
|
||||
/obj/item/weapon/gun/energy/laser/practice,\
|
||||
/obj/item/weapon/melee/telebaton,\
|
||||
/obj/item/weapon/melee/baton/loaded/ntcane)
|
||||
/obj/item/weapon/gun/energy/kinetic_accelerator)
|
||||
|
||||
|
||||
/obj/machinery/bot/secbot/beepsky
|
||||
name = "Officer Beep O'sky"
|
||||
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
|
||||
idcheck = 0
|
||||
weaponscheck = 1
|
||||
weaponscheck = 0
|
||||
auto_patrol = 1
|
||||
|
||||
/obj/machinery/bot/secbot/pingsky
|
||||
name = "Officer Pingsky"
|
||||
desc = "It's Officer Pingsky! Delegated to satellite guard duty for harbouring anti-human sentiment."
|
||||
declare_arrests = 0
|
||||
radio_frequency = AIPRIV_FREQ
|
||||
|
||||
/obj/item/weapon/secbot_assembly
|
||||
name = "helmet/signaler assembly"
|
||||
desc = "Some sort of bizarre assembly."
|
||||
name = "incomplete securitron assembly"
|
||||
desc = "Some sort of bizarre assembly made from a proximity sensor, helmet, and signaler."
|
||||
icon = 'icons/obj/aibots.dmi'
|
||||
icon_state = "helmet_signaler"
|
||||
item_state = "helmet"
|
||||
@@ -87,30 +61,38 @@
|
||||
|
||||
/obj/machinery/bot/secbot/New()
|
||||
..()
|
||||
src.icon_state = "secbot[src.on]"
|
||||
icon_state = "secbot[on]"
|
||||
spawn(3)
|
||||
src.botcard = new /obj/item/weapon/card/id(src)
|
||||
var/datum/job/detective/J = new /datum/job/detective
|
||||
src.botcard.access = J.get_access()
|
||||
if(radio_controller)
|
||||
radio_controller.add_object(src, control_freq, filter = RADIO_SECBOT)
|
||||
radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
|
||||
|
||||
var/datum/job/detective/J = new/datum/job/detective
|
||||
botcard.access = J.get_access()
|
||||
prev_access = botcard.access
|
||||
add_to_beacons(bot_filter)
|
||||
|
||||
|
||||
/obj/machinery/bot/secbot/turn_on()
|
||||
..()
|
||||
src.icon_state = "secbot[src.on]"
|
||||
src.updateUsrDialog()
|
||||
icon_state = "secbot[on]"
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/bot/secbot/turn_off()
|
||||
..()
|
||||
src.target = null
|
||||
src.oldtarget_name = null
|
||||
src.anchored = 0
|
||||
src.mode = SECBOT_IDLE
|
||||
icon_state = "secbot[on]"
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/bot/secbot/bot_reset()
|
||||
..()
|
||||
target = null
|
||||
oldtarget_name = null
|
||||
anchored = 0
|
||||
walk_to(src,0)
|
||||
src.icon_state = "secbot[src.on]"
|
||||
src.updateUsrDialog()
|
||||
last_found = world.time
|
||||
|
||||
/obj/machinery/bot/secbot/set_custom_texts()
|
||||
|
||||
text_hack = "You overload [name]'s target identification system."
|
||||
text_dehack = "You reboot [name] and restore the target identification."
|
||||
text_dehack_fail = "[name] refuses to accept your authority!"
|
||||
|
||||
/obj/machinery/bot/secbot/attack_hand(mob/user as mob)
|
||||
. = ..()
|
||||
@@ -121,151 +103,123 @@
|
||||
|
||||
/obj/machinery/bot/secbot/interact(mob/user as mob)
|
||||
var/dat
|
||||
|
||||
dat += hack(user)
|
||||
dat += text({"
|
||||
<TT><B>Securitron v1.6 controls</B></TT><BR><BR>
|
||||
Status: []<BR>
|
||||
Behaviour controls are [src.locked ? "locked" : "unlocked"]<BR>
|
||||
Maintenance panel panel is [src.open ? "opened" : "closed"]<BR>"},
|
||||
Behaviour controls are [locked ? "locked" : "unlocked"]<BR>
|
||||
Maintenance panel panel is [open ? "opened" : "closed"]"},
|
||||
|
||||
"<A href='?src=\ref[src];power=1'>[src.on ? "On" : "Off"]</A>" )
|
||||
"<A href='?src=\ref[src];power=1'>[on ? "On" : "Off"]</A>" )
|
||||
|
||||
if(!src.locked || issilicon(user))
|
||||
if(!locked || issilicon(user))
|
||||
dat += text({"<BR>
|
||||
Arrest for No ID: []<BR>
|
||||
Arrest Unidentifiable Persons: []<BR>
|
||||
Arrest for Unauthorized Weapons: []<BR>
|
||||
Arrest for Warrant: []<BR>
|
||||
<BR>
|
||||
Operating Mode: []<BR>
|
||||
Report Arrests[]<BR>
|
||||
Auto Patrol: []"},
|
||||
|
||||
"<A href='?src=\ref[src];operation=idcheck'>[src.idcheck ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=\ref[src];operation=weaponscheck'>[src.weaponscheck ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=\ref[src];operation=ignorerec'>[src.check_records ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=\ref[src];operation=switchmode'>[src.arrest_type ? "Detain" : "Arrest"]</A>",
|
||||
"<A href='?src=\ref[src];operation=declarearrests'>[src.declare_arrests ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=\ref[src];operation=idcheck'>[idcheck ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=\ref[src];operation=weaponscheck'>[weaponscheck ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=\ref[src];operation=ignorerec'>[check_records ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=\ref[src];operation=switchmode'>[arrest_type ? "Detain" : "Arrest"]</A>",
|
||||
"<A href='?src=\ref[src];operation=declarearrests'>[declare_arrests ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=\ref[src];operation=patrol'>[auto_patrol ? "On" : "Off"]</A>" )
|
||||
|
||||
var/datum/browser/popup = new(user, "autosec", "Securitron v1.5 controls")
|
||||
var/datum/browser/popup = new(user, "autosec", "Automatic Security Unit v1.6")
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
return
|
||||
|
||||
/obj/machinery/bot/secbot/Topic(href, href_list)
|
||||
usr.set_machine(src)
|
||||
src.add_fingerprint(usr)
|
||||
if((href_list["power"]) && (src.allowed(usr)))
|
||||
if(src.on)
|
||||
turn_off()
|
||||
else
|
||||
turn_on()
|
||||
return
|
||||
|
||||
..()
|
||||
|
||||
switch(href_list["operation"])
|
||||
if("idcheck")
|
||||
src.idcheck = !src.idcheck
|
||||
src.updateUsrDialog()
|
||||
idcheck = !idcheck
|
||||
updateUsrDialog()
|
||||
if("weaponscheck")
|
||||
src.weaponscheck = !src.weaponscheck
|
||||
src.updateUsrDialog()
|
||||
weaponscheck = !weaponscheck
|
||||
updateUsrDialog()
|
||||
if("ignorerec")
|
||||
src.check_records = !src.check_records
|
||||
src.updateUsrDialog()
|
||||
check_records = !check_records
|
||||
updateUsrDialog()
|
||||
if("switchmode")
|
||||
src.arrest_type = !src.arrest_type
|
||||
src.updateUsrDialog()
|
||||
if("patrol")
|
||||
auto_patrol = !auto_patrol
|
||||
mode = SECBOT_IDLE
|
||||
arrest_type = !arrest_type
|
||||
updateUsrDialog()
|
||||
if("declarearrests")
|
||||
src.declare_arrests = !src.declare_arrests
|
||||
src.updateUsrDialog()
|
||||
if("hack")
|
||||
if(!src.emagged)
|
||||
src.emagged = 2
|
||||
src.hacked = 1
|
||||
usr << "<span class='warning'>You overload [src]'s target identification system.</span>"
|
||||
else if(!src.hacked)
|
||||
usr << "<span class='userdanger'>[src] refuses to accept your authority!</span>"
|
||||
else
|
||||
src.emagged = 0
|
||||
src.hacked = 0
|
||||
usr << "<span class='notice'>You reboot [src] and restore the target identification.</span>"
|
||||
src.updateUsrDialog()
|
||||
declare_arrests = !declare_arrests
|
||||
updateUsrDialog()
|
||||
|
||||
|
||||
/obj/machinery/bot/secbot/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
|
||||
if(src.allowed(user) && !open && !emagged)
|
||||
src.locked = !src.locked
|
||||
user << "Controls are now [src.locked ? "locked." : "unlocked."]"
|
||||
if(allowed(user) && !open && !emagged)
|
||||
locked = !locked
|
||||
user << "Controls are now [locked ? "locked." : "unlocked."]"
|
||||
updateUsrDialog()
|
||||
else
|
||||
if(emagged)
|
||||
user << "<span class='warning'>ERROR</span>"
|
||||
if(open)
|
||||
user << "\red Please close the access panel before locking it."
|
||||
user << "<span class='danger'>Please close the access panel before locking it.</span>"
|
||||
else
|
||||
user << "\red Access denied."
|
||||
user << "<span class='danger'> Access denied.</span>"
|
||||
else
|
||||
..()
|
||||
if(!istype(W, /obj/item/weapon/screwdriver) && (W.force) && (!src.target))
|
||||
src.target = user
|
||||
src.mode = SECBOT_HUNT
|
||||
if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != "harm") // Any intent but harm will heal, so we shouldn't get angry.
|
||||
return
|
||||
if(!istype(W, /obj/item/weapon/screwdriver) && (W.force) && (!target)) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
|
||||
threatlevel = user.assess_threat(src)
|
||||
threatlevel += 6
|
||||
if(threatlevel >= 4)
|
||||
target = user
|
||||
mode = BOT_HUNT
|
||||
|
||||
/obj/machinery/bot/secbot/Emag(mob/user as mob)
|
||||
..()
|
||||
if((!locked && open) || !user)
|
||||
if(user) user << "\red You short out [src]'s target assessment circuits."
|
||||
spawn(0)
|
||||
for(var/mob/O in hearers(src, null))
|
||||
O.show_message("\red <B>[src] buzzes oddly!</B>", 1)
|
||||
src.target = null
|
||||
if(user) src.oldtarget_name = user.name
|
||||
src.last_found = world.time
|
||||
src.anchored = 0
|
||||
src.declare_arrests = 0
|
||||
src.emagged = 2
|
||||
src.on = 1
|
||||
src.icon_state = "secbot[src.on]"
|
||||
mode = SECBOT_IDLE
|
||||
|
||||
/obj/machinery/bot/secbot/process()
|
||||
//set background = 1
|
||||
if(emagged == 2)
|
||||
if(user)
|
||||
user << "<span class='danger'> You short out [src]'s target assessment circuits.</span>"
|
||||
oldtarget_name = user.name
|
||||
visible_message("<span class='danger'>[src] buzzes oddly!</span>")
|
||||
declare_arrests = 0
|
||||
icon_state = "secbot[on]"
|
||||
|
||||
if(!src.on)
|
||||
/obj/machinery/bot/secbot/bot_process()
|
||||
if (!..())
|
||||
return
|
||||
|
||||
switch(mode)
|
||||
|
||||
if(SECBOT_IDLE) // idle
|
||||
if(BOT_IDLE) // idle
|
||||
|
||||
walk_to(src,0)
|
||||
look_for_perp() // see if any criminals are in range
|
||||
if(!mode && auto_patrol) // still idle, and set to patrol
|
||||
mode = SECBOT_START_PATROL // switch to patrol mode
|
||||
mode = BOT_START_PATROL // switch to patrol mode
|
||||
|
||||
if(SECBOT_HUNT) // hunting for perp
|
||||
if(BOT_HUNT) // hunting for perp
|
||||
|
||||
// if can't reach perp for long enough, go idle
|
||||
if(src.frustration >= 8)
|
||||
// for(var/mob/O in hearers(src, null))
|
||||
// O << "<span class='game say'><span class='name'>[src]</span> beeps, \"Backup requested! Suspect has evaded arrest.\""
|
||||
src.target = null
|
||||
src.last_found = world.time
|
||||
src.frustration = 0
|
||||
src.mode = SECBOT_IDLE
|
||||
if(frustration >= 8)
|
||||
walk_to(src,0)
|
||||
back_to_idle()
|
||||
return
|
||||
|
||||
if(target) // make sure target exists
|
||||
if(src.Adjacent(target) && isturf(src.target.loc)) // if right next to perp
|
||||
playsound(src.loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
|
||||
src.icon_state = "secbot-c"
|
||||
if(Adjacent(target) && isturf(target.loc)) // if right next to perp
|
||||
playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
|
||||
icon_state = "secbot-c"
|
||||
spawn(2)
|
||||
src.icon_state = "secbot[src.on]"
|
||||
var/mob/living/carbon/M = src.target
|
||||
var/maxstuns = 4
|
||||
icon_state = "secbot[on]"
|
||||
var/mob/living/carbon/M = target
|
||||
if(istype(M, /mob/living/carbon/human))
|
||||
if(M.stuttering < 5 && (!(M_HULK in M.mutations)))
|
||||
if( M.stuttering < 5 && !(M_HULK in M.mutations) )
|
||||
M.stuttering = 5
|
||||
M.Stun(5)
|
||||
M.Weaken(5)
|
||||
@@ -275,412 +229,146 @@ Auto Patrol: []"},
|
||||
M.Stun(5)
|
||||
|
||||
if(declare_arrests)
|
||||
//var/area/location = get_area(src)
|
||||
declare_arrest()
|
||||
target.visible_message("<span class='danger'>[src.target] has been stunned by [src]!</span>",\
|
||||
"<span class='userdanger'>[src.target] has been stunned by [src]!</span>")
|
||||
target.visible_message("<span class='danger'>[target] has been stunned by [src]!</span>",\
|
||||
"<span class='userdanger'>[target] has been stunned by [src]!</span>")
|
||||
|
||||
maxstuns--
|
||||
if(maxstuns <= 0)
|
||||
target = null
|
||||
|
||||
mode = SECBOT_PREP_ARREST
|
||||
src.anchored = 1
|
||||
src.target_lastloc = M.loc
|
||||
mode = BOT_PREP_ARREST
|
||||
anchored = 1
|
||||
target_lastloc = M.loc
|
||||
return
|
||||
|
||||
else // not next to perp
|
||||
var/turf/olddist = get_dist(src, src.target)
|
||||
walk_to(src, src.target,1,4)
|
||||
if((get_dist(src, src.target)) >= (olddist))
|
||||
src.frustration++
|
||||
var/turf/olddist = get_dist(src, target)
|
||||
walk_to(src, target,1,4)
|
||||
if((get_dist(src, target)) >= (olddist))
|
||||
frustration++
|
||||
else
|
||||
src.frustration = 0
|
||||
frustration = 0
|
||||
else
|
||||
src.frustration = 8
|
||||
back_to_idle()
|
||||
|
||||
if(SECBOT_PREP_ARREST) // preparing to arrest target
|
||||
if(BOT_PREP_ARREST) // preparing to arrest target
|
||||
|
||||
// see if he got away
|
||||
if((get_dist(src, src.target) > 1) || ((src.target:loc != src.target_lastloc) && src.target:weakened < 2))
|
||||
src.anchored = 0
|
||||
mode = SECBOT_HUNT
|
||||
// see if he got away. If he's no no longer adjacent or inside a closet or about to get up, we hunt again.
|
||||
if( !Adjacent(target) || !isturf(target.loc) || target.weakened < 2 )
|
||||
back_to_hunt()
|
||||
return
|
||||
|
||||
if(istype(src.target,/mob/living/carbon))
|
||||
var/mob/living/carbon/C = target
|
||||
if(!C.handcuffed && !src.arrest_type)
|
||||
playsound(src.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -2)
|
||||
mode = SECBOT_ARREST
|
||||
target.visible_message("<span class='danger'>[src] is trying to put handcuffs on [src.target]!</span>",\
|
||||
"<span class='userdanger'>[src] is trying to put handcuffs on [src.target]!</span>")
|
||||
|
||||
spawn(60)
|
||||
if(get_dist(src, src.target) <= 1)
|
||||
/*if(src.target.handcuffed)
|
||||
return*/
|
||||
|
||||
if(istype(src.target,/mob/living/carbon))
|
||||
C = target
|
||||
if(!C.handcuffed)
|
||||
C.handcuffed = new /obj/item/weapon/handcuffs(target)
|
||||
C.update_inv_handcuffed() //update the handcuffs overlay
|
||||
|
||||
mode = SECBOT_IDLE
|
||||
src.target = null
|
||||
src.anchored = 0
|
||||
src.last_found = world.time
|
||||
src.frustration = 0
|
||||
|
||||
playsound(src.loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg'), 50, 0)
|
||||
// var/arrest_message = pick("Have a secure day!","I AM THE LAW.", "God made tomorrow for the crooks we don't catch today.","You can't outrun a radio.")
|
||||
// src.speak(arrest_message)
|
||||
|
||||
if(iscarbon(target) && target.canBeHandcuffed())
|
||||
if(!arrest_type)
|
||||
if(!target.handcuffed) //he's not cuffed? Try to cuff him!
|
||||
mode = BOT_ARREST
|
||||
playsound(loc, 'sound/weapons/handcuffs.ogg', 30, 1, -2)
|
||||
target.visible_message("<span class='danger'>[src] is trying to put handcuffs on [target]!</span>",\
|
||||
"<span class='userdanger'>[src] is trying to put handcuffs on [target]!</span>")
|
||||
spawn(80)
|
||||
if( !Adjacent(target) || !isturf(target.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
|
||||
return
|
||||
if(!target.handcuffed)
|
||||
target.handcuffed = new /obj/item/weapon/handcuffs(target)
|
||||
target.update_inv_handcuffed(0) //update the handcuffs overlay
|
||||
playsound(loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg'), 50, 0)
|
||||
back_to_idle()
|
||||
else
|
||||
back_to_idle()
|
||||
return
|
||||
else
|
||||
mode = SECBOT_IDLE
|
||||
src.target = null
|
||||
src.anchored = 0
|
||||
src.last_found = world.time
|
||||
src.frustration = 0
|
||||
|
||||
if(SECBOT_ARREST) // arresting
|
||||
|
||||
if(!target || !istype(target, /mob/living/carbon))
|
||||
src.anchored = 0
|
||||
mode = SECBOT_IDLE
|
||||
back_to_idle()
|
||||
return
|
||||
else
|
||||
var/mob/living/carbon/C = target
|
||||
if(!C.handcuffed)
|
||||
src.anchored = 0
|
||||
mode = SECBOT_IDLE
|
||||
return
|
||||
|
||||
if(BOT_ARREST)
|
||||
if (!target)
|
||||
anchored = 0
|
||||
mode = BOT_IDLE
|
||||
last_found = world.time
|
||||
frustration = 0
|
||||
return
|
||||
|
||||
if(SECBOT_START_PATROL) // start a patrol
|
||||
if(path != null)
|
||||
if(path.len > 0 && patrol_target) // have a valid path, so just resume
|
||||
mode = SECBOT_PATROL
|
||||
return
|
||||
if(target.handcuffed) //no target or target cuffed? back to idle.
|
||||
back_to_idle()
|
||||
return
|
||||
|
||||
else if(patrol_target) // has patrol target already
|
||||
spawn(0)
|
||||
calc_path() // so just find a route to it
|
||||
if(path.len == 0)
|
||||
patrol_target = 0
|
||||
return
|
||||
mode = SECBOT_PATROL
|
||||
if( !Adjacent(target) || !isturf(target.loc) || (target.loc != target_lastloc && target.weakened < 2) ) //if he's changed loc and about to get up or not adjacent or got into a closet, we prep arrest again.
|
||||
back_to_hunt()
|
||||
return
|
||||
else //Try arresting again if the target escapes.
|
||||
mode = BOT_PREP_ARREST
|
||||
anchored = 0
|
||||
|
||||
if(BOT_START_PATROL)
|
||||
look_for_perp()
|
||||
start_patrol()
|
||||
|
||||
else // no patrol target, so need a new one
|
||||
find_patrol_target()
|
||||
speak("Engaging patrol mode.")
|
||||
if(BOT_PATROL)
|
||||
look_for_perp()
|
||||
bot_patrol()
|
||||
|
||||
|
||||
if(SECBOT_PATROL) // patrol mode
|
||||
|
||||
patrol_step()
|
||||
spawn(5)
|
||||
if(mode == SECBOT_PATROL)
|
||||
patrol_step()
|
||||
|
||||
if(SECBOT_SUMMON) // summoned to PDA
|
||||
patrol_step()
|
||||
spawn(4)
|
||||
if(mode == SECBOT_SUMMON)
|
||||
patrol_step()
|
||||
sleep(4)
|
||||
patrol_step()
|
||||
|
||||
return
|
||||
|
||||
/obj/machinery/bot/secbot/proc/back_to_idle()
|
||||
anchored = 0
|
||||
mode = BOT_IDLE
|
||||
target = null
|
||||
last_found = world.time
|
||||
frustration = 0
|
||||
spawn(0)
|
||||
bot_process() //ensure bot quickly responds
|
||||
|
||||
// perform a single patrol step
|
||||
/obj/machinery/bot/secbot/proc/patrol_step()
|
||||
|
||||
if(loc == patrol_target) // reached target
|
||||
at_patrol_target()
|
||||
return
|
||||
|
||||
else if(path.len > 0 && patrol_target) // valid path
|
||||
|
||||
var/turf/next = path[1]
|
||||
if(next == loc)
|
||||
path -= next
|
||||
return
|
||||
|
||||
|
||||
if(istype( next, /turf/simulated))
|
||||
|
||||
var/moved = step_towards(src, next) // attempt to move
|
||||
if(moved) // successful move
|
||||
blockcount = 0
|
||||
path -= loc
|
||||
|
||||
look_for_perp()
|
||||
else // failed to move
|
||||
|
||||
blockcount++
|
||||
|
||||
if(blockcount > 5) // attempt 5 times before recomputing
|
||||
// find new path excluding blocked turf
|
||||
|
||||
spawn(2)
|
||||
calc_path(next)
|
||||
if(path.len == 0)
|
||||
find_patrol_target()
|
||||
else
|
||||
blockcount = 0
|
||||
|
||||
return
|
||||
|
||||
return
|
||||
|
||||
else // not a valid turf
|
||||
mode = SECBOT_IDLE
|
||||
return
|
||||
|
||||
else // no path, so calculate new one
|
||||
mode = SECBOT_START_PATROL
|
||||
|
||||
|
||||
// finds a new patrol target
|
||||
/obj/machinery/bot/secbot/proc/find_patrol_target()
|
||||
send_status()
|
||||
if(awaiting_beacon) // awaiting beacon response
|
||||
awaiting_beacon++
|
||||
if(awaiting_beacon > 5) // wait 5 secs for beacon response
|
||||
find_nearest_beacon() // then go to nearest instead
|
||||
return
|
||||
|
||||
if(next_destination)
|
||||
set_destination(next_destination)
|
||||
else
|
||||
find_nearest_beacon()
|
||||
return
|
||||
|
||||
|
||||
// finds the nearest beacon to self
|
||||
// signals all beacons matching the patrol code
|
||||
/obj/machinery/bot/secbot/proc/find_nearest_beacon()
|
||||
nearest_beacon = null
|
||||
new_destination = "__nearest__"
|
||||
post_signal(beacon_freq, "findbeacon", "patrol")
|
||||
awaiting_beacon = 1
|
||||
spawn(10)
|
||||
awaiting_beacon = 0
|
||||
if(nearest_beacon)
|
||||
set_destination(nearest_beacon)
|
||||
else
|
||||
auto_patrol = 0
|
||||
mode = SECBOT_IDLE
|
||||
speak("Disengaging patrol mode.")
|
||||
send_status()
|
||||
|
||||
|
||||
/obj/machinery/bot/secbot/proc/at_patrol_target()
|
||||
find_patrol_target()
|
||||
return
|
||||
|
||||
|
||||
// sets the current destination
|
||||
// signals all beacons matching the patrol code
|
||||
// beacons will return a signal giving their locations
|
||||
/obj/machinery/bot/secbot/proc/set_destination(var/new_dest)
|
||||
new_destination = new_dest
|
||||
post_signal(beacon_freq, "findbeacon", "patrol")
|
||||
awaiting_beacon = 1
|
||||
|
||||
|
||||
// receive a radio signal
|
||||
// used for beacon reception
|
||||
|
||||
/obj/machinery/bot/secbot/receive_signal(datum/signal/signal)
|
||||
//log_admin("DEBUG \[[world.timeofday]\]: /obj/machinery/bot/secbot/receive_signal([signal.debug_print()])")
|
||||
if(!on)
|
||||
return
|
||||
|
||||
/*
|
||||
world << "rec signal: [signal.source]"
|
||||
for(var/x in signal.data)
|
||||
world << "* [x] = [signal.data[x]]"
|
||||
*/
|
||||
|
||||
var/recv = signal.data["command"]
|
||||
// process all-bot input
|
||||
if(recv=="bot_status")
|
||||
send_status()
|
||||
|
||||
// check to see if we are the commanded bot
|
||||
if(signal.data["active"] == src)
|
||||
// process control input
|
||||
switch(recv)
|
||||
if("stop")
|
||||
mode = SECBOT_IDLE
|
||||
auto_patrol = 0
|
||||
return
|
||||
|
||||
if("go")
|
||||
mode = SECBOT_IDLE
|
||||
auto_patrol = 1
|
||||
return
|
||||
|
||||
if("summon")
|
||||
patrol_target = signal.data["target"]
|
||||
next_destination = destination
|
||||
destination = null
|
||||
awaiting_beacon = 0
|
||||
mode = SECBOT_SUMMON
|
||||
calc_path()
|
||||
speak("Responding.")
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
||||
// receive response from beacon
|
||||
recv = signal.data["beacon"]
|
||||
var/valid = signal.data["patrol"]
|
||||
if(!recv || !valid)
|
||||
return
|
||||
|
||||
if(recv == new_destination) // if the recvd beacon location matches the set destination
|
||||
// the we will navigate there
|
||||
destination = new_destination
|
||||
patrol_target = signal.source.loc
|
||||
next_destination = signal.data["next_patrol"]
|
||||
awaiting_beacon = 0
|
||||
|
||||
// if looking for nearest beacon
|
||||
else if(new_destination == "__nearest__")
|
||||
var/dist = get_dist(src,signal.source.loc)
|
||||
if(nearest_beacon)
|
||||
|
||||
// note we ignore the beacon we are located at
|
||||
if(dist>1 && dist<get_dist(src,nearest_beacon_loc))
|
||||
nearest_beacon = recv
|
||||
nearest_beacon_loc = signal.source.loc
|
||||
return
|
||||
else
|
||||
return
|
||||
else if(dist > 1)
|
||||
nearest_beacon = recv
|
||||
nearest_beacon_loc = signal.source.loc
|
||||
return
|
||||
|
||||
|
||||
// send a radio signal with a single data key/value pair
|
||||
/obj/machinery/bot/secbot/proc/post_signal(var/freq, var/key, var/value)
|
||||
post_signal_multiple(freq, list("[key]" = value) )
|
||||
|
||||
// send a radio signal with multiple data key/values
|
||||
/obj/machinery/bot/secbot/proc/post_signal_multiple(var/freq, var/list/keyval)
|
||||
|
||||
var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
|
||||
|
||||
if(!frequency) return
|
||||
|
||||
var/datum/signal/signal = new()
|
||||
signal.source = src
|
||||
signal.transmission_method = 1
|
||||
//for(var/key in keyval)
|
||||
// signal.data[key] = keyval[key]
|
||||
signal.data = keyval
|
||||
//world << "sent [key],[keyval[key]] on [freq]"
|
||||
if(signal.data["findbeacon"])
|
||||
frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
|
||||
else if(signal.data["type"] == "secbot")
|
||||
frequency.post_signal(src, signal, filter = RADIO_SECBOT)
|
||||
else
|
||||
frequency.post_signal(src, signal)
|
||||
|
||||
// signals bot status etc. to controller
|
||||
/obj/machinery/bot/secbot/proc/send_status()
|
||||
var/list/kv = list(
|
||||
"type" = "secbot",
|
||||
"name" = name,
|
||||
"loca" = loc.loc, // area
|
||||
"mode" = mode
|
||||
)
|
||||
post_signal_multiple(control_freq, kv)
|
||||
|
||||
|
||||
|
||||
// calculates a path to the current destination
|
||||
// given an optional turf to avoid
|
||||
/obj/machinery/bot/secbot/proc/calc_path(var/turf/avoid = null)
|
||||
src.path = AStar(src.loc, patrol_target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 120, id=botcard, exclude=avoid)
|
||||
if(!src.path)
|
||||
src.path = list()
|
||||
|
||||
|
||||
/obj/machinery/bot/secbot/proc/back_to_hunt()
|
||||
anchored = 0
|
||||
frustration = 0
|
||||
mode = BOT_HUNT
|
||||
spawn(0)
|
||||
bot_process() //ensure bot quickly responds
|
||||
// look for a criminal in view of the bot
|
||||
|
||||
/obj/machinery/bot/secbot/proc/look_for_perp()
|
||||
src.anchored = 0
|
||||
anchored = 0
|
||||
for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal
|
||||
if((C.stat) || (C.handcuffed))
|
||||
continue
|
||||
|
||||
if((C.name == src.oldtarget_name) && (world.time < src.last_found + 100))
|
||||
if((C.name == oldtarget_name) && (world.time < last_found + 100))
|
||||
continue
|
||||
|
||||
src.threatlevel = C.assess_threat(src)
|
||||
threatlevel = C.assess_threat(src)
|
||||
|
||||
if(!src.threatlevel)
|
||||
if(!threatlevel)
|
||||
continue
|
||||
|
||||
else if(src.threatlevel >= 4)
|
||||
src.target = C
|
||||
src.oldtarget_name = C.name
|
||||
src.speak("Level [src.threatlevel] infraction alert!")
|
||||
playsound(src.loc, pick('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg'), 50, 0)
|
||||
src.visible_message("<b>[src]</b> points at [C.name]!")
|
||||
mode = SECBOT_HUNT
|
||||
else if(threatlevel >= 4)
|
||||
target = C
|
||||
oldtarget_name = C.name
|
||||
speak("Level [threatlevel] infraction alert!")
|
||||
playsound(loc, pick('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg'), 50, 0)
|
||||
visible_message("<b>[src]</b> points at [C.name]!")
|
||||
mode = BOT_HUNT
|
||||
spawn(0)
|
||||
process() // ensure bot quickly responds to a perp
|
||||
bot_process() // ensure bot quickly responds to a perp
|
||||
break
|
||||
else
|
||||
continue
|
||||
|
||||
/obj/machinery/bot/secbot/proc/check_for_weapons(var/obj/item/slot_item)
|
||||
if(istype(slot_item, /obj/item/weapon/gun) || istype(slot_item, /obj/item/weapon/melee))
|
||||
if(!(slot_item.type in safe_weapons))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/machinery/bot/secbot/Bump(M as mob|obj) //Leave no door unopened!
|
||||
if((istype(M, /obj/machinery/door)) && (!isnull(src.botcard)))
|
||||
var/obj/machinery/door/D = M
|
||||
if(!istype(D, /obj/machinery/door/firedoor) && D.check_access(src.botcard) && !istype(D,/obj/machinery/door/poddoor))
|
||||
D.open()
|
||||
src.frustration = 0
|
||||
else if((istype(M, /mob/living/)) && (!src.anchored))
|
||||
src.loc = M:loc
|
||||
src.frustration = 0
|
||||
return
|
||||
|
||||
/* terrible
|
||||
/obj/machinery/bot/secbot/Bumped(atom/movable/M as mob|obj)
|
||||
spawn(0)
|
||||
if(M)
|
||||
var/turf/T = get_turf(src)
|
||||
M:loc = T
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/obj/machinery/bot/secbot/explode()
|
||||
|
||||
walk_to(src,0)
|
||||
src.visible_message("\red <B>[src] blows apart!</B>", 1)
|
||||
visible_message("<span class='userdanger'>[src] blows apart!</span>")
|
||||
var/turf/Tsec = get_turf(src)
|
||||
|
||||
var/obj/item/weapon/secbot_assembly/Sa = new /obj/item/weapon/secbot_assembly(Tsec)
|
||||
Sa.build_step = 1
|
||||
Sa.overlays += image('icons/obj/aibots.dmi', "hs_hole")
|
||||
Sa.created_name = src.name
|
||||
Sa.overlays += "hs_hole"
|
||||
Sa.created_name = name
|
||||
new /obj/item/device/assembly/prox_sensor(Tsec)
|
||||
new /obj/item/weapon/melee/baton/loaded(Tsec)
|
||||
new /obj/item/weapon/melee/baton(Tsec)
|
||||
|
||||
if(prob(50))
|
||||
new /obj/item/robot_parts/l_arm(Tsec)
|
||||
@@ -689,14 +377,14 @@ Auto Patrol: []"},
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
|
||||
new /obj/effect/decal/cleanable/oil(src.loc)
|
||||
del(src)
|
||||
new /obj/effect/decal/cleanable/oil(loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/bot/secbot/attack_alien(var/mob/living/carbon/alien/user as mob)
|
||||
..()
|
||||
if(!isalien(target))
|
||||
src.target = user
|
||||
src.mode = SECBOT_HUNT
|
||||
target = user
|
||||
mode = BOT_HUNT
|
||||
|
||||
//Secbot Construction
|
||||
|
||||
@@ -706,63 +394,70 @@ Auto Patrol: []"},
|
||||
..()
|
||||
return
|
||||
|
||||
if(src.type != /obj/item/clothing/head/helmet) //Eh, but we don't want people making secbots out of space helmets.
|
||||
if(type != /obj/item/clothing/head/helmet) //Eh, but we don't want people making secbots out of space helmets.
|
||||
return
|
||||
|
||||
if(S.secured)
|
||||
del(S)
|
||||
qdel(S)
|
||||
var/obj/item/weapon/secbot_assembly/A = new /obj/item/weapon/secbot_assembly
|
||||
user.put_in_hands(A)
|
||||
user << "You add the signaler to the helmet."
|
||||
user.drop_from_inventory(src)
|
||||
del(src)
|
||||
user << "<span class='notice'>You add the signaler to the helmet.</span>"
|
||||
user.before_take_item(src, 1)
|
||||
qdel(src)
|
||||
else
|
||||
return
|
||||
|
||||
/obj/item/weapon/secbot_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
/obj/item/weapon/secbot_assembly/attackby(obj/item/I, mob/user)
|
||||
..()
|
||||
if((istype(W, /obj/item/weapon/weldingtool)) && (!src.build_step))
|
||||
var/obj/item/weapon/weldingtool/WT = W
|
||||
if(WT.remove_fuel(0,user))
|
||||
src.build_step++
|
||||
src.overlays += image('icons/obj/aibots.dmi', "hs_hole")
|
||||
user << "You weld a hole in [src]!"
|
||||
if(istype(I, /obj/item/weapon/weldingtool))
|
||||
if(!build_step)
|
||||
var/obj/item/weapon/weldingtool/WT = I
|
||||
if(WT.remove_fuel(0, user))
|
||||
build_step++
|
||||
overlays += "hs_hole"
|
||||
user << "<span class='notice'>You weld a hole in [src]!</span>"
|
||||
else if(build_step == 1)
|
||||
var/obj/item/weapon/weldingtool/WT = I
|
||||
if(WT.remove_fuel(0, user))
|
||||
build_step--
|
||||
overlays -= "hs_hole"
|
||||
user << "<span class='notice'>You weld the hole in [src] shut!</span>"
|
||||
|
||||
else if(isprox(W) && (src.build_step == 1))
|
||||
else if(isprox(I) && (build_step == 1))
|
||||
user.drop_item()
|
||||
src.build_step++
|
||||
user << "You add the prox sensor to [src]!"
|
||||
src.overlays += image('icons/obj/aibots.dmi', "hs_eye")
|
||||
src.name = "helmet/signaler/prox sensor assembly"
|
||||
del(W)
|
||||
build_step++
|
||||
user << "<span class='notice'>You add the prox sensor to [src]!</span>"
|
||||
overlays += "hs_eye"
|
||||
name = "helmet/signaler/prox sensor assembly"
|
||||
qdel(I)
|
||||
|
||||
else if(((istype(W, /obj/item/robot_parts/l_arm)) || (istype(W, /obj/item/robot_parts/r_arm))) && (src.build_step == 2))
|
||||
else if(((istype(I, /obj/item/robot_parts/l_arm)) || (istype(I, /obj/item/robot_parts/r_arm))) && (build_step == 2))
|
||||
user.drop_item()
|
||||
src.build_step++
|
||||
user << "You add the robot arm to [src]!"
|
||||
src.name = "helmet/signaler/prox sensor/robot arm assembly"
|
||||
src.overlays += image('icons/obj/aibots.dmi', "hs_arm")
|
||||
del(W)
|
||||
build_step++
|
||||
user << "<span class='notice'>You add the robot arm to [src]!</span>"
|
||||
name = "helmet/signaler/prox sensor/robot arm assembly"
|
||||
overlays += "hs_arm"
|
||||
qdel(I)
|
||||
|
||||
else if((istype(W, /obj/item/weapon/melee/baton)) && (src.build_step >= 3))
|
||||
else if((istype(I, /obj/item/weapon/melee/baton)) && (build_step >= 3))
|
||||
user.drop_item()
|
||||
src.build_step++
|
||||
user << "You complete the Securitron! Beep boop."
|
||||
build_step++
|
||||
user << "<span class='notice'>You complete the Securitron! Beep boop.</span>"
|
||||
var/obj/machinery/bot/secbot/S = new /obj/machinery/bot/secbot
|
||||
S.loc = get_turf(src)
|
||||
S.name = src.created_name
|
||||
del(W)
|
||||
del(src)
|
||||
S.name = created_name
|
||||
qdel(I)
|
||||
qdel(src)
|
||||
|
||||
else if(istype(W, /obj/item/weapon/pen))
|
||||
var/t = copytext(stripped_input(user, "Enter new robot name", src.name, src.created_name),1,MAX_NAME_LEN)
|
||||
else if(istype(I, /obj/item/weapon/pen))
|
||||
var/t = stripped_input(user, "Enter new robot name", name, created_name,MAX_NAME_LEN)
|
||||
if(!t)
|
||||
return
|
||||
if(!in_range(src, usr) && src.loc != usr)
|
||||
if(!in_range(src, usr) && loc != usr)
|
||||
return
|
||||
created_name = t
|
||||
|
||||
else if(istype(W, /obj/item/weapon/screwdriver))
|
||||
else if(istype(I, /obj/item/weapon/screwdriver))
|
||||
if(!build_step)
|
||||
new /obj/item/device/assembly/signaler(get_turf(src))
|
||||
new /obj/item/clothing/head/helmet(get_turf(src))
|
||||
@@ -780,9 +475,9 @@ Auto Patrol: []"},
|
||||
new /obj/item/robot_parts/l_arm(get_turf(src))
|
||||
user << "<span class='notice'>You remove the robot arm from [src].</span>"
|
||||
build_step--
|
||||
|
||||
/obj/machinery/bot/secbot/proc/declare_arrest()
|
||||
|
||||
/obj/machinery/bot/secbot/proc/declare_arrest()
|
||||
var/area/location = get_area(src)
|
||||
for(var/mob/living/carbon/human/human in world)
|
||||
if((human.z == src.z) && istype(human.glasses, /obj/item/clothing/glasses/hud/security) || istype(human.glasses, /obj/item/clothing/glasses/sunglasses/sechud) && !human.blinded)
|
||||
human << "<span class='info'>\icon[human.glasses] [src.name] is [arrest_type ? "detaining" : "arresting"] level [threatlevel] <b>[target]</b> in <b>[location]</b></span>"
|
||||
human << "<span class='info'>\icon[human.glasses] [src.name] is [arrest_type ? "detaining" : "arresting"] level [threatlevel] threat <b>[target]</b> in <b>[location]</b></span>"
|
||||
+168
-172
@@ -20,144 +20,146 @@
|
||||
|
||||
req_access = list(access_engine)
|
||||
|
||||
New()
|
||||
..()
|
||||
/obj/machinery/navbeacon/New()
|
||||
..()
|
||||
|
||||
set_codes()
|
||||
set_codes()
|
||||
|
||||
var/turf/T = loc
|
||||
hide(T.intact)
|
||||
var/turf/T = loc
|
||||
hide(T.intact)
|
||||
|
||||
spawn(5) // must wait for map loading to finish
|
||||
if(radio_controller)
|
||||
radio_controller.add_object(src, freq, RADIO_NAVBEACONS)
|
||||
spawn(50) // must wait for map loading to finish
|
||||
if(radio_controller)
|
||||
radio_controller.add_object(src, freq, RADIO_NAVBEACONS)
|
||||
|
||||
// set the transponder codes assoc list from codes_txt
|
||||
proc/set_codes()
|
||||
if(!codes_txt)
|
||||
return
|
||||
/obj/machinery/navbeacon/Destroy()
|
||||
if(radio_controller)
|
||||
radio_controller.remove_object(src, freq)
|
||||
..()
|
||||
|
||||
codes = new()
|
||||
// set the transponder codes assoc list from codes_txt
|
||||
/obj/machinery/navbeacon/proc/set_codes()
|
||||
if(!codes_txt)
|
||||
return
|
||||
|
||||
var/list/entries = text2list(codes_txt, ";") // entries are separated by semicolons
|
||||
codes = new()
|
||||
|
||||
for(var/e in entries)
|
||||
var/index = findtext(e, "=") // format is "key=value"
|
||||
if(index)
|
||||
var/key = copytext(e, 1, index)
|
||||
var/val = copytext(e, index+1)
|
||||
codes[key] = val
|
||||
else
|
||||
codes[e] = "1"
|
||||
var/list/entries = text2list(codes_txt, ";") // entries are separated by semicolons
|
||||
|
||||
for(var/e in entries)
|
||||
var/index = findtext(e, "=") // format is "key=value"
|
||||
if(index)
|
||||
var/key = copytext(e, 1, index)
|
||||
var/val = copytext(e, index+1)
|
||||
codes[key] = val
|
||||
else
|
||||
codes[e] = "1"
|
||||
|
||||
|
||||
// called when turf state changes
|
||||
// hide the object if turf is intact
|
||||
hide(var/intact)
|
||||
invisibility = intact ? 101 : 0
|
||||
// called when turf state changes
|
||||
// hide the object if turf is intact
|
||||
/obj/machinery/navbeacon/hide(var/intact)
|
||||
invisibility = intact ? 101 : 0
|
||||
updateicon()
|
||||
|
||||
// update the icon_state
|
||||
/obj/machinery/navbeacon/proc/updateicon()
|
||||
var/state="navbeacon[open]"
|
||||
|
||||
if(invisibility)
|
||||
icon_state = "[state]-f" // if invisible, set icon to faded version
|
||||
// in case revealed by T-scanner
|
||||
else
|
||||
icon_state = "[state]"
|
||||
|
||||
|
||||
// look for a signal of the form "findbeacon=X"
|
||||
// where X is any
|
||||
// or the location
|
||||
// or one of the set transponder keys
|
||||
// if found, return a signal
|
||||
/obj/machinery/navbeacon/receive_signal(datum/signal/signal)
|
||||
var/request = signal.data["findbeacon"]
|
||||
if(request && ((request in codes) || request == "any" || request == location))
|
||||
spawn(1)
|
||||
post_signal()
|
||||
|
||||
// return a signal giving location and transponder codes
|
||||
|
||||
/obj/machinery/navbeacon/proc/post_signal()
|
||||
var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
|
||||
|
||||
if(!frequency) return
|
||||
|
||||
var/datum/signal/signal = new()
|
||||
signal.source = src
|
||||
signal.transmission_method = 1
|
||||
signal.data["beacon"] = location
|
||||
|
||||
for(var/key in codes)
|
||||
signal.data[key] = codes[key]
|
||||
frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
|
||||
|
||||
|
||||
/obj/machinery/navbeacon/attackby(var/obj/item/I, var/mob/user)
|
||||
var/turf/T = loc
|
||||
if(T.intact)
|
||||
return // prevent intraction when T-scanner revealed
|
||||
|
||||
if(istype(I, /obj/item/weapon/screwdriver))
|
||||
open = !open
|
||||
|
||||
user.visible_message("[user] [open ? "opens" : "closes"] the beacon's cover.", "You [open ? "open" : "close"] the beacon's cover.")
|
||||
|
||||
updateicon()
|
||||
|
||||
// update the icon_state
|
||||
proc/updateicon()
|
||||
var/state="navbeacon[open]"
|
||||
|
||||
if(invisibility)
|
||||
icon_state = "[state]-f" // if invisible, set icon to faded version
|
||||
// in case revealed by T-scanner
|
||||
else
|
||||
icon_state = "[state]"
|
||||
|
||||
|
||||
// look for a signal of the form "findbeacon=X"
|
||||
// where X is any
|
||||
// or the location
|
||||
// or one of the set transponder keys
|
||||
// if found, return a signal
|
||||
receive_signal(datum/signal/signal)
|
||||
|
||||
var/request = signal.data["findbeacon"]
|
||||
if(request && ((request in codes) || request == "any" || request == location))
|
||||
spawn(1)
|
||||
post_signal()
|
||||
|
||||
// return a signal giving location and transponder codes
|
||||
|
||||
proc/post_signal()
|
||||
|
||||
var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
|
||||
|
||||
if(!frequency) return
|
||||
|
||||
var/datum/signal/signal = new()
|
||||
signal.source = src
|
||||
signal.transmission_method = 1
|
||||
signal.data["beacon"] = location
|
||||
|
||||
for(var/key in codes)
|
||||
signal.data[key] = codes[key]
|
||||
|
||||
frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
|
||||
|
||||
|
||||
attackby(var/obj/item/I, var/mob/user)
|
||||
var/turf/T = loc
|
||||
if(T.intact)
|
||||
return // prevent intraction when T-scanner revealed
|
||||
|
||||
if(istype(I, /obj/item/weapon/screwdriver))
|
||||
open = !open
|
||||
|
||||
user.visible_message("[user] [open ? "opens" : "closes"] the beacon's cover.", "You [open ? "open" : "close"] the beacon's cover.")
|
||||
|
||||
updateicon()
|
||||
|
||||
else if (istype(I, /obj/item/weapon/card/id)||istype(I, /obj/item/device/pda))
|
||||
if(open)
|
||||
if (src.allowed(user))
|
||||
src.locked = !src.locked
|
||||
user << "Controls are now [src.locked ? "locked." : "unlocked."]"
|
||||
else
|
||||
user << "\red Access denied."
|
||||
updateDialog()
|
||||
else if (istype(I, /obj/item/weapon/card/id)||istype(I, /obj/item/device/pda))
|
||||
if(open)
|
||||
if (src.allowed(user))
|
||||
src.locked = !src.locked
|
||||
user << "Controls are now [src.locked ? "locked." : "unlocked."]"
|
||||
else
|
||||
user << "You must open the cover first!"
|
||||
user << "<span class='danger'>Access denied.</span>"
|
||||
updateDialog()
|
||||
else
|
||||
user << "You must open the cover first!"
|
||||
return
|
||||
|
||||
/obj/machinery/navbeacon/attack_ai(var/mob/user)
|
||||
interact(user, 1)
|
||||
|
||||
/obj/machinery/navbeacon/attack_paw()
|
||||
return
|
||||
|
||||
/obj/machinery/navbeacon/attack_hand(var/mob/user)
|
||||
interact(user, 0)
|
||||
|
||||
/obj/machinery/navbeacon/interact(var/mob/user, var/ai = 0)
|
||||
var/turf/T = loc
|
||||
if(T.intact)
|
||||
return // prevent intraction when T-scanner revealed
|
||||
|
||||
if(!open && !ai) // can't alter controls if not open, unless you're an AI
|
||||
user << "The beacon's control cover is closed."
|
||||
return
|
||||
|
||||
attack_ai(var/mob/user)
|
||||
interact(user, 1)
|
||||
|
||||
attack_paw()
|
||||
return
|
||||
var/t
|
||||
|
||||
attack_hand(var/mob/user)
|
||||
interact(user, 0)
|
||||
|
||||
interact(var/mob/user, var/ai = 0)
|
||||
var/turf/T = loc
|
||||
if(T.intact)
|
||||
return // prevent intraction when T-scanner revealed
|
||||
|
||||
if(!open && !ai) // can't alter controls if not open, unless you're an AI
|
||||
user << "The beacon's control cover is closed."
|
||||
return
|
||||
|
||||
|
||||
var/t
|
||||
|
||||
if(locked && !ai)
|
||||
t = {"<TT><B>Navigation Beacon</B><HR><BR>
|
||||
if(locked && !ai)
|
||||
t = {"<TT><B>Navigation Beacon</B><HR><BR>
|
||||
<i>(swipe card to unlock controls)</i><BR>
|
||||
Frequency: [format_frequency(freq)]<BR><HR>
|
||||
Location: [location ? location : "(none)"]</A><BR>
|
||||
Transponder Codes:<UL>"}
|
||||
|
||||
for(var/key in codes)
|
||||
t += "<LI>[key] ... [codes[key]]"
|
||||
t+= "<UL></TT>"
|
||||
for(var/key in codes)
|
||||
t += "<LI>[key] ... [codes[key]]"
|
||||
t+= "<UL></TT>"
|
||||
|
||||
else
|
||||
else
|
||||
|
||||
t = {"<TT><B>Navigation Beacon</B><HR><BR>
|
||||
t = {"<TT><B>Navigation Beacon</B><HR><BR>
|
||||
<i>(swipe card to lock controls)</i><BR>
|
||||
Frequency:
|
||||
<A href='byond://?src=\ref[src];freq=-10'>-</A>
|
||||
@@ -169,76 +171,70 @@ Frequency:
|
||||
Location: <A href='byond://?src=\ref[src];locedit=1'>[location ? location : "(none)"]</A><BR>
|
||||
Transponder Codes:<UL>"}
|
||||
|
||||
for(var/key in codes)
|
||||
t += "<LI>[key] ... [codes[key]]"
|
||||
t += " <small><A href='byond://?src=\ref[src];edit=1;code=[key]'>(edit)</A>"
|
||||
t += " <A href='byond://?src=\ref[src];delete=1;code=[key]'>(delete)</A></small><BR>"
|
||||
t += "<small><A href='byond://?src=\ref[src];add=1;'>(add new)</A></small><BR>"
|
||||
t+= "<UL></TT>"
|
||||
for(var/key in codes)
|
||||
t += "<LI>[key] ... [codes[key]]"
|
||||
t += " <small><A href='byond://?src=\ref[src];edit=1;code=[key]'>(edit)</A>"
|
||||
t += " <A href='byond://?src=\ref[src];delete=1;code=[key]'>(delete)</A></small><BR>"
|
||||
t += "<small><A href='byond://?src=\ref[src];add=1;'>(add new)</A></small><BR>"
|
||||
t+= "<UL></TT>"
|
||||
|
||||
user << browse(t, "window=navbeacon")
|
||||
onclose(user, "navbeacon")
|
||||
user << browse(t, "window=navbeacon")
|
||||
onclose(user, "navbeacon")
|
||||
return
|
||||
|
||||
/obj/machinery/navbeacon/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
if(open && !locked)
|
||||
usr.set_machine(src)
|
||||
|
||||
Topic(href, href_list)
|
||||
..()
|
||||
if (usr.stat)
|
||||
return
|
||||
if ((in_range(src, usr) && istype(src.loc, /turf)) || (istype(usr, /mob/living/silicon)))
|
||||
if(open && !locked)
|
||||
usr.set_machine(src)
|
||||
if (href_list["freq"])
|
||||
freq = sanitize_frequency(freq + text2num(href_list["freq"]))
|
||||
updateDialog()
|
||||
|
||||
if (href_list["freq"])
|
||||
freq = sanitize_frequency(freq + text2num(href_list["freq"]))
|
||||
updateDialog()
|
||||
else if(href_list["locedit"])
|
||||
var/newloc = copytext(sanitize(input("Enter New Location", "Navigation Beacon", location) as text|null),1,MAX_MESSAGE_LEN)
|
||||
if(newloc)
|
||||
location = newloc
|
||||
updateDialog()
|
||||
|
||||
else if(href_list["locedit"])
|
||||
var/newloc = copytext(sanitize(input("Enter New Location", "Navigation Beacon", location) as text|null),1,MAX_MESSAGE_LEN)
|
||||
if(newloc)
|
||||
location = newloc
|
||||
updateDialog()
|
||||
else if(href_list["edit"])
|
||||
var/codekey = href_list["code"]
|
||||
|
||||
else if(href_list["edit"])
|
||||
var/codekey = href_list["code"]
|
||||
var/newkey = input("Enter Transponder Code Key", "Navigation Beacon", codekey) as text|null
|
||||
if(!newkey)
|
||||
return
|
||||
|
||||
var/newkey = input("Enter Transponder Code Key", "Navigation Beacon", codekey) as text|null
|
||||
if(!newkey)
|
||||
return
|
||||
var/codeval = codes[codekey]
|
||||
var/newval = input("Enter Transponder Code Value", "Navigation Beacon", codeval) as text|null
|
||||
if(!newval)
|
||||
newval = codekey
|
||||
return
|
||||
|
||||
var/codeval = codes[codekey]
|
||||
var/newval = input("Enter Transponder Code Value", "Navigation Beacon", codeval) as text|null
|
||||
if(!newval)
|
||||
newval = codekey
|
||||
return
|
||||
codes.Remove(codekey)
|
||||
codes[newkey] = newval
|
||||
|
||||
codes.Remove(codekey)
|
||||
codes[newkey] = newval
|
||||
updateDialog()
|
||||
|
||||
updateDialog()
|
||||
else if(href_list["delete"])
|
||||
var/codekey = href_list["code"]
|
||||
codes.Remove(codekey)
|
||||
updateDialog()
|
||||
|
||||
else if(href_list["delete"])
|
||||
var/codekey = href_list["code"]
|
||||
codes.Remove(codekey)
|
||||
updateDialog()
|
||||
else if(href_list["add"])
|
||||
|
||||
else if(href_list["add"])
|
||||
|
||||
var/newkey = input("Enter New Transponder Code Key", "Navigation Beacon") as text|null
|
||||
if(!newkey)
|
||||
return
|
||||
|
||||
var/newval = input("Enter New Transponder Code Value", "Navigation Beacon") as text|null
|
||||
if(!newval)
|
||||
newval = "1"
|
||||
return
|
||||
|
||||
if(!codes)
|
||||
codes = new()
|
||||
|
||||
codes[newkey] = newval
|
||||
|
||||
updateDialog()
|
||||
var/newkey = input("Enter New Transponder Code Key", "Navigation Beacon") as text|null
|
||||
if(!newkey)
|
||||
return
|
||||
|
||||
var/newval = input("Enter New Transponder Code Value", "Navigation Beacon") as text|null
|
||||
if(!newval)
|
||||
newval = "1"
|
||||
return
|
||||
|
||||
if(!codes)
|
||||
codes = new()
|
||||
|
||||
codes[newkey] = newval
|
||||
|
||||
updateDialog()
|
||||
@@ -1,209 +1,218 @@
|
||||
/obj/item/radio/integrated
|
||||
name = "PDA radio module"
|
||||
desc = "An electronic radio system of nanotrasen origin."
|
||||
name = "\improper PDA radio module"
|
||||
desc = "An electronic radio system of Nanotrasen origin."
|
||||
icon = 'icons/obj/module.dmi'
|
||||
icon_state = "power_mod"
|
||||
var/obj/item/device/pda/hostpda = null
|
||||
|
||||
var/on = 0 //Are we currently active?
|
||||
var/menu_message = ""
|
||||
|
||||
New()
|
||||
..()
|
||||
if (istype(loc.loc, /obj/item/device/pda))
|
||||
hostpda = loc.loc
|
||||
|
||||
proc/post_signal(var/freq, var/key, var/value, var/key2, var/value2, var/key3, var/value3, s_filter)
|
||||
|
||||
//world << "Post: [freq]: [key]=[value], [key2]=[value2]"
|
||||
var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
|
||||
|
||||
if(!frequency) return
|
||||
|
||||
var/datum/signal/signal = new()
|
||||
signal.source = src
|
||||
signal.transmission_method = 1
|
||||
signal.data[key] = value
|
||||
if(key2)
|
||||
signal.data[key2] = value2
|
||||
if(key3)
|
||||
signal.data[key3] = value3
|
||||
|
||||
frequency.post_signal(src, signal, filter = s_filter)
|
||||
|
||||
return
|
||||
|
||||
proc/generate_menu()
|
||||
|
||||
/obj/item/radio/integrated/beepsky
|
||||
var/list/botlist = null // list of bots
|
||||
var/obj/machinery/bot/secbot/active // the active bot; if null, show bot list
|
||||
var/obj/machinery/bot/active // the active bot; if null, show bot list
|
||||
var/list/botstatus // the status signal sent by the bot
|
||||
var/bot_type //The type of bot it is.
|
||||
var/bot_filter //Determines which radio filter to use.
|
||||
|
||||
var/control_freq = 1447
|
||||
|
||||
// create a new QM cartridge, and register to receive bot control & beacon message
|
||||
New()
|
||||
..()
|
||||
var/on = 0 //Are we currently active??
|
||||
var/menu_message = ""
|
||||
|
||||
/obj/item/radio/integrated/New()
|
||||
..()
|
||||
if (istype(loc.loc, /obj/item/device/pda))
|
||||
hostpda = loc.loc
|
||||
if (bot_filter)
|
||||
spawn(5)
|
||||
if(radio_controller)
|
||||
radio_controller.add_object(src, control_freq, filter = RADIO_SECBOT)
|
||||
Destroy()
|
||||
if(radio_controller)
|
||||
radio_controller.remove_object(src, control_freq)
|
||||
..()
|
||||
// receive radio signals
|
||||
// can detect bot status signals
|
||||
// create/populate list as they are recvd
|
||||
add_to_radio(bot_filter)
|
||||
|
||||
receive_signal(datum/signal/signal)
|
||||
// var/obj/item/device/pda/P = src.loc
|
||||
/obj/item/radio/integrated/Destroy()
|
||||
if(radio_controller)
|
||||
radio_controller.remove_object(src, control_freq)
|
||||
..()
|
||||
|
||||
/*
|
||||
world << "recvd:[P] : [signal.source]"
|
||||
for(var/d in signal.data)
|
||||
world << "- [d] = [signal.data[d]]"
|
||||
/obj/item/radio/integrated/proc/post_signal(var/freq, var/key, var/value, var/key2, var/value2, var/key3, var/value3,var/key4, var/value4, s_filter)
|
||||
|
||||
//world << "Post: [freq]: [key]=[value], [key2]=[value2]"
|
||||
var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
|
||||
|
||||
if(!frequency)
|
||||
return
|
||||
|
||||
var/datum/signal/signal = new()
|
||||
signal.source = src
|
||||
signal.transmission_method = 1
|
||||
signal.data[key] = value
|
||||
if(key2)
|
||||
signal.data[key2] = value2
|
||||
if(key3)
|
||||
signal.data[key3] = value3
|
||||
if(key4)
|
||||
signal.data[key4] = value4
|
||||
|
||||
frequency.post_signal(src, signal, filter = s_filter)
|
||||
|
||||
/obj/item/radio/integrated/receive_signal(datum/signal/signal)
|
||||
/*var/obj/item/device/pda/P = src.loc
|
||||
|
||||
|
||||
world << "recvd:[P] : [signal.source]"
|
||||
for(var/d in signal.data)
|
||||
world << "- [d] = [signal.data[d]]"
|
||||
*/
|
||||
if (signal.data["type"] == "secbot")
|
||||
if(!botlist)
|
||||
botlist = new()
|
||||
|
||||
if(!(signal.source in botlist))
|
||||
botlist += signal.source
|
||||
if (signal.data["type"] == bot_type)
|
||||
if(!botlist)
|
||||
botlist = new()
|
||||
|
||||
if(active == signal.source)
|
||||
var/list/b = signal.data
|
||||
botstatus = b.Copy()
|
||||
if(!(signal.source in botlist))
|
||||
botlist += signal.source
|
||||
|
||||
// if (istype(P)) P.updateSelfDialog()
|
||||
if(active == signal.source)
|
||||
var/list/b = signal.data
|
||||
botstatus = b.Copy()
|
||||
|
||||
Topic(href, href_list)
|
||||
..()
|
||||
var/obj/item/device/pda/PDA = src.hostpda
|
||||
/obj/item/radio/integrated/Topic(href, href_list)
|
||||
..()
|
||||
var/obj/item/device/pda/PDA = src.hostpda
|
||||
|
||||
switch(href_list["op"])
|
||||
switch(href_list["op"])
|
||||
|
||||
if("control")
|
||||
active = locate(href_list["bot"])
|
||||
post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT)
|
||||
if("control")
|
||||
active = locate(href_list["bot"])
|
||||
post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter)
|
||||
|
||||
if("scanbots") // find all bots
|
||||
botlist = null
|
||||
post_signal(control_freq, "command", "bot_status", s_filter = RADIO_SECBOT)
|
||||
if("scanbots") // find all bots
|
||||
botlist = null
|
||||
post_signal(control_freq, "command", "bot_status", s_filter = bot_filter)
|
||||
|
||||
if("botlist")
|
||||
active = null
|
||||
if("botlist")
|
||||
active = null
|
||||
|
||||
if("stop", "go")
|
||||
post_signal(control_freq, "command", href_list["op"], "active", active, s_filter = RADIO_SECBOT)
|
||||
post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT)
|
||||
if("stop", "go")
|
||||
post_signal(control_freq, "command", href_list["op"], "active", active, s_filter = bot_filter)
|
||||
post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter)
|
||||
|
||||
if("summon")
|
||||
post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(PDA) , s_filter = RADIO_SECBOT)
|
||||
post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT)
|
||||
if("summon")
|
||||
post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(PDA) , "useraccess", PDA.GetAccess(), s_filter = bot_filter)
|
||||
post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter)
|
||||
|
||||
/obj/item/radio/integrated/proc/add_to_radio(bot_filter) //Master filter control for bots. Must be placed in the bot's local New() to support map spawned bots.
|
||||
if(radio_controller)
|
||||
radio_controller.add_object(src, control_freq, filter = bot_filter)
|
||||
|
||||
|
||||
/obj/item/radio/integrated/beepsky
|
||||
bot_filter = RADIO_SECBOT
|
||||
bot_type = SEC_BOT
|
||||
|
||||
/obj/item/radio/integrated/medbot
|
||||
bot_filter = RADIO_MEDBOT
|
||||
bot_type = MED_BOT
|
||||
|
||||
/obj/item/radio/integrated/floorbot
|
||||
bot_filter = RADIO_FLOORBOT
|
||||
bot_type = FLOOR_BOT
|
||||
|
||||
/obj/item/radio/integrated/cleanbot
|
||||
bot_filter = RADIO_CLEANBOT
|
||||
bot_type = CLEAN_BOT
|
||||
|
||||
/obj/item/radio/integrated/mule
|
||||
var/list/botlist = null // list of bots
|
||||
var/obj/machinery/bot/mulebot/active // the active bot; if null, show bot list
|
||||
var/list/botstatus // the status signal sent by the bot
|
||||
//var/list/botlist = null // list of bots
|
||||
//var/obj/machinery/bot/mulebot/active // the active bot; if null, show bot list
|
||||
//var/list/botstatus // the status signal sent by the bot
|
||||
var/list/beacons
|
||||
|
||||
var/beacon_freq = 1400
|
||||
var/control_freq = 1447
|
||||
control_freq = 1447
|
||||
|
||||
// create a new QM cartridge, and register to receive bot control & beacon message
|
||||
New()
|
||||
..()
|
||||
spawn(5)
|
||||
if(radio_controller)
|
||||
radio_controller.add_object(src, control_freq, filter = RADIO_MULEBOT)
|
||||
radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
|
||||
spawn(10)
|
||||
post_signal(beacon_freq, "findbeacon", "delivery", s_filter = RADIO_NAVBEACONS)
|
||||
|
||||
Destroy()
|
||||
// create a new QM cartridge, and register to receive bot control & beacon message
|
||||
/obj/item/radio/integrated/mule/New()
|
||||
..()
|
||||
spawn(5)
|
||||
if(radio_controller)
|
||||
radio_controller.remove_object(src, control_freq)
|
||||
radio_controller.remove_object(src, beacon_freq)
|
||||
// receive radio signals
|
||||
// can detect bot status signals
|
||||
// and beacon locations
|
||||
// create/populate lists as they are recvd
|
||||
radio_controller.add_object(src, control_freq, filter = RADIO_MULEBOT)
|
||||
radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
|
||||
spawn(10)
|
||||
post_signal(beacon_freq, "findbeacon", "delivery", s_filter = RADIO_NAVBEACONS)
|
||||
|
||||
receive_signal(datum/signal/signal)
|
||||
// var/obj/item/device/pda/P = src.loc
|
||||
/obj/item/radio/integrated/mule/Destroy()
|
||||
if(radio_controller)
|
||||
radio_controller.remove_object(src,beacon_freq)
|
||||
..()
|
||||
|
||||
/*
|
||||
world << "recvd:[P] : [signal.source]"
|
||||
for(var/d in signal.data)
|
||||
world << "- [d] = [signal.data[d]]"
|
||||
*/
|
||||
if(signal.data["type"] == "mulebot")
|
||||
if(!botlist)
|
||||
botlist = new()
|
||||
// receive radio signals
|
||||
// can detect bot status signals
|
||||
// and beacon locations
|
||||
// create/populate lists as they are recvd
|
||||
|
||||
if(!(signal.source in botlist))
|
||||
botlist += signal.source
|
||||
/obj/item/radio/integrated/mule/receive_signal(datum/signal/signal)
|
||||
// var/obj/item/device/pda/P = src.loc
|
||||
|
||||
if(active == signal.source)
|
||||
var/list/b = signal.data
|
||||
botstatus = b.Copy()
|
||||
/*
|
||||
world << "recvd:[P] : [signal.source]"
|
||||
for(var/d in signal.data)
|
||||
world << "- [d] = [signal.data[d]]"
|
||||
*/
|
||||
if(signal.data["type"] == MULE_BOT)
|
||||
if(!botlist)
|
||||
botlist = new()
|
||||
|
||||
else if(signal.data["beacon"])
|
||||
if(!beacons)
|
||||
beacons = new()
|
||||
if(!(signal.source in botlist))
|
||||
botlist += signal.source
|
||||
|
||||
beacons[signal.data["beacon"] ] = signal.source
|
||||
if(active == signal.source)
|
||||
var/list/b = signal.data
|
||||
botstatus = b.Copy()
|
||||
|
||||
else if(signal.data["beacon"])
|
||||
if(!beacons)
|
||||
beacons = new()
|
||||
|
||||
beacons[signal.data["beacon"] ] = signal.source
|
||||
|
||||
|
||||
// if(istype(P)) P.updateSelfDialog()
|
||||
|
||||
Topic(href, href_list)
|
||||
..()
|
||||
var/cmd = "command"
|
||||
if(active) cmd = "command [active.suffix]"
|
||||
/obj/item/radio/integrated/mule/Topic(href, href_list)
|
||||
//..()
|
||||
//var/obj/item/device/pda/PDA = src.hostpda
|
||||
var/cmd = "command"
|
||||
if(active)
|
||||
cmd = "command [active.suffix]"
|
||||
|
||||
switch(href_list["op"])
|
||||
switch(href_list["op"])
|
||||
|
||||
if("control")
|
||||
active = locate(href_list["bot"])
|
||||
post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
|
||||
if("control")
|
||||
active = locate(href_list["bot"])
|
||||
|
||||
if("scanbots") // find all bots
|
||||
botlist = null
|
||||
post_signal(control_freq, "command", "bot_status", s_filter = RADIO_MULEBOT)
|
||||
if("scanbots") // find all bots
|
||||
botlist = null
|
||||
|
||||
if("botlist")
|
||||
active = null
|
||||
if("botlist")
|
||||
active = null
|
||||
|
||||
if("unload")
|
||||
post_signal(control_freq, cmd, "unload", s_filter = RADIO_MULEBOT)
|
||||
if("setdest")
|
||||
if(beacons)
|
||||
var/dest = input("Select Bot Destination", "Mulebot [active.suffix] Interlink", active.destination) as null|anything in beacons
|
||||
if(dest)
|
||||
post_signal(control_freq, cmd, "target", "destination", dest, s_filter = RADIO_MULEBOT)
|
||||
|
||||
if("unload")
|
||||
post_signal(control_freq, cmd, "unload", s_filter = RADIO_MULEBOT)
|
||||
post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
|
||||
if("setdest")
|
||||
if(beacons)
|
||||
var/dest = input("Select Bot Destination", "Mulebot [active.suffix] Interlink", active.destination) as null|anything in beacons
|
||||
if(dest)
|
||||
post_signal(control_freq, cmd, "target", "destination", dest, s_filter = RADIO_MULEBOT)
|
||||
post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
|
||||
if("retoff")
|
||||
post_signal(control_freq, cmd, "autoret", "value", 0, s_filter = RADIO_MULEBOT)
|
||||
if("reton")
|
||||
post_signal(control_freq, cmd, "autoret", "value", 1, s_filter = RADIO_MULEBOT)
|
||||
|
||||
if("retoff")
|
||||
post_signal(control_freq, cmd, "autoret", "value", 0, s_filter = RADIO_MULEBOT)
|
||||
post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
|
||||
if("reton")
|
||||
post_signal(control_freq, cmd, "autoret", "value", 1, s_filter = RADIO_MULEBOT)
|
||||
post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
|
||||
if("pickoff")
|
||||
post_signal(control_freq, cmd, "autopick", "value", 0, s_filter = RADIO_MULEBOT)
|
||||
|
||||
if("pickoff")
|
||||
post_signal(control_freq, cmd, "autopick", "value", 0, s_filter = RADIO_MULEBOT)
|
||||
post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
|
||||
if("pickon")
|
||||
post_signal(control_freq, cmd, "autopick", "value", 1, s_filter = RADIO_MULEBOT)
|
||||
post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
|
||||
if("pickon")
|
||||
post_signal(control_freq, cmd, "autopick", "value", 1, s_filter = RADIO_MULEBOT)
|
||||
|
||||
if("stop", "go", "home")
|
||||
post_signal(control_freq, cmd, href_list["op"], s_filter = RADIO_MULEBOT)
|
||||
post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
|
||||
if("stop", "go", "home")
|
||||
post_signal(control_freq, cmd, href_list["op"], s_filter = RADIO_MULEBOT)
|
||||
|
||||
post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
|
||||
|
||||
|
||||
|
||||
@@ -218,37 +227,42 @@
|
||||
var/last_transmission
|
||||
var/datum/radio_frequency/radio_connection
|
||||
|
||||
New()
|
||||
..()
|
||||
if(radio_controller)
|
||||
initialize()
|
||||
/obj/item/radio/integrated/signal/New()
|
||||
..()
|
||||
if(radio_controller)
|
||||
initialize()
|
||||
|
||||
initialize()
|
||||
if (src.frequency < 1441 || src.frequency > 1489)
|
||||
src.frequency = sanitize_frequency(src.frequency)
|
||||
|
||||
set_frequency(frequency)
|
||||
|
||||
proc/set_frequency(new_frequency)
|
||||
/obj/item/radio/integrated/signal/Destroy()
|
||||
if(radio_controller)
|
||||
radio_controller.remove_object(src, frequency)
|
||||
frequency = new_frequency
|
||||
radio_connection = radio_controller.add_object(src, frequency)
|
||||
..()
|
||||
|
||||
proc/send_signal(message="ACTIVATE")
|
||||
/obj/item/radio/integrated/signal/initialize()
|
||||
if (src.frequency < 1441 || src.frequency > 1489)
|
||||
src.frequency = sanitize_frequency(src.frequency)
|
||||
|
||||
if(last_transmission && world.time < (last_transmission + 5))
|
||||
return
|
||||
last_transmission = world.time
|
||||
set_frequency(frequency)
|
||||
|
||||
var/time = time2text(world.realtime,"hh:mm:ss")
|
||||
var/turf/T = get_turf(src)
|
||||
lastsignalers.Add("[time] <B>:</B> [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) <B>:</B> [format_frequency(frequency)]/[code]")
|
||||
/obj/item/radio/integrated/signal/proc/set_frequency(new_frequency)
|
||||
radio_controller.remove_object(src, frequency)
|
||||
frequency = new_frequency
|
||||
radio_connection = radio_controller.add_object(src, frequency)
|
||||
|
||||
var/datum/signal/signal = new
|
||||
signal.source = src
|
||||
signal.encryption = code
|
||||
signal.data["message"] = message
|
||||
|
||||
radio_connection.post_signal(src, signal)
|
||||
/obj/item/radio/integrated/signal/proc/send_signal(message="ACTIVATE")
|
||||
|
||||
if(last_transmission && world.time < (last_transmission + 5))
|
||||
return
|
||||
last_transmission = world.time
|
||||
|
||||
var/time = time2text(world.realtime,"hh:mm:ss")
|
||||
var/turf/T = get_turf(src)
|
||||
lastsignalers.Add("[time] <B>:</B> [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) <B>:</B> [format_frequency(frequency)]/[code]")
|
||||
|
||||
var/datum/signal/signal = new
|
||||
signal.source = src
|
||||
signal.encryption = code
|
||||
signal.data["message"] = message
|
||||
|
||||
radio_connection.post_signal(src, signal)
|
||||
|
||||
return
|
||||
@@ -10,9 +10,29 @@
|
||||
var/max_fire_temperature_sustained = 0 //The max temperature of the fire which it was subjected to
|
||||
var/dirt = 0
|
||||
var/dirtoverlay = null
|
||||
|
||||
/turf/simulated/New()
|
||||
..()
|
||||
levelupdate()
|
||||
|
||||
/turf/simulated/proc/MakeSlippery(var/wet_setting = 1) // 1 = Water, 2 = Lube
|
||||
if(wet >= wet_setting)
|
||||
return
|
||||
wet = wet_setting
|
||||
if(wet_setting == 1)
|
||||
if(wet_overlay)
|
||||
overlays -= wet_overlay
|
||||
wet_overlay = null
|
||||
wet_overlay = image('icons/effects/water.dmi', src, "wet_floor_static")
|
||||
overlays += wet_overlay
|
||||
|
||||
spawn(rand(790, 820)) // Purely so for visual effect
|
||||
if(!istype(src, /turf/simulated)) //Because turfs don't get deleted, they change, adapt, transform, evolve and deform. they are one and they are all.
|
||||
return
|
||||
if(wet > wet_setting) return
|
||||
wet = 0
|
||||
if(wet_overlay)
|
||||
overlays -= wet_overlay
|
||||
|
||||
/turf/simulated/proc/AddTracks(var/typepath,var/mob,var/bloodDNA,var/comingdir,var/goingdir)
|
||||
var/obj/effect/decal/cleanable/blood/tracks/tracks = locate(typepath) in src
|
||||
|
||||
@@ -218,7 +218,7 @@
|
||||
return
|
||||
|
||||
var/old_lumcount = lighting_lumcount - initial(lighting_lumcount)
|
||||
|
||||
var/old_opacity = opacity
|
||||
//world << "Replacing [src.type] with [N]"
|
||||
|
||||
if(connections) connections.erase_all()
|
||||
@@ -246,6 +246,11 @@
|
||||
W.lighting_changed = 1
|
||||
lighting_controller.changed_turfs += W
|
||||
|
||||
|
||||
if(old_opacity != W.opacity) //opacity has changed. Need to update surrounding lights
|
||||
if(W.lighting_lumcount) //unless we're being illuminated, don't bother (may be buggy, hard to test)
|
||||
W.UpdateAffectingLights()
|
||||
|
||||
if (istype(W,/turf/simulated/floor))
|
||||
W.RemoveLattice()
|
||||
|
||||
|
||||
@@ -319,3 +319,6 @@ var/recall_time_limit=72000
|
||||
|
||||
//added for Xenoarchaeology, might be useful for other stuff
|
||||
var/global/list/alphabet_uppercase = list("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z")
|
||||
|
||||
// AI controlled bots
|
||||
var/global/list/aibots = list()
|
||||
@@ -572,8 +572,5 @@
|
||||
src << "You do not have enough chemicals stored to reproduce."
|
||||
return
|
||||
|
||||
/mob/living/carbon/proc/assess_threat()
|
||||
return
|
||||
|
||||
/mob/living/carbon/proc/canBeHandcuffed()
|
||||
return 0
|
||||
@@ -1555,7 +1555,7 @@
|
||||
|
||||
//Check for ID
|
||||
var/obj/item/weapon/card/id/idcard = get_idcard()
|
||||
if(judgebot.idcheck && !idcard)
|
||||
if(judgebot.idcheck && !idcard && name=="Unknown")
|
||||
threatcount += 4
|
||||
|
||||
//Check for weapons
|
||||
@@ -1595,7 +1595,7 @@
|
||||
|
||||
//Agent cards lower threatlevel.
|
||||
if(istype(idcard, /obj/item/weapon/card/id/syndicate))
|
||||
threatcount -= 2
|
||||
threatcount -= 5
|
||||
|
||||
return threatcount
|
||||
|
||||
|
||||
@@ -507,6 +507,10 @@
|
||||
return 10 //Everyone is a criminal!
|
||||
var/threatcount = 0
|
||||
|
||||
//Securitrons can't identify monkeys
|
||||
if(!lasercolor && judgebot.idcheck )
|
||||
threatcount += 4
|
||||
|
||||
//Lasertag bullshit
|
||||
if(lasercolor)
|
||||
if(lasercolor == "b")//Lasertag turrets target the opposing team, how great is that? -Sieve
|
||||
|
||||
@@ -233,4 +233,5 @@
|
||||
step(AM, t)
|
||||
now_pushing = null
|
||||
|
||||
|
||||
/mob/living/silicon/assess_threat() //Secbots won't hunt silicon units
|
||||
return -10
|
||||
|
||||
@@ -869,6 +869,7 @@ var/list/slot_equipment_priority = list( \
|
||||
stat(null, "Mob-[master_controller.mobs_cost]\t#[mob_list.len]")
|
||||
stat(null, "Dis-[master_controller.diseases_cost]\t#[active_diseases.len]")
|
||||
stat(null, "Mch-[master_controller.machines_cost]\t#[machines.len]")
|
||||
stat(null, "Bots-[master_controller.aibots_cost]\t#[aibots.len]")
|
||||
stat(null, "Obj-[master_controller.objects_cost]\t#[processing_objects.len]")
|
||||
stat(null, "PiNet-[master_controller.networks_cost]\t#[pipe_networks.len]")
|
||||
stat(null, "Ponet-[master_controller.powernets_cost]\t#[powernets.len]")
|
||||
@@ -1308,3 +1309,6 @@ mob/proc/yank_out_object()
|
||||
if(paralysis)
|
||||
AdjustParalysis(-1)
|
||||
return paralysis
|
||||
|
||||
/mob/proc/assess_threat() //For sec bot threat assessment
|
||||
return
|
||||
+3
-1
@@ -913,4 +913,6 @@ var/list/RESTRICTED_CAMERA_NETWORKS = list( //Those networks can only be accesse
|
||||
#define IS_SKRELL 3
|
||||
#define IS_UNATHI 4
|
||||
|
||||
var/list/hit_appends = list("-OOF", "-ACK", "-UGH", "-HRNK", "-HURGH", "-GLORF")
|
||||
var/list/hit_appends = list("-OOF", "-ACK", "-UGH", "-HRNK", "-HURGH", "-GLORF")
|
||||
|
||||
#define BACKGROUND_ENABLED 0 // The default value for all uses of set background. Set background can cause gradual lag and is recommended you only turn this on if necessary.
|
||||
Reference in New Issue
Block a user