Beepsky refactor and Bot code improvement (#62510)

This commit is contained in:
John Willard
2021-11-08 01:35:54 -08:00
committed by GitHub
parent bf960b1c83
commit b39ccd408e
35 changed files with 471 additions and 470 deletions
+1 -1
View File
@@ -8,7 +8,7 @@
var/preferred_form = null
if(isAdminGhostAI(src))
has_unlimited_silicon_privilege = 1
has_unlimited_silicon_privilege = TRUE
if(client.prefs.unlock_content)
preferred_form = client.prefs.read_preference(/datum/preference/choiced/ghost_form)
+1 -1
View File
@@ -1208,7 +1208,7 @@
Robot.connected_ai.disconnect_shell()
if(Robot.mmi)
qdel(Robot.mmi)
Robot.notify_ai(NEW_BORG)
Robot.notify_ai(AI_NOTIFICATION_NEW_BORG)
else
for(var/obj/item/item in src)
if(!dropItemToGround(item))
@@ -524,15 +524,15 @@
if(!connected_ai)
return
switch(notifytype)
if(NEW_BORG) //New Cyborg
if(AI_NOTIFICATION_NEW_BORG) //New Cyborg
to_chat(connected_ai, "<br><br>[span_notice("NOTICE - New cyborg connection detected: <a href='?src=[REF(connected_ai)];track=[html_encode(name)]'>[name]</a>")]<br>")
if(NEW_MODEL) //New Model
if(AI_NOTIFICATION_NEW_MODEL) //New Model
to_chat(connected_ai, "<br><br>[span_notice("NOTICE - Cyborg model change detected: [name] has loaded the [designation] model.")]<br>")
if(RENAME) //New Name
if(AI_NOTIFICATION_CYBORG_RENAMED) //New Name
to_chat(connected_ai, "<br><br>[span_notice("NOTICE - Cyborg reclassification detected: [oldname] is now designated as [newname].")]<br>")
if(AI_SHELL) //New Shell
if(AI_NOTIFICATION_AI_SHELL) //New Shell
to_chat(connected_ai, "<br><br>[span_notice("NOTICE - New cyborg shell detected: <a href='?src=[REF(connected_ai)];track=[html_encode(name)]'>[name]</a>")]<br>")
if(DISCONNECT) //Tampering with the wires
if(AI_NOTIFICATION_CYBORG_DISCONNECTED) //Tampering with the wires
to_chat(connected_ai, "<br><br>[span_notice("NOTICE - Remote telemetry lost with [name].")]<br>")
/mob/living/silicon/robot/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE, need_hands = FALSE, floor_okay=FALSE)
@@ -647,7 +647,7 @@
builtInCamera.toggle_cam(src,0)
if(admin_revive)
locked = TRUE
notify_ai(NEW_BORG)
notify_ai(AI_NOTIFICATION_NEW_BORG)
. = TRUE
toggle_headlamp(FALSE, TRUE) //This will reenable borg headlamps if doomsday is currently going on still.
@@ -656,7 +656,7 @@
. = ..()
if(!.)
return
notify_ai(RENAME, oldname, newname)
notify_ai(AI_NOTIFICATION_CYBORG_RENAMED, oldname, newname)
if(!QDELETED(builtInCamera))
builtInCamera.c_tag = real_name
custom_name = newname
@@ -252,7 +252,7 @@
cyborg.notransform = FALSE
cyborg.updatehealth()
cyborg.update_icons()
cyborg.notify_ai(NEW_MODEL)
cyborg.notify_ai(AI_NOTIFICATION_NEW_MODEL)
if(cyborg.hud_used)
cyborg.hud_used.update_robot_modules_display()
SSblackbox.record_feedback("tally", "cyborg_modules", 1, cyborg.model)
+1 -1
View File
@@ -1,6 +1,6 @@
/mob/living/silicon
gender = NEUTER
has_unlimited_silicon_privilege = 1
has_unlimited_silicon_privilege = TRUE
verb_say = "states"
verb_ask = "queries"
verb_exclaim = "declares"
@@ -5,7 +5,7 @@
icon_state = "grievous"
health = 150
maxHealth = 150
baton_type = /obj/item/melee/energy/sword/saber
weapon = /obj/item/melee/energy/sword/saber
base_speed = 4 //he's a fast fucker
var/block_chance = 50
weapon_force = 30
@@ -16,7 +16,7 @@
desc = "An adorable looking secbot with four toy swords taped to its arms"
health = 50
maxHealth = 50
baton_type = /obj/item/toy/sword
weapon = /obj/item/toy/sword
weapon_force = 0
/mob/living/simple_animal/bot/secbot/grievous/bullet_act(obj/projectile/P)
@@ -145,6 +145,6 @@
do_sparks(3, TRUE, src)
for(var/IS = 0 to 4)
drop_part(baton_type, Tsec)
drop_part(weapon, Tsec)
new /obj/effect/decal/cleanable/oil(Tsec)
qdel(src)
@@ -11,7 +11,7 @@
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
maxbodytemp = INFINITY
minbodytemp = 0
has_unlimited_silicon_privilege = 1
has_unlimited_silicon_privilege = TRUE
sentience_type = SENTIENCE_ARTIFICIAL
status_flags = NONE //no default canpush
pass_flags = PASSFLAPS
@@ -45,7 +45,8 @@
var/on = TRUE
var/open = FALSE//Maint panel
var/locked = TRUE
var/hacked = FALSE //Used to differentiate between being hacked by silicons and emagged by humans.
///If the bot is hacked by silicons or emagged by humans.
var/hacked = FALSE
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.
@@ -58,7 +59,7 @@
var/list/ignore_list = list() //List of unreachable targets for an ignore-list enabled bot to ignore.
var/mode = BOT_IDLE //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/remote_disabled = FALSE //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/radio/Radio //The bot's radio, for speaking to people.
var/radio_key = null //which channels can the bot listen to
@@ -79,7 +80,7 @@
var/beacon_freq = FREQ_NAV_BEACON
var/model = "" //The type of bot it is.
var/bot_type = 0 //The type of bot it is, for radio control.
var/bot_type = NONE //The type of bot it is, for radio control.
var/data_hud_type = DATA_HUD_DIAGNOSTIC_BASIC //The type of data HUD the bot uses. Diagnostic by default.
//This holds text for what the bot is mode doing, reported on the remote bot control interface. This is in order of the defines for the mode defines in robots.dm, in order
var/list/mode_name = list("In Pursuit","Preparing to Arrest", "Arresting", \
@@ -209,12 +210,11 @@
/mob/living/simple_animal/bot/emag_act(mob/user)
if(locked) //First emag application unlocks the bot's interface. Apply a screwdriver to use the emag again.
locked = FALSE
emagged = 1
to_chat(user, span_notice("You bypass [src]'s controls."))
return
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.
emagged = TRUE
remote_disabled = TRUE //Manually emagging the bot locks out the AI built in panel.
locked = TRUE //Access denied forever!
bot_reset()
turn_on() //The bot automatically turns on when emagged, unless recently hit with EMP.
@@ -274,7 +274,7 @@
ignorelistcleanuptimer++
if(!on || client)
return
return FALSE
if(commissioned && COOLDOWN_FINISHED(src, next_salute_check))
COOLDOWN_START(src, next_salute_check, salute_delay)
@@ -286,10 +286,10 @@
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
return FALSE
if(BOT_SUMMON) //Called to a location
bot_summon()
return
return FALSE
return TRUE //Successful completion. Used to prevent child process() continuing if this one is ended early.
@@ -330,29 +330,29 @@
to_chat(user, span_notice("Controls are now [locked ? "locked" : "unlocked"]."))
return TRUE
/mob/living/simple_animal/bot/attackby(obj/item/W, mob/living/user, params)
if(W.tool_behaviour == TOOL_SCREWDRIVER)
/mob/living/simple_animal/bot/attackby(obj/item/attacking_item, mob/living/user, params)
if(attacking_item.tool_behaviour == TOOL_SCREWDRIVER)
if(!locked)
open = !open
to_chat(user, span_notice("The maintenance panel is now [open ? "opened" : "closed"]."))
else
to_chat(user, span_warning("The maintenance panel is locked!"))
else if(W.GetID())
else if(attacking_item.GetID())
unlock_with_id(user)
else if(istype(W, /obj/item/paicard))
insertpai(user, W)
else if(W.tool_behaviour == TOOL_HEMOSTAT && paicard)
else if(istype(attacking_item, /obj/item/paicard))
insertpai(user, attacking_item)
else if(attacking_item.tool_behaviour == TOOL_HEMOSTAT && paicard)
if(open)
to_chat(user, span_warning("Close the access panel before manipulating the personality slot!"))
else
to_chat(user, span_notice("You attempt to pull [paicard] free..."))
if(do_after(user, 30, target = src))
if (paicard)
user.visible_message(span_notice("[user] uses [W] to pull [paicard] out of [bot_name]!"),span_notice("You pull [paicard] out of [bot_name] with [W]."))
user.visible_message(span_notice("[user] uses [attacking_item] to pull [paicard] out of [bot_name]!"),span_notice("You pull [paicard] out of [bot_name] with [attacking_item]."))
ejectpai(user)
else
user.changeNext_move(CLICK_CD_MELEE)
if(W.tool_behaviour == TOOL_WELDER && !user.combat_mode)
if(attacking_item.tool_behaviour == TOOL_WELDER && !user.combat_mode)
if(health >= maxHealth)
to_chat(user, span_warning("[src] does not need a repair!"))
return
@@ -360,11 +360,11 @@
to_chat(user, span_warning("Unable to repair with the maintenance panel closed!"))
return
if(W.use_tool(src, user, 0, volume=40))
if(attacking_item.use_tool(src, user, 0, volume=40))
adjustHealth(-10)
user.visible_message(span_notice("[user] repairs [src]!"),span_notice("You repair [src]."))
else
if(W.force) //if force is non-zero
if(attacking_item.force) //if force is non-zero
do_sparks(5, TRUE, src)
..()
@@ -728,7 +728,7 @@ Pass a positive integer as an argument to override a bot's default speed.
//PDA control. Some bots, especially MULEs, may have more parameters.
/mob/living/simple_animal/bot/proc/bot_control(command, mob/user, list/user_access = list())
if(!on || emagged == 2 || remote_disabled) //Emagged bots do not respect anyone's authority! Bots with their remote controls off cannot get commands.
if(!on || emagged || remote_disabled) //Emagged bots do not respect anyone's authority! Bots with their remote controls off cannot get commands.
return TRUE //ACCESS DENIED
if(client)
bot_control_message(command, user)
@@ -871,8 +871,8 @@ Pass a positive integer as an argument to override a bot's default speed.
if("remote")
remote_disabled = !remote_disabled
if("hack")
if(emagged != 2)
emagged = 2
if(!emagged)
emagged = TRUE
hacked = TRUE
locked = TRUE
to_chat(usr, span_warning("[text_hack]"))
@@ -911,7 +911,7 @@ Pass a positive integer as an argument to override a bot's default speed.
if(!user.canUseTopic(src, !issilicon(user)))
return TRUE
// 0 for access, 1 for denied.
if(emagged == 2) //An emagged bot cannot be controlled by humans, silicons can if one hacked it.
if(emagged) //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 TRUE
else if(!issilicon(user) && !isAdminGhostAI(user)) //Bot is hacked, so only silicons and admins are allowed access.
@@ -921,7 +921,7 @@ Pass a positive integer as an argument to override a bot's default speed.
/mob/living/simple_animal/bot/proc/hack(mob/user)
var/hack
if(issilicon(user) || isAdminGhostAI(user)) //Allows silicons or admins 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 += "[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'>[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>"
@@ -137,7 +137,7 @@
/mob/living/simple_animal/bot/cleanbot/bot_reset()
..()
if(weapon && emagged == 2)
if(weapon && emagged)
weapon.force = weapon_orig_force
ignore_list = list() //Allows the bot to clean targets it previously ignored due to being unreachable.
target = null
@@ -186,11 +186,12 @@
/mob/living/simple_animal/bot/cleanbot/emag_act(mob/user)
..()
if(emagged == 2)
if(weapon)
weapon.force = weapon_orig_force
if(user)
to_chat(user, span_danger("[src] buzzes and beeps."))
if(!emagged)
return
if(weapon)
weapon.force = weapon_orig_force
if(user)
to_chat(user, span_danger("[src] buzzes and beeps."))
/mob/living/simple_animal/bot/cleanbot/process_scan(atom/A)
if(iscarbon(A))
@@ -207,9 +208,8 @@
if(mode == BOT_CLEANING)
return
if(emagged == 2) //Emag functions
if(emagged) //Emag functions
if(isopenturf(loc))
for(var/mob/living/carbon/victim in loc)
if(victim != target)
UnarmedAttack(victim) // Acid spray
@@ -226,7 +226,7 @@
if(!process_scan(target))
target = null
if(!target && emagged == 2) // When emagged, target humans who slipped on the water and melt their faces off
if(!target && emagged) // When emagged, target humans who slipped on the water and melt their faces off
target = scan(/mob/living/carbon)
if(!target && pests) //Search for pests to exterminate first.
@@ -295,8 +295,8 @@
/obj/effect/decal/cleanable/greenglow,
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/insectguts,
/obj/effect/decal/remains
)
/obj/effect/decal/remains,
)
if(blood)
target_types += /obj/effect/decal/cleanable/xenoblood
@@ -343,7 +343,7 @@
living_target.death()
living_target = null
else if(emagged == 2) //Emag functions
else if(emagged) //Emag functions
if(istype(A, /mob/living/carbon))
var/mob/living/carbon/victim = A
if(victim.stat == DEAD)//cleanbots always finish the job
@@ -397,9 +397,9 @@
dat += hack(user)
dat += showpai(user)
dat += text({"
Status: <A href='?src=[REF(src)];power=1'>[on ? "On" : "Off"]</A><BR>
Behaviour controls are [locked ? "locked" : "unlocked"]<BR>
Maintenance panel panel is [open ? "opened" : "closed"]"})
Status: <A href='?src=[REF(src)];power=1'>[on ? "On" : "Off"]</A><BR>
Behaviour controls are [locked ? "locked" : "unlocked"]<BR>
Maintenance panel panel is [open ? "opened" : "closed"]"})
if(!locked || issilicon(user)|| isAdminGhostAI(user))
dat += "<BR>Clean Blood: <A href='?src=[REF(src)];operation=blood'>[blood ? "Yes" : "No"]</A>"
dat += "<BR>Clean Trash: <A href='?src=[REF(src)];operation=trash'>[trash ? "Yes" : "No"]</A>"
@@ -372,7 +372,7 @@
to_chat(user, span_notice("You complete the Securitron! Beep boop."))
var/mob/living/simple_animal/bot/secbot/S = new(Tsec)
S.name = created_name
S.baton_type = I.type
S.weapon = I.type
S.robot_arm = robot_arm
qdel(I)
qdel(src)
@@ -10,9 +10,9 @@
mob_size = MOB_SIZE_LARGE
model = "ED-209"
bot_type = ADVANCED_SEC_BOT
window_id = "autoed209"
window_name = "Automatic Security Unit v2.6"
ranged = TRUE
var/lastfired = 0
var/shot_delay = 15
var/shoot_sound = 'sound/weapons/laser.ogg'
@@ -40,32 +40,31 @@
/mob/living/simple_animal/bot/secbot/ed209/handle_automated_action()
var/judgement_criteria = judgement_criteria()
var/list/targets = list()
for(var/mob/living/carbon/C in view(7,src)) //Let's find us a target
for(var/mob/living/carbon/nearby_carbon in view(7, src)) //Let's find us a target
var/threatlevel = 0
if(C.incapacitated())
if(nearby_carbon.incapacitated())
continue
threatlevel = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
//speak(C.real_name + text(": threat: []", threatlevel))
threatlevel = nearby_carbon.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
if(threatlevel < 4 )
continue
var/dst = get_dist(src, C)
var/dst = get_dist(src, nearby_carbon)
if(dst <= 1 || dst > 7)
continue
targets += C
if(targets.len>0)
var/mob/living/carbon/t = pick(targets)
if(t.stat != DEAD && !t.handcuffed) //we don't shoot people who are dead, cuffed or lying down.
shootAt(t)
targets += nearby_carbon
if(targets.len > 0)
var/mob/living/carbon/all_targets = pick(targets)
if(all_targets.stat != DEAD && !all_targets.handcuffed) //we don't shoot people who are dead, cuffed or lying down.
shoot_at(all_targets)
..()
/mob/living/simple_animal/bot/secbot/ed209/proc/set_weapon() //used to update the projectile type and firing sound
shoot_sound = 'sound/weapons/laser.ogg'
if(emagged == 2)
if(emagged)
projectile = /obj/projectile/beam
else
projectile = /obj/projectile/beam/disabler
/mob/living/simple_animal/bot/secbot/ed209/proc/shootAt(mob/target)
/mob/living/simple_animal/bot/secbot/ed209/proc/shoot_at(mob/target)
if(world.time <= lastfired + shot_delay)
return
lastfired = world.time
@@ -75,14 +74,13 @@
return
if(!isturf(T))
return
if(!projectile)
return
var/obj/projectile/A = new projectile (loc)
var/obj/projectile/fired_bullet = new projectile(loc)
playsound(src, shoot_sound, 50, TRUE)
A.preparePixelProjectile(target, src)
A.fire()
fired_bullet.preparePixelProjectile(target, src)
fired_bullet.fire()
/mob/living/simple_animal/bot/secbot/ed209/emp_act(severity)
if(severity == 2 && prob(70))
@@ -90,34 +88,36 @@
. = ..()
if(. & EMP_PROTECT_SELF)
return
if (severity >= 2)
new /obj/effect/temp_visual/emp(loc)
var/list/mob/living/carbon/targets = new
for(var/mob/living/carbon/C in view(12,src))
if(C.stat==DEAD)
continue
targets += C
if(severity <= 1)
return
new /obj/effect/temp_visual/emp(loc)
var/list/mob/living/carbon/targets = list()
for(var/mob/living/carbon/nearby_carbons in view(12,src))
if(nearby_carbons.stat == DEAD)
continue
targets += nearby_carbons
if(!targets.len)
return
if(prob(50))
var/mob/toshoot = pick(targets)
if(toshoot)
targets -= toshoot
if(prob(50) && !emagged) // Temporarily emags it
emagged = TRUE
set_weapon()
shoot_at(toshoot)
emagged = FALSE
set_weapon()
else
shoot_at(toshoot)
else if(prob(50))
if(targets.len)
if(prob(50))
var/mob/toshoot = pick(targets)
if(toshoot)
targets-=toshoot
if(prob(50) && emagged < 2)
emagged = 2
set_weapon()
shootAt(toshoot)
emagged = FALSE
set_weapon()
else
shootAt(toshoot)
else if(prob(50))
if(targets.len)
var/mob/toarrest = pick(targets)
if(toarrest)
target = toarrest
mode = BOT_HUNT
var/mob/to_arrest = pick(targets)
if(to_arrest)
target = to_arrest
mode = BOT_HUNT
/mob/living/simple_animal/bot/secbot/ed209/RangedAttack(atom/A)
if(!on)
return
shootAt(A)
shoot_at(A)
@@ -126,7 +126,7 @@
/mob/living/simple_animal/bot/firebot/emag_act(mob/user)
..()
if(emagged == 2)
if(emagged)
if(user)
to_chat(user, span_danger("[src] buzzes and beeps."))
audible_message(span_danger("[src] buzzes oddly!"))
@@ -162,7 +162,7 @@
/mob/living/simple_animal/bot/firebot/proc/is_burning(atom/target)
if(ismob(target))
var/mob/living/M = target
if(M.on_fire || (emagged == 2 && !M.on_fire))
if(M.on_fire || (emagged && !M.on_fire))
return TRUE
else if(isturf(target))
@@ -210,7 +210,7 @@
old_target_fire = target_fire
// Target reached ENGAGE WATER CANNON
if(target_fire && (get_dist(src, target_fire) <= (emagged == 2 ? 1 : 2))) // Make the bot spray water from afar when not emagged
if(target_fire && (get_dist(src, target_fire) <= (emagged ? 1 : 2))) // Make the bot spray water from afar when not emagged
if((speech_cooldown + SPEECH_INTERVAL) < world.time)
if(ishuman(target_fire))
speak("Stop, drop and roll!")
@@ -143,9 +143,10 @@
/mob/living/simple_animal/bot/floorbot/emag_act(mob/user)
..()
if(emagged == 2)
if(user)
to_chat(user, span_danger("[src] buzzes and beeps."))
if(!emagged)
return
if(user)
to_chat(user, span_danger("[src] buzzes and beeps."))
///mobs should use move_resist instead of anchored.
/mob/living/simple_animal/bot/floorbot/proc/toggle_magnet(engage = TRUE, change_icon = TRUE)
@@ -205,7 +206,7 @@
audible_message("[src] makes an excited booping beeping sound!")
//Normal scanning procedure. We have tiles loaded, are not emagged.
if(!target && emagged < 2)
if(!target && emagged)
if(targetdirection != null) //The bot is in line mode.
var/turf/T = get_step(src, targetdirection)
if(isspaceturf(T)) //Check for space
@@ -229,7 +230,7 @@
process_type = REPLACE_TILE //The target must be a tile. The floor must already have a floortile.
target = scan(/turf/open/floor)
if(!target && emagged == 2) //We are emagged! Time to rip up the floors!
if(!target && emagged) //We are emagged! Time to rip up the floors!
process_type = TILE_EMAG
target = scan(/turf/open/floor)
@@ -251,9 +252,9 @@
target = null
path = list()
return
if(isturf(target) && emagged < 2)
if(isturf(target) && !emagged)
repair(target)
else if(emagged == 2 && isfloorturf(target))
else if(emagged && isfloorturf(target))
var/turf/open/floor/F = target
toggle_magnet()
mode = BOT_REPAIRING
@@ -106,7 +106,7 @@ Maintenance panel panel is [open ? "opened" : "closed"]"},
var/final = NONE
if(check_records)
final = final|JUDGE_RECORDCHECK
if(emagged == 2)
if(emagged)
final = final|JUDGE_EMAGGED
return final
@@ -133,13 +133,14 @@ Maintenance panel panel is [open ? "opened" : "closed"]"},
/mob/living/simple_animal/bot/honkbot/emag_act(mob/user)
..()
if(emagged == 2)
if(user)
user << span_danger("You short out [src]'s sound control system. It gives out an evil laugh!!")
oldtarget_name = user.name
audible_message(span_danger("[src] gives out an evil laugh!"))
playsound(src, 'sound/machines/honkbot_evil_laugh.ogg', 75, TRUE, -1) // evil laughter
update_appearance()
if(!emagged)
return
if(user)
to_chat(user, span_danger("You short out [src]'s sound control system. It gives out an evil laugh!!"))
oldtarget_name = user.name
audible_message(span_danger("[src] gives out an evil laugh!"))
playsound(src, 'sound/machines/honkbot_evil_laugh.ogg', 75, TRUE, -1) // evil laughter
update_appearance()
/mob/living/simple_animal/bot/honkbot/bullet_act(obj/projectile/Proj)
if((istype(Proj,/obj/projectile/beam)) || (istype(Proj,/obj/projectile/bullet) && (Proj.damage_type == BURN))||(Proj.damage_type == BRUTE) && (!Proj.nodamage && Proj.damage < health && ishuman(Proj.firer)))
@@ -153,7 +154,7 @@ Maintenance panel panel is [open ? "opened" : "closed"]"},
return
if(iscarbon(A))
var/mob/living/carbon/C = A
if (emagged <= 1)
if(emagged)
honk_attack(A)
else
if(!C.IsParalyzed() || arrest_type)
@@ -174,19 +175,19 @@ Maintenance panel panel is [open ? "opened" : "closed"]"},
..()
/mob/living/simple_animal/bot/honkbot/proc/bike_horn() //use bike_horn
if (emagged <= 1)
if (!limiting_spam)
playsound(src, honksound, 50, TRUE, -1)
limiting_spam = TRUE //prevent spam
sensor_blink()
addtimer(CALLBACK(src, .proc/limiting_spam_false), cooldowntimehorn)
else if (emagged == 2) //emagged honkbots will spam short and memorable sounds.
if (emagged) //emagged honkbots will spam short and memorable sounds.
if (!limiting_spam)
playsound(src, "honkbot_e", 50, FALSE)
limiting_spam = TRUE // prevent spam
icon_state = "honkbot-e"
addtimer(CALLBACK(src, /atom/.proc/update_appearance), 3 SECONDS, TIMER_OVERRIDE|TIMER_UNIQUE)
addtimer(CALLBACK(src, .proc/limiting_spam_false), cooldowntimehorn)
return
if (!limiting_spam)
playsound(src, honksound, 50, TRUE, -1)
limiting_spam = TRUE //prevent spam
sensor_blink()
addtimer(CALLBACK(src, .proc/limiting_spam_false), cooldowntimehorn)
/mob/living/simple_animal/bot/honkbot/proc/honk_attack(mob/living/carbon/C) // horn attack
if(!limiting_spam)
@@ -210,13 +211,14 @@ Maintenance panel panel is [open ? "opened" : "closed"]"},
var/mob/living/carbon/human/H = C
if(client) //prevent spam from players..
limiting_spam = TRUE
if (emagged <= 1) //HONK once, then leave
if (emagged) // you really don't want to hit an emagged honkbot
threatlevel = 6 // will never let you go
else
//HONK once, then leave
var/judgement_criteria = judgement_criteria()
threatlevel = H.assess_threat(judgement_criteria)
threatlevel -= 6
target = oldtarget_name
else // you really don't want to hit an emagged honkbot
threatlevel = 6 // will never let you go
addtimer(CALLBACK(src, .proc/limiting_spam_false), cooldowntime)
log_combat(src,C,"honked")
@@ -212,10 +212,10 @@
dat += hack(user)
dat += showpai(user)
dat += {"
<TT><B>Hygienebot X2 controls</B></TT><BR><BR>
Status: ["<A href='?src=[REF(src)];power=[TRUE]'>[on ? "On" : "Off"]</A>"]<BR>
Behaviour controls are [locked ? "locked" : "unlocked"]<BR>
Maintenance panel is [open ? "opened" : "closed"]"}
<TT><B>Hygienebot X2 controls</B></TT><BR><BR>
Status: ["<A href='?src=[REF(src)];power=[TRUE]'>[on ? "On" : "Off"]</A>"]<BR>
Behaviour controls are [locked ? "locked" : "unlocked"]<BR>
Maintenance panel is [open ? "opened" : "closed"]"}
if(!locked || issilicon(user) || isAdminGhostAI(user))
dat += {"<BR> Auto Patrol: ["<A href='?src=[REF(src)];operation=patrol'>[auto_patrol ? "On" : "Off"]</A>"]"}
@@ -223,7 +223,7 @@ Maintenance panel is [open ? "opened" : "closed"]"}
return dat.Join("")
/mob/living/simple_animal/bot/hygienebot/proc/check_purity(mob/living/L)
if((emagged == 2) && L.stat != DEAD)
if((emagged) && L.stat != DEAD)
return FALSE
for(var/X in list(ITEM_SLOT_HEAD, ITEM_SLOT_MASK, ITEM_SLOT_ICLOTHING, ITEM_SLOT_OCLOTHING, ITEM_SLOT_FEET))
@@ -222,15 +222,16 @@
/mob/living/simple_animal/bot/medbot/emag_act(mob/user)
..()
if(emagged == 2)
declare_crit = 0
if(user)
to_chat(user, span_notice("You short out [src]'s reagent synthesis circuits."))
audible_message(span_danger("[src] buzzes oddly!"))
flick("medibot_spark", src)
playsound(src, "sparks", 75, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
if(user)
oldpatient = user
if(!emagged)
return
declare_crit = FALSE
if(user)
to_chat(user, span_notice("You short out [src]'s reagent synthesis circuits."))
audible_message(span_danger("[src] buzzes oddly!"))
flick("medibot_spark", src)
playsound(src, "sparks", 75, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
if(user)
oldpatient = user
/mob/living/simple_animal/bot/medbot/process_scan(mob/living/carbon/human/H)
if(H.stat == DEAD)
@@ -445,7 +446,7 @@
if(C.suiciding)
return FALSE //Kevorkian school of robotic medical assistants.
if(emagged == 2) //Everyone needs our medicine. (Our medicine is toxins)
if(emagged) //Everyone needs our medicine. (Our medicine is toxins)
return TRUE
if(HAS_TRAIT(C,TRAIT_MEDIBOTCOMINGTHROUGH) && !HAS_TRAIT_FROM(C,TRAIT_MEDIBOTCOMINGTHROUGH,tag)) //the early medbot gets the worm (or in this case the patient)
@@ -542,7 +543,7 @@
if(damagetype_healer == "all" && potential_methods.len)
treatment_method = pick(potential_methods)
if(!treatment_method && emagged != 2) //If they don't need any of that they're probably cured!
if(!treatment_method && !emagged) //If they don't need any of that they're probably cured!
if(C.maxHealth - C.get_organic_health() < heal_threshold)
to_chat(src, span_notice("[C] is healthy! Your programming prevents you from tending the wounds of anyone without at least [heal_threshold] damage of any one type ([heal_threshold + 5] for oxygen damage.)"))
@@ -562,7 +563,7 @@
var/obj/item/storage/firstaid/FA = firstaid
if(treatment_method == BRUTE && initial(FA.damagetype_healed) == BRUTE) //specialized brute gets a bit of bonus, as a snack.
healies *= 1.1
if(emagged == 2)
if(emagged)
patient.reagents.add_reagent(/datum/reagent/toxin/chloralhydrate, 5)
patient.apply_damage_type((healies*1),treatment_method)
log_combat(src, patient, "pretended to tend wounds on", "internal tools", "([uppertext(treatment_method)]) (EMAGGED)")
@@ -23,34 +23,44 @@
combat_mode = TRUE
var/baton_type = /obj/item/melee/baton/security
var/obj/item/weapon
///The tool this Secbot will use to make arrests
var/obj/item/weapon = /obj/item/melee/baton/security
///Their current target
var/mob/living/carbon/target
///Name of their last target to prevent spamming
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
var/ranged = FALSE //used for EDs
///The threat level of the BOT, will arrest anyone at threatlevel 4 or above
var/threatlevel = 0
///The last location their target was seen at
var/target_lastloc
///Time since last seeing their perpetrator
var/last_found
var/fair_market_price_arrest = 25 // On arrest, charges the violator this much. If they don't have that much in their account, the securitron will beat them instead
var/fair_market_price_detain = 5 // Charged each time the violator is stunned on detain
var/weapon_force = 20 // Only used for NAP violation beatdowns on non-grievous securitrons
var/market_verb = "Suspect"
///Flags SecBOTs use on what to check on targets when arresting, and whether they should announce it to security/handcuff their target
var/security_mode_flags = SECBOT_DECLARE_ARRESTS | SECBOT_CHECK_RECORDS | SECBOT_HANDCUFF_TARGET
// Selections: SECBOT_DECLARE_ARRESTS | SECBOT_CHECK_IDS | SECBOT_CHECK_WEAPONS | SECBOT_CHECK_RECORDS | SECBOT_HANDCUFF_TARGET
///On arrest, charges the violator this much. If they don't have that much in their account, they will get beaten instead
var/fair_market_price_arrest = 25
///Charged each time the violator is stunned on detain
var/fair_market_price_detain = 5
/// Force of the harmbaton used on them
var/weapon_force = 20
///The department the secbot will deposit collected money into
var/payment_department = ACCOUNT_SEC
/mob/living/simple_animal/bot/secbot/beepsky
name = "Commander Beep O'sky"
desc = "It's Commander Beep O'sky! Officially the superior officer of all bots on station, Beepsky remains as humble and dedicated to the law as the day he was first fabricated."
idcheck = FALSE
weaponscheck = FALSE
auto_patrol = TRUE
commissioned = TRUE
/mob/living/simple_animal/bot/secbot/beepsky/armsky
name = "Sergeant-At-Armsky"
health = 45
auto_patrol = FALSE
security_mode_flags = SECBOT_DECLARE_ARRESTS | SECBOT_CHECK_IDS | SECBOT_CHECK_RECORDS
/mob/living/simple_animal/bot/secbot/beepsky/jr
name = "Officer Pipsqueak"
desc = "It's Commander Beep O'sky's smaller, just-as aggressive cousin, Pipsqueak."
@@ -61,22 +71,22 @@
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(/datum/reagent/consumable/ethanol/whiskey, 15)
..()
/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 = RADIO_CHANNEL_AI_PRIVATE
/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/drinking_oil = new(Tsec)
drinking_oil.reagents.add_reagent(/datum/reagent/consumable/ethanol/whiskey, 15)
..()
/mob/living/simple_animal/bot/secbot/Initialize(mapload)
. = ..()
weapon = new baton_type()
weapon = new weapon()
update_appearance(UPDATE_ICON)
// Doing this hurts my soul, but simplebot access reworks are for another day.
@@ -131,72 +141,70 @@
dat += hack(user)
dat += showpai(user)
dat += text({"
<TT><B>Securitron v1.6 controls</B></TT><BR><BR>
Status: []<BR>
Behaviour controls are [locked ? "locked" : "unlocked"]<BR>
Maintenance panel panel is [open ? "opened" : "closed"]"},
<TT><B>Securitron v1.6 controls</B></TT><BR><BR>
Status: []<BR>
Behaviour controls are [locked ? "locked" : "unlocked"]<BR>
Maintenance panel panel is [open ? "opened" : "closed"]"},
"<A href='?src=[REF(src)];power=1'>[on ? "On" : "Off"]</A>" )
"<A href='?src=[REF(src)];power=1'>[on ? "On" : "Off"]</A>")
if(!locked || issilicon(user) || isAdminGhostAI(user))
dat += text({"<BR>
Arrest Unidentifiable Persons: []<BR>
Arrest for Unauthorized Weapons: []<BR>
Arrest for Warrant: []<BR>
Operating Mode: []<BR>
Report Arrests[]<BR>
Auto Patrol: []"},
Arrest Unidentifiable Persons: []<BR>
Arrest for Unauthorized Weapons: []<BR>
Arrest for Warrant: []<BR>
Operating Mode: []<BR>
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>" )
"<A href='?src=[REF(src)];operation=idcheck'>[security_mode_flags & SECBOT_CHECK_IDS ? "Yes" : "No"]</A>",
"<A href='?src=[REF(src)];operation=weaponscheck'>[security_mode_flags & SECBOT_CHECK_WEAPONS ? "Yes" : "No"]</A>",
"<A href='?src=[REF(src)];operation=ignorerec'>[security_mode_flags & SECBOT_CHECK_RECORDS ? "Yes" : "No"]</A>",
"<A href='?src=[REF(src)];operation=switchmode'>[security_mode_flags & SECBOT_HANDCUFF_TARGET ? "Arrest" : "Detain"]</A>",
"<A href='?src=[REF(src)];operation=declarearrests'>[security_mode_flags & SECBOT_DECLARE_ARRESTS ? "Yes" : "No"]</A>",
"<A href='?src=[REF(src)];operation=patrol'>[auto_patrol ? "On" : "Off"]</A>")
return dat
/mob/living/simple_animal/bot/secbot/Topic(href, href_list)
if(..())
return 1
. = ..()
if(.)
return TRUE
switch(href_list["operation"])
if("idcheck")
idcheck = !idcheck
update_controls()
security_mode_flags ^= SECBOT_CHECK_IDS
if("weaponscheck")
weaponscheck = !weaponscheck
update_controls()
security_mode_flags ^= SECBOT_CHECK_WEAPONS
if("ignorerec")
check_records = !check_records
update_controls()
security_mode_flags ^= SECBOT_CHECK_RECORDS
if("switchmode")
arrest_type = !arrest_type
update_controls()
security_mode_flags ^= SECBOT_HANDCUFF_TARGET
if("declarearrests")
declare_arrests = !declare_arrests
update_controls()
security_mode_flags ^= SECBOT_DECLARE_ARRESTS
/mob/living/simple_animal/bot/secbot/proc/retaliate(mob/living/carbon/human/H)
update_controls()
/mob/living/simple_animal/bot/secbot/proc/retaliate(mob/living/carbon/human/attacking_human)
var/judgement_criteria = judgement_criteria()
threatlevel = H.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
threatlevel = attacking_human.assess_threat(judgement_criteria, weaponcheck = CALLBACK(src, .proc/check_for_weapons))
threatlevel += 6
if(threatlevel >= 4)
target = H
target = attacking_human
mode = BOT_HUNT
/mob/living/simple_animal/bot/secbot/proc/judgement_criteria()
var/final = FALSE
if(idcheck)
final |= JUDGE_IDCHECK
if(check_records)
final |= JUDGE_RECORDCHECK
if(weaponscheck)
final |= JUDGE_WEAPONCHECK
if(emagged == 2)
if(emagged)
final |= JUDGE_EMAGGED
if(ranged)
if(bot_type == ADVANCED_SEC_BOT)
final |= JUDGE_IGNOREMONKEYS
if(security_mode_flags & SECBOT_CHECK_IDS)
final |= JUDGE_IDCHECK
if(security_mode_flags & SECBOT_CHECK_RECORDS)
final |= JUDGE_RECORDCHECK
if(security_mode_flags & SECBOT_CHECK_WEAPONS)
final |= JUDGE_WEAPONCHECK
return final
/mob/living/simple_animal/bot/secbot/proc/special_retaliate_after_attack(mob/user) //allows special actions to take place after being attacked.
@@ -219,26 +227,26 @@ Auto Patrol: []"},
return ..()
/mob/living/simple_animal/bot/secbot/attackby(obj/item/W, mob/living/user, params)
/mob/living/simple_animal/bot/secbot/attackby(obj/item/attacking_item, mob/living/user, params)
..()
if(!on) // Bots won't remember if you hit them while they're off.
return
if(W.tool_behaviour == TOOL_WELDER && !user.combat_mode) // Any intent but harm will heal, so we shouldn't get angry.
if(attacking_item.tool_behaviour == TOOL_WELDER && !user.combat_mode) // Any intent but harm will heal, so we shouldn't get angry.
return
if(W.tool_behaviour != TOOL_SCREWDRIVER && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
if(attacking_item.tool_behaviour != TOOL_SCREWDRIVER && (attacking_item.force) && (!target) && (attacking_item.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
special_retaliate_after_attack(user)
/mob/living/simple_animal/bot/secbot/emag_act(mob/user)
..()
if(emagged == 2)
if(user)
to_chat(user, span_danger("You short out [src]'s target assessment circuits."))
oldtarget_name = user.name
audible_message(span_danger("[src] buzzes oddly!"))
declare_arrests = FALSE
update_appearance()
if(!emagged)
return
if(user)
to_chat(user, span_danger("You short out [src]'s target assessment circuits."))
oldtarget_name = user.name
audible_message(span_danger("[src] buzzes oddly!"))
security_mode_flags &= ~SECBOT_DECLARE_ARRESTS
update_appearance()
/mob/living/simple_animal/bot/secbot/bullet_act(obj/projectile/Proj)
if(istype(Proj , /obj/projectile/beam)||istype(Proj, /obj/projectile/bullet))
@@ -247,49 +255,48 @@ Auto Patrol: []"},
retaliate(Proj.firer)
return ..()
/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/A, proximity_flag, list/modifiers)
/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)
if(!on)
return
if(HAS_TRAIT(src, TRAIT_HANDS_BLOCKED))
return
if(iscarbon(A))
var/mob/living/carbon/C = A
if(!C.IsParalyzed() || arrest_type)
if(!check_nap_violations())
stun_attack(A, TRUE)
else
stun_attack(A)
else if(C.canBeHandcuffed() && !C.handcuffed)
cuff(A)
else
..()
if(!iscarbon(attack_target))
return ..()
var/mob/living/carbon/carbon_target = attack_target
if(!carbon_target.IsParalyzed() || !(security_mode_flags & SECBOT_HANDCUFF_TARGET))
if(!check_nap_violations())
stun_attack(attack_target, TRUE)
else
stun_attack(attack_target)
else if(carbon_target.canBeHandcuffed() && !carbon_target.handcuffed)
start_handcuffing(attack_target)
/mob/living/simple_animal/bot/secbot/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
if(istype(AM, /obj/item))
var/obj/item/I = AM
var/mob/thrown_by = I.thrownby?.resolve()
if(I.throwforce < src.health && thrown_by && ishuman(thrown_by))
var/mob/living/carbon/human/H = thrown_by
retaliate(H)
/mob/living/simple_animal/bot/secbot/hitby(atom/movable/hitting_atom, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
if(istype(hitting_atom, /obj/item))
var/obj/item/item_hitby = hitting_atom
var/mob/thrown_by = item_hitby.thrownby?.resolve()
if(item_hitby.throwforce < src.health && thrown_by && ishuman(thrown_by))
var/mob/living/carbon/human/human_throwee = thrown_by
retaliate(human_throwee)
..()
/mob/living/simple_animal/bot/secbot/proc/cuff(mob/living/carbon/C)
/mob/living/simple_animal/bot/secbot/proc/start_handcuffing(mob/living/carbon/current_target)
mode = BOT_ARREST
playsound(src, 'sound/weapons/cablecuff.ogg', 30, TRUE, -2)
C.visible_message(span_danger("[src] is trying to put zipties on [C]!"),\
current_target.visible_message(span_danger("[src] is trying to put zipties on [current_target]!"),\
span_userdanger("[src] is trying to put zipties on you!"))
addtimer(CALLBACK(src, .proc/attempt_handcuff, C), 60)
addtimer(CALLBACK(src, .proc/handcuff_target, target), 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.
/mob/living/simple_animal/bot/secbot/proc/handcuff_target(mob/living/carbon/current_target)
if(!on || !Adjacent(current_target) || !isturf(current_target.loc)) //if he's in a closet or not adjacent, we cancel cuffing.
return
if(!C.handcuffed)
C.set_handcuffed(new /obj/item/restraints/handcuffs/cable/zipties/used(C))
C.update_handcuffed()
if(!current_target.handcuffed)
current_target.set_handcuffed(new /obj/item/restraints/handcuffs/cable/zipties/used(current_target))
current_target.update_handcuffed()
playsound(src, "law", 50, FALSE)
back_to_idle()
/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/C, harm = FALSE)
/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/current_target, harm = FALSE)
var/judgement_criteria = judgement_criteria()
playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
icon_state = "[initial(icon_state)]-c"
@@ -297,84 +304,81 @@ Auto Patrol: []"},
var/threat = 5
if(harm)
weapon.attack(C, src)
if(ishuman(C))
C.stuttering = 5
C.Paralyze(100)
var/mob/living/carbon/human/H = C
threat = H.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
weapon.attack(current_target, src)
if(ishuman(current_target))
current_target.stuttering = 5
current_target.Paralyze(100)
var/mob/living/carbon/human/human_target = current_target
threat = human_target.assess_threat(judgement_criteria, weaponcheck = CALLBACK(src, .proc/check_for_weapons))
else
C.Paralyze(100)
C.stuttering = 5
threat = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
current_target.Paralyze(100)
current_target.stuttering = 5
threat = current_target.assess_threat(judgement_criteria, weaponcheck = CALLBACK(src, .proc/check_for_weapons))
log_combat(src,C,"stunned")
if(declare_arrests)
log_combat(src, target, "stunned")
if(security_mode_flags & SECBOT_DECLARE_ARRESTS)
var/area/location = get_area(src)
speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag <b>[C]</b> in [location].", radio_channel)
C.visible_message(span_danger("[src] stuns [C]!"),\
speak("[security_mode_flags & SECBOT_HANDCUFF_TARGET ? "Arresting" : "Detaining"] level [threat] scumbag <b>[current_target]</b> in [location].", radio_channel)
current_target.visible_message(span_danger("[src] stuns [current_target]!"),\
span_userdanger("[src] stuns you!"))
/mob/living/simple_animal/bot/secbot/handle_automated_action()
if(!..())
. = ..()
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
if(!check_nap_violations())
stun_attack(target, TRUE)
else
stun_attack(target)
mode = BOT_PREP_ARREST
set_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
if(!target) // make sure target exists
back_to_idle()
return
if(Adjacent(target) && isturf(target.loc)) // if right next to perp
if(!check_nap_violations())
stun_attack(target, TRUE)
else
stun_attack(target)
mode = BOT_PREP_ARREST
set_anchored(TRUE)
target_lastloc = target.loc
return
// 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
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.AmountParalyzed() < 40)
if(!Adjacent(target) || !isturf(target.loc) || target.AmountParalyzed() < 40)
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
if(!iscarbon(target) || !target.canBeHandcuffed())
back_to_idle()
return
if(security_mode_flags & SECBOT_HANDCUFF_TARGET)
if(!target.handcuffed) //he's not cuffed? Try to cuff him!
start_handcuffing(target)
else
back_to_idle()
return
if(BOT_ARREST)
if(!target)
@@ -406,9 +410,6 @@ Auto Patrol: []"},
look_for_perp()
bot_patrol()
return
/mob/living/simple_animal/bot/secbot/proc/back_to_idle()
set_anchored(FALSE)
mode = BOT_IDLE
@@ -427,32 +428,30 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/proc/look_for_perp()
set_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))
for(var/mob/living/carbon/nearby_carbons in view(7,src)) //Let's find us a criminal
if((nearby_carbons.stat) || (nearby_carbons.handcuffed))
continue
if((C.name == oldtarget_name) && (world.time < last_found + 100))
if((nearby_carbons.name == oldtarget_name) && (world.time < last_found + 100))
continue
threatlevel = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
threatlevel = nearby_carbons.assess_threat(judgement_criteria, weaponcheck = CALLBACK(src, .proc/check_for_weapons))
if(!threatlevel)
continue
else if(threatlevel >= 4)
target = C
oldtarget_name = C.name
if(threatlevel >= 4)
target = nearby_carbons
oldtarget_name = nearby_carbons.name
speak("Level [threatlevel] infraction alert!")
if(ranged)
if(bot_type == ADVANCED_SEC_BOT)
playsound(src, pick('sound/voice/ed209_20sec.ogg', 'sound/voice/edplaceholder.ogg'), 50, FALSE)
else
playsound(src, pick('sound/voice/beepsky/criminal.ogg', 'sound/voice/beepsky/justice.ogg', 'sound/voice/beepsky/freeze.ogg'), 50, FALSE)
visible_message("<b>[src]</b> points at [C.name]!")
visible_message("<b>[src]</b> points at [nearby_carbons.name]!")
mode = BOT_HUNT
INVOKE_ASYNC(src, .proc/handle_automated_action)
break
else
continue
/mob/living/simple_animal/bot/secbot/proc/check_for_weapons(obj/item/slot_item)
if(slot_item && (slot_item.item_flags & NEEDS_PERMIT))
@@ -461,18 +460,18 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/explode()
walk_to(src,0)
walk_to(src, 0)
visible_message(span_boldannounce("[src] blows apart!"))
var/atom/Tsec = drop_location()
if(ranged)
var/obj/item/bot_assembly/ed209/Sa = new (Tsec)
Sa.build_step = 1
Sa.add_overlay("hs_hole")
Sa.created_name = name
if(bot_type == ADVANCED_SEC_BOT)
var/obj/item/bot_assembly/ed209/ed_assembly = new(Tsec)
ed_assembly.build_step = ASSEMBLY_FIRST_STEP
ed_assembly.add_overlay("hs_hole")
ed_assembly.created_name = name
new /obj/item/assembly/prox_sensor(Tsec)
var/obj/item/gun/energy/disabler/G = new (Tsec)
G.cell.charge = 0
G.update_appearance()
var/obj/item/gun/energy/disabler/disabler_gun = new(Tsec)
disabler_gun.cell.charge = 0
disabler_gun.update_appearance()
if(prob(50))
new /obj/item/bodypart/l_leg/robot(Tsec)
if(prob(25))
@@ -483,12 +482,12 @@ Auto Patrol: []"},
else
new /obj/item/clothing/suit/armor/vest(Tsec)
else
var/obj/item/bot_assembly/secbot/Sa = new (Tsec)
Sa.build_step = 1
Sa.add_overlay("hs_hole")
Sa.created_name = name
var/obj/item/bot_assembly/secbot/secbot_assembly = new(Tsec)
secbot_assembly.build_step = ASSEMBLY_FIRST_STEP
secbot_assembly.add_overlay("hs_hole")
secbot_assembly.created_name = name
new /obj/item/assembly/prox_sensor(Tsec)
drop_part(baton_type, Tsec)
drop_part(weapon, Tsec)
if(prob(50))
drop_part(robot_arm, Tsec)
@@ -511,7 +510,6 @@ Auto Patrol: []"},
if(!istype(C) || !C || in_range(src, target))
return
knockOver(C)
return
/obj/machinery/bot_core/secbot
req_access = list(ACCESS_SECURITY)
@@ -520,32 +518,31 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/proc/check_nap_violations()
if(!SSeconomy.full_ancap)
return TRUE
if(target)
if(ishuman(target))
var/mob/living/carbon/human/H = target
var/obj/item/card/id/I = H.get_idcard(TRUE)
if(I)
var/datum/bank_account/insurance = I.registered_account
if(!insurance)
say("[market_verb] NAP Violation: No bank account found.")
nap_violation(target)
return FALSE
else
var/fair_market_price = (arrest_type ? fair_market_price_detain : fair_market_price_arrest)
if(!insurance.adjust_money(-fair_market_price))
say("[market_verb] NAP Violation: Unable to pay.")
nap_violation(target)
return FALSE
var/datum/bank_account/D = SSeconomy.get_dep_account(payment_department)
say("Thank you for your compliance. Your account been charged [fair_market_price] credits.")
if(D)
D.adjust_money(fair_market_price)
else
say("[market_verb] NAP Violation: No ID card found.")
nap_violation(target)
return FALSE
return TRUE
if(!target)
return TRUE
if(!ishuman(target))
return TRUE
var/mob/living/carbon/human/human_target = target
var/obj/item/card/id/target_id = human_target.get_idcard()
if(!target_id)
say("Suspect NAP Violation: No ID card found.")
nap_violation(target)
return FALSE
var/datum/bank_account/insurance = target_id.registered_account
if(!insurance)
say("Suspect NAP Violation: No bank account found.")
nap_violation(target)
return FALSE
var/fair_market_price = (security_mode_flags & SECBOT_HANDCUFF_TARGET ? fair_market_price_detain : fair_market_price_arrest)
if(!insurance.adjust_money(-fair_market_price))
say("Suspect NAP Violation: Unable to pay.")
nap_violation(target)
return FALSE
var/datum/bank_account/beepsky_department_account = SSeconomy.get_dep_account(payment_department)
say("Thank you for your compliance. Your account been charged [fair_market_price] credits.")
if(beepsky_department_account)
beepsky_department_account.adjust_money(fair_market_price)
return TRUE
/// Does nothing
/mob/living/simple_animal/bot/secbot/proc/nap_violation(mob/violator)
@@ -39,7 +39,7 @@
bubble_icon = "machine"
initial_language_holder = /datum/language_holder/drone
mob_size = MOB_SIZE_SMALL
has_unlimited_silicon_privilege = 1
has_unlimited_silicon_privilege = TRUE
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
hud_possible = list(DIAG_STAT_HUD, DIAG_HUD, ANTAG_HUD)
unique_name = TRUE
+1 -1
View File
@@ -169,7 +169,7 @@
var/status_flags = CANSTUN|CANKNOCKDOWN|CANUNCONSCIOUS|CANPUSH
/// Can they interact with station electronics
var/has_unlimited_silicon_privilege = 0
var/has_unlimited_silicon_privilege = FALSE
///Used by admins to possess objects. All mobs should have this var
var/obj/control_object
+1 -1
View File
@@ -154,7 +154,7 @@
R.mmi.brainmob.name = real_name
R.job = "Cyborg"
R.notify_ai(NEW_BORG)
R.notify_ai(AI_NOTIFICATION_NEW_BORG)
. = R
if(R.ckey && is_banned_from(R.ckey, "Cyborg"))