diff --git a/code/datums/spells/conjure.dm b/code/datums/spells/conjure.dm index de84db5915b..1a489524517 100644 --- a/code/datums/spells/conjure.dm +++ b/code/datums/spells/conjure.dm @@ -58,7 +58,7 @@ name = "Dispense Wizard Justice" desc = "This spell dispenses wizard justice." - summon_type = list(/obj/machinery/bot/ed209) + summon_type = list(/obj/item/weapon/secbot_assembly/ed209_assembly) summon_amt = 10 range = 3 newVars = list("emagged" = 1,"name" = "Wizard's Justicebot") diff --git a/code/game/machinery/bots/ed209bot.dm b/code/game/machinery/bots/ed209bot.dm index fe7425ee8ce..2b7515e35ab 100644 --- a/code/game/machinery/bots/ed209bot.dm +++ b/code/game/machinery/bots/ed209bot.dm @@ -1,785 +1,34 @@ -/obj/machinery/bot/ed209 +/obj/machinery/bot/secbot/ed209 name = "ED-209 Security Robot" desc = "A security robot. He looks less than thrilled." icon = 'icons/obj/aibots.dmi' icon_state = "ed2090" - layer = 5.0 density = 1 - anchored = 0 -// weight = 1.0E7 - req_one_access = list(access_security, access_forensics_lockers) health = 100 maxhealth = 100 - fire_dam_coeff = 0.7 - brute_dam_coeff = 0.5 - var/lastfired = 0 - var/shot_delay = 3 //.3 seconds between shots - var/lasercolor = "" - var/disabled = 0//A holder for if it needs to be disabled, if true it will not seach for targets, shoot at targets, or move, currently only used for lasertag + bot_version = "2.5" + search_range = 12 - //var/lasers = 0 + preparing_arrest_sounds = new() + secbot_assembly = /obj/item/weapon/secbot_assembly/ed209_assembly - var/mob/living/carbon/target - var/oldtarget_name - 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/idcheck = 1 //If false, all station IDs are authorized for weapons. - var/check_records = 1 //Does it check security records? - var/arrest_type = 0 //If true, don't handcuff - var/declare_arrests = 0 //When making an arrest, should it notify everyone wearing sechuds? - var/projectile = null//Holder for projectile type, to avoid so many else if chains - - var/mode = 0 -#define SECBOT_IDLE 0 // idle -#define SECBOT_HUNT 1 // found target, hunting -#define SECBOT_PREP_ARREST 2 // at target, preparing to arrest -#define SECBOT_ARREST 3 // arresting target -#define SECBOT_START_PATROL 4 // start patrol -#define SECBOT_PATROL 5 // patrolling -#define SECBOT_SUMMON 6 // summoned by PDA - - var/auto_patrol = 0 // set to make bot automatically patrol - - var/beacon_freq = 1445 // navigation beacon frequency - var/control_freq = 1447 // bot control frequency - - - var/turf/patrol_target // this is turf to navigate to (location of beacon) - var/new_destination // pending new destination (waiting for beacon response) - var/destination // destination description tag - var/next_destination // the next destination in the patrol route - var/list/path = new // list of path turfs - - var/blockcount = 0 //number of times retried a blocked path - var/awaiting_beacon = 0 // count of pticks awaiting a beacon response - - var/nearest_beacon // the nearest beacon's tag - var/turf/nearest_beacon_loc // the nearest beacon's location - - -/obj/item/weapon/ed209_assembly +/obj/item/weapon/secbot_assembly/ed209_assembly name = "ED-209 assembly" desc = "Some sort of bizarre assembly." icon = 'icons/obj/aibots.dmi' icon_state = "ed209_frame" item_state = "ed209_frame" - var/build_step = 0 - var/created_name = "ED-209 Security Robot" //To preserve the name if it's a unique securitron I guess + created_name = "ED-209 Security Robot" //To preserve the name if it's a unique securitron I guess var/lasercolor = "" - -/obj/machinery/bot/ed209/New(loc,created_name,created_lasercolor) - ..() - if(created_name) name = created_name - if(created_lasercolor) lasercolor = created_lasercolor - src.icon_state = "[lasercolor]ed209[src.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) - if(lasercolor) - shot_delay = 6//Longer shot delay because JESUS CHRIST - check_records = 0//Don't actively target people set to arrest - arrest_type = 1//Don't even try to cuff - req_access = list(access_maint_tunnels) - arrest_type = 1 - if((lasercolor == "b") && (name == "ED-209 Security Robot"))//Picks a name if there isn't already a custome one - name = pick("BLUE BALLER","SANIC","BLUE KILLDEATH MURDERBOT") - if((lasercolor == "r") && (name == "ED-209 Security Robot")) - name = pick("RED RAMPAGE","RED ROVER","RED KILLDEATH MURDERBOT") - -/obj/machinery/bot/ed209/turn_on() - . = ..() - src.icon_state = "[lasercolor]ed209[src.on]" - src.mode = SECBOT_IDLE - src.updateUsrDialog() - -/obj/machinery/bot/ed209/turn_off() - ..() - src.target = null - src.oldtarget_name = null - src.anchored = 0 - src.mode = SECBOT_IDLE - walk_to(src,0) - src.icon_state = "[lasercolor]ed209[src.on]" - src.updateUsrDialog() - -/obj/machinery/bot/ed209/attack_hand(mob/user as mob) - . = ..() - if (.) - return - var/dat - - dat += text({" -Automatic Security Unit v2.5

-Status: []
-Behaviour controls are [src.locked ? "locked" : "unlocked"]
-Maintenance panel panel is [src.open ? "opened" : "closed"]"}, - -"[src.on ? "On" : "Off"]" ) - - if(!src.locked || issilicon(user)) - if(!lasercolor) - dat += text({"
-Check for Weapon Authorization: []
-Check Security Records: []
-Operating Mode: []
-Report Arrests: []
-Auto Patrol: []"}, - -"[src.idcheck ? "Yes" : "No"]", -"[src.check_records ? "Yes" : "No"]", -"[src.arrest_type ? "Detain" : "Arrest"]", -"[src.declare_arrests ? "Yes" : "No"]", -"[auto_patrol ? "On" : "Off"]" ) - else - dat += text({"
-Auto Patrol: []"}, - -"[auto_patrol ? "On" : "Off"]" ) - - - user << browse("Securitron v2.5 controls[dat]", "window=autosec") - onclose(user, "autosec") - 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) - turn_off() - else - turn_on() - return - - switch(href_list["operation"]) - if ("idcheck") - src.idcheck = !src.idcheck - 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 - updateUsrDialog() - if("declarearrests") - src.declare_arrests = !src.declare_arrests - src.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 << "Controls are now [src.locked ? "locked" : "unlocked"]." - else - if(emagged) - user << "ERROR" - if(open) - user << "Please close the access panel before locking it." - else - user << "Access denied." +/obj/machinery/bot/secbot/ed209/update_icon() + if(on && is_attacking) + src.icon_state = "[lasercolor]ed209-c" else - ..() - if (!istype(W, /obj/item/weapon/screwdriver) && (!src.target)) - if(hasvar(W,"force") && W.force)//If force is defined and non-zero - src.target = user - if(lasercolor)//To make up for the fact that lasertag bots don't hunt - src.shootAt(user) - src.mode = SECBOT_HUNT - -/obj/machinery/bot/ed209/Emag(mob/user as mob) - ..() - if(open && !locked) - if(user) user << "You short out [src]'s target assessment circuits." - spawn(0) - for(var/mob/O in hearers(src, null)) - O.show_message("\red [src] buzzes oddly!", 1) - src.target = null - if(user) src.oldtarget_name = user.name - src.last_found = world.time - src.anchored = 0 - src.emagged = 2 - src.on = 1 src.icon_state = "[lasercolor]ed209[src.on]" - src.projectile = null - mode = SECBOT_IDLE - -/obj/machinery/bot/ed209/process() - set background = 1 - - if (!src.on) - return - var/list/targets = list() - for (var/mob/living/carbon/C in view(12,src)) //Let's find us a target - var/threatlevel = 0 - if ((C.stat) || (C.lying)) - continue - if (istype(C, /mob/living/carbon/human)) - threatlevel = src.assess_perp(C) - //src.speak(C.real_name + text(": threat: []", threatlevel)) - if (threatlevel < 4 ) - continue - - var/dst = get_dist(src, C) - if ( dst <= 1 || dst > 12) - continue - - targets += C - if (targets.len>0) - var/mob/t = pick(targets) - if (istype(t, /mob/living)) - if ((t.stat!=2) && (t.lying != 1)) - //src.speak("selected target: " + t.real_name) - src.shootAt(t) - switch(mode) - - if(SECBOT_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 - - if(SECBOT_HUNT) // hunting for perp - if(src.lasercolor)//Lasertag bots do not tase or arrest anyone, just patrol and shoot and whatnot - mode = SECBOT_IDLE - return - // if can't reach perp for long enough, go idle - if (src.frustration >= 8) - // for(var/mob/O in hearers(src, null)) - // O << "[src] beeps, \"Backup requested! Suspect has evaded arrest.\"" - src.target = null - src.last_found = world.time - src.frustration = 0 - src.mode = 0 - walk_to(src,0) - - if (target) // make sure target exists - if (Adjacent(target)) // if right next to perp - playsound(src.loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) - src.icon_state = "[lasercolor]ed209-c" - spawn(2) - src.icon_state = "[lasercolor]ed209[src.on]" - var/mob/living/carbon/M = src.target - var/maxstuns = 4 - if (istype(M, /mob/living/carbon/human)) - if (M.stuttering < 10 && (!(HULK in M.mutations)) /*&& (!istype(M:wear_suit, /obj/item/clothing/suit/judgerobe))*/) - M.stuttering = 10 - M.Stun(10) - M.Weaken(10) - else - M.Weaken(10) - M.stuttering = 10 - M.Stun(10) - maxstuns-- - if (maxstuns <= 0) - target = null - - if(declare_arrests) - var/area/location = get_area(src) - broadcast_security_hud_message("[src.name] is [arrest_type ? "detaining" : "arresting"] level [threatlevel] suspect [target] in [location]", src) - visible_message("\red [src.target] has been stunned by [src]!") - - mode = SECBOT_PREP_ARREST - src.anchored = 1 - src.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++ - else - src.frustration = 0 - - if(SECBOT_PREP_ARREST) // preparing to arrest target - if(src.lasercolor) - mode = SECBOT_IDLE - return - if (!target) - mode = SECBOT_IDLE - src.anchored = 0 - return - // see if he got away - if ((get_dist(src, src.target) > 1) || ((src.target:loc != src.target_lastloc) && src.target:weakened < 2)) - src.anchored = 0 - mode = SECBOT_HUNT - return - - if(istype(src.target,/mob/living/carbon)) - if (!src.target.handcuffed && !src.arrest_type) - playsound(src.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -2) - mode = SECBOT_ARREST - visible_message("\red [src] is trying to put handcuffs on [src.target]!") - - spawn(60) - if (get_dist(src, src.target) <= 1) - if (src.target.handcuffed) - return - - if(istype(src.target,/mob/living/carbon)) - src.target.handcuffed = new /obj/item/weapon/handcuffs(src.target) - target.update_inv_handcuffed() //update handcuff overlays - - mode = SECBOT_IDLE - src.target = null - src.anchored = 0 - src.last_found = world.time - src.frustration = 0 - - // playsound(src.loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg'), 50, 0) - // var/arrest_message = pick("Have a secure day!","I AM THE LAW.", "God made tomorrow for the crooks we don't catch today.","You can't outrun a radio.") - // src.speak(arrest_message) - else - mode = SECBOT_IDLE - src.target = null - src.anchored = 0 - src.last_found = world.time - src.frustration = 0 - - if(SECBOT_ARREST) // arresting - if(src.lasercolor) - mode = SECBOT_IDLE - return - if (!target || src.target.handcuffed) - src.anchored = 0 - mode = SECBOT_IDLE - return - - - 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 - - -// 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 - - look_for_perp() - if(lasercolor) - sleep(20) - 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() - 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/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 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, 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) - return - src.anchored = 0 - src.threatlevel = 0 - for (var/mob/living/carbon/C in view(12,src)) //Let's find us a criminal - if ((C.stat) || (C.handcuffed)) - continue - - if((src.lasercolor) && (C.lying)) - continue//Does not shoot at people lyind down when in lasertag mode, because it's just annoying, and they can fire once they get up. - - if ((C.name == src.oldtarget_name) && (world.time < src.last_found + 100)) - continue - - if (istype(C, /mob/living/carbon/human)) - src.threatlevel = src.assess_perp(C) - - if (!src.threatlevel) - continue - - else if (src.threatlevel >= 4) - src.target = C - src.oldtarget_name = C.name - src.speak("Level [src.threatlevel] infraction alert!") - if(!src.lasercolor) - playsound(src.loc, pick('sound/voice/ed209_20sec.ogg', 'sound/voice/EDPlaceholder.ogg'), 50, 0) - src.visible_message("[src] points at [C.name]!") - mode = SECBOT_HUNT - spawn(0) - process() // ensure bot quickly responds to a perp - break - else - continue - - -//If the security records say to arrest them, arrest them -//Or if they have weapons and aren't security, arrest them. -/obj/machinery/bot/ed209/proc/assess_perp(mob/living/carbon/human/perp as mob) - var/threatcount = 0 - - if(src.emagged == 2) return 10 //Everyone is a criminal! - - if((src.idcheck) || (isnull(perp:wear_id)) || (istype(perp:wear_id.GetID(), /obj/item/weapon/card/id/syndicate))) - - if((istype(perp.l_hand, /obj/item/weapon/gun) && !istype(perp.l_hand, /obj/item/weapon/gun/projectile/shotgun)) || istype(perp.l_hand, /obj/item/weapon/melee/baton)) - if(!istype(perp.l_hand, /obj/item/weapon/gun/energy/laser/bluetag) \ - && !istype(perp.l_hand, /obj/item/weapon/gun/energy/laser/redtag) \ - && !istype(perp.l_hand, /obj/item/weapon/gun/energy/laser/practice)) - threatcount += 4 - - if(istype(perp.r_hand, /obj/item/weapon/gun) || istype(perp.r_hand, /obj/item/weapon/melee)) - if(!istype(perp.r_hand, /obj/item/weapon/gun/energy/laser/bluetag) \ - && !istype(perp.r_hand, /obj/item/weapon/gun/energy/laser/redtag) \ - && !istype(perp.r_hand, /obj/item/weapon/gun/energy/laser/practice)) - threatcount += 4 - - if(istype(perp:belt, /obj/item/weapon/gun) || istype(perp:belt, /obj/item/weapon/melee)) - if(!istype(perp:belt, /obj/item/weapon/gun/energy/laser/bluetag) \ - && !istype(perp:belt, /obj/item/weapon/gun/energy/laser/redtag) \ - && !istype(perp:belt, /obj/item/weapon/gun/energy/laser/practice)) - threatcount += 2 - - if(istype(perp:wear_suit, /obj/item/clothing/suit/wizrobe)) - threatcount += 2 - - if(perp.dna && perp.dna.mutantrace && perp.dna.mutantrace != "none") - threatcount += 2 - -//Agent cards lower threatlevel when normal idchecking is off. - if((perp.wear_id && istype(perp:wear_id.GetID(), /obj/item/weapon/card/id/syndicate)) && src.idcheck) - threatcount -= 2 - - if(src.lasercolor == "b")//Lasertag turrets target the opposing team, how great is that? -Sieve - threatcount = 0//They will not, however shoot at people who have guns, because it gets really fucking annoying - if(istype(perp.wear_suit, /obj/item/clothing/suit/redtag)) - threatcount += 4 - if((istype(perp:r_hand,/obj/item/weapon/gun/energy/laser/redtag)) || (istype(perp:l_hand,/obj/item/weapon/gun/energy/laser/redtag))) - threatcount += 4 - if(istype(perp:belt, /obj/item/weapon/gun/energy/laser/redtag)) - threatcount += 2 - - if(src.lasercolor == "r") - threatcount = 0 - if(istype(perp.wear_suit, /obj/item/clothing/suit/bluetag)) - threatcount += 4 - if((istype(perp:r_hand,/obj/item/weapon/gun/energy/laser/bluetag)) || (istype(perp:l_hand,/obj/item/weapon/gun/energy/laser/bluetag))) - threatcount += 4 - if(istype(perp:belt, /obj/item/weapon/gun/energy/laser/bluetag)) - threatcount += 2 - - if(src.check_records) - for (var/datum/data/record/E in data_core.general) - var/perpname = perp.name - if(perp.wear_id) - var/obj/item/weapon/card/id/id = perp.wear_id.GetID() - if(id) - perpname = id.registered_name - - if(E.fields["name"] == perpname) - for (var/datum/data/record/R in data_core.security) - if((R.fields["id"] == E.fields["id"]) && (R.fields["criminal"] == "*Arrest*")) - threatcount = 4 - break - - if((src.idcheck) && (src.allowed(perp)) && !(src.lasercolor)) - threatcount = 0//Corrupt cops cannot exist beep boop - - return threatcount - -/obj/machinery/bot/ed209/Bump(M as mob|obj) //Leave no door unopened! - if ((istype(M, /obj/machinery/door)) && !isnull(src.botcard)) - var/obj/machinery/door/D = M - if (!istype(D, /obj/machinery/door/firedoor) && D.check_access(src.botcard) && !istype(D,/obj/machinery/door/poddoor)) - D.open() - src.frustration = 0 - else if(!src.anchored) - if ((istype(M, /mob/living/))) - var/mob/living/O = M - src.loc = O.loc - src.frustration = 0 - else if (istype(M, /obj/machinery/bot)) - var/obj/machinery/bot/B = M - if (B.dir != src.dir) // Avoids issues if two bots are currently patrolling in the same direction - src.loc = B.loc - src.frustration = 0 - return - -/* terrible -/obj/machinery/bot/ed209/Bumped(atom/movable/M as mob|obj) - spawn(0) - if (M) - var/turf/T = get_turf(src) - M:loc = T -*/ - -/obj/machinery/bot/ed209/proc/speak(var/message) - for(var/mob/O in hearers(src, null)) - O.show_message("[src] beeps, \"[message]\"",2) - return - -/obj/machinery/bot/ed209/explode() - walk_to(src,0) - src.visible_message("\red [src] blows apart!", 1) - 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 - new /obj/item/device/assembly/prox_sensor(Tsec) +/obj/machinery/bot/secbot/ed209/on_explosion(var/turf/Tsec) if(!lasercolor) var/obj/item/weapon/gun/energy/taser/G = new /obj/item/weapon/gun/energy/taser(Tsec) G.power_supply.charge = 0 @@ -789,7 +38,6 @@ Auto Patrol: []"}, else if(lasercolor == "r") var/obj/item/weapon/gun/energy/laser/redtag/G = new /obj/item/weapon/gun/energy/laser/redtag(Tsec) G.power_supply.charge = 0 - if (prob(50)) new /obj/item/robot_parts/l_leg(Tsec) if (prob(25)) @@ -805,104 +53,7 @@ Auto Patrol: []"}, if(lasercolor == "r") new /obj/item/clothing/suit/redtag(Tsec) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - - new /obj/effect/decal/cleanable/blood/oil(src.loc) - del(src) - - -/obj/machinery/bot/ed209/proc/shootAt(var/mob/target) - if(lastfired && world.time - lastfired < shot_delay) - return - lastfired = world.time - var/turf/T = loc - var/atom/U = (istype(target, /atom/movable) ? target.loc : target) - if ((!( U ) || !( T ))) - return - while(!( istype(U, /turf) )) - U = U.loc - if (!( istype(T, /turf) )) - return - - //if(lastfired && world.time - lastfired < 100) - // playsound(src.loc, 'ed209_shoot.ogg', 50, 0) - - if(!projectile) - if(!lasercolor) - if (src.emagged == 2) - projectile = /obj/item/projectile/beam - else - projectile = /obj/item/projectile/beam/stun - else if(lasercolor == "b") - if (src.emagged == 2) - projectile = /obj/item/projectile/beam/lastertag/omni - else - projectile = /obj/item/projectile/beam/lastertag/blue - else if(lasercolor == "r") - if (src.emagged == 2) - projectile = /obj/item/projectile/beam/lastertag/omni - else - projectile = /obj/item/projectile/beam/lastertag/red - - if (!( istype(U, /turf) )) - return - var/obj/item/projectile/A = new projectile (loc) - A.current = U - A.yo = U.y - T.y - A.xo = U.x - T.x - spawn( 0 ) - A.process() - return - return - -/obj/machinery/bot/ed209/attack_alien(var/mob/living/carbon/alien/user as mob) - ..() - if (!isalien(target)) - src.target = user - src.mode = SECBOT_HUNT - - -/obj/machinery/bot/ed209/emp_act(severity) - - if(severity==2 && prob(70)) - ..(severity-1) - else - var/obj/effect/overlay/pulse2 = new/obj/effect/overlay ( src.loc ) - pulse2.icon = 'icons/effects/effects.dmi' - pulse2.icon_state = "empdisable" - pulse2.name = "emp sparks" - pulse2.anchored = 1 - pulse2.dir = pick(cardinal) - spawn(10) - pulse2.delete() - var/list/mob/living/carbon/targets = new - for (var/mob/living/carbon/C in view(12,src)) - if (C.stat==2) - continue - targets += C - if(targets.len) - if(prob(50)) - var/mob/toshoot = pick(targets) - if (toshoot) - targets-=toshoot - if (prob(50) && emagged < 2) - emagged = 2 - shootAt(toshoot) - emagged = 0 - else - shootAt(toshoot) - else if(prob(50)) - if(targets.len) - var/mob/toarrest = pick(targets) - if (toarrest) - src.target = toarrest - src.mode = SECBOT_HUNT - - - -/obj/item/weapon/ed209_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob) +/obj/item/weapon/secbot_assembly/ed209_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob) ..() if(istype(W, /obj/item/weapon/pen)) @@ -1021,14 +172,14 @@ Auto Patrol: []"}, build_step++ user << "You complete the ED-209." var/turf/T = get_turf(src) - new /obj/machinery/bot/ed209(T,created_name,lasercolor) + new /obj/machinery/bot/secbot/ed209(T,created_name,lasercolor) user.drop_item() del(W) user.drop_from_inventory(src) del(src) -/obj/machinery/bot/ed209/bullet_act(var/obj/item/projectile/Proj) +/obj/machinery/bot/secbot/ed209/bullet_act(var/obj/item/projectile/Proj) if((src.lasercolor == "b") && (src.disabled == 0)) if(istype(Proj, /obj/item/projectile/beam/lastertag/red)) src.disabled = 1 @@ -1048,11 +199,11 @@ Auto Patrol: []"}, else ..() -/obj/machinery/bot/ed209/bluetag/New()//If desired, you spawn red and bluetag bots easily - new /obj/machinery/bot/ed209(get_turf(src),null,"b") +/obj/machinery/bot/secbot/ed209/bluetag/New()//If desired, you spawn red and bluetag bots easily + new /obj/machinery/bot/secbot/ed209(get_turf(src),null,"b") del(src) -/obj/machinery/bot/ed209/redtag/New() - new /obj/machinery/bot/ed209(get_turf(src),null,"r") - del(src) \ No newline at end of file +/obj/machinery/bot/secbot/ed209/redtag/New() + new /obj/machinery/bot/secbot/ed209(get_turf(src),null,"r") + del(src) diff --git a/code/game/machinery/bots/secbot.dm b/code/game/machinery/bots/secbot.dm index fa7df5de995..9c05abb7fae 100644 --- a/code/game/machinery/bots/secbot.dm +++ b/code/game/machinery/bots/secbot.dm @@ -10,20 +10,26 @@ maxhealth = 25 fire_dam_coeff = 0.7 brute_dam_coeff = 0.5 -// weight = 1.0E7 req_one_access = list(access_security, access_forensics_lockers) + var/mob/target var/oldtarget_name 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/idcheck = 0 //If false, all station IDs are authorized for weapons. var/check_records = 1 //Does it check security records? var/arrest_type = 0 //If true, don't handcuff var/declare_arrests = 0 //When making an arrest, should it notify everyone wearing sechuds? + var/next_harm_time = 0 + var/lastfired = 0 + var/shot_delay = 3 //.3 seconds between shots + var/lasercolor = "" + var/projectile = null//Holder for projectile type, to avoid so many else if chains + var/disabled = 0//A holder for if it needs to be disabled, if true it will not seach for targets, shoot at targets, or move, currently only used for lasertag var/mode = 0 #define SECBOT_IDLE 0 // idle @@ -52,6 +58,14 @@ var/nearest_beacon // the nearest beacon's tag var/turf/nearest_beacon_loc // the nearest beacon's location + var/bot_version = "1.3" + var/search_range = 7 + var/is_attacking = 0 + + var/obj/item/weapon/secbot_assembly = /obj/item/weapon/secbot_assembly + + var/list/threat_found_sounds = new('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg') + var/list/preparing_arrest_sounds = new('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg') /obj/machinery/bot/secbot/beepsky name = "Officer Beep O'sky" @@ -68,24 +82,39 @@ var/build_step = 0 var/created_name = "Securitron" //To preserve the name if it's a unique securitron I guess +/obj/machinery/bot/secbot/New(loc, created_name, created_lasercolor) + ..() + if(created_name) name = created_name + if(created_lasercolor) lasercolor = created_lasercolor + update_icon() + 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) + if(lasercolor) + shot_delay = 6 //Longer shot delay because JESUS CHRIST + check_records = 0 //Don't actively target people set to arrest + arrest_type = 1 //Don't even try to cuff + req_access = list(access_maint_tunnels) + arrest_type = 1 + if((lasercolor == "b") && (name == created_name))//Picks a name if there isn't already a custome one + name = pick("BLUE BALLER","SANIC","BLUE KILLDEATH MURDERBOT") + if((lasercolor == "r") && (name == created_name)) + name = pick("RED RAMPAGE","RED ROVER","RED KILLDEATH MURDERBOT") -/obj/machinery/bot/secbot - New() - ..() +/obj/machinery/bot/secbot/update_icon() + if(on && is_attacking) + src.icon_state = "secbot-c" + else src.icon_state = "secbot[src.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) - /obj/machinery/bot/secbot/turn_on() ..() - src.icon_state = "secbot[src.on]" + update_icon() src.updateUsrDialog() /obj/machinery/bot/secbot/turn_off() @@ -95,7 +124,7 @@ src.anchored = 0 src.mode = SECBOT_IDLE walk_to(src,0) - src.icon_state = "secbot[src.on]" + update_icon() src.updateUsrDialog() /obj/machinery/bot/secbot/attack_hand(mob/user as mob) @@ -109,7 +138,7 @@ var/dat dat += text({" -Automatic Security Unit v1.3

+Automatic Security Unit v[bot_version]

Status: []
Behaviour controls are [src.locked ? "locked" : "unlocked"]
Maintenance panel panel is [src.open ? "opened" : "closed"]"}, @@ -131,60 +160,67 @@ Auto Patrol: []"}, "[auto_patrol ? "On" : "Off"]" ) - user << browse("Securitron v1.3 controls[dat]", "window=autosec") + user << browse("Securitron v[bot_version] controls[dat]", "window=autosec") onclose(user, "autosec") return /obj/machinery/bot/secbot/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) turn_off() else turn_on() + src.updateUsrDialog() return switch(href_list["operation"]) if("idcheck") src.idcheck = !src.idcheck - 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 - updateUsrDialog() if("declarearrests") src.declare_arrests = !src.declare_arrests - src.updateUsrDialog() + src.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."]" + user << "Controls are now [src.locked ? "locked" : "unlocked"]." else if(emagged) user << "ERROR" if(open) - user << "\red Please close the access panel before locking it." + user << "Please close the access panel before locking it." else - user << "\red Access denied." + user << "Access denied." else ..() - if(!istype(W, /obj/item/weapon/screwdriver) && (W.force) && (!src.target)) + if(!istype(W, /obj/item/weapon/screwdriver) && W.force && !src.target) src.target = user + if(lasercolor)//To make up for the fact that lasertag bots don't hunt + src.shootAt(user) src.mode = SECBOT_HUNT /obj/machinery/bot/secbot/Emag(mob/user as mob) ..() if(open && !locked) - if(user) user << "\red You short out [src]'s target assessment circuits." + if(user) user << "You short out [src]'s target assessment circuits." spawn(0) for(var/mob/O in hearers(src, null)) O.show_message("\red [src] buzzes oddly!", 1) @@ -194,7 +230,8 @@ Auto Patrol: []"}, src.anchored = 0 src.emagged = 2 src.on = 1 - src.icon_state = "secbot[src.on]" + update_icon() + src.projectile = null mode = SECBOT_IDLE /obj/machinery/bot/secbot/process() @@ -206,14 +243,15 @@ Auto Patrol: []"}, switch(mode) if(SECBOT_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 if(SECBOT_HUNT) // hunting for perp - + if(src.lasercolor)//Lasertag bots do not tase or arrest anyone, just patrol and shoot and whatnot + mode = SECBOT_IDLE + return // if can't reach perp for long enough, go idle if(src.frustration >= 8) // for(var/mob/O in hearers(src, null)) @@ -228,9 +266,11 @@ Auto Patrol: []"}, if(Adjacent(target)) // if right next to perp if(istype(src.target,/mob/living/carbon)) playsound(src.loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) - src.icon_state = "secbot-c" + is_attacking = 1 + update_icon() spawn(2) - src.icon_state = "secbot[src.on]" + is_attacking = 0 + update_icon() var/mob/living/carbon/M = src.target var/maxstuns = 4 if(istype(M, /mob/living/carbon/human)) @@ -271,7 +311,6 @@ Auto Patrol: []"}, if(S.stat) src.frustration = 8 playsound(src.loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/bcreep.ogg'), 50, 0) - else // not next to perp var/turf/olddist = get_dist(src, src.target) walk_to(src, src.target,1,4) @@ -283,9 +322,15 @@ Auto Patrol: []"}, src.frustration = 8 if(SECBOT_PREP_ARREST) // preparing to arrest target - + if(src.lasercolor) + mode = SECBOT_IDLE + return + if(!target) + mode = SECBOT_IDLE + src.anchored = 0 + return // see if he got away - if((get_dist(src, src.target) > 1) || ((src.target:loc != src.target_lastloc) && src.target:weakened < 2)) + if((get_dist(src, src.target) > 1) || ((src.target.loc != src.target_lastloc) && src.target.weakened < 2)) src.anchored = 0 mode = SECBOT_HUNT return @@ -314,10 +359,10 @@ Auto Patrol: []"}, src.last_found = world.time src.frustration = 0 - playsound(src.loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg'), 50, 0) + if(preparing_arrest_sounds.len > 0) + playsound(src.loc, pick(preparing_arrest_sounds), 50, 0) // var/arrest_message = pick("Have a secure day!","I AM THE LAW.", "God made tomorrow for the crooks we don't catch today.","You can't outrun a radio.") // src.speak(arrest_message) - else mode = SECBOT_IDLE src.target = null @@ -326,7 +371,9 @@ Auto Patrol: []"}, src.frustration = 0 if(SECBOT_ARREST) // arresting - + if(src.lasercolor) + mode = SECBOT_IDLE + return if(!target || !istype(target, /mob/living/carbon)) src.anchored = 0 mode = SECBOT_IDLE @@ -360,7 +407,6 @@ Auto Patrol: []"}, if(SECBOT_PATROL) // patrol mode - patrol_step() spawn(5) if(mode == SECBOT_PATROL) @@ -378,33 +424,27 @@ Auto Patrol: []"}, // 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() + if(lasercolor) + sleep(20) else // failed to move - blockcount++ - if(blockcount > 5) // attempt 5 times before recomputing // find new path excluding blocked turf @@ -414,19 +454,14 @@ Auto Patrol: []"}, 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() @@ -442,7 +477,6 @@ Auto Patrol: []"}, 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() @@ -460,12 +494,10 @@ Auto Patrol: []"}, speak("Disengaging patrol mode.") send_status() - /obj/machinery/bot/secbot/proc/at_patrol_target() find_patrol_target() return - // sets the current destination // signals all beacons matching the patrol code // beacons will return a signal giving their locations @@ -477,7 +509,6 @@ Auto Patrol: []"}, // 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) @@ -587,24 +618,26 @@ Auto Patrol: []"}, ) 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, 0, 120, id=botcard, exclude=avoid) - if (!path) path = list() + if(!path) path = list() // look for a criminal in view of the bot - /obj/machinery/bot/secbot/proc/look_for_perp() + if(src.disabled) + return src.anchored = 0 - for (var/mob/living/M in view(7,src)) //Let's find us a criminal + for(var/mob/living/M in view(search_range,src)) //Let's find us a criminal if(istype(M, /mob/living/carbon)) var/mob/living/carbon/C = M if((C.stat) || (C.handcuffed)) continue + if((src.lasercolor) && (C.lying)) + continue//Does not shoot at people lying down when in lasertag mode, because it's just annoying, and they can fire once they get up. + if((C.name == src.oldtarget_name) && (world.time < src.last_found + 100)) continue @@ -624,7 +657,8 @@ Auto Patrol: []"}, src.target = M src.oldtarget_name = M.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) + if(!src.lasercolor && threat_found_sounds.len > 0) + playsound(src.loc, pick(threat_found_sounds), 50, 0) src.visible_message("[src] points at [M.name]!") mode = SECBOT_HUNT spawn(0) @@ -633,7 +667,6 @@ Auto Patrol: []"}, else continue - //If the security records say to arrest them, arrest them //Or if they have weapons and aren't security, arrest them. /obj/machinery/bot/secbot/proc/assess_perp(mob/living/carbon/human/perp as mob) @@ -642,7 +675,6 @@ Auto Patrol: []"}, if(src.emagged == 2) return 10 //Everyone is a criminal! if(src.idcheck && !src.allowed(perp)) - if(istype(perp.l_hand, /obj/item/weapon/gun) || istype(perp.l_hand, /obj/item/weapon/melee)) if(!istype(perp.l_hand, /obj/item/weapon/gun/energy/laser/bluetag) \ && !istype(perp.l_hand, /obj/item/weapon/gun/energy/laser/redtag) \ @@ -655,24 +687,42 @@ Auto Patrol: []"}, && !istype(perp.r_hand, /obj/item/weapon/gun/energy/laser/practice)) threatcount += 4 - if(istype(perp:belt, /obj/item/weapon/gun) || istype(perp:belt, /obj/item/weapon/melee)) - if(!istype(perp:belt, /obj/item/weapon/gun/energy/laser/bluetag) \ - && !istype(perp:belt, /obj/item/weapon/gun/energy/laser/redtag) \ - && !istype(perp:belt, /obj/item/weapon/gun/energy/laser/practice)) + if(istype(perp.belt, /obj/item/weapon/gun) || istype(perp.belt, /obj/item/weapon/melee)) + if(!istype(perp.belt, /obj/item/weapon/gun/energy/laser/bluetag) \ + && !istype(perp.belt, /obj/item/weapon/gun/energy/laser/redtag) \ + && !istype(perp.belt, /obj/item/weapon/gun/energy/laser/practice)) threatcount += 2 - if(istype(perp:wear_suit, /obj/item/clothing/suit/wizrobe)) + if(istype(perp.wear_suit, /obj/item/clothing/suit/wizrobe)) threatcount += 2 if(perp.dna && perp.dna.mutantrace && perp.dna.mutantrace != "none") threatcount += 2 //Agent cards lower threatlevel. - if(perp.wear_id && istype(perp:wear_id.GetID(), /obj/item/weapon/card/id/syndicate)) + if(perp.wear_id && istype(perp.wear_id.GetID(), /obj/item/weapon/card/id/syndicate)) threatcount -= 2 + if(src.lasercolor == "b")//Lasertag turrets target the opposing team, how great is that? -Sieve + threatcount = 0//They will not, however shoot at people who have guns, because it gets really fucking annoying + if(istype(perp.wear_suit, /obj/item/clothing/suit/redtag)) + threatcount += 4 + if((istype(perp.r_hand,/obj/item/weapon/gun/energy/laser/redtag)) || (istype(perp.l_hand,/obj/item/weapon/gun/energy/laser/redtag))) + threatcount += 4 + if(istype(perp.belt, /obj/item/weapon/gun/energy/laser/redtag)) + threatcount += 2 + + if(src.lasercolor == "r") + threatcount = 0 + if(istype(perp.wear_suit, /obj/item/clothing/suit/bluetag)) + threatcount += 4 + if((istype(perp.r_hand,/obj/item/weapon/gun/energy/laser/bluetag)) || (istype(perp.l_hand,/obj/item/weapon/gun/energy/laser/bluetag))) + threatcount += 4 + if(istype(perp.belt, /obj/item/weapon/gun/energy/laser/bluetag)) + threatcount += 2 + if(src.check_records) - for (var/datum/data/record/E in data_core.general) + for(var/datum/data/record/E in data_core.general) var/perpname = perp.name if(perp.wear_id) var/obj/item/weapon/card/id/id = perp.wear_id.GetID() @@ -680,7 +730,7 @@ Auto Patrol: []"}, perpname = id.registered_name if(E.fields["name"] == perpname) - for (var/datum/data/record/R in data_core.security) + for(var/datum/data/record/R in data_core.security) if((R.fields["id"] == E.fields["id"]) && (R.fields["criminal"] == "*Arrest*")) threatcount = 4 break @@ -688,45 +738,41 @@ Auto Patrol: []"}, return threatcount /obj/machinery/bot/secbot/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(src.botcard)) var/obj/machinery/door/D = M if(!istype(D, /obj/machinery/door/firedoor) && D.check_access(src.botcard) && !istype(D,/obj/machinery/door/poddoor)) D.open() src.frustration = 0 - else if((istype(M, /mob/living/)) && (!src.anchored)) - src.loc = M:loc - src.frustration = 0 + else if(!src.anchored) + if((istype(M, /mob/living/))) + var/mob/living/O = M + src.loc = O.loc + src.frustration = 0 + else if(istype(M, /obj/machinery/bot)) + var/obj/machinery/bot/B = M + if(B.dir != src.dir) // Avoids issues if two bots are currently patrolling in the same direction + src.loc = B.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/proc/speak(var/message) for(var/mob/O in hearers(src, null)) O.show_message("[src] beeps, \"[message]\"",2) return - /obj/machinery/bot/secbot/explode() - walk_to(src,0) src.visible_message("\red [src] blows apart!", 1) var/turf/Tsec = get_turf(src) - var/obj/item/weapon/secbot_assembly/Sa = new /obj/item/weapon/secbot_assembly(Tsec) + var/obj/item/weapon/secbot_assembly/Sa = new secbot_assembly(Tsec) Sa.build_step = 1 Sa.overlays += image('icons/obj/aibots.dmi', "hs_hole") Sa.created_name = src.name new /obj/item/device/assembly/prox_sensor(Tsec) new /obj/item/weapon/melee/baton(Tsec) - if(prob(50)) - new /obj/item/robot_parts/l_arm(Tsec) + on_explosion() var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread s.set_up(3, 1, src) @@ -735,6 +781,12 @@ Auto Patrol: []"}, new /obj/effect/decal/cleanable/blood/oil(src.loc) del(src) + +/obj/machinery/bot/secbot/proc/on_explosion(var/turf/Tsec) + new /obj/item/weapon/melee/baton(Tsec) + if(prob(50)) + new /obj/item/robot_parts/l_arm(Tsec) + /obj/machinery/bot/secbot/attack_alien(var/mob/living/carbon/alien/user as mob) ..() if(!isalien(target)) @@ -804,3 +856,82 @@ Auto Patrol: []"}, if(!in_range(src, usr) && src.loc != usr) return src.created_name = t + +/obj/machinery/bot/secbot/proc/shootAt(var/mob/target) + if(lastfired && world.time - lastfired < shot_delay) + return + lastfired = world.time + var/turf/T = loc + var/atom/U = (istype(target, /atom/movable) ? target.loc : target) + if((!( U ) || !( T ))) + return + while(!( istype(U, /turf) )) + U = U.loc + if(!( istype(T, /turf) )) + return + + //if(lastfired && world.time - lastfired < 100) + // playsound(src.loc, 'ed209_shoot.ogg', 50, 0) + + if(!projectile) + if(!lasercolor) + if(src.emagged == 2) + projectile = /obj/item/projectile/beam + else + projectile = /obj/item/projectile/beam/stun + else if(lasercolor == "b") + if(src.emagged == 2) + projectile = /obj/item/projectile/beam/lastertag/omni + else + projectile = /obj/item/projectile/beam/lastertag/blue + else if(lasercolor == "r") + if(src.emagged == 2) + projectile = /obj/item/projectile/beam/lastertag/omni + else + projectile = /obj/item/projectile/beam/lastertag/red + + if(!( istype(U, /turf) )) + return + var/obj/item/projectile/A = new projectile (loc) + A.current = U + A.yo = U.y - T.y + A.xo = U.x - T.x + spawn( 0 ) + A.process() + return + return + +/obj/machinery/bot/secbot/emp_act(severity) + if(severity==2 && prob(70)) + ..(severity-1) + else + var/obj/effect/overlay/pulse2 = new/obj/effect/overlay ( src.loc ) + pulse2.icon = 'icons/effects/effects.dmi' + pulse2.icon_state = "empdisable" + pulse2.name = "emp sparks" + pulse2.anchored = 1 + pulse2.dir = pick(cardinal) + spawn(10) + pulse2.delete() + var/list/mob/living/carbon/targets = new + for(var/mob/living/carbon/C in view(12,src)) + if(C.stat==2) + continue + targets += C + if(targets.len) + if(prob(50)) + var/mob/toshoot = pick(targets) + if(toshoot) + targets-=toshoot + if(prob(50) && emagged < 2) + emagged = 2 + shootAt(toshoot) + emagged = 0 + else + shootAt(toshoot) + else if(prob(50)) + if(targets.len) + var/mob/toarrest = pick(targets) + if(toarrest) + src.target = toarrest + src.mode = SECBOT_HUNT diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index 1c9bec63e98..a5274598dd6 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -106,7 +106,7 @@ if(istype(W, /obj/item/stack/sheet/metal) && !l_arm && !r_arm && !l_leg && !r_leg && !chest && !head) var/obj/item/stack/sheet/metal/M = W if (M.use(1)) - var/obj/item/weapon/ed209_assembly/B = new /obj/item/weapon/ed209_assembly + var/obj/item/weapon/secbot_assembly/ed209_assembly/B = new /obj/item/weapon/secbot_assembly/ed209_assembly B.loc = get_turf(src) user << "You armed the robot frame." if (user.get_inactive_hand()==src)