/mob/living/simple_animal/bot/secbot name = "\improper Securitron" desc = "A little security robot. He looks less than thrilled." icon = 'icons/mob/aibots.dmi' icon_state = "secbot" density = FALSE anchored = FALSE health = 25 maxHealth = 25 damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) pass_flags = PASSMOB radio_key = /obj/item/encryptionkey/secbot //AI Priv + Security radio_channel = "Security" //Security channel bot_type = SEC_BOT model = "Securitron" bot_core_type = /obj/machinery/bot_core/secbot window_id = "autosec" window_name = "Automatic Security Unit v1.6" allow_pai = 0 data_hud_type = DATA_HUD_SECURITY_ADVANCED path_image_color = "#FF0000" var/baton_type = /obj/item/melee/baton var/mob/living/carbon/target var/oldtarget_name var/threatlevel = FALSE var/target_lastloc //Loc of target when arrested. var/last_found //There's a delay var/declare_arrests = TRUE //When making an arrest, should it notify everyone on the security channel? var/idcheck = FALSE //If true, arrest people with no IDs var/weaponscheck = FALSE //If true, arrest people for weapons if they lack access var/check_records = TRUE //Does it check security records? var/arrest_type = FALSE //If true, don't handcuff /mob/living/simple_animal/bot/secbot/beepsky name = "Officer Beep O'sky" desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey." idcheck = FALSE weaponscheck = FALSE auto_patrol = TRUE /mob/living/simple_animal/bot/secbot/beepsky/jr name = "Officer Pipsqueak" desc = "It's Officer Beep O'sky's smaller, just-as aggressive cousin, Pipsqueak." /mob/living/simple_animal/bot/secbot/beepsky/jr/Initialize() . = ..() resize = 0.8 update_transform() /mob/living/simple_animal/bot/secbot/beepsky/explode() var/atom/Tsec = drop_location() new /obj/item/stock_parts/cell/potato(Tsec) var/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass/S = new(Tsec) S.reagents.add_reagent("whiskey", 15) S.on_reagent_change(ADD_REAGENT) ..() /mob/living/simple_animal/bot/secbot/pingsky name = "Officer Pingsky" desc = "It's Officer Pingsky! Delegated to satellite guard duty for harbouring anti-human sentiment." radio_channel = "AI Private" /mob/living/simple_animal/bot/secbot/Initialize() . = ..() update_icon() var/datum/job/detective/J = new/datum/job/detective access_card.access += J.get_access() prev_access = access_card.access //SECHUD var/datum/atom_hud/secsensor = GLOB.huds[DATA_HUD_SECURITY_ADVANCED] secsensor.add_hud_to(src) /mob/living/simple_animal/bot/secbot/update_icon() if(mode == BOT_HUNT) icon_state = "[initial(icon_state)]-c" return ..() /mob/living/simple_animal/bot/secbot/turn_off() ..() mode = BOT_IDLE /mob/living/simple_animal/bot/secbot/bot_reset() ..() target = null oldtarget_name = null anchored = FALSE walk_to(src,0) last_found = world.time /mob/living/simple_animal/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!" /mob/living/simple_animal/bot/secbot/get_controls(mob/user) var/dat dat += hack(user) dat += showpai(user) dat += text({" Securitron v1.6 controls

Status: []
Behaviour controls are [locked ? "locked" : "unlocked"]
Maintenance panel panel is [open ? "opened" : "closed"]"}, "[on ? "On" : "Off"]" ) if(!locked || issilicon(user) || IsAdminGhost(user)) dat += text({"
Arrest Unidentifiable Persons: []
Arrest for Unauthorized Weapons: []
Arrest for Warrant: []
Operating Mode: []
Report Arrests[]
Auto Patrol: []"}, "[idcheck ? "Yes" : "No"]", "[weaponscheck ? "Yes" : "No"]", "[check_records ? "Yes" : "No"]", "[arrest_type ? "Detain" : "Arrest"]", "[declare_arrests ? "Yes" : "No"]", "[auto_patrol ? "On" : "Off"]" ) return dat /mob/living/simple_animal/bot/secbot/Topic(href, href_list) if(..()) return 1 switch(href_list["operation"]) if("idcheck") idcheck = !idcheck update_controls() if("weaponscheck") weaponscheck = !weaponscheck update_controls() if("ignorerec") check_records = !check_records update_controls() if("switchmode") arrest_type = !arrest_type update_controls() if("declarearrests") declare_arrests = !declare_arrests update_controls() /mob/living/simple_animal/bot/secbot/proc/retaliate(mob/living/carbon/human/H) var/judgement_criteria = judgement_criteria() threatlevel = H.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) threatlevel += 6 if(threatlevel >= 4) target = H mode = BOT_HUNT /mob/living/simple_animal/bot/secbot/proc/judgement_criteria() var/final = FALSE if(idcheck) final = final|JUDGE_IDCHECK if(check_records) final = final|JUDGE_RECORDCHECK if(weaponscheck) final = final|JUDGE_WEAPONCHECK if(emagged == 2) final = final|JUDGE_EMAGGED return final /mob/living/simple_animal/bot/secbot/proc/special_retaliate_after_attack(mob/user) //allows special actions to take place after being attacked. return /mob/living/simple_animal/bot/secbot/attack_hand(mob/living/carbon/human/H) if((H.a_intent == INTENT_HARM) || (H.a_intent == INTENT_DISARM)) retaliate(H) if(special_retaliate_after_attack(H)) return return ..() /mob/living/simple_animal/bot/secbot/attackby(obj/item/W, mob/user, params) ..() if(istype(W, /obj/item/weldingtool) && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry. return if(!istype(W, /obj/item/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass. retaliate(user) if(special_retaliate_after_attack(user)) return /mob/living/simple_animal/bot/secbot/emag_act(mob/user) ..() if(emagged == 2) if(user) to_chat(user, "You short out [src]'s target assessment circuits.") oldtarget_name = user.name audible_message("[src] buzzes oddly!") declare_arrests = FALSE update_icon() /mob/living/simple_animal/bot/secbot/bullet_act(obj/item/projectile/Proj) if(istype(Proj , /obj/item/projectile/beam)||istype(Proj, /obj/item/projectile/bullet)) if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE)) if(!Proj.nodamage && Proj.damage < src.health && ishuman(Proj.firer)) retaliate(Proj.firer) ..() /mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/A) if(!on) return if(iscarbon(A)) var/mob/living/carbon/C = A if(C.canmove || arrest_type) // CIT CHANGE - makes sentient secbots check for canmove rather than !isstun. stun_attack(A) else if(C.canBeHandcuffed() && !C.handcuffed) cuff(A) else ..() /mob/living/simple_animal/bot/secbot/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE) if(istype(AM, /obj/item)) var/obj/item/I = AM if(I.throwforce < src.health && I.thrownby && ishuman(I.thrownby)) var/mob/living/carbon/human/H = I.thrownby retaliate(H) ..() /mob/living/simple_animal/bot/secbot/proc/cuff(mob/living/carbon/C) mode = BOT_ARREST playsound(src, 'sound/weapons/cablecuff.ogg', 30, TRUE, -2) C.visible_message("[src] is trying to put zipties on [C]!",\ "[src] is trying to put zipties on you!") addtimer(CALLBACK(src, .proc/attempt_handcuff, C), 60) /mob/living/simple_animal/bot/secbot/proc/attempt_handcuff(mob/living/carbon/C) if( !on || !Adjacent(C) || !isturf(C.loc) ) //if he's in a closet or not adjacent, we cancel cuffing. return if(!C.handcuffed) C.handcuffed = new /obj/item/restraints/handcuffs/cable/zipties/used(C) C.update_handcuffed() playsound(src, "law", 50, 0) back_to_idle() /mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/C) var/judgement_criteria = judgement_criteria() playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1) icon_state = "secbot-c" addtimer(CALLBACK(src, .proc/update_icon), 2) var/threat = 5 if(ishuman(C)) C.stuttering = 5 C.Knockdown(100) var/mob/living/carbon/human/H = C threat = H.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) else C.Knockdown(100) C.stuttering = 5 threat = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) log_combat(src,C,"stunned") if(declare_arrests) var/area/location = get_area(src) speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag [C] in [location].", radio_channel) C.visible_message("[src] has stunned [C]!",\ "[src] has stunned you!") /mob/living/simple_animal/bot/secbot/handle_automated_action() if(!..()) return switch(mode) 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 = BOT_START_PATROL // switch to patrol mode if(BOT_HUNT) // hunting for perp // if can't reach perp for long enough, go idle if(frustration >= 8) walk_to(src,0) back_to_idle() return if(target) // make sure target exists if(Adjacent(target) && isturf(target.loc)) // if right next to perp stun_attack(target) mode = BOT_PREP_ARREST anchored = TRUE target_lastloc = target.loc return else // not next to perp var/turf/olddist = get_dist(src, target) walk_to(src, target,1,4) if((get_dist(src, target)) >= (olddist)) frustration++ else frustration = 0 else back_to_idle() 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( !Adjacent(target) || !isturf(target.loc) || target.getStaminaLoss() <= 120 || !target.recoveringstam) //CIT CHANGE - replaces amountknockdown with checks for stamina so secbots dont run into an infinite loop back_to_hunt() return if(iscarbon(target) && target.canBeHandcuffed()) if(!arrest_type) if(!target.handcuffed) //he's not cuffed? Try to cuff him! cuff(target) else back_to_idle() return else back_to_idle() return if(BOT_ARREST) if(!target) anchored = FALSE mode = BOT_IDLE last_found = world.time frustration = 0 return if(target.handcuffed) //no target or target cuffed? back to idle. back_to_idle() return if(!Adjacent(target) || !isturf(target.loc) || (target.loc != target_lastloc && !target.recoveringstam && target.getStaminaLoss() <= 120)) //if he's changed loc and about to get up or not adjacent or got into a closet, we prep arrest again. CIT CHANGE - replaces amountknockdown with recoveringstam and staminaloss check back_to_hunt() return else //Try arresting again if the target escapes. mode = BOT_PREP_ARREST anchored = FALSE if(BOT_START_PATROL) look_for_perp() start_patrol() if(BOT_PATROL) look_for_perp() bot_patrol() return /mob/living/simple_animal/bot/secbot/proc/back_to_idle() anchored = FALSE mode = BOT_IDLE target = null last_found = world.time frustration = 0 INVOKE_ASYNC(src, .proc/handle_automated_action) /mob/living/simple_animal/bot/secbot/proc/back_to_hunt() anchored = FALSE frustration = 0 mode = BOT_HUNT INVOKE_ASYNC(src, .proc/handle_automated_action) // look for a criminal in view of the bot /mob/living/simple_animal/bot/secbot/proc/look_for_perp() anchored = FALSE var/judgement_criteria = judgement_criteria() 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 == oldtarget_name) && (world.time < last_found + 100)) continue threatlevel = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) if(!threatlevel) continue else if(threatlevel >= 4) target = C oldtarget_name = C.name speak("Level [threatlevel] infraction alert!") playsound(loc, pick('sound/voice/beepsky/criminal.ogg', 'sound/voice/beepsky/justice.ogg', 'sound/voice/beepsky/freeze.ogg'), 50, FALSE) visible_message("[src] points at [C.name]!") mode = BOT_HUNT INVOKE_ASYNC(src, .proc/handle_automated_action) break else continue /mob/living/simple_animal/bot/secbot/proc/check_for_weapons(var/obj/item/slot_item) if(slot_item && (slot_item.item_flags & NEEDS_PERMIT)) return TRUE return FALSE /mob/living/simple_animal/bot/secbot/explode() walk_to(src,0) visible_message("[src] blows apart!") var/atom/Tsec = drop_location() var/obj/item/bot_assembly/secbot/Sa = new (Tsec) Sa.build_step = 1 Sa.add_overlay("hs_hole") Sa.created_name = name new /obj/item/assembly/prox_sensor(Tsec) drop_part(baton_type, Tsec) if(prob(50)) drop_part(robot_arm, Tsec) do_sparks(3, TRUE, src) new /obj/effect/decal/cleanable/oil(loc) ..() /mob/living/simple_animal/bot/secbot/attack_alien(var/mob/living/carbon/alien/user as mob) ..() if(!isalien(target)) target = user mode = BOT_HUNT /mob/living/simple_animal/bot/secbot/Crossed(atom/movable/AM) if(has_gravity() && ismob(AM) && target) var/mob/living/carbon/C = AM if(!istype(C) || !C || in_range(src, target)) return knockOver(C) return ..() /obj/machinery/bot_core/secbot req_access = list(ACCESS_SECURITY)