mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 21:18:37 +01:00
Merge pull request #4974 from GunHog/Botcall_TG_Edition
Botcall, TG edition!
This commit is contained in:
@@ -58,6 +58,10 @@
|
||||
aicamera.camera_mode_off()
|
||||
aicamera.captureimage(A, usr)
|
||||
return
|
||||
if(waypoint_mode)
|
||||
set_waypoint(A)
|
||||
waypoint_mode = 0
|
||||
return
|
||||
|
||||
/*
|
||||
AI restrained() currently does nothing
|
||||
|
||||
@@ -176,6 +176,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
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
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,7 +15,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()
|
||||
@@ -26,26 +94,46 @@
|
||||
/obj/machinery/bot/proc/turn_off()
|
||||
on = 0
|
||||
SetLuminosity(0)
|
||||
bot_reset() //Resets an AI's call, should it exist.
|
||||
|
||||
/obj/machinery/bot/New()
|
||||
..()
|
||||
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.
|
||||
if(radio_controller)
|
||||
radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
|
||||
if(bot_filter)
|
||||
radio_controller.add_object(src, control_freq, filter = bot_filter)
|
||||
|
||||
/obj/machinery/bot/proc/explode()
|
||||
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)
|
||||
/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)
|
||||
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(mob/user)
|
||||
..()
|
||||
if (src.health < maxhealth)
|
||||
if (src.health > maxhealth/3)
|
||||
if (health < maxhealth)
|
||||
if (health > maxhealth/3)
|
||||
user << "<span class='danger'>[src]'s parts look loose.</span>"
|
||||
else
|
||||
user << "<span class='danger'>[src]'s parts look very loose.</span>"
|
||||
@@ -54,32 +142,96 @@
|
||||
|
||||
/obj/machinery/bot/attack_alien(var/mob/living/carbon/alien/user as mob)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
src.health -= rand(15,30)*brute_dam_coeff
|
||||
src.visible_message("<span class='userdanger'>[user] has slashed [src]!</span>")
|
||||
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
|
||||
if(M.melee_damage_upper == 0)
|
||||
return
|
||||
M.changeNext_move(CLICK_CD_MELEE)
|
||||
src.health -= M.melee_damage_upper
|
||||
src.visible_message("<span class='userdanger'>[M] has [M.attacktext] [src]!</span>")
|
||||
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/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>"
|
||||
user << "<span class='notice'>Maintenance panel is now [open ? "opened" : "closed"].</span>"
|
||||
else
|
||||
user << "<span class='warning'>Maintenance panel is locked.</span>"
|
||||
else if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != "harm")
|
||||
@@ -103,10 +255,10 @@
|
||||
s.set_up(5, 1, src)
|
||||
switch(W.damtype)
|
||||
if("fire")
|
||||
src.health -= W.force * fire_dam_coeff
|
||||
health -= W.force * fire_dam_coeff
|
||||
s.start()
|
||||
if("brute")
|
||||
src.health -= W.force * brute_dam_coeff
|
||||
health -= W.force * brute_dam_coeff
|
||||
s.start()
|
||||
..()
|
||||
healthcheck()
|
||||
@@ -124,24 +276,24 @@
|
||||
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
|
||||
@@ -149,7 +301,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"
|
||||
@@ -167,17 +319,467 @@
|
||||
|
||||
/obj/machinery/bot/proc/hack(mob/user)
|
||||
var/hack
|
||||
if(issilicon(user))
|
||||
hack += "[src.emagged ? "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'>[src.emagged ? "DANGER" : "Engaged"]</A><BR>"
|
||||
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/attack_ai(mob/user as mob)
|
||||
src.attack_hand(user)
|
||||
/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/proc/speak(var/message)
|
||||
if((!src.on) || (!message))
|
||||
/obj/machinery/bot/attack_ai(mob/user as mob)
|
||||
attack_hand(user)
|
||||
|
||||
/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
|
||||
audible_message("<span class='game say'><span class='name'>[src]</span> beeps, \"[message]\"</span>",2)
|
||||
if(freq)
|
||||
Radio.set_frequency(radio_frequency)
|
||||
Radio.talk_into(src, message, radio_frequency)
|
||||
else
|
||||
say(message)
|
||||
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.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
|
||||
|
||||
/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
|
||||
|
||||
@@ -24,51 +24,57 @@
|
||||
//weight = 1.0E7
|
||||
health = 25
|
||||
maxhealth = 25
|
||||
var/cleaning = 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)
|
||||
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 = SERV_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()
|
||||
..()
|
||||
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)
|
||||
. = ..()
|
||||
@@ -81,76 +87,39 @@
|
||||
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 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 && !src.emagged)
|
||||
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", "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() */
|
||||
if("hack")
|
||||
if(!src.emagged)
|
||||
src.emagged = 2
|
||||
src.hacked = 1
|
||||
usr << "<span class='warning'>You corrupt [src]'s cleaning software.</span>"
|
||||
else if(!src.hacked)
|
||||
usr << "<span class='userdanger'>[src] does not seem to respond to your repair code!</span>"
|
||||
else
|
||||
src.hacked = 0
|
||||
src.emagged = 0
|
||||
usr << "<span class='notice'>[src]'s software has been reset!</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>"
|
||||
@@ -163,135 +132,76 @@ text("<A href='?src=\ref[src];operation=oddbutton'>[src.oddbutton ? "Yes" : "No"
|
||||
|
||||
/obj/machinery/bot/cleanbot/Emag(mob/user as mob)
|
||||
..()
|
||||
if(open && !locked)
|
||||
if(user) user << "<span class='notice'>[src] buzzes and beeps.</span>"
|
||||
src.emagged = 2
|
||||
if(emagged == 2)
|
||||
if(user)
|
||||
user << "<span class='danger'>[src] buzzes and beeps.</span>"
|
||||
|
||||
/obj/machinery/bot/cleanbot/process_scan(var/obj/effect/decal/cleanable/D)
|
||||
for(var/T in target_types)
|
||||
if(istype(D, T))
|
||||
return D
|
||||
|
||||
/obj/machinery/bot/cleanbot/process()
|
||||
set background = BACKGROUND_ENABLED
|
||||
|
||||
if(!src.on)
|
||||
if (!..())
|
||||
return
|
||||
if(src.cleaning)
|
||||
return
|
||||
var/list/cleanbottargets = list()
|
||||
|
||||
if(!src.emagged && 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.emagged && prob(10)) //Wets floors randomly
|
||||
if(istype(loc,/turf/simulated))
|
||||
var/turf/simulated/T = src.loc
|
||||
T.MakeSlippery()
|
||||
if(!target) //Search for cleanables it can see.
|
||||
target = scan(/obj/effect/decal/cleanable/, oldtarget)
|
||||
oldtarget = target
|
||||
|
||||
if(src.emagged && 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(src.loc)
|
||||
if(!target)
|
||||
if(loc != oldloc)
|
||||
oldtarget = null
|
||||
|
||||
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(!(D in cleanbottargets) && (D.type == T || D.parent_type == T) && D != src.oldtarget)
|
||||
src.oldtarget = D
|
||||
src.target = D
|
||||
return
|
||||
if(auto_patrol)
|
||||
if(mode == BOT_IDLE || mode == BOT_START_PATROL)
|
||||
start_patrol()
|
||||
|
||||
if(!src.target || src.target == null)
|
||||
if(src.loc != src.oldloc)
|
||||
src.oldtarget = null
|
||||
if(mode == BOT_PATROL)
|
||||
bot_patrol()
|
||||
|
||||
if (!should_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
|
||||
return
|
||||
mode = BOT_MOVING
|
||||
else if (!bot_move(target))
|
||||
target = null
|
||||
mode = BOT_IDLE
|
||||
|
||||
if(loc == target.loc)
|
||||
clean(target)
|
||||
path = list()
|
||||
target = null
|
||||
return
|
||||
|
||||
if (!patrol_path || patrol_path.len < 1)
|
||||
var/datum/radio_frequency/frequency = radio_controller.return_frequency(beacon_freq)
|
||||
|
||||
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_cardinal, 0, 120, id=botcard, exclude=null)
|
||||
if(!patrol_path)
|
||||
patrol_path = list()
|
||||
else
|
||||
patrol_move()
|
||||
|
||||
return
|
||||
|
||||
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
|
||||
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
|
||||
@@ -306,7 +216,7 @@ text("<A href='?src=\ref[src];operation=oddbutton'>[src.oddbutton ? "Yes" : "No"
|
||||
target_types += /obj/effect/decal/cleanable/greenglow
|
||||
target_types += /obj/effect/decal/cleanable/dirt
|
||||
|
||||
if(src.blood)
|
||||
if(blood)
|
||||
target_types += /obj/effect/decal/cleanable/xenoblood/
|
||||
target_types += /obj/effect/decal/cleanable/xenoblood/xgibs
|
||||
target_types += /obj/effect/decal/cleanable/blood/
|
||||
@@ -314,20 +224,21 @@ text("<A href='?src=\ref[src];operation=oddbutton'>[src.oddbutton ? "Yes" : "No"
|
||||
target_types += /obj/effect/decal/cleanable/trail_holder
|
||||
|
||||
/obj/machinery/bot/cleanbot/proc/clean(var/obj/effect/decal/cleanable/target)
|
||||
src.anchored = 1
|
||||
src.icon_state = "cleanbot-c"
|
||||
anchored = 1
|
||||
icon_state = "cleanbot-c"
|
||||
visible_message("<span class='notice'>[src] begins to clean up [target]</span>")
|
||||
src.cleaning = 1
|
||||
mode = BOT_CLEANING
|
||||
spawn(50)
|
||||
src.cleaning = 0
|
||||
qdel(target)
|
||||
src.icon_state = "cleanbot[src.on]"
|
||||
src.anchored = 0
|
||||
src.target = null
|
||||
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("<span class='userdanger'><B>[src] blows apart!</B></span>")
|
||||
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)
|
||||
@@ -348,17 +259,17 @@ text("<A href='?src=\ref[src];operation=oddbutton'>[src.oddbutton ? "Yes" : "No"
|
||||
if(istype(W, /obj/item/robot_parts/l_arm) || istype(W, /obj/item/robot_parts/r_arm))
|
||||
user.drop_item()
|
||||
qdel(W)
|
||||
var/turf/T = get_turf(src.loc)
|
||||
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.unEquip(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 = copytext(stripped_input(user, "Enter new robot name", name, created_name),1,MAX_NAME_LEN)
|
||||
if (!t)
|
||||
return
|
||||
if (!in_range(src, usr) && src.loc != usr)
|
||||
if (!in_range(src, usr) && loc != usr)
|
||||
return
|
||||
src.created_name = t
|
||||
created_name = t
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
var/threatlevel = 0
|
||||
var/target_lastloc //Loc of target when arrested.
|
||||
var/last_found //There's a delay
|
||||
var/frustration = 0
|
||||
//var/emagged = 0 //Emagged Secbots view everyone as a criminal
|
||||
var/declare_arrests = 1 //When making an arrest, should it notify everyone wearing sechuds?
|
||||
var/idcheck = 1 //If true, arrest people with no IDs
|
||||
@@ -34,38 +33,17 @@
|
||||
var/arrest_type = 0 //If true, don't handcuff
|
||||
var/projectile = /obj/item/projectile/energy/electrode //Holder for projectile type
|
||||
var/shoot_sound = 'sound/weapons/Taser.ogg'
|
||||
|
||||
var/mode = 0
|
||||
#define SECBOT_IDLE 0 // idle
|
||||
#define SECBOT_HUNT 1 // found target, hunting
|
||||
#define SECBOT_PREP_ARREST 2 // at target, preparing to arrest
|
||||
#define SECBOT_ARREST 3 // arresting target
|
||||
#define SECBOT_START_PATROL 4 // start patrol
|
||||
#define SECBOT_PATROL 5 // patrolling
|
||||
#define SECBOT_SUMMON 6 // summoned by PDA
|
||||
|
||||
var/auto_patrol = 0 // set to make bot automatically patrol
|
||||
|
||||
var/beacon_freq = 1445 // navigation beacon frequency
|
||||
var/control_freq = 1447 // bot control frequency
|
||||
|
||||
radio_frequency = SEC_FREQ
|
||||
bot_type = SEC_BOT
|
||||
bot_filter = RADIO_SECBOT
|
||||
/
|
||||
//List of weapons that secbots will not arrest for
|
||||
var/safe_weapons = list(\
|
||||
/obj/item/weapon/gun/energy/laser/bluetag,\
|
||||
/obj/item/weapon/gun/energy/laser/redtag,\
|
||||
/obj/item/weapon/gun/energy/laser/practice)
|
||||
|
||||
var/turf/patrol_target // this is turf to navigate to (location of beacon)
|
||||
var/new_destination // pending new destination (waiting for beacon response)
|
||||
var/destination // destination description tag
|
||||
var/next_destination // the next destination in the patrol route
|
||||
var/list/path = new // list of path turfs
|
||||
|
||||
var/blockcount = 0 //number of times retried a blocked path
|
||||
var/awaiting_beacon = 0 // count of pticks awaiting a beacon response
|
||||
|
||||
var/nearest_beacon // the nearest beacon's tag
|
||||
var/turf/nearest_beacon_loc // the nearest beacon's location
|
||||
/obj/item/weapon/gun/energy/laser/practice,\
|
||||
/obj/item/weapon/melee/telebaton,\
|
||||
/obj/item/weapon/gun/energy/kinetic_accelerator)
|
||||
|
||||
|
||||
/obj/item/weapon/ed209_assembly
|
||||
@@ -85,16 +63,15 @@
|
||||
name = created_name
|
||||
if(created_lasercolor)
|
||||
lasercolor = created_lasercolor
|
||||
src.icon_state = "[lasercolor]ed209[src.on]"
|
||||
src.set_weapon() //giving it the right projectile and firing sound.
|
||||
icon_state = "[lasercolor]ed209[on]"
|
||||
set_weapon() //giving it the right projectile and firing sound.
|
||||
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()
|
||||
botcard.access = J.get_access()
|
||||
prev_access = botcard.access
|
||||
|
||||
if(radio_controller)
|
||||
radio_controller.add_object(src, control_freq, filter = RADIO_SECBOT)
|
||||
radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
|
||||
|
||||
add_to_beacons(bot_filter)
|
||||
if(lasercolor)
|
||||
shot_delay = 6//Longer shot delay because JESUS CHRIST
|
||||
check_records = 0//Don't actively target people set to arrest
|
||||
@@ -108,19 +85,28 @@
|
||||
|
||||
/obj/machinery/bot/ed209/turn_on()
|
||||
. = ..()
|
||||
src.icon_state = "[lasercolor]ed209[src.on]"
|
||||
src.mode = SECBOT_IDLE
|
||||
src.updateUsrDialog()
|
||||
icon_state = "[lasercolor]ed209[on]"
|
||||
mode = BOT_IDLE
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/bot/ed209/turn_off()
|
||||
..()
|
||||
src.target = null
|
||||
src.oldtarget_name = null
|
||||
src.anchored = 0
|
||||
src.mode = SECBOT_IDLE
|
||||
icon_state = "[lasercolor]ed209[on]"
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/bot/ed209/bot_reset()
|
||||
..()
|
||||
target = null
|
||||
oldtarget_name = null
|
||||
anchored = 0
|
||||
walk_to(src,0)
|
||||
src.icon_state = "[lasercolor]ed209[src.on]"
|
||||
src.updateUsrDialog()
|
||||
last_found = world.time
|
||||
set_weapon()
|
||||
|
||||
/obj/machinery/bot/ed209/set_custom_texts()
|
||||
text_hack = "You disable [name]'s combat inhibitor."
|
||||
text_dehack = "You restore [name]'s combat inhibitor."
|
||||
text_dehack_fail = "[name] ignores your attempts to restrict him!"
|
||||
|
||||
/obj/machinery/bot/ed209/attack_hand(mob/user as mob)
|
||||
. = ..()
|
||||
@@ -129,13 +115,14 @@
|
||||
var/dat
|
||||
dat += hack(user)
|
||||
dat += text({"
|
||||
<TT><B>Security Unit v2.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"]<BR>"},
|
||||
|
||||
"<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))
|
||||
if(!lasercolor)
|
||||
dat += text({"<BR>
|
||||
Arrest Unidentifiable Persons: []<BR>
|
||||
@@ -143,82 +130,50 @@ Arrest for Unauthorized Weapons: []<BR>
|
||||
Arrest for Warrant: []<BR>
|
||||
<BR>
|
||||
Operating Mode: []<BR>
|
||||
Report Arrests[]"},
|
||||
|
||||
"<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>" )
|
||||
|
||||
dat += text({"<BR>
|
||||
Auto Patrol: []"},
|
||||
Report Arrests[]<BR>
|
||||
Auto Patrol[]"},
|
||||
|
||||
"<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 v2.0.9 controls")
|
||||
var/datum/browser/popup = new(user, "autoed209", "Automatic Security Unit v2.6")
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
return
|
||||
|
||||
/obj/machinery/bot/ed209/Topic(href, href_list)
|
||||
if (..())
|
||||
return
|
||||
usr.set_machine(src)
|
||||
src.add_fingerprint(usr)
|
||||
if(lasercolor && (istype(usr,/mob/living/carbon/human)))
|
||||
var/mob/living/carbon/human/H = usr
|
||||
if((lasercolor == "b") && (istype(H.wear_suit, /obj/item/clothing/suit/redtag)))//Opposing team cannot operate it
|
||||
return
|
||||
else if((lasercolor == "r") && (istype(H.wear_suit, /obj/item/clothing/suit/bluetag)))
|
||||
return
|
||||
if ((href_list["power"]) && (src.allowed(usr)))
|
||||
if (src.on && !src.emagged)
|
||||
turn_off()
|
||||
else
|
||||
turn_on()
|
||||
return
|
||||
..()
|
||||
|
||||
switch(href_list["operation"])
|
||||
if ("idcheck")
|
||||
src.idcheck = !src.idcheck
|
||||
src.updateUsrDialog()
|
||||
idcheck = !idcheck
|
||||
if("weaponscheck")
|
||||
src.weaponscheck = !src.weaponscheck
|
||||
src.updateUsrDialog()
|
||||
if("ignorerec")
|
||||
src.check_records = !src.check_records
|
||||
src.updateUsrDialog()
|
||||
if("switchmode")
|
||||
src.arrest_type = !src.arrest_type
|
||||
src.updateUsrDialog()
|
||||
if("patrol")
|
||||
auto_patrol = !auto_patrol
|
||||
mode = SECBOT_IDLE
|
||||
weaponscheck = !weaponscheck
|
||||
updateUsrDialog()
|
||||
if ("ignorerec")
|
||||
check_records = !check_records
|
||||
updateUsrDialog()
|
||||
if ("switchmode")
|
||||
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
|
||||
src.set_weapon()
|
||||
usr << "<span class='warning'>You disable [src]'s combat inhibitor.</span>"
|
||||
else if(!src.hacked)
|
||||
usr << "<span class='userdanger'>[src] ignores your attempts to restrict it!</span>"
|
||||
else
|
||||
src.emagged = 0
|
||||
src.hacked = 0
|
||||
src.set_weapon()
|
||||
usr << "<span class='notice'>You restore [src]'s combat inhibitor.</span>"
|
||||
src.updateUsrDialog()
|
||||
declare_arrests = !declare_arrests
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/bot/ed209/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>"
|
||||
if (allowed(user) && !open && !emagged)
|
||||
locked = !locked
|
||||
user << "<span class='notice'>Controls are now [locked ? "locked" : "unlocked"].</span>"
|
||||
else
|
||||
if(emagged)
|
||||
user << "<span class='warning'>ERROR</span>"
|
||||
@@ -230,79 +185,75 @@ Auto Patrol: []"},
|
||||
..()
|
||||
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) && (!src.target)) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
|
||||
if (!istype(W, /obj/item/weapon/screwdriver) && (!target)) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
|
||||
if(W.force && W.damtype != STAMINA)//If force is non-zero and damage type isn't stamina.
|
||||
threatlevel = user.assess_threat(src)
|
||||
threatlevel += 6
|
||||
if(threatlevel >= 4)
|
||||
src.target = user
|
||||
target = user
|
||||
if(lasercolor)//To make up for the fact that lasertag bots don't hunt
|
||||
src.shootAt(user)
|
||||
src.mode = SECBOT_HUNT
|
||||
shootAt(user)
|
||||
mode = BOT_HUNT
|
||||
|
||||
/obj/machinery/bot/ed209/Emag(mob/user as mob)
|
||||
..()
|
||||
if(open && !locked)
|
||||
if(user) user << "<span class='warning'>You short out [src]'s target assessment circuits.</span>"
|
||||
spawn(0)
|
||||
audible_message("<span class='danger'>[src] buzzes oddly!</span>")
|
||||
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 = "[lasercolor]ed209[src.on]"
|
||||
src.set_weapon()
|
||||
mode = SECBOT_IDLE
|
||||
if(emagged == 2)
|
||||
if(user)
|
||||
user << "<span class='warning'>You short out [src]'s target assessment circuits.</span>"
|
||||
oldtarget_name = user.name
|
||||
audible_message("<span class='danger'>[src] buzzes oddly!</span>")
|
||||
declare_arrests = 0
|
||||
icon_state = "[lasercolor]ed209[on]"
|
||||
set_weapon()
|
||||
|
||||
/obj/machinery/bot/ed209/process()
|
||||
set background = BACKGROUND_ENABLED
|
||||
|
||||
if (!src.on || src.disabled)
|
||||
if (!..())
|
||||
return
|
||||
|
||||
if(disabled)
|
||||
return
|
||||
|
||||
var/list/targets = list()
|
||||
for (var/mob/living/carbon/C in view(9,src)) //Let's find us a target
|
||||
for (var/mob/living/carbon/C in view(7,src)) //Let's find us a target
|
||||
var/threatlevel = 0
|
||||
if ((C.stat) || (C.lying))
|
||||
continue
|
||||
threatlevel = C.assess_threat(src, lasercolor)
|
||||
//src.speak(C.real_name + text(": threat: []", threatlevel))
|
||||
//speak(C.real_name + text(": threat: []", threatlevel))
|
||||
if (threatlevel < 4 )
|
||||
continue
|
||||
|
||||
var/dst = get_dist(src, C)
|
||||
if ( dst <= 1 || dst > 12)
|
||||
if ( dst <= 1 || dst > 7)
|
||||
continue
|
||||
|
||||
targets += C
|
||||
if (targets.len>0)
|
||||
var/mob/living/carbon/t = pick(targets)
|
||||
if ((t.stat!=2) && (t.lying != 1) && (!t.handcuffed)) //we don't shoot people who are dead, cuffed or lying down.
|
||||
src.shootAt(t)
|
||||
shootAt(t)
|
||||
switch(mode)
|
||||
|
||||
if(SECBOT_IDLE) // idle
|
||||
if(BOT_IDLE) // idle
|
||||
walk_to(src,0)
|
||||
if(!src.lasercolor) //lasertag bots don't want to arrest anyone
|
||||
if(!lasercolor) //lasertag bots don't want to arrest anyone
|
||||
look_for_perp() // see if any criminals are in range
|
||||
if(!mode && auto_patrol) // still idle, and set to patrol
|
||||
mode = SECBOT_START_PATROL // switch to patrol mode
|
||||
mode = BOT_START_PATROL // switch to patrol mode
|
||||
|
||||
if(SECBOT_HUNT) // hunting for perp
|
||||
if(BOT_HUNT) // hunting for perp
|
||||
// if can't reach perp for long enough, go idle
|
||||
if(src.frustration >= 8)
|
||||
if (frustration >= 8)
|
||||
walk_to(src,0)
|
||||
back_to_idle()
|
||||
|
||||
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 = "[lasercolor]ed209-c"
|
||||
if(Adjacent(target) && isturf(target.loc)) // if right next to perp
|
||||
playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
|
||||
icon_state = "[lasercolor]ed209-c"
|
||||
spawn(2)
|
||||
src.icon_state = "[lasercolor]ed209[src.on]"
|
||||
var/mob/living/carbon/M = src.target
|
||||
icon_state = "[lasercolor]ed209[on]"
|
||||
var/mob/living/carbon/M = target
|
||||
if(istype(M, /mob/living/carbon/human))
|
||||
if( M.stuttering < 5 && !(HULK in M.mutations) )
|
||||
M.stuttering = 5
|
||||
@@ -315,45 +266,45 @@ Auto Patrol: []"},
|
||||
|
||||
if(declare_arrests)
|
||||
var/area/location = get_area(src)
|
||||
broadcast_hud_message("[src.name] is [arrest_type ? "detaining" : "arresting"] level [threatlevel] scumbag <b>[target.name]</b> in <b>[location]</b>", src)
|
||||
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></span>")
|
||||
speak("[arrest_type ? "Detaining" : "Arresting"] level [threatlevel] scumbag <b>[target]</b> in [location].", radio_frequency)
|
||||
target.visible_message("<span class='danger'>[target] has been stunned by [src]!</span>",\
|
||||
"<span class='userdanger'>[target] has been stunned by [src]!</span></span>")
|
||||
|
||||
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
|
||||
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 he's no no longer adjacent or inside a closet or about to get up, we hunt again.
|
||||
if( !src.Adjacent(target) || !isturf(src.target.loc) || src.target.weakened < 2 )
|
||||
if( !Adjacent(target) || !isturf(target.loc) || target.weakened < 2 )
|
||||
back_to_hunt()
|
||||
return
|
||||
|
||||
if(iscarbon(target) && target.canBeHandcuffed())
|
||||
if(!src.arrest_type)
|
||||
if(!src.target.handcuffed) //he's not cuffed? Try to cuff him!
|
||||
mode = SECBOT_ARREST
|
||||
playsound(src.loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
|
||||
target.visible_message("<span class='danger'>[src] is trying to put zipties on [src.target]!</span>",\
|
||||
"<span class='userdanger'>[src] is trying to put zipties on [src.target]!</span>")
|
||||
if(!arrest_type)
|
||||
if(!target.handcuffed) //he's not cuffed? Try to cuff him!
|
||||
mode = BOT_ARREST
|
||||
playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
|
||||
target.visible_message("<span class='danger'>[src] is trying to put zipties on [target]!</span>",\
|
||||
"<span class='userdanger'>[src] is trying to put zipties on [target]!</span>")
|
||||
|
||||
spawn(60)
|
||||
if( !src.Adjacent(target) || !isturf(src.target.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
|
||||
if( !Adjacent(target) || !isturf(target.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
|
||||
return
|
||||
if(!src.target.handcuffed)
|
||||
src.target.handcuffed = new /obj/item/weapon/restraints/handcuffs/cable/zipties/used(src.target)
|
||||
if(!target.handcuffed)
|
||||
target.handcuffed = new /obj/item/weapon/restraints/handcuffs/cable/zipties/used(target)
|
||||
target.update_inv_handcuffed(0) //update the handcuffs overlay
|
||||
back_to_idle()
|
||||
else
|
||||
@@ -363,325 +314,78 @@ Auto Patrol: []"},
|
||||
back_to_idle()
|
||||
return
|
||||
|
||||
if(SECBOT_ARREST)
|
||||
if(BOT_ARREST)
|
||||
if (!target)
|
||||
src.anchored = 0
|
||||
mode = SECBOT_IDLE
|
||||
src.last_found = world.time
|
||||
anchored = 0
|
||||
mode = BOT_IDLE
|
||||
last_found = world.time
|
||||
frustration = 0
|
||||
return
|
||||
|
||||
if(src.target.handcuffed) //no target or target cuffed? back to idle.
|
||||
if(target.handcuffed) //no target or target cuffed? back to idle.
|
||||
back_to_idle()
|
||||
return
|
||||
|
||||
if( !src.Adjacent(target) || !isturf(src.target.loc) || (src.target.loc != src.target_lastloc && src.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.
|
||||
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
|
||||
mode = BOT_PREP_ARREST
|
||||
anchored = 0
|
||||
|
||||
if(BOT_START_PATROL)
|
||||
look_for_perp()
|
||||
start_patrol()
|
||||
|
||||
if(BOT_PATROL)
|
||||
look_for_perp()
|
||||
bot_patrol()
|
||||
|
||||
|
||||
if(SECBOT_START_PATROL) // start a patrol
|
||||
|
||||
if(path.len > 0 && patrol_target) // have a valid path, so just resume
|
||||
mode = SECBOT_PATROL
|
||||
return
|
||||
|
||||
else if(patrol_target) // has patrol target already
|
||||
spawn(0)
|
||||
calc_path() // so just find a route to it
|
||||
if(path.len == 0)
|
||||
patrol_target = 0
|
||||
return
|
||||
mode = SECBOT_PATROL
|
||||
|
||||
|
||||
else // no patrol target, so need a new one
|
||||
find_patrol_target()
|
||||
speak("Engaging patrol mode.")
|
||||
|
||||
|
||||
if(SECBOT_PATROL) // patrol mode
|
||||
patrol_step()
|
||||
spawn(5)
|
||||
if(mode == SECBOT_PATROL)
|
||||
patrol_step()
|
||||
|
||||
if(SECBOT_SUMMON) // summoned to PDA
|
||||
patrol_step()
|
||||
spawn(4)
|
||||
if(mode == SECBOT_SUMMON)
|
||||
patrol_step()
|
||||
sleep(4)
|
||||
patrol_step()
|
||||
return
|
||||
|
||||
/obj/machinery/bot/ed209/proc/back_to_idle()
|
||||
src.anchored = 0
|
||||
mode = SECBOT_IDLE
|
||||
src.target = null
|
||||
src.last_found = world.time
|
||||
anchored = 0
|
||||
mode = BOT_IDLE
|
||||
target = null
|
||||
last_found = world.time
|
||||
frustration = 0
|
||||
spawn(0)
|
||||
process() //ensure bot quickly responds
|
||||
|
||||
/obj/machinery/bot/ed209/proc/back_to_hunt()
|
||||
src.anchored = 0
|
||||
src.frustration = 0
|
||||
mode = SECBOT_HUNT
|
||||
anchored = 0
|
||||
frustration = 0
|
||||
mode = BOT_HUNT
|
||||
spawn(0)
|
||||
process() //ensure bot quickly responds
|
||||
|
||||
// perform a single patrol step
|
||||
/obj/machinery/bot/ed209/proc/patrol_step()
|
||||
|
||||
if(loc == patrol_target) // reached target
|
||||
at_patrol_target()
|
||||
return
|
||||
|
||||
else if(path.len > 0 && patrol_target) // valid path
|
||||
|
||||
var/turf/next = path[1]
|
||||
if(next == loc)
|
||||
path -= next
|
||||
return
|
||||
|
||||
|
||||
if(istype( next, /turf/simulated))
|
||||
|
||||
var/moved = step_towards(src, next) // attempt to move
|
||||
if(moved) // successful move
|
||||
blockcount = 0
|
||||
path -= loc
|
||||
|
||||
if(lasercolor)
|
||||
sleep(20)
|
||||
else
|
||||
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/ed209/proc/find_patrol_target()
|
||||
send_status()
|
||||
if(awaiting_beacon) // awaiting beacon response
|
||||
awaiting_beacon++
|
||||
if(awaiting_beacon > 5) // wait 5 secs for beacon response
|
||||
find_nearest_beacon() // then go to nearest instead
|
||||
return
|
||||
|
||||
if(next_destination)
|
||||
set_destination(next_destination)
|
||||
else
|
||||
find_nearest_beacon()
|
||||
return
|
||||
|
||||
|
||||
// finds the nearest beacon to self
|
||||
// signals all beacons matching the patrol code
|
||||
/obj/machinery/bot/ed209/proc/find_nearest_beacon()
|
||||
nearest_beacon = null
|
||||
new_destination = "__nearest__"
|
||||
post_signal(beacon_freq, "findbeacon", "patrol")
|
||||
awaiting_beacon = 1
|
||||
spawn(10)
|
||||
awaiting_beacon = 0
|
||||
if(nearest_beacon)
|
||||
set_destination(nearest_beacon)
|
||||
else
|
||||
auto_patrol = 0
|
||||
mode = SECBOT_IDLE
|
||||
speak("Disengaging patrol mode.")
|
||||
send_status()
|
||||
|
||||
|
||||
/obj/machinery/bot/ed209/proc/at_patrol_target()
|
||||
if(auto_patrol)
|
||||
find_patrol_target()
|
||||
else
|
||||
mode = SECBOT_IDLE
|
||||
return
|
||||
|
||||
|
||||
// sets the current destination
|
||||
// signals all beacons matching the patrol code
|
||||
// beacons will return a signal giving their locations
|
||||
/obj/machinery/bot/ed209/proc/set_destination(var/new_dest)
|
||||
new_destination = new_dest
|
||||
post_signal(beacon_freq, "findbeacon", "patrol")
|
||||
awaiting_beacon = 1
|
||||
|
||||
|
||||
// receive a radio signal
|
||||
// used for beacon reception
|
||||
|
||||
/obj/machinery/bot/ed209/receive_signal(datum/signal/signal)
|
||||
|
||||
if(!on)
|
||||
return
|
||||
|
||||
/*
|
||||
world << "rec signal: [signal.source]"
|
||||
for(var/x in signal.data)
|
||||
world << "* [x] = [signal.data[x]]"
|
||||
*/
|
||||
|
||||
var/recv = signal.data["command"]
|
||||
// process all-bot input
|
||||
if(recv=="bot_status")
|
||||
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/ed209/proc/post_signal(var/freq, var/key, var/value)
|
||||
post_signal_multiple(freq, list("[key]" = value) )
|
||||
|
||||
// send a radio signal with multiple data key/values
|
||||
/obj/machinery/bot/ed209/proc/post_signal_multiple(var/freq, var/list/keyval)
|
||||
|
||||
var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
|
||||
|
||||
if(!frequency) return
|
||||
|
||||
var/datum/signal/signal = new()
|
||||
signal.source = src
|
||||
signal.transmission_method = 1
|
||||
//for(var/key in keyval)
|
||||
// signal.data[key] = keyval[key]
|
||||
//world << "sent [key],[keyval[key]] on [freq]"
|
||||
signal.data = keyval
|
||||
if (signal.data["findbeacon"])
|
||||
frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
|
||||
else if (signal.data["type"] == "secbot")
|
||||
frequency.post_signal(src, signal, filter = RADIO_SECBOT)
|
||||
else
|
||||
frequency.post_signal(src, signal)
|
||||
|
||||
// signals bot status etc. to controller
|
||||
/obj/machinery/bot/ed209/proc/send_status()
|
||||
var/list/kv = list(
|
||||
"type" = "secbot",
|
||||
"name" = name,
|
||||
"loca" = loc.loc, // area
|
||||
"mode" = mode,
|
||||
)
|
||||
post_signal_multiple(control_freq, kv)
|
||||
|
||||
|
||||
|
||||
// calculates a path to the current destination
|
||||
// given an optional turf to avoid
|
||||
/obj/machinery/bot/ed209/proc/calc_path(var/turf/avoid = null)
|
||||
src.path = AStar(src.loc, patrol_target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 120, id=botcard, exclude=avoid)
|
||||
if(!src.path)
|
||||
src.path = list()
|
||||
|
||||
|
||||
// look for a criminal in view of the bot
|
||||
|
||||
/obj/machinery/bot/ed209/proc/look_for_perp()
|
||||
if(src.disabled)
|
||||
if(disabled)
|
||||
return
|
||||
src.anchored = 0
|
||||
src.threatlevel = 0
|
||||
for (var/mob/living/carbon/C in view(12,src)) //Let's find us a criminal
|
||||
anchored = 0
|
||||
threatlevel = 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, lasercolor)
|
||||
threatlevel = C.assess_threat(src, lasercolor)
|
||||
|
||||
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/ed209_20sec.ogg', 'sound/voice/EDPlaceholder.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/ed209_20sec.ogg', 'sound/voice/EDPlaceholder.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
|
||||
break
|
||||
@@ -695,14 +399,14 @@ Auto Patrol: []"},
|
||||
return 0
|
||||
|
||||
/obj/machinery/bot/ed209/Bump(M as mob|obj) //Leave no door unopened!
|
||||
if ((istype(M, /obj/machinery/door)) && (!isnull(src.botcard)))
|
||||
if ((istype(M, /obj/machinery/door)) && (!isnull(botcard)))
|
||||
var/obj/machinery/door/D = M
|
||||
if (!istype(D, /obj/machinery/door/firedoor) && D.check_access(src.botcard))
|
||||
if (!istype(D, /obj/machinery/door/firedoor) && D.check_access(botcard))
|
||||
D.open()
|
||||
src.frustration = 0
|
||||
else if ((istype(M, /mob/living/)) && (!src.anchored))
|
||||
src.loc = M:loc
|
||||
src.frustration = 0
|
||||
frustration = 0
|
||||
else if ((istype(M, /mob/living/)) && (!anchored))
|
||||
loc = M:loc
|
||||
frustration = 0
|
||||
return
|
||||
|
||||
/* terrible
|
||||
@@ -715,13 +419,13 @@ Auto Patrol: []"},
|
||||
|
||||
/obj/machinery/bot/ed209/explode()
|
||||
walk_to(src,0)
|
||||
src.visible_message("<span class='userdanger'>[src] blows apart!</span>")
|
||||
visible_message("<span class='userdanger'>[src] blows apart!</span>")
|
||||
var/turf/Tsec = get_turf(src)
|
||||
|
||||
var/obj/item/weapon/ed209_assembly/Sa = new /obj/item/weapon/ed209_assembly(Tsec)
|
||||
Sa.build_step = 1
|
||||
Sa.overlays += image('icons/obj/aibots.dmi', "hs_hole")
|
||||
Sa.created_name = src.name
|
||||
Sa.created_name = name
|
||||
new /obj/item/device/assembly/prox_sensor(Tsec)
|
||||
|
||||
if(!lasercolor)
|
||||
@@ -756,12 +460,12 @@ Auto Patrol: []"},
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
|
||||
new /obj/effect/decal/cleanable/oil(src.loc)
|
||||
new /obj/effect/decal/cleanable/oil(loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/bot/ed209/proc/set_weapon() //used to update the projectile type and firing sound
|
||||
shoot_sound = 'sound/weapons/laser.ogg'
|
||||
if(src.emagged == 2)
|
||||
if(emagged == 2)
|
||||
if(lasercolor)
|
||||
projectile = /obj/item/projectile/lasertag
|
||||
else
|
||||
@@ -796,7 +500,7 @@ Auto Patrol: []"},
|
||||
if (!( istype(U, /turf) ))
|
||||
return
|
||||
var/obj/item/projectile/A = new projectile (loc)
|
||||
playsound(src.loc, shoot_sound, 50, 1)
|
||||
playsound(loc, shoot_sound, 50, 1)
|
||||
A.current = U
|
||||
A.yo = U.y - T.y
|
||||
A.xo = U.x - T.x
|
||||
@@ -808,8 +512,8 @@ Auto Patrol: []"},
|
||||
/obj/machinery/bot/ed209/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
|
||||
|
||||
|
||||
/obj/machinery/bot/ed209/emp_act(severity)
|
||||
@@ -817,7 +521,7 @@ Auto Patrol: []"},
|
||||
if(severity==2 && prob(70))
|
||||
..(severity-1)
|
||||
else
|
||||
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"
|
||||
@@ -847,8 +551,8 @@ Auto Patrol: []"},
|
||||
if(targets.len)
|
||||
var/mob/toarrest = pick(targets)
|
||||
if (toarrest)
|
||||
src.target = toarrest
|
||||
src.mode = SECBOT_HUNT
|
||||
target = toarrest
|
||||
mode = BOT_HUNT
|
||||
|
||||
|
||||
|
||||
@@ -856,9 +560,9 @@ Auto Patrol: []"},
|
||||
..()
|
||||
|
||||
if(istype(W, /obj/item/weapon/pen))
|
||||
var/t = copytext(stripped_input(user, "Enter new robot name", src.name, src.created_name),1,MAX_NAME_LEN)
|
||||
var/t = copytext(stripped_input(user, "Enter new robot name", name, created_name),1,MAX_NAME_LEN)
|
||||
if(!t) return
|
||||
if(!in_range(src, usr) && src.loc != usr) return
|
||||
if(!in_range(src, usr) && loc != usr) return
|
||||
created_name = t
|
||||
return
|
||||
|
||||
@@ -962,14 +666,14 @@ Auto Patrol: []"},
|
||||
return
|
||||
build_step++
|
||||
user << "<span class='notice'>You add [W] to [src].</span>"
|
||||
src.item_state = "[lasercolor]ed209_taser"
|
||||
src.icon_state = "[lasercolor]ed209_taser"
|
||||
item_state = "[lasercolor]ed209_taser"
|
||||
icon_state = "[lasercolor]ed209_taser"
|
||||
user.drop_item()
|
||||
qdel(W)
|
||||
|
||||
if(8)
|
||||
if(istype(W, /obj/item/weapon/screwdriver))
|
||||
playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1)
|
||||
playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1)
|
||||
var/turf/T = get_turf(user)
|
||||
user << "<span class='notice'>Now attaching the gun to the frame...</span>"
|
||||
sleep(40)
|
||||
@@ -993,18 +697,18 @@ Auto Patrol: []"},
|
||||
/obj/machinery/bot/ed209/bullet_act(var/obj/item/projectile/Proj)
|
||||
if(!disabled)
|
||||
var/lasertag_check = 0
|
||||
if((src.lasercolor == "b"))
|
||||
if((lasercolor == "b"))
|
||||
if(istype(Proj, /obj/item/projectile/lasertag/redtag))
|
||||
lasertag_check++
|
||||
else if((src.lasercolor == "r"))
|
||||
else if((lasercolor == "r"))
|
||||
if(istype(Proj, /obj/item/projectile/lasertag/bluetag))
|
||||
lasertag_check++
|
||||
if(lasertag_check)
|
||||
icon_state = "[lasercolor]ed2090"
|
||||
src.disabled = 1
|
||||
disabled = 1
|
||||
target = null
|
||||
spawn(100)
|
||||
src.disabled = 0
|
||||
disabled = 0
|
||||
icon_state = "[lasercolor]ed2091"
|
||||
return 1
|
||||
else
|
||||
|
||||
@@ -36,35 +36,64 @@
|
||||
maxhealth = 25
|
||||
//weight = 1.0E7
|
||||
var/amount = 10
|
||||
var/repairing = 0
|
||||
var/improvefloors = 0
|
||||
var/replacetiles = 0
|
||||
var/eattiles = 0
|
||||
var/maketiles = 0
|
||||
var/fixfloors = 0
|
||||
var/autotile = 0
|
||||
var/nag_on_empty = 1
|
||||
var/nagged = 0 //Prevents the Floorbot nagging more than once per refill.
|
||||
var/max_targets = 50
|
||||
var/turf/target
|
||||
var/turf/oldtarget
|
||||
var/oldloc = null
|
||||
req_access = list(access_construction)
|
||||
var/path[] = new()
|
||||
req_one_access = list(access_construction, access_robotics)
|
||||
var/targetdirection
|
||||
|
||||
radio_frequency = ENG_FREQ //Engineering channel
|
||||
bot_type = FLOOR_BOT
|
||||
bot_filter = RADIO_FLOORBOT
|
||||
var/process_type //Determines what to do when process_scan() recieves a target. See process_scan() for details.
|
||||
#define HULL_BREACH 1
|
||||
#define BRIDGE_MODE 2
|
||||
#define FIX_TILE 3
|
||||
#define AUTO_TILE 4
|
||||
#define REPLACE_TILE 5
|
||||
#define TILE_EMAG 6
|
||||
|
||||
/obj/machinery/bot/floorbot/New()
|
||||
..()
|
||||
src.updateicon()
|
||||
updateicon()
|
||||
var/datum/job/engineer/J = new/datum/job/engineer
|
||||
botcard.access = J.get_access()
|
||||
prev_access = botcard.access
|
||||
|
||||
spawn(5)
|
||||
add_to_beacons(bot_filter)
|
||||
|
||||
/obj/machinery/bot/floorbot/turn_on()
|
||||
. = ..()
|
||||
src.updateicon()
|
||||
src.updateUsrDialog()
|
||||
updateicon()
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/bot/floorbot/turn_off()
|
||||
..()
|
||||
src.target = null
|
||||
src.oldtarget = null
|
||||
src.oldloc = null
|
||||
src.updateicon()
|
||||
src.path = new()
|
||||
src.updateUsrDialog()
|
||||
updateicon()
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/bot/floorbot/bot_reset()
|
||||
..()
|
||||
target = null
|
||||
oldtarget = null
|
||||
oldloc = null
|
||||
ignore_list = list()
|
||||
nagged = 0
|
||||
anchored = 0
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/bot/floorbot/set_custom_texts()
|
||||
text_hack = "You corrupt [name]'s construction protocols."
|
||||
text_dehack = "You detect errors in [name] and reset his programming."
|
||||
text_dehack_fail = "[name] is not responding to reset commands!"
|
||||
|
||||
/obj/machinery/bot/floorbot/attack_hand(mob/user as mob)
|
||||
. = ..()
|
||||
@@ -76,44 +105,50 @@
|
||||
/obj/machinery/bot/floorbot/interact(mob/user as mob)
|
||||
var/dat
|
||||
dat += hack(user)
|
||||
dat += "<TT><B>Automatic Station Floor Repairer v1.0</B></TT><BR><BR>"
|
||||
dat += "Status: <A href='?src=\ref[src];operation=start'>[src.on ? "On" : "Off"]</A><BR>"
|
||||
dat += "Maintenance panel panel is [src.open ? "opened" : "closed"]<BR>"
|
||||
dat += "Tiles left: [src.amount]<BR>"
|
||||
dat += "Behvaiour controls are [src.locked ? "locked" : "unlocked"]<BR>"
|
||||
if(!src.locked || issilicon(user))
|
||||
dat += "Improves floors: <A href='?src=\ref[src];operation=improve'>[src.improvefloors ? "Yes" : "No"]</A><BR>"
|
||||
dat += "Finds tiles: <A href='?src=\ref[src];operation=tiles'>[src.eattiles ? "Yes" : "No"]</A><BR>"
|
||||
dat += "Make singles pieces of metal into tiles when empty: <A href='?src=\ref[src];operation=make'>[src.maketiles ? "Yes" : "No"]</A><BR>"
|
||||
dat += "<TT><B>Floor Repairer 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 += "Tiles left: [amount]<BR>"
|
||||
dat += "Behvaiour controls are [locked ? "locked" : "unlocked"]<BR>"
|
||||
if(!locked || issilicon(user))
|
||||
dat += "Add tiles to new hull plating: <A href='?src=\ref[src];operation=autotile'>[autotile ? "Yes" : "No"]</A><BR>"
|
||||
dat += "Replace floor tiles: <A href='?src=\ref[src];operation=replace'>[replacetiles ? "Yes" : "No"]</A><BR>"
|
||||
dat += "Finds tiles: <A href='?src=\ref[src];operation=tiles'>[eattiles ? "Yes" : "No"]</A><BR>"
|
||||
dat += "Make pieces of metal into tiles when empty: <A href='?src=\ref[src];operation=make'>[maketiles ? "Yes" : "No"]</A><BR>"
|
||||
dat += "Transmit notice when empty: <A href='?src=\ref[src];operation=emptynag'>[nag_on_empty ? "Yes" : "No"]</A><BR>"
|
||||
dat += "Repair damaged tiles and platings: <A href='?src=\ref[src];operation=fix'>[fixfloors ? "Yes" : "No"]</A><BR>"
|
||||
dat += "Patrol Station: <A href='?src=\ref[src];operation=patrol'>[auto_patrol ? "Yes" : "No"]</A><BR>"
|
||||
var/bmode
|
||||
if (src.targetdirection)
|
||||
bmode = dir2text(src.targetdirection)
|
||||
if (targetdirection)
|
||||
bmode = dir2text(targetdirection)
|
||||
else
|
||||
bmode = "Disabled"
|
||||
dat += "<BR><BR>Bridge Mode : <A href='?src=\ref[src];operation=bridgemode'>[bmode]</A><BR>"
|
||||
bmode = "disabled"
|
||||
dat += "Bridge Mode : <A href='?src=\ref[src];operation=bridgemode'>[bmode]</A><BR>"
|
||||
|
||||
user << browse("<HEAD><TITLE>Repairbot v1.0 controls</TITLE></HEAD>[dat]", "window=autorepair")
|
||||
onclose(user, "autorepair")
|
||||
var/datum/browser/popup = new(user, "autofloor", "Automatic Station Floor Repairer v1.1")
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/bot/floorbot/attackby(var/obj/item/W , mob/user as mob)
|
||||
if(istype(W, /obj/item/stack/tile/plasteel))
|
||||
var/obj/item/stack/tile/plasteel/T = W
|
||||
if(src.amount >= 50)
|
||||
if(amount >= 50)
|
||||
return
|
||||
var/loaded = min(50 - src.amount, T.get_amount())
|
||||
var/loaded = min(50-amount, T.amount)
|
||||
T.use(loaded)
|
||||
src.amount += loaded
|
||||
amount += loaded
|
||||
if (loaded > 0)
|
||||
user << "<span class='notice'>You load [loaded] tiles into the floorbot. He now contains [src.amount] tiles.</span>"
|
||||
src.updateicon()
|
||||
user << "<span class='notice'>You load [loaded] tiles into the floorbot. He now contains [amount] tiles.</span>"
|
||||
nagged = 0
|
||||
updateicon()
|
||||
else
|
||||
user << "<span class='warning'>You need at least one floor tile to put into the floorbot.</span>"
|
||||
user << "<span class='warning'>You need at least one floor tile to put into [src]</span>"
|
||||
else if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
|
||||
if(src.allowed(usr) && !open && !emagged)
|
||||
src.locked = !src.locked
|
||||
user << "<span class='notice'>You [src.locked ? "lock" : "unlock"] the [src] behaviour controls.</span>"
|
||||
if(allowed(user) && !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>"
|
||||
@@ -121,265 +156,301 @@
|
||||
user << "<span class='warning'>Please close the access panel before locking it.</span>"
|
||||
else
|
||||
user << "<span class='warning'>Access denied.</span>"
|
||||
src.updateUsrDialog()
|
||||
updateUsrDialog()
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/machinery/bot/floorbot/Emag(mob/user as mob)
|
||||
..()
|
||||
if(open && !locked)
|
||||
if(user) user << "<span class='notice'>The [src] buzzes and beeps.</span>"
|
||||
if(emagged == 2)
|
||||
if(user)
|
||||
user << "<span class='danger'>[src] buzzes and beeps.</span>"
|
||||
|
||||
/obj/machinery/bot/floorbot/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
usr.set_machine(src)
|
||||
src.add_fingerprint(usr)
|
||||
..()
|
||||
switch(href_list["operation"])
|
||||
if("start")
|
||||
if (src.on && !src.emagged)
|
||||
turn_off()
|
||||
else
|
||||
turn_on()
|
||||
if("improve")
|
||||
src.improvefloors = !src.improvefloors
|
||||
src.updateUsrDialog()
|
||||
if("replace")
|
||||
replacetiles = !replacetiles
|
||||
if("tiles")
|
||||
src.eattiles = !src.eattiles
|
||||
src.updateUsrDialog()
|
||||
eattiles = !eattiles
|
||||
if("make")
|
||||
src.maketiles = !src.maketiles
|
||||
src.updateUsrDialog()
|
||||
if("hack")
|
||||
if(!src.emagged)
|
||||
src.emagged = 2
|
||||
src.hacked = 1
|
||||
usr << "<span class='warning'>You corrupt [src]'s construction protocols.</span>"
|
||||
else if(!src.hacked)
|
||||
usr << "<span class='userdanger'>[src] is not responding to reset commands!</span>"
|
||||
else
|
||||
src.emagged = 0
|
||||
src.hacked = 0
|
||||
usr << "<span class='notice'>You detect errors in [src] and reset its programming.</span>"
|
||||
src.updateUsrDialog()
|
||||
maketiles = !maketiles
|
||||
if("fix")
|
||||
fixfloors = !fixfloors
|
||||
if("autotile")
|
||||
autotile = !autotile
|
||||
if("emptynag")
|
||||
nag_on_empty = !nag_on_empty
|
||||
|
||||
if("bridgemode")
|
||||
switch(src.targetdirection)
|
||||
if(null)
|
||||
var/setdir = input("Select construction direction:") as null|anything in list("north","east","south","west","disable")
|
||||
switch(setdir)
|
||||
if("north")
|
||||
targetdirection = 1
|
||||
if(1)
|
||||
if("south")
|
||||
targetdirection = 2
|
||||
if(2)
|
||||
if("east")
|
||||
targetdirection = 4
|
||||
if(4)
|
||||
if("west")
|
||||
targetdirection = 8
|
||||
if(8)
|
||||
if("disable")
|
||||
targetdirection = null
|
||||
else
|
||||
targetdirection = null
|
||||
src.updateUsrDialog()
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/bot/floorbot/process()
|
||||
set background = BACKGROUND_ENABLED
|
||||
if (!..())
|
||||
return
|
||||
|
||||
if(!src.on)
|
||||
if(mode == BOT_REPAIRING)
|
||||
return
|
||||
if(src.repairing)
|
||||
return
|
||||
var/list/floorbottargets = list()
|
||||
if(src.amount <= 0 && ((src.target == null) || !src.target))
|
||||
if(src.eattiles)
|
||||
for(var/obj/item/stack/tile/plasteel/T in view(7, src))
|
||||
if(T != src.oldtarget && !(target in floorbottargets))
|
||||
src.oldtarget = T
|
||||
src.target = T
|
||||
break
|
||||
if(src.target == null || !src.target)
|
||||
if(src.maketiles)
|
||||
if(src.target == null || !src.target)
|
||||
for(var/obj/item/stack/sheet/metal/M in view(7, src))
|
||||
if(!(M in floorbottargets) && M != src.oldtarget && M.amount == 1 && !(istype(M.loc, /turf/simulated/wall)))
|
||||
src.oldtarget = M
|
||||
src.target = M
|
||||
break
|
||||
else
|
||||
|
||||
if(amount <= 0 && !target) //Out of tiles! We must refill!
|
||||
if(eattiles) //Configured to find and consume floortiles!
|
||||
target = scan(/obj/item/stack/tile/plasteel, oldtarget)
|
||||
process_type = null
|
||||
|
||||
if(!target && maketiles) //We did not manage to find any floor tiles! Scan for metal stacks and make our own!
|
||||
target = scan(/obj/item/stack/sheet/metal, oldtarget)
|
||||
process_type = null
|
||||
return
|
||||
else
|
||||
if(nag_on_empty) //Floorbot is empty and cannot acquire more tiles, nag the engineers for more!
|
||||
nag()
|
||||
|
||||
if(prob(5))
|
||||
visible_message("[src] makes an excited booping beeping sound!")
|
||||
|
||||
if((!src.target || src.target == null) && emagged < 2)
|
||||
if(targetdirection != null)
|
||||
/*
|
||||
for (var/turf/space/D in view(7,src))
|
||||
if(!(D in floorbottargets) && D != src.oldtarget) // Added for bridging mode
|
||||
if(get_dir(src, D) == targetdirection)
|
||||
src.oldtarget = D
|
||||
src.target = D
|
||||
break
|
||||
*/
|
||||
//Normal scanning procedure. We have tiles loaded, are not emagged.
|
||||
if(!target && emagged < 2 && amount > 0)
|
||||
if(targetdirection != null) //The bot is in bridge mode.
|
||||
//Try to find a space tile immediately in our selected direction.
|
||||
var/turf/T = get_step(src, targetdirection)
|
||||
if(istype(T, /turf/space))
|
||||
src.oldtarget = T
|
||||
src.target = T
|
||||
if(!src.target || src.target == null)
|
||||
for (var/turf/space/D in view(7,src))
|
||||
if(!(D in floorbottargets) && D != src.oldtarget && (D.loc.name != "Space"))
|
||||
src.oldtarget = D
|
||||
src.target = D
|
||||
break
|
||||
if((!src.target || src.target == null ) && src.improvefloors)
|
||||
for (var/turf/simulated/floor/F in view(7,src))
|
||||
if(!(F in floorbottargets) && F != src.oldtarget && F.icon_state == "Floor1" && !(istype(F, /turf/simulated/floor/plating)))
|
||||
src.oldtarget = F
|
||||
src.target = F
|
||||
break
|
||||
if((!src.target || src.target == null) && src.eattiles)
|
||||
for(var/obj/item/stack/tile/plasteel/T in view(7, src))
|
||||
if(!(T in floorbottargets) && T != src.oldtarget)
|
||||
src.oldtarget = T
|
||||
src.target = T
|
||||
break
|
||||
target = T
|
||||
|
||||
if((!src.target || src.target == null) && emagged == 2)
|
||||
if(!src.target || src.target == null)
|
||||
for (var/turf/simulated/floor/D in view(7,src))
|
||||
if(!(D in floorbottargets) && D != src.oldtarget && D.floor_tile)
|
||||
src.oldtarget = D
|
||||
src.target = D
|
||||
break
|
||||
|
||||
if(!src.target || src.target == null)
|
||||
if(src.loc != src.oldloc)
|
||||
src.oldtarget = null
|
||||
return
|
||||
|
||||
if(src.target && (src.target != null) && src.path.len == 0)
|
||||
spawn(0)
|
||||
if(!istype(src.target, /turf/))
|
||||
var/turf/TL = get_turf(target)
|
||||
src.path = AStar(src.loc, TL, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30)
|
||||
else
|
||||
src.path = AStar(src.loc, src.target, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30)
|
||||
if(!src.path)
|
||||
src.path = list()
|
||||
if(src.path.len == 0)
|
||||
src.oldtarget = src.target
|
||||
src.target = null
|
||||
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)
|
||||
src.path = new()
|
||||
|
||||
if(src.loc == src.target || src.loc == src.target.loc)
|
||||
if(istype(src.target, /obj/item/stack/tile/plasteel))
|
||||
src.eattile(src.target)
|
||||
else if(istype(src.target, /obj/item/stack/sheet/metal))
|
||||
src.maketile(src.target)
|
||||
else if(istype(src.target, /turf/) && emagged < 2)
|
||||
repair(src.target)
|
||||
else if(emagged == 2 && istype(src.target,/turf/simulated/floor))
|
||||
var/turf/simulated/floor/F = src.target
|
||||
src.anchored = 1
|
||||
src.repairing = 1
|
||||
if(prob(90))
|
||||
F.break_tile_to_plating()
|
||||
else
|
||||
F.ReplaceWithLattice()
|
||||
visible_message("<span class='danger'>[src] makes an excited booping sound.</span>")
|
||||
spawn(50)
|
||||
src.amount ++
|
||||
src.anchored = 0
|
||||
src.repairing = 0
|
||||
src.target = null
|
||||
src.path = new()
|
||||
return
|
||||
|
||||
src.oldloc = src.loc
|
||||
|
||||
|
||||
/obj/machinery/bot/floorbot/proc/repair(var/turf/target)
|
||||
if(istype(target, /turf/space/))
|
||||
if(target.loc.name == "Space")
|
||||
else //Find a space tile farther way!
|
||||
target = scan(/turf/space, oldtarget)
|
||||
anchored = 1
|
||||
process_type = BRIDGE_MODE
|
||||
return
|
||||
else if(!istype(target, /turf/simulated/floor))
|
||||
|
||||
if(!target)
|
||||
process_type = HULL_BREACH //Ensures the floorbot does not try to "fix" space areas or shuttle docking zones.
|
||||
target = scan(/turf/space, oldtarget)
|
||||
anchored = 1 //Prevent the floorbot being blown off-course while trying to reach a hull breach.
|
||||
return
|
||||
|
||||
if(!target && replacetiles) //Finds a floor without a tile and gives it one.
|
||||
process_type = REPLACE_TILE //The target must be the floor and not a tile. The floor must not already have a floortile.
|
||||
//target = scan(/turf/simulated/floor, oldtarget)
|
||||
return
|
||||
|
||||
if(!target && fixfloors) //Repairs damaged floors and tiles.
|
||||
process_type = FIX_TILE
|
||||
target = scan(/turf/simulated/floor, oldtarget)
|
||||
return
|
||||
|
||||
if(!target && emagged == 2) //We are emagged! Time to rip up the floors!
|
||||
process_type = TILE_EMAG
|
||||
target = scan(/turf/simulated/floor, oldtarget)
|
||||
return
|
||||
if(src.amount <= 0)
|
||||
|
||||
|
||||
if(!target)
|
||||
|
||||
if(auto_patrol)
|
||||
if(mode == BOT_IDLE || mode == BOT_START_PATROL)
|
||||
start_patrol()
|
||||
|
||||
if(mode == BOT_PATROL)
|
||||
bot_patrol()
|
||||
|
||||
if(!target)
|
||||
if(loc != oldloc)
|
||||
oldtarget = null
|
||||
return
|
||||
src.anchored = 1
|
||||
src.icon_state = "floorbot-c"
|
||||
if(istype(target, /turf/space/))
|
||||
visible_message("<span class='danger'>[src] begins to repair the hole.</span>")
|
||||
var/obj/item/stack/tile/plasteel/T = new /obj/item/stack/tile/plasteel
|
||||
src.repairing = 1
|
||||
spawn(50)
|
||||
T.build(src.loc)
|
||||
src.repairing = 0
|
||||
src.amount -= 1
|
||||
src.updateicon()
|
||||
src.anchored = 0
|
||||
src.target = null
|
||||
|
||||
if(target)
|
||||
if(path.len == 0)
|
||||
if(!istype(target, /turf/))
|
||||
var/turf/TL = get_turf(target)
|
||||
path = AStar(loc, TL, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30, id=botcard)
|
||||
else
|
||||
path = AStar(loc, target, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30, id=botcard)
|
||||
|
||||
if(!bot_move(target))
|
||||
add_to_ignore(target)
|
||||
oldtarget = target
|
||||
target = null
|
||||
mode = BOT_IDLE
|
||||
return
|
||||
else if( !bot_move(target) )
|
||||
oldtarget = target
|
||||
target = null
|
||||
mode = BOT_IDLE
|
||||
return
|
||||
|
||||
if(loc == target || loc == target.loc)
|
||||
if(istype(target, /obj/item/stack/tile/plasteel))
|
||||
eattile(target)
|
||||
else if(istype(target, /obj/item/stack/sheet/metal))
|
||||
maketile(target)
|
||||
else if(istype(target, /turf/) && emagged < 2)
|
||||
repair(target)
|
||||
else if(emagged == 2 && istype(target,/turf/simulated/floor))
|
||||
var/turf/simulated/floor/F = target
|
||||
anchored = 1
|
||||
mode = BOT_REPAIRING
|
||||
if(prob(90))
|
||||
F.break_tile_to_plating()
|
||||
else
|
||||
F.ReplaceWithLattice()
|
||||
visible_message("<span class='danger'>[src] makes an excited booping sound.</span>")
|
||||
spawn(50)
|
||||
amount ++
|
||||
anchored = 0
|
||||
mode = BOT_IDLE
|
||||
target = null
|
||||
path = new()
|
||||
return
|
||||
|
||||
oldloc = loc
|
||||
|
||||
/obj/machinery/bot/floorbot/proc/nag() //Annoy everyone on the channel to refill us!
|
||||
if(!nagged)
|
||||
speak("Requesting refill at <b>[get_area(src)]</b>!", radio_frequency)
|
||||
nagged = 1
|
||||
|
||||
/obj/machinery/bot/floorbot/proc/is_hull_breach(var/turf/t) //Ignore space tiles not considered part of a structure, also ignores shuttle docking areas.
|
||||
var/area/t_area = get_area(t)
|
||||
if (t_area && (t_area.name == "Space" || findtext(t_area.name, "huttle")))
|
||||
return 0
|
||||
else
|
||||
visible_message("<span class='danger'>[src] begins to improve the floor.</span>")
|
||||
src.repairing = 1
|
||||
return 1
|
||||
|
||||
//Floorbots, having several functions, need sort out special conditions here.
|
||||
obj/machinery/bot/floorbot/process_scan(var/scan_target)
|
||||
var/result
|
||||
var/turf/simulated/floor/F
|
||||
switch(process_type)
|
||||
if(HULL_BREACH) //The most common job, patching breaches in the station's hull.
|
||||
if(is_hull_breach(scan_target)) //Ensure that the targeted space turf is actually part of the station, and not random space.
|
||||
result = scan_target
|
||||
if(BRIDGE_MODE) //Only space turfs in our chosen direction are considered.
|
||||
if(get_dir(src, scan_target) == targetdirection)
|
||||
result = scan_target
|
||||
if(REPLACE_TILE)
|
||||
F = scan_target
|
||||
if(F.is_plating()) //The floor must not already have a tile.
|
||||
result = F
|
||||
if(FIX_TILE) //Selects only damaged floors.
|
||||
F = scan_target
|
||||
if(F.broken || F.burnt)
|
||||
result = F
|
||||
if(TILE_EMAG) //Emag mode! Rip up the floor and cause breaches to space!
|
||||
F = scan_target
|
||||
if(!F.is_plating())
|
||||
result = F
|
||||
else //If no special processing is needed, simply return the result.
|
||||
result = scan_target
|
||||
return result
|
||||
|
||||
/obj/machinery/bot/floorbot/proc/repair(var/turf/target_turf)
|
||||
|
||||
if(istype(target_turf, /turf/space/))
|
||||
//Must be a hull breach or in bridge mode to continue.
|
||||
if(!is_hull_breach(target_turf) && !targetdirection)
|
||||
target = null
|
||||
return
|
||||
else if(!istype(target_turf, /turf/simulated/floor))
|
||||
return
|
||||
if(amount <= 0)
|
||||
mode = BOT_IDLE
|
||||
target = null
|
||||
return
|
||||
var/turf/simulated/floor/F
|
||||
var/obj/item/stack/tile/plasteel/T = new /obj/item/stack/tile/plasteel
|
||||
anchored = 1
|
||||
icon_state = "floorbot-c"
|
||||
if(istype(target_turf, /turf/space/)) //If we are fixing an area not part of pure space, it is
|
||||
visible_message("<span class='notice'> [targetdirection ? "[src] begins installing a bridge plating." : "[src] begins to repair the hole."] </span>")
|
||||
mode = BOT_REPAIRING
|
||||
spawn(50)
|
||||
src.loc.icon_state = "floor"
|
||||
src.repairing = 0
|
||||
src.amount -= 1
|
||||
src.updateicon()
|
||||
src.anchored = 0
|
||||
src.target = null
|
||||
if(mode == BOT_REPAIRING)
|
||||
if(autotile) //Build the floor and include a tile.
|
||||
F = target_turf.ChangeTurf(/turf/simulated/floor)
|
||||
else //Build a hull plating without a floor tile.
|
||||
T.build(loc)
|
||||
mode = BOT_IDLE
|
||||
amount -= 1
|
||||
updateicon()
|
||||
anchored = 0
|
||||
target = null
|
||||
else
|
||||
F = target_turf
|
||||
|
||||
mode = BOT_REPAIRING
|
||||
visible_message("<span class='notice'> [src] begins repairing the floor.</span>")
|
||||
spawn(50)
|
||||
if(mode == BOT_REPAIRING)
|
||||
F = target_turf
|
||||
F.make_plasteel_floor(T)
|
||||
mode = BOT_IDLE
|
||||
amount -= 1
|
||||
updateicon()
|
||||
anchored = 0
|
||||
target = null
|
||||
|
||||
/obj/machinery/bot/floorbot/proc/eattile(var/obj/item/stack/tile/plasteel/T)
|
||||
if(!istype(T, /obj/item/stack/tile/plasteel))
|
||||
return
|
||||
visible_message("<span class='danger'>[src] begins to collect tiles.</span>")
|
||||
src.repairing = 1
|
||||
visible_message("<span class='notice'> [src] begins to collect tiles.</span>")
|
||||
mode = BOT_REPAIRING
|
||||
spawn(20)
|
||||
if(isnull(T))
|
||||
src.target = null
|
||||
src.repairing = 0
|
||||
target = null
|
||||
mode = BOT_IDLE
|
||||
return
|
||||
if(src.amount + T.amount > 50)
|
||||
var/i = 50 - src.amount
|
||||
src.amount += i
|
||||
if(amount + T.amount > 50)
|
||||
var/i = 50 - amount
|
||||
amount += i
|
||||
T.amount -= i
|
||||
else
|
||||
src.amount += T.amount
|
||||
amount += T.amount
|
||||
qdel(T)
|
||||
src.updateicon()
|
||||
src.target = null
|
||||
src.repairing = 0
|
||||
updateicon()
|
||||
target = null
|
||||
mode = BOT_IDLE
|
||||
|
||||
/obj/machinery/bot/floorbot/proc/maketile(var/obj/item/stack/sheet/metal/M)
|
||||
if(!istype(M, /obj/item/stack/sheet/metal))
|
||||
return
|
||||
if(M.amount > 1)
|
||||
return
|
||||
visible_message("<span class='danger'>[src] begins to create tiles.</span>")
|
||||
src.repairing = 1
|
||||
visible_message("<span class='notice'> [src] begins to create tiles.</span>")
|
||||
mode = BOT_REPAIRING
|
||||
spawn(20)
|
||||
if(isnull(M))
|
||||
src.target = null
|
||||
src.repairing = 0
|
||||
target = null
|
||||
mode = BOT_IDLE
|
||||
return
|
||||
var/obj/item/stack/tile/plasteel/T = new /obj/item/stack/tile/plasteel
|
||||
T.amount = 4
|
||||
T.loc = M.loc
|
||||
qdel(M)
|
||||
src.target = null
|
||||
src.repairing = 0
|
||||
if(M.amount > 1)
|
||||
M.amount--
|
||||
else
|
||||
qdel(M)
|
||||
target = null
|
||||
mode = BOT_IDLE
|
||||
|
||||
/obj/machinery/bot/floorbot/proc/updateicon()
|
||||
if(src.amount > 0)
|
||||
src.icon_state = "floorbot[src.on]"
|
||||
if(amount > 0)
|
||||
icon_state = "floorbot[on]"
|
||||
else
|
||||
src.icon_state = "floorbot[src.on]e"
|
||||
icon_state = "floorbot[on]e"
|
||||
|
||||
/obj/machinery/bot/floorbot/explode()
|
||||
src.on = 0
|
||||
src.visible_message("<span class='userdanger'>[src] blows apart!</span>")
|
||||
on = 0
|
||||
visible_message("<span class='userdanger'>[src] blows apart!</span>")
|
||||
var/turf/Tsec = get_turf(src)
|
||||
|
||||
var/obj/item/weapon/storage/toolbox/mechanical/N = new /obj/item/weapon/storage/toolbox/mechanical(Tsec)
|
||||
@@ -397,7 +468,7 @@
|
||||
amount -= 16
|
||||
else
|
||||
var/obj/item/stack/tile/plasteel/T = new (Tsec)
|
||||
T.amount = src.amount
|
||||
T.amount = amount
|
||||
amount = 0
|
||||
|
||||
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
|
||||
@@ -411,7 +482,7 @@
|
||||
if(!istype(T, /obj/item/stack/tile/plasteel))
|
||||
..()
|
||||
return
|
||||
if(src.contents.len >= 1)
|
||||
if(contents.len >= 1)
|
||||
user << "<span class='alert'>They won't fit in, as there is already stuff inside.</span>"
|
||||
return
|
||||
if(T.use(10))
|
||||
@@ -431,20 +502,20 @@
|
||||
if(isprox(W))
|
||||
qdel(W)
|
||||
var/obj/item/weapon/toolbox_tiles_sensor/B = new /obj/item/weapon/toolbox_tiles_sensor()
|
||||
B.created_name = src.created_name
|
||||
B.created_name = created_name
|
||||
user.put_in_hands(B)
|
||||
user << "<span class='notice'>You add the sensor to the toolbox and tiles!</span>"
|
||||
user.unEquip(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 = copytext(stripped_input(user, "Enter new robot name", name, created_name),1,MAX_NAME_LEN)
|
||||
if (!t)
|
||||
return
|
||||
if (!in_range(src, usr) && src.loc != usr)
|
||||
if (!in_range(src, usr) && loc != usr)
|
||||
return
|
||||
|
||||
src.created_name = t
|
||||
created_name = t
|
||||
|
||||
/obj/item/weapon/toolbox_tiles_sensor/attackby(var/obj/item/W, mob/user as mob)
|
||||
..()
|
||||
@@ -452,16 +523,16 @@
|
||||
qdel(W)
|
||||
var/turf/T = get_turf(user.loc)
|
||||
var/obj/machinery/bot/floorbot/A = new /obj/machinery/bot/floorbot(T)
|
||||
A.name = src.created_name
|
||||
A.name = created_name
|
||||
user << "<span class='notice'>You add the robot arm to the odd looking toolbox assembly! Boop beep!</span>"
|
||||
user.unEquip(src, 1)
|
||||
qdel(src)
|
||||
else if (istype(W, /obj/item/weapon/pen))
|
||||
var/t = stripped_input(user, "Enter new robot name", src.name, src.created_name)
|
||||
var/t = stripped_input(user, "Enter new robot name", name, created_name)
|
||||
|
||||
if (!t)
|
||||
return
|
||||
if (!in_range(src, usr) && src.loc != usr)
|
||||
if (!in_range(src, usr) && loc != usr)
|
||||
return
|
||||
|
||||
src.created_name = t
|
||||
created_name = t
|
||||
+274
-296
@@ -13,31 +13,34 @@
|
||||
anchored = 0
|
||||
health = 20
|
||||
maxhealth = 20
|
||||
req_access =list(access_medical)
|
||||
req_one_access =list(access_medical, access_robotics)
|
||||
var/stunned = 0 //It can be stunned by tasers. Delicate circuits.
|
||||
// var/emagged = 0
|
||||
var/list/botcard_access = list(access_medical)
|
||||
var/obj/item/weapon/reagent_containers/glass/reagent_glass = null //Can be set to draw from this for reagents.
|
||||
var/skin = null //Set to "tox", "ointment" or "o2" for the other two firstaid kits.
|
||||
var/frustration = 0
|
||||
var/path[] = new()
|
||||
var/mob/living/carbon/patient = null
|
||||
var/mob/living/carbon/oldpatient = null
|
||||
var/oldloc = null
|
||||
var/last_found = 0
|
||||
var/last_newpatient_speak = 0 //Don't spam the "HEY I'M COMING" messages
|
||||
var/currently_healing = 0
|
||||
var/injection_amount = 15 //How much reagent do we inject at a time?
|
||||
var/heal_threshold = 10 //Start healing when they have this much damage in a category
|
||||
var/use_beaker = 0 //Use reagents in beaker instead of default treatment agents.
|
||||
|
||||
var/declare_crit = 1 //If active, the bot will transmit a critical patient alert to MedHUD users.
|
||||
var/declare_cooldown = 0 //Prevents spam of critical patient alerts.
|
||||
var/stationary_mode = 0 //If enabled, the Medibot will not move automatically.
|
||||
radio_frequency = 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 = 1 //If on, the bot will attempt to treat viral infections, curing them if possible.
|
||||
var/shut_up = 0 //self explanatory :)
|
||||
bot_type = MED_BOT
|
||||
bot_filter = RADIO_MEDBOT
|
||||
|
||||
/obj/machinery/bot/medbot/mysterious
|
||||
name = "\improper Mysterious Medibot"
|
||||
@@ -58,43 +61,63 @@
|
||||
var/skin = null //Same as medbot, set to tox or ointment for the respective kits.
|
||||
w_class = 3.0
|
||||
|
||||
New()
|
||||
/obj/item/weapon/firstaid_arm_assembly/New()
|
||||
..()
|
||||
spawn(5)
|
||||
if(src.skin)
|
||||
src.overlays += image('icons/obj/aibots.dmi', "kit_skin_[src.skin]")
|
||||
if(skin)
|
||||
overlays += image('icons/obj/aibots.dmi', "kit_skin_[skin]")
|
||||
|
||||
/obj/machinery/bot/medbot/proc/updateicon()
|
||||
if(!on)
|
||||
icon_state = "medibot0"
|
||||
return
|
||||
if(mode == BOT_HEALING)
|
||||
icon_state = "medibots[stationary_mode]"
|
||||
return
|
||||
else if(stationary_mode) //Bot has yellow light to indicate stationary mode.
|
||||
icon_state = "medibot2"
|
||||
else
|
||||
icon_state = "medibot1"
|
||||
|
||||
/obj/machinery/bot/medbot/New()
|
||||
..()
|
||||
src.icon_state = "medibot[src.on]"
|
||||
updateicon()
|
||||
|
||||
spawn(4)
|
||||
if(src.skin)
|
||||
src.overlays += image('icons/obj/aibots.dmi', "medskin_[src.skin]")
|
||||
if(skin)
|
||||
overlays += image('icons/obj/aibots.dmi', "medskin_[skin]")
|
||||
|
||||
src.botcard = new /obj/item/weapon/card/id(src)
|
||||
if(isnull(src.botcard_access) || (src.botcard_access.len < 1))
|
||||
if(isnull(botcard_access) || (botcard_access.len < 1))
|
||||
var/datum/job/doctor/J = new/datum/job/doctor
|
||||
src.botcard.access = J.get_access()
|
||||
botcard.access = J.get_access()
|
||||
else
|
||||
src.botcard.access = src.botcard_access
|
||||
botcard.access = botcard_access
|
||||
prev_access = botcard.access
|
||||
add_to_beacons(bot_filter)
|
||||
|
||||
/obj/machinery/bot/medbot/turn_on()
|
||||
. = ..()
|
||||
src.icon_state = "medibot[src.on]"
|
||||
src.updateUsrDialog()
|
||||
updateicon()
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/bot/medbot/turn_off()
|
||||
..()
|
||||
src.patient = null
|
||||
src.oldpatient = null
|
||||
src.oldloc = null
|
||||
src.path = new()
|
||||
src.currently_healing = 0
|
||||
src.last_found = world.time
|
||||
src.icon_state = "medibot[src.on]"
|
||||
src.updateUsrDialog()
|
||||
updateicon()
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/bot/medbot/bot_reset()
|
||||
..()
|
||||
patient = null
|
||||
oldpatient = null
|
||||
oldloc = null
|
||||
last_found = world.time
|
||||
declare_cooldown = 0
|
||||
|
||||
/obj/machinery/bot/medbot/set_custom_texts()
|
||||
|
||||
text_hack = "You corrupt [name]'s reagent processor circuits."
|
||||
text_dehack = "You reset [name]'s reagent processor circuits."
|
||||
text_dehack_fail = "[name] seems damaged and does not respond to reprogramming!"
|
||||
|
||||
/obj/machinery/bot/medbot/attack_paw(mob/user as mob)
|
||||
return attack_hand(user)
|
||||
@@ -105,99 +128,93 @@
|
||||
return
|
||||
var/dat
|
||||
dat += hack(user)
|
||||
dat += "<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 += "<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 && !src.emagged)
|
||||
turn_off()
|
||||
else
|
||||
turn_on()
|
||||
..()
|
||||
|
||||
else if((href_list["adj_threshold"]) && (!src.locked || issilicon(usr)))
|
||||
if(href_list["adj_threshold"])
|
||||
var/adjust_num = text2num(href_list["adj_threshold"])
|
||||
src.heal_threshold += adjust_num
|
||||
if(src.heal_threshold < 5)
|
||||
src.heal_threshold = 5
|
||||
if(src.heal_threshold > 75)
|
||||
src.heal_threshold = 75
|
||||
heal_threshold += adjust_num
|
||||
if(heal_threshold < 5)
|
||||
heal_threshold = 5
|
||||
if(heal_threshold > 75)
|
||||
heal_threshold = 75
|
||||
|
||||
else if((href_list["adj_inject"]) && (!src.locked || issilicon(usr)))
|
||||
else if(href_list["adj_inject"])
|
||||
var/adjust_num = text2num(href_list["adj_inject"])
|
||||
src.injection_amount += adjust_num
|
||||
if(src.injection_amount < 5)
|
||||
src.injection_amount = 5
|
||||
if(src.injection_amount > 15)
|
||||
src.injection_amount = 15
|
||||
injection_amount += adjust_num
|
||||
if(injection_amount < 5)
|
||||
injection_amount = 5
|
||||
if(injection_amount > 15)
|
||||
injection_amount = 15
|
||||
|
||||
else if((href_list["use_beaker"]) && (!src.locked || issilicon(usr)))
|
||||
src.use_beaker = !src.use_beaker
|
||||
else if(href_list["use_beaker"])
|
||||
use_beaker = !use_beaker
|
||||
|
||||
else if (href_list["eject"] && (!isnull(src.reagent_glass)))
|
||||
if(!src.locked)
|
||||
src.reagent_glass.loc = get_turf(src)
|
||||
src.reagent_glass = null
|
||||
else
|
||||
usr << "<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
|
||||
|
||||
else if (href_list["operation"])
|
||||
if(!src.emagged)
|
||||
src.emagged = 2
|
||||
src.hacked = 1
|
||||
usr << "<span class='warning'>You corrupt [src]'s reagent processor circuits.</span>"
|
||||
else if(!src.hacked)
|
||||
usr << "<span class='userdanger'>[src] seems damaged and does not respond to reprogramming!</span>"
|
||||
else
|
||||
src.hacked = 0
|
||||
src.emagged = 0
|
||||
usr << "<span class='notice'>You reset [src]'s reagent circuits.</span>"
|
||||
src.updateUsrDialog()
|
||||
else if (href_list["critalerts"])
|
||||
declare_crit = !declare_crit
|
||||
|
||||
else if (href_list["stationary"])
|
||||
stationary_mode = !stationary_mode
|
||||
path = new()
|
||||
updateicon()
|
||||
|
||||
else if (href_list["virus"])
|
||||
treat_virus = !treat_virus
|
||||
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/bot/medbot/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
|
||||
if (src.allowed(user) && !open && !emagged)
|
||||
src.locked = !src.locked
|
||||
user << "<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>"
|
||||
@@ -207,18 +224,18 @@
|
||||
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
|
||||
@@ -229,106 +246,103 @@
|
||||
|
||||
/obj/machinery/bot/medbot/Emag(mob/user as mob)
|
||||
..()
|
||||
if(open && !locked)
|
||||
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)
|
||||
audible_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_scan(var/mob/living/carbon/human/H)
|
||||
if (H.stat == 2)
|
||||
return
|
||||
|
||||
if ((H == oldpatient) && (world.time < last_found + 100))
|
||||
return
|
||||
|
||||
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
|
||||
|
||||
/obj/machinery/bot/medbot/process()
|
||||
set background = BACKGROUND_ENABLED
|
||||
|
||||
if(!src.on)
|
||||
src.stunned = 0
|
||||
if (!..())
|
||||
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(mode == BOT_HEALING)
|
||||
return
|
||||
|
||||
if(src.frustration > 8)
|
||||
src.oldpatient = src.patient
|
||||
src.patient = null
|
||||
src.currently_healing = 0
|
||||
src.last_found = world.time
|
||||
src.path = new()
|
||||
if(stunned)
|
||||
icon_state = "medibota"
|
||||
stunned--
|
||||
|
||||
if(!src.patient)
|
||||
if(!src.shut_up && prob(1))
|
||||
oldpatient = patient
|
||||
patient = null
|
||||
mode = BOT_IDLE
|
||||
|
||||
if(stunned <= 0)
|
||||
updateicon()
|
||||
stunned = 0
|
||||
return
|
||||
|
||||
if(frustration > 8)
|
||||
oldpatient = patient
|
||||
patient = null
|
||||
mode = BOT_IDLE
|
||||
last_found = world.time
|
||||
path = new()
|
||||
|
||||
if(!patient)
|
||||
if(!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
|
||||
if((src.last_newpatient_speak + 300) < world.time) //Don't spam these messages!
|
||||
var/message = pick("Hey, [C.name]! Hold on, I'm coming.","Wait [C.name]! I want to help!","[C.name], you appear to be injured!")
|
||||
src.speak(message)
|
||||
src.last_newpatient_speak = world.time
|
||||
break
|
||||
else
|
||||
continue
|
||||
|
||||
|
||||
if(src.patient && (get_dist(src,src.patient) <= 1))
|
||||
if(!src.currently_healing)
|
||||
src.currently_healing = 1
|
||||
src.frustration = 0
|
||||
src.medicate_patient(src.patient)
|
||||
if(patient && (get_dist(src,patient) <= 1)) //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.len) && (get_dist(patient,path[path.len]) > 2))
|
||||
path = new()
|
||||
mode = BOT_IDLE
|
||||
last_found = world.time
|
||||
|
||||
if(src.patient && src.path.len == 0 && (get_dist(src,src.patient) > 1))
|
||||
if(!stationary_mode && patient && path.len == 0 && (get_dist(src,patient) > 1))
|
||||
spawn(0)
|
||||
src.path = AStar(src.loc, get_turf(src.patient), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 30,id=botcard)
|
||||
if(!src.path)
|
||||
src.path = list()
|
||||
if(src.path.len == 0)
|
||||
src.oldpatient = src.patient
|
||||
src.patient = null
|
||||
src.currently_healing = 0
|
||||
src.last_found = world.time
|
||||
path = AStar(loc, get_turf(patient), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 30,id=botcard)
|
||||
|
||||
if(path.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
|
||||
|
||||
@@ -340,127 +354,131 @@
|
||||
if(C.suiciding)
|
||||
return 0 //Kevorkian school of robotic medical assistants.
|
||||
|
||||
if(src.emagged == 2) //Everyone needs our medicine. (Our medicine is toxins)
|
||||
if(emagged == 2) //Everyone needs our medicine. (Our medicine is toxins)
|
||||
return 1
|
||||
|
||||
if(declare_crit && C.health <= 0) //Critical condition! Call for help!
|
||||
declare(C)
|
||||
|
||||
//If they're injured, we're using a beaker, and don't have one of our WONDERCHEMS.
|
||||
if((src.reagent_glass) && (src.use_beaker) && ((C.getBruteLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getOxyLoss() >= (heal_threshold + 15))))
|
||||
for(var/datum/reagent/R in src.reagent_glass.reagents.reagent_list)
|
||||
if((reagent_glass) && (use_beaker) && ((C.getBruteLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getOxyLoss() >= (heal_threshold + 15))))
|
||||
for(var/datum/reagent/R in reagent_glass.reagents.reagent_list)
|
||||
if(!C.reagents.has_reagent(R.id))
|
||||
return 1
|
||||
|
||||
//They're injured enough for it!
|
||||
if((C.getBruteLoss() >= heal_threshold) && (!C.reagents.has_reagent(src.treatment_brute)))
|
||||
if((C.getBruteLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_brute)))
|
||||
return 1 //If they're already medicated don't bother!
|
||||
|
||||
if((C.getOxyLoss() >= (15 + heal_threshold)) && (!C.reagents.has_reagent(src.treatment_oxy)))
|
||||
if((C.getOxyLoss() >= (15 + heal_threshold)) && (!C.reagents.has_reagent(treatment_oxy)))
|
||||
return 1
|
||||
|
||||
if((C.getFireLoss() >= heal_threshold) && (!C.reagents.has_reagent(src.treatment_fire)))
|
||||
if((C.getFireLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_fire)))
|
||||
return 1
|
||||
|
||||
if((C.getToxLoss() >= heal_threshold) && (!C.reagents.has_reagent(src.treatment_tox)))
|
||||
if((C.getToxLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_tox)))
|
||||
return 1
|
||||
|
||||
if(treat_virus)
|
||||
for(var/datum/disease/D in C.viruses)
|
||||
if((D.hidden[SCANNER]) || (D.hidden[PANDEMIC])) //the medibot can't detect viruses that are undetectable to Health Analyzers or Pandemic machines.
|
||||
return 0
|
||||
if(D.severity == D.non_threat) // medibot doesn't try to heal truly harmless viruses
|
||||
return 0
|
||||
if((D.stage > 1) || (D.spread_type == AIRBORNE)) // medibot can't detect a virus in its initial stage unless it spreads airborne.
|
||||
|
||||
for(var/datum/disease/D in C.viruses)
|
||||
if((D.hidden[SCANNER]) || (D.hidden[PANDEMIC])) //the medibot can't detect viruses that are undetectable to Health Analyzers or Pandemic machines.
|
||||
return 0
|
||||
if(D.severity == D.non_threat) // medibot doesn't try to heal truly harmless viruses
|
||||
return 0
|
||||
if((D.stage > 1) || (D.spread_type == AIRBORNE)) // medibot can't detect a virus in its initial stage unless it spreads airborne.
|
||||
|
||||
if (!C.reagents.has_reagent(src.treatment_virus))
|
||||
return 1 //STOP DISEASE FOREVER
|
||||
if (!C.reagents.has_reagent(treatment_virus))
|
||||
return 1 //STOP DISEASE FOREVER
|
||||
|
||||
return 0
|
||||
|
||||
/obj/machinery/bot/medbot/proc/medicate_patient(mob/living/carbon/C as mob)
|
||||
if(!src.on)
|
||||
if(!on)
|
||||
return
|
||||
|
||||
if(!istype(C))
|
||||
src.oldpatient = src.patient
|
||||
src.patient = null
|
||||
src.currently_healing = 0
|
||||
src.last_found = world.time
|
||||
oldpatient = patient
|
||||
patient = null
|
||||
mode = BOT_IDLE
|
||||
last_found = world.time
|
||||
return
|
||||
|
||||
if(C.stat == 2)
|
||||
var/death_message = pick("No! NO!","Live, damnit! LIVE!","I...I've never lost a patient before. Not today, I mean.")
|
||||
src.speak(death_message)
|
||||
src.oldpatient = src.patient
|
||||
src.patient = null
|
||||
src.currently_healing = 0
|
||||
src.last_found = world.time
|
||||
speak(death_message)
|
||||
oldpatient = patient
|
||||
patient = null
|
||||
mode = BOT_IDLE
|
||||
last_found = world.time
|
||||
return
|
||||
|
||||
var/reagent_id = null
|
||||
|
||||
if(src.emagged == 2) //Emagged! Time to poison everybody.
|
||||
if(emagged == 2) //Emagged! Time to poison everybody.
|
||||
reagent_id = "toxin"
|
||||
|
||||
else
|
||||
var/virus = 0
|
||||
for(var/datum/disease/D in C.viruses)
|
||||
if((!D.hidden[SCANNER]) && (!D.hidden[PANDEMIC])) //detectable virus
|
||||
if(D.severity != D.non_threat) //virus is harmful
|
||||
if((D.stage > 1) || (D.spread_type == AIRBORNE))
|
||||
virus = 1
|
||||
if(treat_virus)
|
||||
var/virus = 0
|
||||
for(var/datum/disease/D in C.viruses)
|
||||
if((!D.hidden[SCANNER]) && (!D.hidden[PANDEMIC])) //detectable virus
|
||||
if(D.severity != D.non_threat) //virus is harmful
|
||||
if((D.stage > 1) || (D.spread_type == AIRBORNE))
|
||||
virus = 1
|
||||
|
||||
if (!reagent_id && (virus))
|
||||
if(!C.reagents.has_reagent(src.treatment_virus))
|
||||
reagent_id = src.treatment_virus
|
||||
if (!reagent_id && (virus))
|
||||
if(!C.reagents.has_reagent(treatment_virus))
|
||||
reagent_id = treatment_virus
|
||||
|
||||
if (!reagent_id && (C.getBruteLoss() >= heal_threshold))
|
||||
if(!C.reagents.has_reagent(src.treatment_brute))
|
||||
reagent_id = src.treatment_brute
|
||||
if(!C.reagents.has_reagent(treatment_brute))
|
||||
reagent_id = treatment_brute
|
||||
|
||||
if (!reagent_id && (C.getOxyLoss() >= (15 + heal_threshold)))
|
||||
if(!C.reagents.has_reagent(src.treatment_oxy))
|
||||
reagent_id = src.treatment_oxy
|
||||
if(!C.reagents.has_reagent(treatment_oxy))
|
||||
reagent_id = treatment_oxy
|
||||
|
||||
if (!reagent_id && (C.getFireLoss() >= heal_threshold))
|
||||
if(!C.reagents.has_reagent(src.treatment_fire))
|
||||
reagent_id = src.treatment_fire
|
||||
if(!C.reagents.has_reagent(treatment_fire))
|
||||
reagent_id = treatment_fire
|
||||
|
||||
if (!reagent_id && (C.getToxLoss() >= heal_threshold))
|
||||
if(!C.reagents.has_reagent(src.treatment_tox))
|
||||
reagent_id = src.treatment_tox
|
||||
if(!C.reagents.has_reagent(treatment_tox))
|
||||
reagent_id = treatment_tox
|
||||
|
||||
//If the patient is injured but doesn't have our special reagent in them then we should give it to them first
|
||||
if(reagent_id && src.use_beaker && src.reagent_glass && src.reagent_glass.reagents.total_volume)
|
||||
for(var/datum/reagent/R in src.reagent_glass.reagents.reagent_list)
|
||||
if(reagent_id && use_beaker && reagent_glass && reagent_glass.reagents.total_volume)
|
||||
for(var/datum/reagent/R in reagent_glass.reagents.reagent_list)
|
||||
if(!C.reagents.has_reagent(R.id))
|
||||
reagent_id = "internal_beaker"
|
||||
break
|
||||
|
||||
if(!reagent_id) //If they don't need any of that they're probably cured!
|
||||
src.oldpatient = src.patient
|
||||
src.patient = null
|
||||
src.currently_healing = 0
|
||||
src.last_found = world.time
|
||||
oldpatient = patient
|
||||
patient = null
|
||||
mode = BOT_IDLE
|
||||
last_found = world.time
|
||||
var/message = pick("All patched up!","An apple a day keeps me away.","Feel better soon!")
|
||||
src.speak(message)
|
||||
speak(message)
|
||||
updateicon()
|
||||
return
|
||||
else
|
||||
src.icon_state = "medibots"
|
||||
C.visible_message("<span class='danger'>[src] is trying to inject [src.patient]!</span>", \
|
||||
"<span class='userdanger'>[src] is trying to inject [src.patient]!</span>")
|
||||
C.visible_message("<span class='danger'>[src] is trying to inject [patient]!</span>", \
|
||||
"<span class='userdanger'>[src] is trying to inject [patient]!</span>")
|
||||
|
||||
spawn(30)
|
||||
if ((get_dist(src, src.patient) <= 1) && (src.on))
|
||||
if ((get_dist(src, patient) <= 1) && (on))
|
||||
if(reagent_id == "internal_beaker")
|
||||
if(src.use_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)
|
||||
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
|
||||
src.patient.reagents.add_reagent(reagent_id,src.injection_amount)
|
||||
C.visible_message("<span class='danger'>[src] injects [src.patient] with the syringe!</span>", \
|
||||
"<span class='userdanger'>[src] injects [src.patient] with the syringe!</span>")
|
||||
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>")
|
||||
|
||||
src.icon_state = "medibot[src.on]"
|
||||
src.currently_healing = 0
|
||||
mode = BOT_IDLE
|
||||
updateicon()
|
||||
return
|
||||
|
||||
reagent_id = null
|
||||
@@ -468,11 +486,11 @@
|
||||
|
||||
/obj/machinery/bot/medbot/bullet_act(var/obj/item/projectile/Proj)
|
||||
if(Proj.flag == "taser")
|
||||
src.stunned = min(stunned+10,20)
|
||||
stunned = min(stunned+10,20)
|
||||
..()
|
||||
|
||||
/obj/machinery/bot/medbot/explode()
|
||||
src.on = 0
|
||||
on = 0
|
||||
visible_message("<span class='userdanger'>[src] blows apart!</span>")
|
||||
var/turf/Tsec = get_turf(src)
|
||||
|
||||
@@ -482,9 +500,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)
|
||||
@@ -495,54 +513,14 @@
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/obj/machinery/bot/medbot/Bump(M as mob|obj) //Leave no door unopened!
|
||||
if ((istype(M, /obj/machinery/door)) && (!isnull(src.botcard)))
|
||||
var/obj/machinery/door/D = M
|
||||
if (!istype(D, /obj/machinery/door/firedoor) && D.check_access(src.botcard))
|
||||
D.open()
|
||||
src.frustration = 0
|
||||
else if ((istype(M, /mob/living/)) && (!src.anchored))
|
||||
src.loc = M:loc
|
||||
src.frustration = 0
|
||||
return
|
||||
|
||||
/* 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)
|
||||
speak("Medical emergency! [crit_patient ? "<b>[crit_patient]</b>" : "A patient"] is in critical condition at [location]!",radio_frequency)
|
||||
declare_cooldown = 1
|
||||
spawn(200) //Twenty seconds
|
||||
declare_cooldown = 0
|
||||
|
||||
/*
|
||||
* Medbot Assembly -- Can be made out of all three medkits.
|
||||
@@ -555,7 +533,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
|
||||
|
||||
@@ -577,33 +555,33 @@
|
||||
/obj/item/weapon/firstaid_arm_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
..()
|
||||
if(istype(W, /obj/item/weapon/pen))
|
||||
var/t = copytext(stripped_input(user, "Enter new robot name", src.name, src.created_name),1,MAX_NAME_LEN)
|
||||
var/t = copytext(stripped_input(user, "Enter new robot name", name, created_name),1,MAX_NAME_LEN)
|
||||
if (!t)
|
||||
return
|
||||
if (!in_range(src, usr) && src.loc != usr)
|
||||
if (!in_range(src, usr) && loc != usr)
|
||||
return
|
||||
src.created_name = t
|
||||
created_name = t
|
||||
else
|
||||
switch(build_step)
|
||||
if(0)
|
||||
if(istype(W, /obj/item/device/healthanalyzer))
|
||||
user.drop_item()
|
||||
qdel(W)
|
||||
src.build_step++
|
||||
build_step++
|
||||
user << "<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()
|
||||
qdel(W)
|
||||
src.build_step++
|
||||
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 = src.skin
|
||||
S.name = src.created_name
|
||||
S.skin = skin
|
||||
S.name = created_name
|
||||
user.unEquip(src, 1)
|
||||
qdel(src)
|
||||
|
||||
|
||||
+149
-123
@@ -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/stock_parts/cell/cell
|
||||
var/datum/wires/mulebot/wires = null
|
||||
@@ -67,18 +61,16 @@ var/global/mulebot_count = 0
|
||||
/obj/machinery/bot/mulebot/New()
|
||||
..()
|
||||
wires = new(src)
|
||||
botcard = new(src)
|
||||
var/datum/job/cargo_tech/J = new/datum/job/cargo_tech
|
||||
botcard.access = J.get_access()
|
||||
prev_access = botcard.access
|
||||
// botcard.access += access_robotics //Why --Ikki
|
||||
cell = new(src)
|
||||
cell.charge = 2000
|
||||
cell.maxcharge = 2000
|
||||
|
||||
spawn(5) // must wait for map loading to finish
|
||||
if(radio_controller)
|
||||
radio_controller.add_object(src, control_freq, filter = RADIO_MULEBOT)
|
||||
radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
|
||||
add_to_beacons(bot_filter)
|
||||
|
||||
mulebot_count += 1
|
||||
if(!suffix)
|
||||
@@ -100,8 +92,8 @@ var/global/mulebot_count = 0
|
||||
locked = !locked
|
||||
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 << "<span class='notice'>Controls [(locked ? "locked" : "unlocked")].</span>"
|
||||
|
||||
@@ -118,30 +110,30 @@ var/global/mulebot_count = 0
|
||||
|
||||
open = !open
|
||||
if(open)
|
||||
src.visible_message("[user] opens the maintenance hatch of [src]", "<span class='notice'>You open [src]'s maintenance hatch.</span>")
|
||||
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]", "<span class='notice'>You close [src]'s maintenance hatch.</span>")
|
||||
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(
|
||||
"<span class='danger'>[user] repairs [src]!</span>",
|
||||
"<span class='notice'>[user] repairs [src]!</span>",
|
||||
"<span class='notice'>You repair [src]!</span>"
|
||||
)
|
||||
else
|
||||
user << "<span class='notice'>[src] does not need a repair!</span>"
|
||||
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("<span class='danger'>[user] knocks [load] off [src] with \the [I]!</span>", "<span class='danger'>You knock [load] off [src] with \the [I]!</span>")
|
||||
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
|
||||
@@ -164,7 +156,7 @@ var/global/mulebot_count = 0
|
||||
if(prob(50) && !isnull(load))
|
||||
unload(0)
|
||||
if(prob(25))
|
||||
src.visible_message("<span class='danger'>Something shorts out inside [src]!</span>")
|
||||
visible_message("<span class='danger'> Something shorts out inside [src]!</span>")
|
||||
wires.RandomCut()
|
||||
..()
|
||||
|
||||
@@ -182,29 +174,30 @@ var/global/mulebot_count = 0
|
||||
|
||||
/obj/machinery/bot/mulebot/interact(var/mob/user, var/ai=0)
|
||||
var/dat
|
||||
dat += "<h3>Multiple Utility Load Effector Mk. IV</h3>"
|
||||
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 += "<h3>Status</h3>"
|
||||
|
||||
dat += "<div class='statusDisplay'>"
|
||||
switch(mode)
|
||||
if(0)
|
||||
dat += "Ready"
|
||||
if(1)
|
||||
dat += "<span class='good'>Loading/Unloading</span>"
|
||||
if(2)
|
||||
dat += "<span class='good'>Navigating to Delivery Location</span>"
|
||||
if(3)
|
||||
dat += "<span class='good'>Navigating to Home</span>"
|
||||
if(4)
|
||||
dat += "<span class='average'>Waiting for clear path</span>"
|
||||
if(5,6)
|
||||
dat += "<span class='average'>Calculating navigation path</span>"
|
||||
if(7)
|
||||
dat += "<span class='bad'>Unable to reach destination</span>"
|
||||
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 += "<b>Current Load:</b> [load ? load.name : "<i>none</i>"]<BR>"
|
||||
@@ -225,6 +218,7 @@ 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>"
|
||||
@@ -245,9 +239,9 @@ var/global/mulebot_count = 0
|
||||
|
||||
//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. III [suffix ? "([suffix])" : ""]", 350, 500)
|
||||
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(src.icon, src.icon_state))
|
||||
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
|
||||
popup.open()
|
||||
return
|
||||
|
||||
@@ -261,7 +255,7 @@ var/global/mulebot_count = 0
|
||||
return
|
||||
if (usr.stat)
|
||||
return
|
||||
if ((in_range(src, usr) && istype(src.loc, /turf)) || (istype(usr, /mob/living/silicon)))
|
||||
if ((in_range(src, usr) && istype(loc, /turf)) || (istype(usr, /mob/living/silicon)))
|
||||
usr.set_machine(src)
|
||||
|
||||
switch(href_list["op"])
|
||||
@@ -269,7 +263,7 @@ var/global/mulebot_count = 0
|
||||
toggle_lock(usr)
|
||||
|
||||
if("power")
|
||||
if (src.on)
|
||||
if (on)
|
||||
turn_off()
|
||||
else if (cell && !open)
|
||||
if (!turn_on())
|
||||
@@ -305,23 +299,23 @@ var/global/mulebot_count = 0
|
||||
|
||||
|
||||
if("stop")
|
||||
if(mode >=2)
|
||||
mode = 0
|
||||
if(mode >= BOT_DELIVER)
|
||||
bot_reset()
|
||||
updateDialog()
|
||||
|
||||
if("go")
|
||||
if(mode == 0)
|
||||
if(mode == BOT_IDLE)
|
||||
start()
|
||||
updateDialog()
|
||||
|
||||
if("home")
|
||||
if(mode == 0 || mode == 2)
|
||||
if(mode == BOT_IDLE || mode == BOT_DELIVER)
|
||||
start_home()
|
||||
updateDialog()
|
||||
|
||||
if("destination")
|
||||
refresh=0
|
||||
var/new_dest = input("Enter new destination tag", "Mulebot [suffix ? "([suffix])" : ""]", destination) as text|null
|
||||
var/new_dest = input("Select M.U.L.E. Destination", "Mulebot [suffix ? "([suffix])" : ""]", destination) as null|anything in delivery_beacons
|
||||
refresh=1
|
||||
if(new_dest)
|
||||
set_destination(new_dest)
|
||||
@@ -357,12 +351,15 @@ var/global/mulebot_count = 0
|
||||
if("autopick")
|
||||
auto_pickup = !auto_pickup
|
||||
|
||||
if("report")
|
||||
report_delivery = !report_delivery
|
||||
|
||||
if("close")
|
||||
usr.unset_machine()
|
||||
usr << browse(null,"window=mulebot")
|
||||
|
||||
updateDialog()
|
||||
//src.updateUsrDialog()
|
||||
//updateUsrDialog()
|
||||
else
|
||||
usr << browse(null, "window=mulebot")
|
||||
usr.unset_machine()
|
||||
@@ -375,7 +372,7 @@ var/global/mulebot_count = 0
|
||||
return !open && cell && cell.charge > 0 && wires.HasPower()
|
||||
|
||||
/obj/machinery/bot/mulebot/proc/toggle_lock(var/mob/user)
|
||||
if(src.allowed(user))
|
||||
if(allowed(user))
|
||||
locked = !locked
|
||||
updateDialog()
|
||||
return 1
|
||||
@@ -403,8 +400,8 @@ var/global/mulebot_count = 0
|
||||
// called to load a crate
|
||||
/obj/machinery/bot/mulebot/proc/load(var/atom/movable/C)
|
||||
if(wires.LoadCheck() && !istype(C,/obj/structure/closet/crate))
|
||||
src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
|
||||
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
|
||||
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
return // if not emagged, only allow crates to be loaded
|
||||
|
||||
//I'm sure someone will come along and ask why this is here... well people were dragging screen items onto the mule, and that was not cool.
|
||||
@@ -416,16 +413,16 @@ var/global/mulebot_count = 0
|
||||
|
||||
if(get_dist(C, src) > 1 || load || !on)
|
||||
return
|
||||
mode = 1
|
||||
mode = BOT_LOADING
|
||||
|
||||
// if a create, close before loading
|
||||
var/obj/structure/closet/crate/crate = C
|
||||
if(istype(crate))
|
||||
crate.close()
|
||||
|
||||
C.loc = src.loc
|
||||
C.loc = loc
|
||||
sleep(2)
|
||||
if(C.loc != src.loc) //To prevent you from going onto more thano ne bot.
|
||||
if(C.loc != loc) //To prevent you from going onto more thano ne bot.
|
||||
return
|
||||
C.loc = src
|
||||
load = C
|
||||
@@ -441,7 +438,7 @@ var/global/mulebot_count = 0
|
||||
M.client.perspective = EYE_PERSPECTIVE
|
||||
M.client.eye = src
|
||||
|
||||
mode = 0
|
||||
mode = BOT_IDLE
|
||||
send_status()
|
||||
|
||||
// called to unload the bot
|
||||
@@ -451,7 +448,7 @@ var/global/mulebot_count = 0
|
||||
if(!load)
|
||||
return
|
||||
|
||||
mode = 1
|
||||
mode = BOT_LOADING
|
||||
overlays.Cut()
|
||||
|
||||
if(ismob(load))
|
||||
@@ -461,11 +458,11 @@ var/global/mulebot_count = 0
|
||||
M.client.eye = src
|
||||
|
||||
|
||||
load.loc = src.loc
|
||||
load.loc = loc
|
||||
load.pixel_y -= 9
|
||||
load.layer = initial(load.layer)
|
||||
if(dirn)
|
||||
var/turf/T = src.loc
|
||||
var/turf/T = loc
|
||||
var/turf/newT = get_step(T,dirn)
|
||||
if(load.CanPass(load,newT)) //Can't get off onto anything that wouldn't let you pass normally
|
||||
step(load, dirn)
|
||||
@@ -477,9 +474,9 @@ var/global/mulebot_count = 0
|
||||
// with items dropping as mobs are loaded
|
||||
|
||||
for(var/atom/movable/AM in src)
|
||||
if(AM == cell || AM == botcard) continue
|
||||
if(AM == cell || istype(AM , botcard) || AM == Radio) continue
|
||||
|
||||
AM.loc = src.loc
|
||||
AM.loc = loc
|
||||
AM.layer = initial(AM.layer)
|
||||
AM.pixel_y = initial(AM.pixel_y)
|
||||
if(ismob(AM))
|
||||
@@ -487,8 +484,17 @@ 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()
|
||||
if(!has_power())
|
||||
@@ -520,13 +526,14 @@ var/global/mulebot_count = 0
|
||||
|
||||
/obj/machinery/bot/mulebot/proc/process_bot()
|
||||
//if(mode) world << "Mode: [mode]"
|
||||
|
||||
switch(mode)
|
||||
if(0) // idle
|
||||
if(BOT_IDLE) // idle
|
||||
icon_state = "mulebot0"
|
||||
return
|
||||
if(1) // loading/unloading
|
||||
if(BOT_LOADING) // loading/unloading
|
||||
return
|
||||
if(2,3,4) // navigating to deliver,home, or blocked
|
||||
if(BOT_DELIVER,BOT_GO_HOME,BOT_BLOCKED) // navigating to deliver,home, or blocked
|
||||
|
||||
if(loc == target) // reached target
|
||||
at_target()
|
||||
@@ -569,14 +576,14 @@ var/global/mulebot_count = 0
|
||||
path -= loc
|
||||
|
||||
|
||||
if(mode==4)
|
||||
if(mode == BOT_BLOCKED)
|
||||
spawn(1)
|
||||
send_status()
|
||||
|
||||
if(destination == home_destination)
|
||||
mode = 3
|
||||
mode = BOT_GO_HOME
|
||||
else
|
||||
mode = 2
|
||||
mode = BOT_DELIVER
|
||||
|
||||
else // failed to move
|
||||
|
||||
@@ -585,73 +592,74 @@ var/global/mulebot_count = 0
|
||||
|
||||
|
||||
blockcount++
|
||||
mode = 4
|
||||
mode = BOT_BLOCKED
|
||||
if(blockcount == 3)
|
||||
src.visible_message("[src] makes an annoyed buzzing sound.", "You hear an electronic buzzing sound.")
|
||||
playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0)
|
||||
visible_message("[src] makes an annoyed buzzing sound.", "You hear an electronic buzzing sound.")
|
||||
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
|
||||
|
||||
if(blockcount > 10) // attempt 10 times before recomputing
|
||||
// find new path excluding blocked turf
|
||||
src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
|
||||
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
|
||||
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
|
||||
spawn(2)
|
||||
calc_path(next)
|
||||
if(path.len > 0)
|
||||
src.visible_message("[src] makes a delighted ping!", "You hear a ping.")
|
||||
playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
|
||||
mode = 4
|
||||
mode =6
|
||||
visible_message("[src] makes a delighted ping!", "You hear a ping.")
|
||||
playsound(loc, 'sound/machines/ping.ogg', 50, 0)
|
||||
mode = BOT_BLOCKED
|
||||
mode = BOT_WAIT_FOR_NAV
|
||||
return
|
||||
return
|
||||
else
|
||||
src.visible_message("[src] makes an annoyed buzzing sound.", "You hear an electronic buzzing sound.")
|
||||
playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0)
|
||||
visible_message("[src] makes an annoyed buzzing sound.", "You hear an electronic buzzing sound.")
|
||||
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
|
||||
//world << "Bad turf."
|
||||
mode = 5
|
||||
mode = BOT_NAV
|
||||
return
|
||||
else
|
||||
//world << "No path."
|
||||
mode = 5
|
||||
mode = BOT_NAV
|
||||
return
|
||||
|
||||
if(5) // calculate new path
|
||||
if(BOT_NAV) // calculate new path
|
||||
//world << "Calc new path."
|
||||
mode = 6
|
||||
mode = BOT_WAIT_FOR_NAV
|
||||
spawn(0)
|
||||
|
||||
calc_path()
|
||||
|
||||
if(path.len > 0)
|
||||
blockcount = 0
|
||||
mode = 4
|
||||
src.visible_message("[src] makes a delighted ping!", "You hear a ping.")
|
||||
playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
|
||||
mode = BOT_BLOCKED
|
||||
visible_message("[src] makes a delighted ping!", "You hear a ping.")
|
||||
playsound(loc, 'sound/machines/ping.ogg', 50, 0)
|
||||
|
||||
else
|
||||
src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
|
||||
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
|
||||
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
|
||||
mode = 7
|
||||
mode = BOT_NO_ROUTE
|
||||
//if(6)
|
||||
//world << "Pending path calc."
|
||||
//if(7)
|
||||
//world << "No dest / no route."
|
||||
|
||||
return
|
||||
|
||||
|
||||
// calculates a path to the current destination
|
||||
// given an optional turf to avoid
|
||||
/obj/machinery/bot/mulebot/proc/calc_path(var/turf/avoid = null)
|
||||
src.path = AStar(src.loc, src.target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 250, id=botcard, exclude=avoid)
|
||||
if(!src.path)
|
||||
src.path = list()
|
||||
/obj/machinery/bot/mulebot/calc_path(var/turf/avoid = null)
|
||||
path = AStar(loc, target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance_cardinal, 0, 250, id=botcard, exclude=avoid)
|
||||
if(!path)
|
||||
path = list()
|
||||
|
||||
|
||||
// sets the current destination
|
||||
// signals all beacons matching the delivery code
|
||||
// beacons will return a signal giving their locations
|
||||
/obj/machinery/bot/mulebot/proc/set_destination(var/new_dest)
|
||||
/obj/machinery/bot/mulebot/set_destination(var/new_dest)
|
||||
spawn(0)
|
||||
new_destination = new_dest
|
||||
post_signal(beacon_freq, "findbeacon", "delivery")
|
||||
@@ -660,9 +668,9 @@ var/global/mulebot_count = 0
|
||||
// starts bot moving to current destination
|
||||
/obj/machinery/bot/mulebot/proc/start()
|
||||
if(destination == home_destination)
|
||||
mode = 3
|
||||
mode = BOT_GO_HOME
|
||||
else
|
||||
mode = 2
|
||||
mode = BOT_DELIVER
|
||||
icon_state = "mulebot[(wires.MobAvoid() != 0)]"
|
||||
|
||||
// starts bot moving to home
|
||||
@@ -670,17 +678,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 = SUPP_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
|
||||
@@ -695,14 +713,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
|
||||
|
||||
@@ -714,13 +734,12 @@ var/global/mulebot_count = 0
|
||||
var/mob/M = obs
|
||||
if(ismob(M))
|
||||
if(istype(M,/mob/living/silicon/robot))
|
||||
src.visible_message("<span class='danger'>[src] bumps into [M]!</span>")
|
||||
visible_message("<span class='danger'>[src] bumps into [M]!</span>")
|
||||
else
|
||||
src.visible_message("<span class='danger'>[src] knocks over [M]!</span>")
|
||||
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()
|
||||
@@ -730,8 +749,8 @@ var/global/mulebot_count = 0
|
||||
// called from mob/living/carbon/human/Crossed()
|
||||
// when mulebot is in the same loc
|
||||
/obj/machinery/bot/mulebot/proc/RunOver(var/mob/living/carbon/human/H)
|
||||
src.visible_message("<span class='danger'>[src] drives over [H]!</span>")
|
||||
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1)
|
||||
visible_message("<span class='danger'>[src] drives over [H]!</span>")
|
||||
playsound(loc, 'sound/effects/splat.ogg', 50, 1)
|
||||
|
||||
var/damage = rand(5,15)
|
||||
H.apply_damage(2*damage, BRUTE, "head")
|
||||
@@ -741,7 +760,7 @@ var/global/mulebot_count = 0
|
||||
H.apply_damage(0.5*damage, BRUTE, "l_arm")
|
||||
H.apply_damage(0.5*damage, BRUTE, "r_arm")
|
||||
|
||||
var/obj/effect/decal/cleanable/blood/B = new(src.loc)
|
||||
var/obj/effect/decal/cleanable/blood/B = new(loc)
|
||||
B.blood_DNA = list()
|
||||
B.blood_DNA[H.dna.unique_enzymes] = H.dna.blood_type
|
||||
|
||||
@@ -779,7 +798,7 @@ var/global/mulebot_count = 0
|
||||
// process control input
|
||||
switch(recv)
|
||||
if("stop")
|
||||
mode = 0
|
||||
bot_reset()
|
||||
return
|
||||
|
||||
if("go")
|
||||
@@ -815,6 +834,7 @@ var/global/mulebot_count = 0
|
||||
|
||||
// receive response from beacon
|
||||
recv = signal.data["beacon"]
|
||||
|
||||
if(wires.BeaconRX())
|
||||
if(recv == new_destination) // if the recvd beacon location matches the set destination
|
||||
// the we will navigate there
|
||||
@@ -829,12 +849,18 @@ var/global/mulebot_count = 0
|
||||
calc_path()
|
||||
updateDialog()
|
||||
|
||||
//Detects and stores current active delivery beacons.
|
||||
if(signal.data["beacon"])
|
||||
if(!delivery_beacons)
|
||||
delivery_beacons = new()
|
||||
delivery_beacons[signal.data["beacon"] ] = signal.source
|
||||
|
||||
// send a radio signal with a single data key/value pair
|
||||
/obj/machinery/bot/mulebot/proc/post_signal(var/freq, var/key, var/value)
|
||||
/obj/machinery/bot/mulebot/post_signal(var/freq, var/key, var/value)
|
||||
post_signal_multiple(freq, list("[key]" = value) )
|
||||
|
||||
// send a radio signal with multiple data key/values
|
||||
/obj/machinery/bot/mulebot/proc/post_signal_multiple(var/freq, var/list/keyval)
|
||||
/obj/machinery/bot/mulebot/post_signal_multiple(var/freq, var/list/keyval)
|
||||
|
||||
if(freq == beacon_freq && !(wires.BeaconRX()))
|
||||
return
|
||||
@@ -856,17 +882,17 @@ var/global/mulebot_count = 0
|
||||
//world << "sent [key],[keyval[key]] on [freq]"
|
||||
if (signal.data["findbeacon"])
|
||||
frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
|
||||
else if (signal.data["type"] == "mulebot")
|
||||
else if (signal.data["type"] == MULE_BOT)
|
||||
frequency.post_signal(src, signal, filter = RADIO_MULEBOT)
|
||||
else
|
||||
frequency.post_signal(src, signal)
|
||||
|
||||
// signals bot status etc. to controller
|
||||
/obj/machinery/bot/mulebot/proc/send_status()
|
||||
/obj/machinery/bot/mulebot/send_status()
|
||||
var/list/kv = list(
|
||||
"type" = "mulebot",
|
||||
"type" = MULE_BOT,
|
||||
"name" = suffix,
|
||||
"loca" = (loc ? loc.loc : "Unknown"), // somehow loc can be null and cause a runtime - Quarxink
|
||||
"loca" = get_area(src),
|
||||
"mode" = mode,
|
||||
"powr" = (cell ? cell.percent() : 0),
|
||||
"dest" = destination,
|
||||
@@ -886,7 +912,7 @@ var/global/mulebot_count = 0
|
||||
|
||||
|
||||
/obj/machinery/bot/mulebot/explode()
|
||||
src.visible_message("<span class='userdanger'>[src] blows apart!</span>")
|
||||
visible_message("<span class='userdanger'>[src] blows apart!</span>")
|
||||
var/turf/Tsec = get_turf(src)
|
||||
|
||||
new /obj/item/device/assembly/prox_sensor(Tsec)
|
||||
@@ -902,6 +928,6 @@ var/global/mulebot_count = 0
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
|
||||
new /obj/effect/decal/cleanable/oil(src.loc)
|
||||
new /obj/effect/decal/cleanable/oil(loc)
|
||||
unload(0)
|
||||
qdel(src)
|
||||
|
||||
+143
-453
@@ -17,45 +17,23 @@
|
||||
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 = 0 //If true, arrest people for weapons if they don't have access
|
||||
var/weaponscheck = 0 //If true, arrest people for weapons if they lack access
|
||||
var/check_records = 1 //Does it check security records?
|
||||
var/arrest_type = 0 //If true, don't handcuff
|
||||
|
||||
var/mode = 0
|
||||
#define SECBOT_IDLE 0 // idle
|
||||
#define SECBOT_HUNT 1 // found target, hunting
|
||||
#define SECBOT_PREP_ARREST 2 // at target, preparing to arrest
|
||||
#define SECBOT_ARREST 3 // arresting target
|
||||
#define SECBOT_START_PATROL 4 // start patrol
|
||||
#define SECBOT_PATROL 5 // patrolling
|
||||
#define SECBOT_SUMMON 6 // summoned by PDA
|
||||
|
||||
var/auto_patrol = 0 // set to make bot automatically patrol
|
||||
|
||||
var/beacon_freq = 1445 // navigation beacon frequency
|
||||
var/control_freq = 1447 // bot control frequency
|
||||
radio_frequency = 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(\
|
||||
/obj/item/weapon/gun/energy/laser/bluetag,\
|
||||
/obj/item/weapon/gun/energy/laser/redtag,\
|
||||
/obj/item/weapon/gun/energy/laser/practice)
|
||||
|
||||
var/turf/patrol_target // this is turf to navigate to (location of beacon)
|
||||
var/new_destination // pending new destination (waiting for beacon response)
|
||||
var/destination // destination description tag
|
||||
var/next_destination // the next destination in the patrol route
|
||||
var/list/path = new // list of path turfs
|
||||
|
||||
var/blockcount = 0 //number of times retried a blocked path
|
||||
var/awaiting_beacon = 0 // count of pticks awaiting a beacon response
|
||||
|
||||
var/nearest_beacon // the nearest beacon's tag
|
||||
var/turf/nearest_beacon_loc // the nearest beacon's location
|
||||
/obj/item/weapon/gun/energy/laser/practice,\
|
||||
/obj/item/weapon/melee/telebaton,\
|
||||
/obj/item/weapon/gun/energy/kinetic_accelerator)
|
||||
|
||||
|
||||
/obj/machinery/bot/secbot/beepsky
|
||||
@@ -68,7 +46,7 @@
|
||||
/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 = "incomplete securitron assembly"
|
||||
@@ -83,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)
|
||||
. = ..()
|
||||
@@ -119,147 +105,118 @@
|
||||
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 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.1 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)
|
||||
if(..())
|
||||
return
|
||||
usr.set_machine(src)
|
||||
if((href_list["power"]) && (src.allowed(usr)))
|
||||
if (src.on && !src.emagged)
|
||||
turn_off()
|
||||
else
|
||||
turn_on()
|
||||
return
|
||||
|
||||
..()
|
||||
|
||||
switch(href_list["operation"])
|
||||
if("idcheck")
|
||||
src.idcheck = !src.idcheck
|
||||
src.updateUsrDialog()
|
||||
idcheck = !idcheck
|
||||
updateUsrDialog()
|
||||
if("weaponscheck")
|
||||
src.weaponscheck = !src.weaponscheck
|
||||
src.updateUsrDialog()
|
||||
weaponscheck = !weaponscheck
|
||||
updateUsrDialog()
|
||||
if("ignorerec")
|
||||
src.check_records = !src.check_records
|
||||
src.updateUsrDialog()
|
||||
check_records = !check_records
|
||||
updateUsrDialog()
|
||||
if("switchmode")
|
||||
src.arrest_type = !src.arrest_type
|
||||
src.updateUsrDialog()
|
||||
if("patrol")
|
||||
auto_patrol = !auto_patrol
|
||||
mode = SECBOT_IDLE
|
||||
arrest_type = !arrest_type
|
||||
updateUsrDialog()
|
||||
if("declarearrests")
|
||||
src.declare_arrests = !src.declare_arrests
|
||||
src.updateUsrDialog()
|
||||
if("hack")
|
||||
if(!src.emagged)
|
||||
src.emagged = 2
|
||||
src.hacked = 1
|
||||
usr << "<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."]"
|
||||
else
|
||||
if(emagged)
|
||||
user << "<span class='warning'>ERROR</span>"
|
||||
if(open)
|
||||
user << "<span class='danger'>Please close the access panel before locking it.</span>"
|
||||
else
|
||||
user << "<span class='danger'>Access denied.</span>"
|
||||
user << "<span class='danger'> Access denied.</span>"
|
||||
else
|
||||
..()
|
||||
if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != "harm") // Any intent but harm will heal, so we shouldn't get angry.
|
||||
return
|
||||
if(!istype(W, /obj/item/weapon/screwdriver) && (W.force) && (!src.target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
|
||||
if(!istype(W, /obj/item/weapon/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
|
||||
threatlevel = user.assess_threat(src)
|
||||
threatlevel += 6
|
||||
if(threatlevel >= 4)
|
||||
src.target = user
|
||||
src.mode = SECBOT_HUNT
|
||||
target = user
|
||||
mode = BOT_HUNT
|
||||
|
||||
/obj/machinery/bot/secbot/Emag(mob/user as mob)
|
||||
..()
|
||||
if(open && !locked)
|
||||
if(user) user << "<span class='danger'>You short out [src]'s target assessment circuits.</span>"
|
||||
spawn(0)
|
||||
audible_message("<span class='danger'>[src] buzzes oddly!</span>")
|
||||
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
|
||||
|
||||
if(emagged == 2)
|
||||
if(user)
|
||||
user << "<span class='danger'> You short out [src]'s target assessment circuits.</span>"
|
||||
oldtarget_name = user.name
|
||||
audible_message("<span class='danger'>[src] buzzes oddly!</span>")
|
||||
declare_arrests = 0
|
||||
icon_state = "secbot[on]"
|
||||
|
||||
/obj/machinery/bot/secbot/process()
|
||||
set background = BACKGROUND_ENABLED
|
||||
|
||||
if(!src.on)
|
||||
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)
|
||||
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
|
||||
icon_state = "secbot[on]"
|
||||
var/mob/living/carbon/M = target
|
||||
if(istype(M, /mob/living/carbon/human))
|
||||
if( M.stuttering < 5 && !(HULK in M.mutations) )
|
||||
M.stuttering = 5
|
||||
@@ -272,46 +229,46 @@ Auto Patrol: []"},
|
||||
|
||||
if(declare_arrests)
|
||||
var/area/location = get_area(src)
|
||||
broadcast_hud_message("[src.name] is [arrest_type ? "detaining" : "arresting"] level [threatlevel] scumbag <b>[target.name]</b> in <b>[location]</b>", src)
|
||||
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>")
|
||||
speak("[arrest_type ? "Detaining" : "Arresting"] level [threatlevel] scumbag <b>[target]</b> in [location].", radio_frequency)
|
||||
target.visible_message("<span class='danger'>[target] has been stunned by [src]!</span>",\
|
||||
"<span class='userdanger'>[target] has been stunned by [src]!</span>")
|
||||
|
||||
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
|
||||
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 he's no no longer adjacent or inside a closet or about to get up, we hunt again.
|
||||
if( !src.Adjacent(target) || !isturf(src.target.loc) || src.target.weakened < 2 )
|
||||
if( !Adjacent(target) || !isturf(target.loc) || target.weakened < 2 )
|
||||
back_to_hunt()
|
||||
return
|
||||
|
||||
if(iscarbon(target) && target.canBeHandcuffed())
|
||||
if(!src.arrest_type)
|
||||
if(!src.target.handcuffed) //he's not cuffed? Try to cuff him!
|
||||
mode = SECBOT_ARREST
|
||||
playsound(src.loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
|
||||
target.visible_message("<span class='danger'>[src] is trying to put zipties on [src.target]!</span>",\
|
||||
"<span class='userdanger'>[src] is trying to put zipties on [src.target]!</span>")
|
||||
if(!arrest_type)
|
||||
if(!target.handcuffed) //he's not cuffed? Try to cuff him!
|
||||
mode = BOT_ARREST
|
||||
playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
|
||||
target.visible_message("<span class='danger'>[src] is trying to put zipties on [target]!</span>",\
|
||||
"<span class='userdanger'>[src] is trying to put zipties on [target]!</span>")
|
||||
spawn(60)
|
||||
if( !src.Adjacent(target) || !isturf(src.target.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
|
||||
if( !Adjacent(target) || !isturf(target.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
|
||||
return
|
||||
if(!src.target.handcuffed)
|
||||
if(!target.handcuffed)
|
||||
target.handcuffed = new /obj/item/weapon/restraints/handcuffs/cable/zipties/used(target)
|
||||
target.update_inv_handcuffed(0) //update the handcuffs overlay
|
||||
playsound(src.loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg'), 50, 0)
|
||||
playsound(loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg'), 50, 0)
|
||||
back_to_idle()
|
||||
else
|
||||
back_to_idle()
|
||||
@@ -320,362 +277,95 @@ Auto Patrol: []"},
|
||||
back_to_idle()
|
||||
return
|
||||
|
||||
if(SECBOT_ARREST)
|
||||
|
||||
if(BOT_ARREST)
|
||||
if (!target)
|
||||
src.anchored = 0
|
||||
mode = SECBOT_IDLE
|
||||
src.last_found = world.time
|
||||
anchored = 0
|
||||
mode = BOT_IDLE
|
||||
last_found = world.time
|
||||
frustration = 0
|
||||
return
|
||||
|
||||
if(src.target.handcuffed) //no target or target cuffed? back to idle.
|
||||
if(target.handcuffed) //no target or target cuffed? back to idle.
|
||||
back_to_idle()
|
||||
return
|
||||
|
||||
if( !src.Adjacent(target) || !isturf(src.target.loc) || (src.target.loc != src.target_lastloc && src.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.
|
||||
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()
|
||||
|
||||
if(BOT_PATROL)
|
||||
look_for_perp()
|
||||
bot_patrol()
|
||||
|
||||
|
||||
if(SECBOT_START_PATROL) // start a patrol
|
||||
|
||||
if(path.len > 0 && patrol_target) // have a valid path, so just resume
|
||||
mode = SECBOT_PATROL
|
||||
return
|
||||
|
||||
else if(patrol_target) // has patrol target already
|
||||
spawn(0)
|
||||
calc_path() // so just find a route to it
|
||||
if(path.len == 0)
|
||||
patrol_target = 0
|
||||
return
|
||||
mode = SECBOT_PATROL
|
||||
|
||||
|
||||
else // no patrol target, so need a new one
|
||||
find_patrol_target()
|
||||
speak("Engaging patrol mode.")
|
||||
|
||||
|
||||
if(SECBOT_PATROL) // patrol mode
|
||||
|
||||
patrol_step()
|
||||
spawn(5)
|
||||
if(mode == SECBOT_PATROL)
|
||||
patrol_step()
|
||||
|
||||
if(SECBOT_SUMMON) // summoned to PDA
|
||||
patrol_step()
|
||||
spawn(4)
|
||||
if(mode == SECBOT_SUMMON)
|
||||
patrol_step()
|
||||
sleep(4)
|
||||
patrol_step()
|
||||
return
|
||||
|
||||
/obj/machinery/bot/secbot/proc/back_to_idle()
|
||||
src.anchored = 0
|
||||
mode = SECBOT_IDLE
|
||||
src.target = null
|
||||
src.last_found = world.time
|
||||
anchored = 0
|
||||
mode = BOT_IDLE
|
||||
target = null
|
||||
last_found = world.time
|
||||
frustration = 0
|
||||
spawn(0)
|
||||
process() //ensure bot quickly responds
|
||||
|
||||
/obj/machinery/bot/secbot/proc/back_to_hunt()
|
||||
src.anchored = 0
|
||||
src.frustration = 0
|
||||
mode = SECBOT_HUNT
|
||||
anchored = 0
|
||||
frustration = 0
|
||||
mode = BOT_HUNT
|
||||
spawn(0)
|
||||
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()
|
||||
if(auto_patrol)
|
||||
find_patrol_target()
|
||||
else
|
||||
mode = SECBOT_IDLE
|
||||
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()
|
||||
|
||||
|
||||
// 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
|
||||
break
|
||||
else
|
||||
continue
|
||||
|
||||
/obj/machinery/bot/secbot/proc/check_for_weapons(var/obj/item/slot_item)
|
||||
if(istype(slot_item, /obj/item/weapon/gun) || istype(slot_item, /obj/item/weapon/melee))
|
||||
if(!(slot_item.type in safe_weapons))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/machinery/bot/secbot/Bump(M as mob|obj) //Leave no door unopened!
|
||||
if((istype(M, /obj/machinery/door)) && (!isnull(src.botcard)))
|
||||
var/obj/machinery/door/D = M
|
||||
if(!istype(D, /obj/machinery/door/firedoor) && D.check_access(src.botcard))
|
||||
D.open()
|
||||
src.frustration = 0
|
||||
else if((istype(M, /mob/living/)) && (!src.anchored))
|
||||
src.loc = M:loc
|
||||
src.frustration = 0
|
||||
return
|
||||
|
||||
/* terrible
|
||||
/obj/machinery/bot/secbot/Bumped(atom/movable/M as mob|obj)
|
||||
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("<span class='userdanger'>[src] blows apart!</span>")
|
||||
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 += "hs_hole"
|
||||
Sa.created_name = src.name
|
||||
Sa.created_name = name
|
||||
new /obj/item/device/assembly/prox_sensor(Tsec)
|
||||
new /obj/item/weapon/melee/baton(Tsec)
|
||||
|
||||
@@ -686,14 +376,14 @@ Auto Patrol: []"},
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
|
||||
new /obj/effect/decal/cleanable/oil(src.loc)
|
||||
new /obj/effect/decal/cleanable/oil(loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/bot/secbot/attack_alien(var/mob/living/carbon/alien/user as mob)
|
||||
..()
|
||||
if(!isalien(target))
|
||||
src.target = user
|
||||
src.mode = SECBOT_HUNT
|
||||
target = user
|
||||
mode = BOT_HUNT
|
||||
|
||||
//Secbot Construction
|
||||
|
||||
@@ -703,7 +393,7 @@ Auto Patrol: []"},
|
||||
..()
|
||||
return
|
||||
|
||||
if(src.type != /obj/item/clothing/head/helmet) //Eh, but we don't want people making secbots out of space helmets.
|
||||
if(type != /obj/item/clothing/head/helmet) //Eh, but we don't want people making secbots out of space helmets.
|
||||
return
|
||||
|
||||
if(S.secured)
|
||||
|
||||
@@ -297,12 +297,18 @@ var/global/list/obj/item/device/pda/PDAs = list()
|
||||
dat += "<h4>Engineering Functions</h4>"
|
||||
dat += "<ul>"
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=43'><img src=pda_power.png> Power Monitor</a></li>"
|
||||
if(istype(cartridge.radio, /obj/item/radio/integrated/floorbot))
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=51'><img src=pda_floorbot.png> Floorbot Access</a></li>"
|
||||
dat += "</ul>"
|
||||
if (cartridge.access_medical)
|
||||
dat += "<h4>Medical Functions</h4>"
|
||||
dat += "<ul>"
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=44'><img src=pda_medical.png> Medical Records</a></li>"
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=Medical Scan'><img src=pda_scanner.png> [scanmode == 1 ? "Disable" : "Enable"] Medical Scanner</a></li>"
|
||||
if(istype(cartridge.radio, /obj/item/radio/integrated/medbot))
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=52'><img src=pda_medbot.png> Medibot Access</a></li>"
|
||||
dat += "</ul>"
|
||||
else
|
||||
dat += "</ul>"
|
||||
if (cartridge.access_security)
|
||||
dat += "<h4>Security Functions</h4>"
|
||||
@@ -325,6 +331,8 @@ var/global/list/obj/item/device/pda/PDAs = list()
|
||||
if (cartridge)
|
||||
if (cartridge.access_janitor)
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=49'><img src=pda_bucket.png> Custodial Locator</a></li>"
|
||||
if(istype(cartridge.radio, /obj/item/radio/integrated/cleanbot))
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=50'><img src=pda_cleanbot.png> Cleanbot Access</a></li>"
|
||||
if (istype(cartridge.radio, /obj/item/radio/integrated/signal))
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=40'><img src=pda_signaler.png> Signaler System</a></li>"
|
||||
if (cartridge.access_reagent_scanner)
|
||||
@@ -467,9 +475,9 @@ var/global/list/obj/item/device/pda/PDAs = list()
|
||||
mode = 0
|
||||
else
|
||||
mode = round(mode/10)
|
||||
if(mode==4)//Fix for cartridges. Redirects to hub.
|
||||
if(mode==4 || mode == 5)//Fix for cartridges. Redirects to hub.
|
||||
mode = 0
|
||||
else if(mode >= 40 && mode <= 49)//Fix for cartridges. Redirects to refresh the menu.
|
||||
else if(mode >= 40 && mode <= 59)//Fix for cartridges. Redirects to refresh the menu.
|
||||
cartridge.mode = mode
|
||||
cartridge.unlock()
|
||||
if ("Authenticate")//Checks for ID
|
||||
@@ -1082,4 +1090,4 @@ var/global/list/obj/item/device/pda/PDAs = list()
|
||||
for(var/obj/item/device/pda/P in PDAs)
|
||||
if(!P.owner || P.toff || P.hidden) continue
|
||||
. += P
|
||||
return .
|
||||
return .
|
||||
|
||||
@@ -38,21 +38,37 @@
|
||||
icon_state = "cart-e"
|
||||
access_engine = 1
|
||||
|
||||
/obj/item/weapon/cartridge/engineering/New()
|
||||
..()
|
||||
radio = new /obj/item/radio/integrated/floorbot(src)
|
||||
|
||||
/obj/item/weapon/cartridge/atmos
|
||||
name = "\improper BreatheDeep cartridge"
|
||||
icon_state = "cart-a"
|
||||
access_atmos = 1
|
||||
|
||||
/obj/item/weapon/cartridge/atmos/New()
|
||||
..()
|
||||
radio = new /obj/item/radio/integrated/floorbot(src)
|
||||
|
||||
/obj/item/weapon/cartridge/medical
|
||||
name = "\improper Med-U cartridge"
|
||||
icon_state = "cart-m"
|
||||
access_medical = 1
|
||||
|
||||
/obj/item/weapon/cartridge/medical/New()
|
||||
..()
|
||||
radio = new /obj/item/radio/integrated/medbot(src)
|
||||
|
||||
/obj/item/weapon/cartridge/chemistry
|
||||
name = "\improper ChemWhiz cartridge"
|
||||
icon_state = "cart-chem"
|
||||
access_reagent_scanner = 1
|
||||
|
||||
/obj/item/weapon/cartridge/chemistry/New()
|
||||
..()
|
||||
radio = new /obj/item/radio/integrated/medbot(src)
|
||||
|
||||
/obj/item/weapon/cartridge/security
|
||||
name = "\improper R.O.B.U.S.T. cartridge"
|
||||
icon_state = "cart-s"
|
||||
@@ -79,6 +95,10 @@
|
||||
icon_state = "cart-j"
|
||||
access_janitor = 1
|
||||
|
||||
/obj/item/weapon/cartridge/janitor/New()
|
||||
..()
|
||||
radio = new /obj/item/radio/integrated/cleanbot(src)
|
||||
|
||||
/obj/item/weapon/cartridge/lawyer
|
||||
name = "\improper P.R.O.V.E. cartridge"
|
||||
icon_state = "cart-s"
|
||||
@@ -167,6 +187,10 @@
|
||||
access_engine = 1
|
||||
access_atmos = 1
|
||||
|
||||
/obj/item/weapon/cartridge/ce/New()
|
||||
..()
|
||||
radio = new /obj/item/radio/integrated/floorbot(src)
|
||||
|
||||
/obj/item/weapon/cartridge/cmo
|
||||
name = "\improper Med-U DELUXE cartridge"
|
||||
icon_state = "cart-cmo"
|
||||
@@ -175,6 +199,10 @@
|
||||
access_reagent_scanner = 1
|
||||
access_medical = 1
|
||||
|
||||
/obj/item/weapon/cartridge/cmo/New()
|
||||
..()
|
||||
radio = new /obj/item/radio/integrated/medbot(src)
|
||||
|
||||
/obj/item/weapon/cartridge/rd
|
||||
name = "\improper Signal Ace DELUXE cartridge"
|
||||
icon_state = "cart-rd"
|
||||
@@ -249,6 +277,67 @@
|
||||
|
||||
frequency.post_signal(src, status_signal)
|
||||
|
||||
/obj/item/weapon/cartridge/proc/bot_control(var/obj/item/radio/integrated/SC)
|
||||
|
||||
|
||||
if(!SC)
|
||||
menu = "Interlink Error - Please reinsert cartridge."
|
||||
return
|
||||
|
||||
if(!SC.active)
|
||||
// list of bots
|
||||
if(!SC.botlist || (SC.botlist && SC.botlist.len==0))
|
||||
menu += "No bots found.<BR>"
|
||||
|
||||
else
|
||||
for(var/obj/machinery/bot/B in SC.botlist)
|
||||
menu += "<A href='byond://?src=\ref[SC];op=control;bot=\ref[B]'>[B] at [get_area(B)]</A><BR>"
|
||||
|
||||
menu += "<BR><A href='byond://?src=\ref[SC];op=scanbots'><img src=pda_scanner.png> Scan for active bots</A><BR>"
|
||||
|
||||
else // bot selected, control it
|
||||
|
||||
menu += "<B>[SC.active]</B><BR> Status: (<A href='byond://?src=\ref[SC];op=control;bot=\ref[SC.active]'><img src=pda_refresh.png><i>refresh</i></A>)<BR>"
|
||||
|
||||
if(!SC.botstatus)
|
||||
menu += "Waiting for response...<BR>"
|
||||
else
|
||||
|
||||
menu += "Location: [SC.botstatus["loca"] ]<BR>"
|
||||
menu += "Mode: "
|
||||
|
||||
switch(SC.botstatus["mode"])
|
||||
if(BOT_IDLE)
|
||||
menu += "Ready"
|
||||
if(BOT_HUNT)
|
||||
menu += "Apprehending target"
|
||||
if(BOT_PREP_ARREST,BOT_ARREST)
|
||||
menu += "Arresting target"
|
||||
if(BOT_START_PATROL)
|
||||
menu += "Starting patrol"
|
||||
if(BOT_PATROL)
|
||||
menu += "On patrol"
|
||||
if(BOT_SUMMON)
|
||||
menu += "Responding to summons"
|
||||
if(BOT_CLEANING)
|
||||
menu += "Cleaning"
|
||||
if(BOT_MOVING)
|
||||
menu += "Proceeding to work site"
|
||||
if(BOT_REPAIRING)
|
||||
menu += "Performing repairs"
|
||||
if(BOT_HEALING)
|
||||
menu += "Medicating patient"
|
||||
if(BOT_RESPONDING)
|
||||
menu += "Proceeding to AI waypoint"
|
||||
|
||||
menu += "<BR>\[<A href='byond://?src=\ref[SC];op=stop'>Stop Patrol</A>\] "
|
||||
menu += "\[<A href='byond://?src=\ref[SC];op=go'>Start Patrol</A>\] "
|
||||
menu += "\[<A href='byond://?src=\ref[SC];op=summon'>Summon Bot</A>\]<BR>"
|
||||
menu += "<HR><A href='byond://?src=\ref[SC];op=botlist'><img src=pda_back.png>Return to bot list</A><BR>"
|
||||
menu += "Keep an ID inserted to upload access codes upon summoning."
|
||||
return menu
|
||||
|
||||
|
||||
/obj/item/weapon/cartridge/proc/generate_menu()
|
||||
switch(mode)
|
||||
if(40) //signaller
|
||||
@@ -457,55 +546,8 @@ Code:
|
||||
menu += "<br>"
|
||||
if (46) //beepsky control
|
||||
var/obj/item/radio/integrated/beepsky/SC = radio
|
||||
if(!SC)
|
||||
menu = "Interlink Error - Please reinsert cartridge."
|
||||
return
|
||||
|
||||
menu = "<h4><img src=pda_cuffs.png> Securitron Interlink</h4>"
|
||||
|
||||
if(!SC.active)
|
||||
// list of bots
|
||||
if(!SC.botlist || (SC.botlist && SC.botlist.len==0))
|
||||
menu += "No bots found.<BR>"
|
||||
|
||||
else
|
||||
for(var/obj/machinery/bot/secbot/B in SC.botlist)
|
||||
menu += "<A href='byond://?src=\ref[SC];op=control;bot=\ref[B]'>[B] at [B.loc.loc]</A><BR>"
|
||||
|
||||
for(var/obj/machinery/bot/ed209/B in SC.botlist)
|
||||
menu += "<A href='byond://?src=\ref[SC];op=control;bot=\ref[B]'>[B] at [B.loc.loc]</A><BR>"
|
||||
|
||||
menu += "<BR><A href='byond://?src=\ref[SC];op=scanbots'><img src=pda_scanner.png> Scan for active bots</A><BR>"
|
||||
|
||||
else // bot selected, control it
|
||||
|
||||
menu += "<B>[SC.active]</B><BR> Status: (<A href='byond://?src=\ref[SC];op=control;bot=\ref[SC.active]'><img src=pda_refresh.png><i>refresh</i></A>)<BR>"
|
||||
|
||||
if(!SC.botstatus)
|
||||
menu += "Waiting for response...<BR>"
|
||||
else
|
||||
|
||||
menu += "Location: [SC.botstatus["loca"] ]<BR>"
|
||||
menu += "Mode: "
|
||||
|
||||
switch(SC.botstatus["mode"])
|
||||
if(0)
|
||||
menu += "Ready"
|
||||
if(1)
|
||||
menu += "Apprehending target"
|
||||
if(2,3)
|
||||
menu += "Arresting target"
|
||||
if(4)
|
||||
menu += "Starting patrol"
|
||||
if(5)
|
||||
menu += "On patrol"
|
||||
if(6)
|
||||
menu += "Responding to summons"
|
||||
|
||||
menu += "<BR>\[<A href='byond://?src=\ref[SC];op=stop'>Stop Patrol</A>\] "
|
||||
menu += "\[<A href='byond://?src=\ref[SC];op=go'>Start Patrol</A>\] "
|
||||
menu += "\[<A href='byond://?src=\ref[SC];op=summon'>Summon Bot</A>\]<BR>"
|
||||
menu += "<HR><A href='byond://?src=\ref[SC];op=botlist'><img src=pda_back.png>Return to bot list</A>"
|
||||
bot_control(SC)
|
||||
|
||||
if (47) //quartermaster order records
|
||||
menu = "<h4><img src=pda_crate.png> Supply Record Interlink</h4>"
|
||||
@@ -529,7 +571,6 @@ Code:
|
||||
if(!QC)
|
||||
menu = "Interlink Error - Please reinsert cartridge."
|
||||
return
|
||||
|
||||
menu = "<h4><img src=pda_mule.png> M.U.L.E. bot Interlink V0.8</h4>"
|
||||
|
||||
if(!QC.active)
|
||||
@@ -555,19 +596,19 @@ Code:
|
||||
menu += "Mode: "
|
||||
|
||||
switch(QC.botstatus["mode"])
|
||||
if(0)
|
||||
if(BOT_IDLE)
|
||||
menu += "Ready"
|
||||
if(1)
|
||||
if(BOT_LOADING)
|
||||
menu += "Loading/Unloading"
|
||||
if(2)
|
||||
if(BOT_DELIVER)
|
||||
menu += "Navigating to Delivery Location"
|
||||
if(3)
|
||||
if(BOT_GO_HOME)
|
||||
menu += "Navigating to Home"
|
||||
if(4)
|
||||
if(BOT_BLOCKED)
|
||||
menu += "Waiting for clear path"
|
||||
if(5,6)
|
||||
if(BOT_NAV,BOT_WAIT_FOR_NAV)
|
||||
menu += "Calculating navigation path"
|
||||
if(7)
|
||||
if(BOT_NO_ROUTE)
|
||||
menu += "Unable to locate destination"
|
||||
var/obj/structure/closet/crate/C = QC.botstatus["load"]
|
||||
menu += "<BR>Current Load: [ !C ? "<i>none</i>" : "[C.name] (<A href='byond://?src=\ref[QC];op=unload'><i>unload</i></A>)" ]<BR>"
|
||||
@@ -644,6 +685,20 @@ Code:
|
||||
menu += "ERROR: Unable to determine current location."
|
||||
menu += "<br><br><A href='byond://?src=\ref[src];choice=49'>Refresh GPS Locator</a>"
|
||||
|
||||
if (50) //Cleanbot control
|
||||
menu = "<br><h4><img src=pda_cleanbot.png> Cleanbot Interlink</h4>"
|
||||
var/obj/item/radio/integrated/cleanbot/SC = radio
|
||||
bot_control(SC)
|
||||
|
||||
if (51) //floorbot control
|
||||
menu = "<h4><img src=pda_floorbot.png> Floorbot Interlink</h4>"
|
||||
var/obj/item/radio/integrated/floorbot/SC = radio
|
||||
bot_control(SC)
|
||||
|
||||
if (52) //Medibot control
|
||||
menu = "<h4><img src=pda_medbot.png> Medibot Interlink</h4>"
|
||||
var/obj/item/radio/integrated/medbot/SC = radio
|
||||
bot_control(SC)
|
||||
|
||||
/obj/item/weapon/cartridge/Topic(href, href_list)
|
||||
..()
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
icon = 'icons/obj/module.dmi'
|
||||
icon_state = "power_mod"
|
||||
var/obj/item/device/pda/hostpda = null
|
||||
var/list/botlist = null // list of bots
|
||||
var/obj/machinery/bot/active // the active bot; if null, show bot list
|
||||
var/list/botstatus // the status signal sent by the bot
|
||||
var/bot_type //The type of bot it is.
|
||||
var/bot_filter //Determines which radio filter to use.
|
||||
|
||||
var/control_freq = 1447
|
||||
|
||||
var/on = 0 //Are we currently active??
|
||||
var/menu_message = ""
|
||||
@@ -12,13 +19,17 @@
|
||||
..()
|
||||
if (istype(loc.loc, /obj/item/device/pda))
|
||||
hostpda = loc.loc
|
||||
if (bot_filter)
|
||||
spawn(5)
|
||||
add_to_radio(bot_filter)
|
||||
|
||||
/obj/item/radio/integrated/proc/post_signal(var/freq, var/key, var/value, var/key2, var/value2, var/key3, var/value3, s_filter)
|
||||
/obj/item/radio/integrated/proc/post_signal(var/freq, var/key, var/value, var/key2, var/value2, var/key3, var/value3,var/key4, var/value4, s_filter)
|
||||
|
||||
//world << "Post: [freq]: [key]=[value], [key2]=[value2]"
|
||||
var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
|
||||
|
||||
if(!frequency) return
|
||||
if(!frequency)
|
||||
return
|
||||
|
||||
var/datum/signal/signal = new()
|
||||
signal.source = src
|
||||
@@ -28,6 +39,8 @@
|
||||
signal.data[key2] = value2
|
||||
if(key3)
|
||||
signal.data[key3] = value3
|
||||
if(key4)
|
||||
signal.data[key4] = value4
|
||||
|
||||
frequency.post_signal(src, signal, filter = s_filter)
|
||||
|
||||
@@ -44,33 +57,18 @@
|
||||
|
||||
/obj/item/radio/integrated/proc/generate_menu()
|
||||
|
||||
/obj/item/radio/integrated/beepsky
|
||||
var/list/botlist = null // list of bots
|
||||
var/obj/machinery/bot/secbot/active // the active bot; if null, show bot list
|
||||
var/list/botstatus // the status signal sent by the bot
|
||||
|
||||
var/control_freq = 1447
|
||||
|
||||
// create a new QM cartridge, and register to receive bot control & beacon message
|
||||
/obj/item/radio/integrated/beepsky/New()
|
||||
..()
|
||||
spawn(5)
|
||||
if(radio_controller)
|
||||
radio_controller.add_object(src, control_freq, filter = RADIO_SECBOT)
|
||||
/obj/item/radio/integrated/receive_signal(datum/signal/signal)
|
||||
/*var/obj/item/device/pda/P = src.loc
|
||||
|
||||
// receive radio signals
|
||||
// can detect bot status signals
|
||||
// create/populate list as they are recvd
|
||||
|
||||
/obj/item/radio/integrated/beepsky/receive_signal(datum/signal/signal)
|
||||
// var/obj/item/device/pda/P = src.loc
|
||||
|
||||
/*
|
||||
world << "recvd:[P] : [signal.source]"
|
||||
for(var/d in signal.data)
|
||||
world << "- [d] = [signal.data[d]]"
|
||||
*/
|
||||
if (signal.data["type"] == "secbot")
|
||||
*/
|
||||
|
||||
if (signal.data["type"] == bot_type)
|
||||
if(!botlist)
|
||||
botlist = new()
|
||||
|
||||
@@ -81,9 +79,7 @@
|
||||
var/list/b = signal.data
|
||||
botstatus = b.Copy()
|
||||
|
||||
// if (istype(P)) P.updateSelfDialog()
|
||||
|
||||
/obj/item/radio/integrated/beepsky/Topic(href, href_list)
|
||||
/obj/item/radio/integrated/Topic(href, href_list)
|
||||
..()
|
||||
var/obj/item/device/pda/PDA = src.hostpda
|
||||
|
||||
@@ -91,32 +87,53 @@
|
||||
|
||||
if("control")
|
||||
active = locate(href_list["bot"])
|
||||
post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT)
|
||||
post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter)
|
||||
|
||||
if("scanbots") // find all bots
|
||||
botlist = null
|
||||
post_signal(control_freq, "command", "bot_status", s_filter = RADIO_SECBOT)
|
||||
post_signal(control_freq, "command", "bot_status", s_filter = bot_filter)
|
||||
|
||||
if("botlist")
|
||||
active = null
|
||||
|
||||
if("stop", "go")
|
||||
post_signal(control_freq, "command", href_list["op"], "active", active, s_filter = RADIO_SECBOT)
|
||||
post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT)
|
||||
post_signal(control_freq, "command", href_list["op"], "active", active, s_filter = bot_filter)
|
||||
post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter)
|
||||
|
||||
if("summon")
|
||||
post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(PDA) , s_filter = RADIO_SECBOT)
|
||||
post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT)
|
||||
post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(PDA) , "useraccess", PDA.GetAccess(), s_filter = bot_filter)
|
||||
post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter)
|
||||
PDA.cartridge.unlock()
|
||||
|
||||
/obj/item/radio/integrated/proc/add_to_radio(bot_filter) //Master filter control for bots. Must be placed in the bot's local New() to support map spawned bots.
|
||||
if(radio_controller)
|
||||
radio_controller.add_object(src, control_freq, filter = bot_filter)
|
||||
|
||||
|
||||
/obj/item/radio/integrated/beepsky
|
||||
bot_filter = RADIO_SECBOT
|
||||
bot_type = SEC_BOT
|
||||
|
||||
/obj/item/radio/integrated/medbot
|
||||
bot_filter = RADIO_MEDBOT
|
||||
bot_type = MED_BOT
|
||||
|
||||
/obj/item/radio/integrated/floorbot
|
||||
bot_filter = RADIO_FLOORBOT
|
||||
bot_type = FLOOR_BOT
|
||||
|
||||
/obj/item/radio/integrated/cleanbot
|
||||
bot_filter = RADIO_CLEANBOT
|
||||
bot_type = CLEAN_BOT
|
||||
|
||||
/obj/item/radio/integrated/mule
|
||||
var/list/botlist = null // list of bots
|
||||
var/obj/machinery/bot/mulebot/active // the active bot; if null, show bot list
|
||||
var/list/botstatus // the status signal sent by the bot
|
||||
//var/list/botlist = null // list of bots
|
||||
//var/obj/machinery/bot/mulebot/active // the active bot; if null, show bot list
|
||||
//var/list/botstatus // the status signal sent by the bot
|
||||
var/list/beacons
|
||||
|
||||
var/beacon_freq = 1400
|
||||
var/control_freq = 1447
|
||||
control_freq = 1447
|
||||
|
||||
// create a new QM cartridge, and register to receive bot control & beacon message
|
||||
/obj/item/radio/integrated/mule/New()
|
||||
@@ -141,7 +158,7 @@
|
||||
for(var/d in signal.data)
|
||||
world << "- [d] = [signal.data[d]]"
|
||||
*/
|
||||
if(signal.data["type"] == "mulebot")
|
||||
if(signal.data["type"] == MULE_BOT)
|
||||
if(!botlist)
|
||||
botlist = new()
|
||||
|
||||
@@ -162,52 +179,46 @@
|
||||
// if(istype(P)) P.updateSelfDialog()
|
||||
|
||||
/obj/item/radio/integrated/mule/Topic(href, href_list)
|
||||
..()
|
||||
//..()
|
||||
var/obj/item/device/pda/PDA = src.hostpda
|
||||
var/cmd = "command"
|
||||
if(active) cmd = "command [active.suffix]"
|
||||
if(active)
|
||||
cmd = "command [active.suffix]"
|
||||
|
||||
switch(href_list["op"])
|
||||
|
||||
if("control")
|
||||
active = locate(href_list["bot"])
|
||||
post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
|
||||
|
||||
if("scanbots") // find all bots
|
||||
botlist = null
|
||||
post_signal(control_freq, "command", "bot_status", s_filter = RADIO_MULEBOT)
|
||||
|
||||
if("botlist")
|
||||
active = null
|
||||
|
||||
|
||||
if("unload")
|
||||
post_signal(control_freq, cmd, "unload", s_filter = RADIO_MULEBOT)
|
||||
post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
|
||||
if("setdest")
|
||||
if(beacons)
|
||||
var/dest = input("Select Bot Destination", "Mulebot [active.suffix] Interlink", active.destination) as null|anything in beacons
|
||||
if(dest)
|
||||
post_signal(control_freq, cmd, "target", "destination", dest, s_filter = RADIO_MULEBOT)
|
||||
post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
|
||||
|
||||
if("retoff")
|
||||
post_signal(control_freq, cmd, "autoret", "value", 0, s_filter = RADIO_MULEBOT)
|
||||
post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
|
||||
if("reton")
|
||||
post_signal(control_freq, cmd, "autoret", "value", 1, s_filter = RADIO_MULEBOT)
|
||||
post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
|
||||
|
||||
if("pickoff")
|
||||
post_signal(control_freq, cmd, "autopick", "value", 0, s_filter = RADIO_MULEBOT)
|
||||
post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
|
||||
|
||||
if("pickon")
|
||||
post_signal(control_freq, cmd, "autopick", "value", 1, s_filter = RADIO_MULEBOT)
|
||||
post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
|
||||
|
||||
if("stop", "go", "home")
|
||||
post_signal(control_freq, cmd, href_list["op"], s_filter = RADIO_MULEBOT)
|
||||
post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
|
||||
|
||||
post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
|
||||
PDA.cartridge.unlock()
|
||||
|
||||
|
||||
@@ -227,10 +238,10 @@
|
||||
..()
|
||||
if(radio_controller)
|
||||
initialize()
|
||||
|
||||
|
||||
/obj/item/radio/integrated/signal/initialize()
|
||||
if (src.frequency < 1441 || src.frequency > 1489)
|
||||
src.frequency = sanitize_frequency(src.frequency)
|
||||
src.frequency = sanitize_frequency(src.frequency)
|
||||
|
||||
set_frequency(frequency)
|
||||
|
||||
@@ -256,4 +267,4 @@
|
||||
|
||||
radio_connection.post_signal(src, signal)
|
||||
|
||||
return
|
||||
return
|
||||
@@ -258,6 +258,9 @@ var/next_external_rsc = 0
|
||||
'icons/pda_icons/pda_blank.png',
|
||||
'icons/pda_icons/pda_boom.png',
|
||||
'icons/pda_icons/pda_bucket.png',
|
||||
'icons/pda_icons/pda_medbot.png',
|
||||
'icons/pda_icons/pda_floorbot.png',
|
||||
'icons/pda_icons/pda_cleanbot.png',
|
||||
'icons/pda_icons/pda_crate.png',
|
||||
'icons/pda_icons/pda_cuffs.png',
|
||||
'icons/pda_icons/pda_eject.png',
|
||||
|
||||
@@ -31,6 +31,7 @@ var/list/ai_list = list()
|
||||
var/obj/item/device/pda/ai/aiPDA = null
|
||||
var/obj/item/device/multitool/aiMulti = null
|
||||
var/obj/item/device/camera/siliconcam/aicamera = null
|
||||
var/obj/machinery/bot/Bot
|
||||
|
||||
//MALFUNCTION
|
||||
var/datum/module_picker/malf_picker
|
||||
@@ -54,6 +55,8 @@ var/list/ai_list = list()
|
||||
var/last_paper_seen = null
|
||||
var/can_shunt = 1
|
||||
var/last_announcement = "" // For AI VOX, if enabled
|
||||
var/turf/waypoint //Holds the turf of the currently selected waypoint.
|
||||
var/waypoint_mode = 0 //Waypoint mode is for selecting a turf via clicking.
|
||||
|
||||
/mob/living/silicon/ai/New(loc, var/datum/ai_laws/L, var/obj/item/device/mmi/B, var/safety = 0)
|
||||
var/list/possibleNames = ai_names
|
||||
@@ -94,7 +97,7 @@ var/list/ai_list = list()
|
||||
if (istype(loc, /turf))
|
||||
verbs.Add(/mob/living/silicon/ai/proc/ai_network_change, \
|
||||
/mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \
|
||||
/mob/living/silicon/ai/proc/toggle_camera_light)
|
||||
/mob/living/silicon/ai/proc/toggle_camera_light, /mob/living/silicon/ai/proc/botcall)
|
||||
|
||||
if(!safety)//Only used by AIize() to successfully spawn an AI.
|
||||
if (!B)//If there is no player/brain inside.
|
||||
@@ -355,6 +358,24 @@ var/list/ai_list = list()
|
||||
A.ai_actual_track(target)
|
||||
return
|
||||
|
||||
if (href_list["callbot"]) //Command a bot to move to a selected location.
|
||||
Bot = locate(href_list["callbot"]) in machines
|
||||
if(!Bot || Bot.remote_disabled || src.control_disabled)
|
||||
return //True if there is no bot found, the bot is manually emagged, or the AI is carded with wireless off.
|
||||
waypoint_mode = 1
|
||||
src << "<span class='notice'>Set your waypoint by clicking on a valid location free of obstructions.</span>"
|
||||
return
|
||||
|
||||
if (href_list["interface"]) //Remotely connect to a bot!
|
||||
Bot = locate(href_list["interface"]) in machines
|
||||
if(!Bot || Bot.remote_disabled || src.control_disabled)
|
||||
return
|
||||
Bot.attack_ai(src)
|
||||
|
||||
if (href_list["botrefresh"]) //Refreshes the bot control panel.
|
||||
botcall()
|
||||
return
|
||||
|
||||
else if (href_list["faketrack"])
|
||||
var/mob/target = locate(href_list["track"]) in mob_list
|
||||
var/mob/living/silicon/ai/A = locate(href_list["track2"]) in mob_list
|
||||
@@ -449,6 +470,61 @@ var/list/ai_list = list()
|
||||
|
||||
return 1
|
||||
|
||||
/mob/living/silicon/ai/proc/botcall()
|
||||
set category = "AI Commands"
|
||||
set name = "Access Robot Control"
|
||||
set desc = "Wirelessly control various automatic robots."
|
||||
if(stat == 2)
|
||||
src << "<span class='danger'>Critical error. System offline.</span>"
|
||||
return
|
||||
|
||||
if(control_disabled)
|
||||
src << "Wireless communication is disabled."
|
||||
return
|
||||
var/turf/ai_current_turf = get_turf(src)
|
||||
var/ai_Zlevel = ai_current_turf.z
|
||||
var/d
|
||||
var/area/bot_area
|
||||
d += "<A HREF=?src=\ref[src];botrefresh=\ref[Bot]>Query network status</A><br>"
|
||||
d += "<table width='100%'><tr><td width='40%'><h3>Name</h3></td><td width='30%'><h3>Status</h3></td><td width='30%'><h3>Location</h3></td><td width='10%'><h3>Control</h3></td></tr>"
|
||||
|
||||
for (Bot in machines)
|
||||
if(Bot.z == ai_Zlevel && !Bot.remote_disabled) //Only non-emagged bots on the same Z-level are detected!
|
||||
bot_area = get_area(Bot)
|
||||
d += "<tr><td width='30%'>[Bot.hacked ? "<span class='bad'>(!) </span>[Bot.name]" : Bot.name]</td>"
|
||||
//If the bot is on, it will display the bot's current mode status. If the bot is not mode, it will just report "Idle". "Inactive if it is not on at all.
|
||||
d += "<td width='30%'>[Bot.on ? "[Bot.mode ? "<span class='average'>[ Bot.mode_name[Bot.mode] ]</span>": "<span class='good'>Idle</span>"]" : "<span class='bad'>Inactive</span>"]</td>"
|
||||
d += "<td width='30%'>[bot_area.name]</td>"
|
||||
d += "<td width='10%'><A HREF=?src=\ref[src];interface=\ref[Bot]>Interface</A></td>"
|
||||
d += "<td width='10%'><A HREF=?src=\ref[src];callbot=\ref[Bot]>Call</A></td>"
|
||||
d += "</tr>"
|
||||
d = format_text(d)
|
||||
|
||||
var/datum/browser/popup = new(src, "botcall", "Remote Robot Control", 700, 400)
|
||||
popup.set_content(d)
|
||||
popup.open()
|
||||
|
||||
/mob/living/silicon/ai/proc/set_waypoint(var/atom/A)
|
||||
var/turf/turf_check = get_turf(A)
|
||||
//The target must be in view of a camera or near the core.
|
||||
if(turf_check in range(get_turf(src)))
|
||||
call_bot(turf_check)
|
||||
else if(cameranet && cameranet.checkTurfVis(turf_check))
|
||||
call_bot(turf_check)
|
||||
else
|
||||
src << "<span class='danger'>Selected location is not visible.</span>"
|
||||
|
||||
/mob/living/silicon/ai/proc/call_bot(var/turf/waypoint)
|
||||
|
||||
if(!Bot)
|
||||
return
|
||||
|
||||
if(Bot.calling_ai && Bot.calling_ai != src) //Prevents an override if another AI is controlling this bot.
|
||||
src << "<span class='danger'>Interface error. Unit is already in use.</span>"
|
||||
return
|
||||
|
||||
Bot.call_bot(src, waypoint)
|
||||
|
||||
/mob/living/silicon/ai/triggerAlarm(var/class, area/A, var/O, var/alarmsource)
|
||||
if (stat == 2)
|
||||
return 1
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 48 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 183 B |
Binary file not shown.
|
After Width: | Height: | Size: 214 B |
Binary file not shown.
|
After Width: | Height: | Size: 219 B |
Reference in New Issue
Block a user