Bot port from /tg/

This commit is contained in:
Markolie
2014-12-02 06:29:15 +01:00
parent 79125ffb37
commit b21575f088
26 changed files with 2745 additions and 2882 deletions
@@ -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]"
+18 -1
View File
@@ -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)
+8 -1
View File
@@ -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
+36 -2
View File
@@ -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]
+3 -1
View File
@@ -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
+681 -59
View File
@@ -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
+144 -240
View File
@@ -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
View File
@@ -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
View File
@@ -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 += "&nbsp;<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 += "&nbsp;<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
View File
@@ -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
View File
@@ -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()
+197 -183
View File
@@ -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
+20
View File
@@ -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
+6 -1
View File
@@ -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()
+3
View File
@@ -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()
-3
View File
@@ -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
+2 -1
View File
@@ -233,4 +233,5 @@
step(AM, t)
now_pushing = null
/mob/living/silicon/assess_threat() //Secbots won't hunt silicon units
return -10
+4
View File
@@ -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
View File
@@ -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.