mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-26 01:53:02 +00:00
Merge pull request #5555 from VOREStation/upstream-merge-6366
[MIRROR] Tweaks Security Bots
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
#define SECBOT_WAIT_TIME 5 //number of in-game seconds to wait for someone to surrender
|
#define SECBOT_WAIT_TIME 3 //Around number*2 real seconds to surrender.
|
||||||
#define SECBOT_THREAT_ARREST 4 //threat level at which we decide to arrest someone
|
#define SECBOT_THREAT_ARREST 4 //threat level at which we decide to arrest someone
|
||||||
#define SECBOT_THREAT_ATTACK 8 //threat level at which was assume immediate danger and attack right away
|
#define SECBOT_THREAT_ATTACK 8 //threat level at which was assume immediate danger and attack right away
|
||||||
|
|
||||||
@@ -9,18 +9,20 @@
|
|||||||
maxHealth = 100
|
maxHealth = 100
|
||||||
health = 100
|
health = 100
|
||||||
req_one_access = list(access_security, access_forensics_lockers)
|
req_one_access = list(access_security, access_forensics_lockers)
|
||||||
botcard_access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels)
|
botcard_access = list(access_security, access_sec_doors, access_forensics_lockers, access_maint_tunnels)
|
||||||
patrol_speed = 2
|
patrol_speed = 2
|
||||||
target_speed = 3
|
target_speed = 3
|
||||||
|
|
||||||
var/default_icon_state = "secbot"
|
var/default_icon_state = "secbot"
|
||||||
var/idcheck = 0 // If true, arrests for having weapons without authorization.
|
var/idcheck = FALSE // If true, arrests for having weapons without authorization.
|
||||||
var/check_records = 0 // If true, arrests people without a record.
|
var/check_records = FALSE // If true, arrests people without a record.
|
||||||
var/check_arrest = 1 // If true, arrests people who are set to arrest.
|
var/check_arrest = TRUE // If true, arrests people who are set to arrest.
|
||||||
var/arrest_type = 0 // If true, doesn't handcuff. You monster.
|
var/arrest_type = FALSE // If true, doesn't handcuff. You monster.
|
||||||
var/declare_arrests = 0 // If true, announces arrests over sechuds.
|
var/declare_arrests = FALSE // If true, announces arrests over sechuds.
|
||||||
|
var/threat = 0 // How much of a threat something is. Set upon acquiring a target.
|
||||||
|
var/attacked = FALSE // If true, gives the bot enough threat assessment to attack immediately.
|
||||||
|
|
||||||
var/is_ranged = 0
|
var/is_ranged = FALSE
|
||||||
var/awaiting_surrender = 0
|
var/awaiting_surrender = 0
|
||||||
var/can_next_insult = 0 // Uses world.time
|
var/can_next_insult = 0 // Uses world.time
|
||||||
var/stun_strength = 60 // For humans.
|
var/stun_strength = 60 // For humans.
|
||||||
@@ -45,7 +47,7 @@
|
|||||||
/mob/living/bot/secbot/beepsky
|
/mob/living/bot/secbot/beepsky
|
||||||
name = "Officer Beepsky"
|
name = "Officer Beepsky"
|
||||||
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
|
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
|
||||||
will_patrol = 1
|
will_patrol = TRUE
|
||||||
|
|
||||||
/mob/living/bot/secbot/slime
|
/mob/living/bot/secbot/slime
|
||||||
name = "Slime Securitron"
|
name = "Slime Securitron"
|
||||||
@@ -126,18 +128,18 @@
|
|||||||
. = ..()
|
. = ..()
|
||||||
if(!emagged)
|
if(!emagged)
|
||||||
if(user)
|
if(user)
|
||||||
user << "<span class='notice'>\The [src] buzzes and beeps.</span>"
|
to_chat(user, "<span class='notice'>\The [src] buzzes and beeps.</span>")
|
||||||
emagged = 1
|
emagged = TRUE
|
||||||
patrol_speed = 3
|
patrol_speed = 3
|
||||||
target_speed = 4
|
target_speed = 4
|
||||||
return 1
|
return TRUE
|
||||||
else
|
else
|
||||||
user << "<span class='notice'>\The [src] is already corrupt.</span>"
|
to_chat(user, "<span class='notice'>\The [src] is already corrupt.</span>")
|
||||||
|
|
||||||
/mob/living/bot/secbot/attackby(var/obj/item/O, var/mob/user)
|
/mob/living/bot/secbot/attackby(var/obj/item/O, var/mob/user)
|
||||||
var/curhealth = health
|
var/curhealth = health
|
||||||
. = ..()
|
. = ..()
|
||||||
if(health < curhealth && on == 1)
|
if(health < curhealth && on == TRUE)
|
||||||
react_to_attack(user)
|
react_to_attack(user)
|
||||||
|
|
||||||
/mob/living/bot/secbot/bullet_act(var/obj/item/projectile/P)
|
/mob/living/bot/secbot/bullet_act(var/obj/item/projectile/P)
|
||||||
@@ -154,18 +156,21 @@
|
|||||||
..()
|
..()
|
||||||
|
|
||||||
/mob/living/bot/secbot/proc/react_to_attack(mob/attacker)
|
/mob/living/bot/secbot/proc/react_to_attack(mob/attacker)
|
||||||
|
if(!on) // We don't want it to react if it's off
|
||||||
|
return
|
||||||
|
|
||||||
if(!target)
|
if(!target)
|
||||||
playsound(src.loc, pick(threat_found_sounds), 50)
|
playsound(src.loc, pick(threat_found_sounds), 50)
|
||||||
global_announcer.autosay("[src] was attacked by a hostile <b>[target_name(attacker)]</b> in <b>[get_area(src)]</b>.", "[src]", "Security")
|
global_announcer.autosay("[src] was attacked by a hostile <b>[target_name(attacker)]</b> in <b>[get_area(src)]</b>.", "[src]", "Security")
|
||||||
target = attacker
|
target = attacker
|
||||||
awaiting_surrender = INFINITY // Don't try and wait for surrender
|
attacked = TRUE
|
||||||
|
|
||||||
// Say "freeze!" and demand surrender
|
// Say "freeze!" and demand surrender
|
||||||
/mob/living/bot/secbot/proc/demand_surrender(mob/target, var/threat)
|
/mob/living/bot/secbot/proc/demand_surrender(mob/target, var/threat)
|
||||||
var/suspect_name = target_name(target)
|
var/suspect_name = target_name(target)
|
||||||
if(declare_arrests)
|
if(declare_arrests)
|
||||||
global_announcer.autosay("[src] is [arrest_type ? "detaining" : "arresting"] a level [threat] suspect <b>[suspect_name]</b> in <b>[get_area(src)]</b>.", "[src]", "Security")
|
global_announcer.autosay("[src] is [arrest_type ? "detaining" : "arresting"] a level [threat] suspect <b>[suspect_name]</b> in <b>[get_area(src)]</b>.", "[src]", "Security")
|
||||||
say("Down on the floor, [suspect_name]! You have [SECBOT_WAIT_TIME] seconds to comply.")
|
say("Down on the floor, [suspect_name]! You have [SECBOT_WAIT_TIME*2] seconds to comply.")
|
||||||
playsound(src.loc, pick(preparing_arrest_sounds), 50)
|
playsound(src.loc, pick(preparing_arrest_sounds), 50)
|
||||||
// Register to be told when the target moves
|
// Register to be told when the target moves
|
||||||
GLOB.moved_event.register(target, src, /mob/living/bot/secbot/proc/target_moved)
|
GLOB.moved_event.register(target, src, /mob/living/bot/secbot/proc/target_moved)
|
||||||
@@ -179,7 +184,8 @@
|
|||||||
/mob/living/bot/secbot/resetTarget()
|
/mob/living/bot/secbot/resetTarget()
|
||||||
..()
|
..()
|
||||||
GLOB.moved_event.unregister(target, src)
|
GLOB.moved_event.unregister(target, src)
|
||||||
awaiting_surrender = -1
|
awaiting_surrender = 0
|
||||||
|
attacked = FALSE
|
||||||
walk_to(src, 0)
|
walk_to(src, 0)
|
||||||
|
|
||||||
/mob/living/bot/secbot/startPatrol()
|
/mob/living/bot/secbot/startPatrol()
|
||||||
@@ -189,17 +195,18 @@
|
|||||||
|
|
||||||
/mob/living/bot/secbot/confirmTarget(var/atom/A)
|
/mob/living/bot/secbot/confirmTarget(var/atom/A)
|
||||||
if(!..())
|
if(!..())
|
||||||
return 0
|
return FALSE
|
||||||
return (check_threat(A) >= SECBOT_THREAT_ARREST)
|
check_threat(A)
|
||||||
|
if(threat >= SECBOT_THREAT_ARREST)
|
||||||
|
return TRUE
|
||||||
|
|
||||||
/mob/living/bot/secbot/lookForTargets()
|
/mob/living/bot/secbot/lookForTargets()
|
||||||
for(var/mob/living/M in view(src))
|
for(var/mob/living/M in view(src))
|
||||||
if(M.stat == DEAD)
|
if(M.stat == DEAD)
|
||||||
continue
|
continue
|
||||||
if(confirmTarget(M))
|
if(confirmTarget(M))
|
||||||
var/threat = check_threat(M)
|
|
||||||
target = M
|
target = M
|
||||||
awaiting_surrender = -1
|
awaiting_surrender = 0
|
||||||
say("Level [threat] infraction alert!")
|
say("Level [threat] infraction alert!")
|
||||||
custom_emote(1, "points at [M.name]!")
|
custom_emote(1, "points at [M.name]!")
|
||||||
playsound(src.loc, pick(threat_found_sounds), 50)
|
playsound(src.loc, pick(threat_found_sounds), 50)
|
||||||
@@ -207,15 +214,15 @@
|
|||||||
|
|
||||||
/mob/living/bot/secbot/handleAdjacentTarget()
|
/mob/living/bot/secbot/handleAdjacentTarget()
|
||||||
var/mob/living/carbon/human/H = target
|
var/mob/living/carbon/human/H = target
|
||||||
var/threat = check_threat(target)
|
check_threat(target)
|
||||||
if(awaiting_surrender < SECBOT_WAIT_TIME && istype(H) && !H.lying && threat < SECBOT_THREAT_ATTACK)
|
if(awaiting_surrender < SECBOT_WAIT_TIME && istype(H) && !H.lying && threat < SECBOT_THREAT_ATTACK)
|
||||||
if(awaiting_surrender == -1) // On first tick of awaiting...
|
if(awaiting_surrender == 0) // On first tick of awaiting...
|
||||||
demand_surrender(target, threat)
|
demand_surrender(target, threat)
|
||||||
++awaiting_surrender
|
++awaiting_surrender
|
||||||
else
|
else
|
||||||
if(declare_arrests)
|
if(declare_arrests)
|
||||||
var/action = arrest_type ? "detaining" : "arresting"
|
var/action = arrest_type ? "detaining" : "arresting"
|
||||||
if(istype(target, /mob/living/simple_mob))
|
if(!ishuman(target))
|
||||||
action = "fighting"
|
action = "fighting"
|
||||||
global_announcer.autosay("[src] is [action] a level [threat] [action != "fighting" ? "suspect" : "threat"] <b>[target_name(target)]</b> in <b>[get_area(src)]</b>.", "[src]", "Security")
|
global_announcer.autosay("[src] is [action] a level [threat] [action != "fighting" ? "suspect" : "threat"] <b>[target_name(target)]</b> in <b>[get_area(src)]</b>.", "[src]", "Security")
|
||||||
UnarmedAttack(target)
|
UnarmedAttack(target)
|
||||||
@@ -224,7 +231,6 @@
|
|||||||
/mob/living/bot/secbot/proc/insult(var/mob/living/L)
|
/mob/living/bot/secbot/proc/insult(var/mob/living/L)
|
||||||
if(can_next_insult > world.time)
|
if(can_next_insult > world.time)
|
||||||
return
|
return
|
||||||
var/threat = check_threat(L)
|
|
||||||
if(threat >= 10)
|
if(threat >= 10)
|
||||||
playsound(src.loc, 'sound/voice/binsult.ogg', 75)
|
playsound(src.loc, 'sound/voice/binsult.ogg', 75)
|
||||||
can_next_insult = world.time + 20 SECONDS
|
can_next_insult = world.time + 20 SECONDS
|
||||||
@@ -240,47 +246,47 @@
|
|||||||
if(!istype(M))
|
if(!istype(M))
|
||||||
return
|
return
|
||||||
|
|
||||||
if(istype(M, /mob/living/carbon))
|
if(ishuman(M))
|
||||||
var/mob/living/carbon/C = M
|
var/mob/living/carbon/human/H = M
|
||||||
var/cuff = 1
|
var/cuff = TRUE
|
||||||
if(istype(C, /mob/living/carbon/human))
|
|
||||||
var/mob/living/carbon/human/H = C
|
if(!H.lying || H.handcuffed || arrest_type)
|
||||||
if(istype(H.back, /obj/item/weapon/rig) && istype(H.gloves,/obj/item/clothing/gloves/gauntlets/rig))
|
cuff = FALSE
|
||||||
cuff = 0
|
|
||||||
if(!C.lying || C.handcuffed || arrest_type)
|
|
||||||
cuff = 0
|
|
||||||
if(!cuff)
|
if(!cuff)
|
||||||
C.stun_effect_act(0, stun_strength, null)
|
H.stun_effect_act(0, stun_strength, null)
|
||||||
playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
|
playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
|
||||||
do_attack_animation(C)
|
do_attack_animation(H)
|
||||||
busy = 1
|
busy = TRUE
|
||||||
update_icons()
|
update_icons()
|
||||||
spawn(2)
|
spawn(2)
|
||||||
busy = 0
|
busy = FALSE
|
||||||
update_icons()
|
update_icons()
|
||||||
visible_message("<span class='warning'>\The [C] was prodded by \the [src] with a stun baton!</span>")
|
visible_message("<span class='warning'>\The [H] was prodded by \the [src] with a stun baton!</span>")
|
||||||
insult(C)
|
insult(H)
|
||||||
else
|
else
|
||||||
playsound(loc, 'sound/weapons/handcuffs.ogg', 30, 1, -2)
|
playsound(loc, 'sound/weapons/handcuffs.ogg', 30, 1, -2)
|
||||||
visible_message("<span class='warning'>\The [src] is trying to put handcuffs on \the [C]!</span>")
|
visible_message("<span class='warning'>\The [src] is trying to put handcuffs on \the [H]!</span>")
|
||||||
busy = 1
|
busy = TRUE
|
||||||
if(do_mob(src, C, 60))
|
if(do_mob(src, H, 60))
|
||||||
if(!C.handcuffed)
|
if(!H.handcuffed)
|
||||||
C.handcuffed = new /obj/item/weapon/handcuffs(C)
|
if(istype(H.back, /obj/item/weapon/rig) && istype(H.gloves,/obj/item/clothing/gloves/gauntlets/rig))
|
||||||
C.update_inv_handcuffed()
|
H.handcuffed = new /obj/item/weapon/handcuffs/cable(H) // Better to be cable cuffed than stun-locked
|
||||||
busy = 0
|
else
|
||||||
else if(istype(M, /mob/living/simple_mob))
|
H.handcuffed = new /obj/item/weapon/handcuffs(H)
|
||||||
var/mob/living/simple_mob/S = M
|
H.update_inv_handcuffed()
|
||||||
S.adjustBruteLoss(xeno_harm_strength)
|
busy = FALSE
|
||||||
|
else if(istype(M, /mob/living))
|
||||||
|
var/mob/living/L = M
|
||||||
|
L.adjustBruteLoss(xeno_harm_strength)
|
||||||
do_attack_animation(M)
|
do_attack_animation(M)
|
||||||
playsound(loc, "swing_hit", 50, 1, -1)
|
playsound(loc, "swing_hit", 50, 1, -1)
|
||||||
busy = 1
|
busy = TRUE
|
||||||
update_icons()
|
update_icons()
|
||||||
spawn(2)
|
spawn(2)
|
||||||
busy = 0
|
busy = FALSE
|
||||||
update_icons()
|
update_icons()
|
||||||
visible_message("<span class='warning'>\The [M] was beaten by \the [src] with a stun baton!</span>")
|
visible_message("<span class='warning'>\The [M] was beaten by \the [src] with a stun baton!</span>")
|
||||||
insult(S)
|
insult(L)
|
||||||
|
|
||||||
/mob/living/bot/secbot/slime/UnarmedAttack(var/mob/living/L, var/proximity)
|
/mob/living/bot/secbot/slime/UnarmedAttack(var/mob/living/L, var/proximity)
|
||||||
..()
|
..()
|
||||||
@@ -317,12 +323,15 @@
|
|||||||
|
|
||||||
/mob/living/bot/secbot/proc/check_threat(var/mob/living/M)
|
/mob/living/bot/secbot/proc/check_threat(var/mob/living/M)
|
||||||
if(!M || !istype(M) || M.stat == DEAD || src == M)
|
if(!M || !istype(M) || M.stat == DEAD || src == M)
|
||||||
return 0
|
threat = 0
|
||||||
|
|
||||||
if(emagged && !M.incapacitated()) //check incapacitated so emagged secbots don't keep attacking the same target forever
|
else if(emagged && !M.incapacitated()) //check incapacitated so emagged secbots don't keep attacking the same target forever
|
||||||
return 10
|
threat = 10
|
||||||
|
|
||||||
return M.assess_perp(access_scanner, 0, idcheck, check_records, check_arrest)
|
else
|
||||||
|
threat = M.assess_perp(access_scanner, 0, idcheck, check_records, check_arrest) // Set base threat level
|
||||||
|
if(attacked)
|
||||||
|
threat += SECBOT_THREAT_ATTACK // Increase enough so we can attack immediately in return
|
||||||
|
|
||||||
//Secbot Construction
|
//Secbot Construction
|
||||||
|
|
||||||
@@ -365,12 +374,12 @@
|
|||||||
if(WT.remove_fuel(0, user))
|
if(WT.remove_fuel(0, user))
|
||||||
build_step = 1
|
build_step = 1
|
||||||
overlays += image('icons/obj/aibots.dmi', "hs_hole")
|
overlays += image('icons/obj/aibots.dmi', "hs_hole")
|
||||||
user << "You weld a hole in \the [src]."
|
to_chat(user, "You weld a hole in \the [src].")
|
||||||
|
|
||||||
else if(isprox(W) && (build_step == 1))
|
else if(isprox(W) && (build_step == 1))
|
||||||
user.drop_item()
|
user.drop_item()
|
||||||
build_step = 2
|
build_step = 2
|
||||||
user << "You add \the [W] to [src]."
|
to_chat(user, "You add \the [W] to [src].")
|
||||||
overlays += image('icons/obj/aibots.dmi', "hs_eye")
|
overlays += image('icons/obj/aibots.dmi', "hs_eye")
|
||||||
name = "helmet/signaler/prox sensor assembly"
|
name = "helmet/signaler/prox sensor assembly"
|
||||||
qdel(W)
|
qdel(W)
|
||||||
@@ -378,14 +387,14 @@
|
|||||||
else if((istype(W, /obj/item/robot_parts/l_arm) || istype(W, /obj/item/robot_parts/r_arm) || (istype(W, /obj/item/organ/external/arm) && ((W.name == "robotic right arm") || (W.name == "robotic left arm")))) && build_step == 2)
|
else if((istype(W, /obj/item/robot_parts/l_arm) || istype(W, /obj/item/robot_parts/r_arm) || (istype(W, /obj/item/organ/external/arm) && ((W.name == "robotic right arm") || (W.name == "robotic left arm")))) && build_step == 2)
|
||||||
user.drop_item()
|
user.drop_item()
|
||||||
build_step = 3
|
build_step = 3
|
||||||
user << "You add \the [W] to [src]."
|
to_chat(user, "You add \the [W] to [src].")
|
||||||
name = "helmet/signaler/prox sensor/robot arm assembly"
|
name = "helmet/signaler/prox sensor/robot arm assembly"
|
||||||
overlays += image('icons/obj/aibots.dmi', "hs_arm")
|
overlays += image('icons/obj/aibots.dmi', "hs_arm")
|
||||||
qdel(W)
|
qdel(W)
|
||||||
|
|
||||||
else if(istype(W, /obj/item/weapon/melee/baton) && build_step == 3)
|
else if(istype(W, /obj/item/weapon/melee/baton) && build_step == 3)
|
||||||
user.drop_item()
|
user.drop_item()
|
||||||
user << "You complete the Securitron! Beep boop."
|
to_chat(user, "You complete the Securitron! Beep boop.")
|
||||||
if(istype(W, /obj/item/weapon/melee/baton/slime))
|
if(istype(W, /obj/item/weapon/melee/baton/slime))
|
||||||
var/mob/living/bot/secbot/slime/S = new /mob/living/bot/secbot/slime(get_turf(src))
|
var/mob/living/bot/secbot/slime/S = new /mob/living/bot/secbot/slime(get_turf(src))
|
||||||
S.name = created_name
|
S.name = created_name
|
||||||
@@ -399,6 +408,6 @@
|
|||||||
var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN)
|
var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN)
|
||||||
if(!t)
|
if(!t)
|
||||||
return
|
return
|
||||||
if(!in_range(src, usr) && loc != usr)
|
if(!in_range(src, user) && loc != user)
|
||||||
return
|
return
|
||||||
created_name = t
|
created_name = t
|
||||||
38
html/changelogs/Nalarac - Sec Bot.yml
Normal file
38
html/changelogs/Nalarac - Sec Bot.yml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
################################
|
||||||
|
# Example Changelog File
|
||||||
|
#
|
||||||
|
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
|
||||||
|
#
|
||||||
|
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
|
||||||
|
# When it is, any changes listed below will disappear.
|
||||||
|
#
|
||||||
|
# Valid Prefixes:
|
||||||
|
# bugfix
|
||||||
|
# wip (For works in progress)
|
||||||
|
# tweak
|
||||||
|
# soundadd
|
||||||
|
# sounddel
|
||||||
|
# rscadd (general adding of nice things)
|
||||||
|
# rscdel (general deleting of nice things)
|
||||||
|
# imageadd
|
||||||
|
# imagedel
|
||||||
|
# maptweak
|
||||||
|
# spellcheck (typo fixes)
|
||||||
|
# experiment
|
||||||
|
#################################
|
||||||
|
|
||||||
|
# Your name.
|
||||||
|
author: Nalarac
|
||||||
|
|
||||||
|
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
|
||||||
|
delete-after: True
|
||||||
|
|
||||||
|
# Any changes you've made. See valid prefix list above.
|
||||||
|
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
|
||||||
|
# SCREW THIS UP AND IT WON'T WORK.
|
||||||
|
# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
|
||||||
|
# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
|
||||||
|
changes:
|
||||||
|
- bugfix: "Security bots will smack attackers once again."
|
||||||
|
- tweak: "Security bots will cable cuff people with hardsuit gauntlets instead of stun-locking."
|
||||||
|
- tweak: "Cut real time for security bots demanding surrender in half (6 seconds)."
|
||||||
Reference in New Issue
Block a user