From 751dc6da3fae7716c9637691df1fe8ec8802acae Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Mon, 13 Feb 2023 11:49:33 -0500 Subject: [PATCH 01/20] the fuzz --- code/controllers/subsystem/traumas.dm | 4 +- code/datums/components/crafting/recipes.dm | 5 +- .../devil/true_devil/_true_devil.dm | 2 +- code/modules/mob/living/carbon/alien/alien.dm | 2 +- code/modules/mob/living/carbon/human/human.dm | 10 +- .../mob/living/carbon/monkey/monkey.dm | 8 +- code/modules/mob/living/silicon/silicon.dm | 2 +- .../living/simple_animal/bot/SuperBeepsky.dm | 4 +- .../living/simple_animal/bot/construction.dm | 93 +--- .../mob/living/simple_animal/bot/ed209bot.dm | 504 +----------------- .../mob/living/simple_animal/bot/honkbot.dm | 14 +- .../mob/living/simple_animal/bot/secbot.dm | 79 ++- .../simple_animal/friendly/drone/_drone.dm | 2 +- code/modules/mob/mob.dm | 2 +- code/modules/spells/spell_types/conjure.dm | 4 +- code/modules/spells/spell_types/shapeshift.dm | 2 +- 16 files changed, 129 insertions(+), 608 deletions(-) diff --git a/code/controllers/subsystem/traumas.dm b/code/controllers/subsystem/traumas.dm index 3774784febc43..6211a01ca3451 100644 --- a/code/controllers/subsystem/traumas.dm +++ b/code/controllers/subsystem/traumas.dm @@ -36,7 +36,7 @@ SUBSYSTEM_DEF(traumas) ) phobia_mobs = list("spiders" = typecacheof(list(/mob/living/simple_animal/hostile/poison/giant_spider)), - "security" = typecacheof(list(/mob/living/simple_animal/bot/secbot, /mob/living/simple_animal/bot/ed209)), + "security" = typecacheof(list(/mob/living/simple_animal/bot/secbot)), "lizards" = typecacheof(list(/mob/living/simple_animal/hostile/lizard)), "skeletons" = typecacheof(list(/mob/living/simple_animal/hostile/skeleton)), "snakes" = typecacheof(list(/mob/living/simple_animal/hostile/retaliate/poison/snake)), @@ -46,7 +46,7 @@ SUBSYSTEM_DEF(traumas) "the supernatural" = typecacheof(list(/mob/living/simple_animal/hostile/construct, /mob/living/simple_animal/revenant, /mob/living/simple_animal/shade)), "aliens" = typecacheof(list(/mob/living/carbon/alien, /mob/living/simple_animal/slime)), - "conspiracies" = typecacheof(list(/mob/living/simple_animal/bot/secbot, /mob/living/simple_animal/bot/ed209, /mob/living/simple_animal/drone, + "conspiracies" = typecacheof(list(/mob/living/simple_animal/bot/secbot, /mob/living/simple_animal/drone, /mob/living/simple_animal/pet/penguin)), "birds" = typecacheof(list(/mob/living/simple_animal/parrot, /mob/living/simple_animal/chick, /mob/living/simple_animal/chicken, /mob/living/simple_animal/pet/penguin)), diff --git a/code/datums/components/crafting/recipes.dm b/code/datums/components/crafting/recipes.dm index db8ee7245289a..a5924f2b5cd04 100644 --- a/code/datums/components/crafting/recipes.dm +++ b/code/datums/components/crafting/recipes.dm @@ -158,7 +158,7 @@ /datum/crafting_recipe/ed209 name = "ED209" - result = /mob/living/simple_animal/bot/ed209 + result = /mob/living/simple_animal/bot/secbot/ed209 reqs = list(/obj/item/robot_suit = 1, /obj/item/clothing/head/helmet = 1, /obj/item/clothing/suit/armor/vest = 1, @@ -166,8 +166,7 @@ /obj/item/bodypart/r_leg/robot = 1, /obj/item/stack/sheet/iron = 1, /obj/item/stack/cable_coil = 1, - /obj/item/gun/energy/e_gun/dragnet = 1, - /obj/item/stock_parts/cell = 1, + /obj/item/gun/energy/disabler = 1, /obj/item/assembly/prox_sensor = 1) tools = list(TOOL_WELDER, TOOL_SCREWDRIVER) time = 60 diff --git a/code/modules/antagonists/devil/true_devil/_true_devil.dm b/code/modules/antagonists/devil/true_devil/_true_devil.dm index 58659ec13d9f1..4d53ad3931ada 100644 --- a/code/modules/antagonists/devil/true_devil/_true_devil.dm +++ b/code/modules/antagonists/devil/true_devil/_true_devil.dm @@ -103,7 +103,7 @@ return FALSE return TRUE -/mob/living/carbon/true_devil/assess_threat(judgment_criteria, lasercolor = "", datum/callback/weaponcheck=null) +/mob/living/carbon/true_devil/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) return 666 /mob/living/carbon/true_devil/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0) diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index 6d6396d172fc1..322ba19a12fb9 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -38,7 +38,7 @@ internal_organs += new /obj/item/organ/ears return ..() -/mob/living/carbon/alien/assess_threat(judgment_criteria, lasercolor = "", datum/callback/weaponcheck=null) // beepsky won't hunt aliums +/mob/living/carbon/alien/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) // beepsky won't hunt aliums return -10 /mob/living/carbon/alien/handle_environment(datum/gas_mixture/environment) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index b3b35ad5d61c6..e3545514ff8d2 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -448,8 +448,8 @@ return FALSE return TRUE -/mob/living/carbon/human/assess_threat(judgment_criteria, lasercolor = "", datum/callback/weaponcheck=null) - if(judgment_criteria & JUDGE_EMAGGED) +/mob/living/carbon/human/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) + if(judgement_criteria & JUDGE_EMAGGED) return 10 //Everyone is a criminal! var/threatcount = 0 @@ -476,11 +476,11 @@ //Check for ID var/obj/item/card/id/idcard = get_idcard(FALSE) - if( (judgment_criteria & JUDGE_IDCHECK) && !idcard && name=="Unknown") + if( (judgement_criteria & JUDGE_IDCHECK) && !idcard && name=="Unknown") threatcount += 4 //Check for weapons - if( (judgment_criteria & JUDGE_WEAPONCHECK) && weaponcheck) + if( (judgement_criteria & JUDGE_WEAPONCHECK) && weaponcheck) if(!idcard || !(ACCESS_WEAPONS in idcard.access)) for(var/obj/item/I in held_items) //if they're holding a gun if(weaponcheck.Invoke(I)) @@ -489,7 +489,7 @@ threatcount += 2 //not enough to trigger look_for_perp() on it's own unless they also have criminal status. //Check for arrest warrant - if(judgment_criteria & JUDGE_RECORDCHECK) + if(judgement_criteria & JUDGE_RECORDCHECK) var/perpname = get_face_name(get_id_name()) var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.security) if(R && R.fields["criminal"]) diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index 83725e88b04f7..eda101d4c41d8 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -121,14 +121,14 @@ GLOBAL_LIST_INIT(strippable_monkey_items, create_strippable_list(list( /mob/living/carbon/monkey/canBeHandcuffed() return TRUE -/mob/living/carbon/monkey/assess_threat(judgment_criteria, lasercolor = "", datum/callback/weaponcheck=null) - if(judgment_criteria & JUDGE_EMAGGED) +/mob/living/carbon/monkey/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) + if(judgement_criteria & JUDGE_EMAGGED) return 10 //Everyone is a criminal! var/threatcount = 0 //Securitrons can't identify monkeys - if( !(judgment_criteria & JUDGE_IGNOREMONKEYS) && (judgment_criteria & JUDGE_IDCHECK) ) + if( !(judgement_criteria & JUDGE_IGNOREMONKEYS) && (judgement_criteria & JUDGE_IDCHECK) ) threatcount += 4 //Lasertag bullshit @@ -144,7 +144,7 @@ GLOBAL_LIST_INIT(strippable_monkey_items, create_strippable_list(list( return threatcount //Check for weapons - if( (judgment_criteria & JUDGE_WEAPONCHECK) && weaponcheck ) + if( (judgement_criteria & JUDGE_WEAPONCHECK) && weaponcheck ) for(var/obj/item/I in held_items) //if they're holding a gun if(weaponcheck.Invoke(I)) threatcount += 4 diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 8f214bcd7dfdf..a98694f11b091 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -433,7 +433,7 @@ return 0 -/mob/living/silicon/assess_threat(judgment_criteria, lasercolor = "", datum/callback/weaponcheck=null) //Secbots won't hunt silicon units +/mob/living/silicon/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) //Secbots won't hunt silicon units return -10 /mob/living/silicon/proc/remove_sensors() diff --git a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm index e61cb0a0f0044..bab7bc405a5e7 100644 --- a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm +++ b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm @@ -111,7 +111,7 @@ /mob/living/simple_animal/bot/secbot/grievous/look_for_perp() anchored = FALSE - var/judgment_criteria = judgment_criteria() + 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 @@ -119,7 +119,7 @@ if((C.name == oldtarget_name) && (world.time < last_found + 100)) continue - threatlevel = C.assess_threat(judgment_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) + threatlevel = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) if(!threatlevel) continue diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index 3beef6741982c..46def9188a276 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -100,21 +100,14 @@ build_step++ if(ASSEMBLY_THIRD_STEP) - var/newcolor = "" - if(istype(W, /obj/item/clothing/suit/redtag)) - newcolor = "r" - else if(istype(W, /obj/item/clothing/suit/bluetag)) - newcolor = "b" - if(newcolor || istype(W, /obj/item/clothing/suit/armor/vest)) + if(istype(W, /obj/item/clothing/suit/armor/vest)) if(!user.temporarilyRemoveItemFromInventory(W)) return - lasercolor = newcolor - vest_type = W.type to_chat(user, "You add [W] to [src].") qdel(W) name = "vest/legs/frame assembly" - item_state = "[lasercolor]ed209_shell" - icon_state = "[lasercolor]ed209_shell" + item_state = "ed209_shell" + icon_state = "ed209_shell" build_step++ if(ASSEMBLY_FOURTH_STEP) @@ -125,27 +118,15 @@ build_step++ if(ASSEMBLY_FIFTH_STEP) - switch(lasercolor) - if("b") - if(!istype(W, /obj/item/clothing/head/helmet/bluetaghelm)) - return - - if("r") - if(!istype(W, /obj/item/clothing/head/helmet/redtaghelm)) - return - - if("") - if(!istype(W, /obj/item/clothing/head/helmet)) - return - - if(!user.temporarilyRemoveItemFromInventory(W)) - return - to_chat(user, "You add [W] to [src].") - qdel(W) - name = "covered and shielded frame assembly" - item_state = "[lasercolor]ed209_hat" - icon_state = "[lasercolor]ed209_hat" - build_step++ + if(istype(W, /obj/item/clothing/head/helmet)) + if(!user.temporarilyRemoveItemFromInventory(W)) + return + to_chat(user, "You add [W] to [src].") + qdel(W) + name = "covered and shielded frame assembly" + item_state = "ed209_hat" + icon_state = "ed209_hat" + build_step++ if(5) if(isprox(W)) @@ -155,8 +136,8 @@ to_chat(user, "You add [W] to [src].") qdel(W) name = "covered, shielded and sensored frame assembly" - item_state = "[lasercolor]ed209_prox" - icon_state = "[lasercolor]ed209_prox" + item_state = "ed209_prox" + icon_state = "ed209_prox" if(6) if(istype(W, /obj/item/stack/cable_coil)) @@ -173,46 +154,24 @@ build_step++ if(7) - switch(lasercolor) - if("b") - if(!istype(W, /obj/item/gun/energy/laser/bluetag)) - return - if("r") - if(!istype(W, /obj/item/gun/energy/laser/redtag)) - return - if("") - if(!istype(W, /obj/item/gun/energy/disabler)) - return - else + if(istype(W, /obj/item/gun/energy/disabler)) + if(!user.temporarilyRemoveItemFromInventory(W)) return - if(!user.temporarilyRemoveItemFromInventory(W)) - return - name = "[W.name] ED-209 assembly" - to_chat(user, "You add [W] to [src].") - item_state = "[lasercolor]ed209_taser" - icon_state = "[lasercolor]ed209_taser" - qdel(W) - build_step++ + name = "[W.name] ED-209 assembly" + to_chat(user, "You add [W] to [src].") + item_state = "ed209_taser" + icon_state = "ed209_taser" + qdel(W) + build_step++ if(8) if(W.tool_behaviour == TOOL_SCREWDRIVER) to_chat(user, "You start attaching the gun to the frame...") if(W.use_tool(src, user, 40, volume=100)) - name = "armed [name]" - to_chat(user, "The gun is now securely fastened to the frame.") - build_step++ - - if(9) - if(istype(W, /obj/item/stock_parts/cell)) - if(!can_finish_build(W, user)) - return - var/mob/living/simple_animal/bot/ed209/B = new(drop_location(),created_name,lasercolor) - to_chat(user, "You complete the ED-209.") - B.cell_type = W.type - qdel(W) - B.vest_type = vest_type - qdel(src) - + var/mob/living/simple_animal/bot/secbot/ed209/B = new(drop_location()) + B.name = created_name + to_chat(user, "You complete the ED-209.") + qdel(src) //Floorbot assemblies /obj/item/bot_assembly/floorbot diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm index 324f8541875d9..5ab772db396e5 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -1,439 +1,72 @@ -/mob/living/simple_animal/bot/ed209 +/mob/living/simple_animal/bot/secbot/ed209 name = "\improper ED-209 Security Robot" - desc = "A security robot. He looks less than thrilled." - icon = 'icons/mob/aibots.dmi' + desc = "A security robot. He looks less than thrilled." icon_state = "ed2090" density = TRUE - anchored = FALSE health = 100 maxHealth = 100 - damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) obj_damage = 60 environment_smash = ENVIRONMENT_SMASH_WALLS //Walls can't stop THE LAW mob_size = MOB_SIZE_LARGE - radio_key = /obj/item/encryptionkey/headset_sec - radio_channel = RADIO_CHANNEL_SECURITY - bot_type = SEC_BOT model = "ED-209" - bot_core_type = /obj/machinery/bot_core/secbot window_id = "autoed209" window_name = "Automatic Security Unit v2.6" - allow_pai = 0 - data_hud_type = DATA_HUD_SECURITY_ADVANCED - path_image_color = "#FF0000" - + ranged = TRUE var/lastfired = 0 var/shot_delay = 15 - var/lasercolor = "" - var/disabled = FALSE //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/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/declare_arrests = TRUE //When making an arrest, should it notify everyone wearing sechuds? - var/idcheck = TRUE //If true, arrest people with no IDs - var/weaponscheck = TRUE //If true, arrest people for weapons if they don't have access - var/check_records = TRUE //Does it check security records? - var/arrest_type = FALSE //If true, don't handcuff - var/projectile = /obj/item/projectile/energy/electrode //Holder for projectile type - var/shoot_sound = 'sound/weapons/taser2.ogg' - var/cell_type = /obj/item/stock_parts/cell - var/vest_type = /obj/item/clothing/suit/armor/vest - + var/shoot_sound = 'sound/weapons/laser.ogg' + var/projectile = /obj/item/projectile/beam/disabler + var/fair_market_projectile = /obj/item/projectile/bullet/c38 // For shooting the worst scumbags of all: the poor do_footstep = TRUE -/mob/living/simple_animal/bot/ed209/Initialize(mapload,created_name,created_lasercolor) +/mob/living/simple_animal/bot/secbot/ed209/Initialize(mapload) . = ..() - if(created_name) - name = created_name - if(created_lasercolor) - lasercolor = created_lasercolor - icon_state = "[lasercolor]ed209[on]" set_weapon() //giving it the right projectile and firing sound. - var/datum/job/detective/J = new/datum/job/detective - access_card.access += J.get_access() - prev_access = access_card.access - 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 - bot_core.req_access = list(ACCESS_MAINT_TUNNELS, ACCESS_THEATRE) - arrest_type = 1 - if((lasercolor == "b") && (name == "\improper 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 == "\improper ED-209 Security Robot")) - name = pick("RED RAMPAGE","RED ROVER","RED KILLDEATH MURDERBOT") - - //SECHUD - var/datum/atom_hud/secsensor = GLOB.huds[DATA_HUD_SECURITY_ADVANCED] - secsensor.add_hud_to(src) - -/mob/living/simple_animal/bot/ed209/turn_on() - . = ..() - icon_state = "[lasercolor]ed209[on]" - mode = BOT_IDLE - -/mob/living/simple_animal/bot/ed209/turn_off() - ..() - icon_state = "[lasercolor]ed209[on]" -/mob/living/simple_animal/bot/ed209/bot_reset() +/mob/living/simple_animal/bot/secbot/ed209/bot_reset() ..() - target = null - oldtarget_name = null - anchored = FALSE - SSmove_manager.stop_looping(src) - last_found = world.time set_weapon() -/mob/living/simple_animal/bot/ed209/electrocute_act(shock_damage, source, siemens_coeff = 1, safety = FALSE, override = FALSE, tesla_shock = FALSE, illusion = FALSE, stun = TRUE) - return 0 - -/mob/living/simple_animal/bot/ed209/set_custom_texts() +/mob/living/simple_animal/bot/secbot/ed209/set_custom_texts() text_hack = "You disable [name]'s combat inhibitor." text_dehack = "You restore [name]'s combat inhibitor." text_dehack_fail = "[name] ignores your attempts to restrict him!" -/mob/living/simple_animal/bot/ed209/get_controls(mob/user) - var/dat - dat += hack(user) - dat += showpai(user) - dat += text({" -Security Unit v2.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)) - if(!lasercolor) - 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/ed209/Topic(href, href_list) - if(lasercolor && ishuman(usr)) - 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(..()) - 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/ed209/proc/judgment_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 - //ED209's ignore monkeys - final = final|JUDGE_IGNOREMONKEYS - return final - -/mob/living/simple_animal/bot/ed209/proc/retaliate(mob/living/carbon/human/H) - var/judgment_criteria = judgment_criteria() - threatlevel = H.assess_threat(judgment_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) - threatlevel += 6 - if(threatlevel >= 4) - target = H - mode = BOT_HUNT - -/mob/living/simple_animal/bot/ed209/attack_hand(mob/living/carbon/human/H) - if(H.a_intent == INTENT_HARM) - retaliate(H) - return ..() - -/mob/living/simple_animal/bot/ed209/attackby(obj/item/W, mob/user, params) +/mob/living/simple_animal/bot/secbot/ed209/on_emag(atom/target, mob/user) ..() - if(W.tool_behaviour == TOOL_WELDER && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry. - return - if(W.tool_behaviour != TOOL_SCREWDRIVER && (!target)) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass. - if(W.force && W.damtype != STAMINA)//If force is non-zero and damage type isn't stamina. - retaliate(user) - if(lasercolor)//To make up for the fact that lasertag bots don't hunt - shootAt(user) - -/mob/living/simple_animal/bot/ed209/on_emag(atom/target, 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 - icon_state = "[lasercolor]ed209[on]" - set_weapon() - -/mob/living/simple_animal/bot/ed209/bullet_act(obj/item/projectile/Proj) - if(istype(Proj , /obj/item/projectile/beam/laser)||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) - return ..() - -/mob/living/simple_animal/bot/ed209/handle_automated_action() - if(!..()) - return - - if(disabled) - return + icon_state = "ed209[on]" + set_weapon() - var/judgment_criteria = judgment_criteria() +/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 var/threatlevel = 0 if(C.incapacitated()) continue - threatlevel = C.assess_threat(judgment_criteria, lasercolor, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) + threatlevel = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) //speak(C.real_name + text(": threat: []", threatlevel)) if(threatlevel < 4 ) continue - var/dst = get_dist(src, C) if(dst <= 1 || dst > 7) continue - targets += C if(targets.len>0) var/mob/living/carbon/t = pick(targets) - if(t.stat != DEAD && (t.mobility_flags & MOBILITY_STAND) && !t.handcuffed) //we don't shoot people who are dead, cuffed or lying down. + if(t.stat != DEAD && !t.handcuffed) //we don't shoot people who are dead, cuffed or lying down. shootAt(t) - switch(mode) - - if(BOT_IDLE) // idle - SSmove_manager.stop_looping(src) - if(!lasercolor) //lasertag bots don't want to arrest anyone - look_for_perp() // see if any criminals are in range - if(!mode && auto_patrol) // still idle, and set to patrol - mode = 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) - SSmove_manager.stop_looping(src) - back_to_idle() - - 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) - SSmove_manager.move_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.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 - 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.AmountParalyzed() < 40)) //if he's changed loc and about to get up or not adjacent or got into a closet, we prep arrest again. - back_to_hunt() - return - else - mode = BOT_PREP_ARREST - anchored = FALSE - - if(BOT_START_PATROL) - look_for_perp() - start_patrol() - - if(BOT_PATROL) - look_for_perp() - bot_patrol() - - - return - -/mob/living/simple_animal/bot/ed209/proc/back_to_idle() - anchored = FALSE - mode = BOT_IDLE - target = null - last_found = world.time - frustration = 0 - INVOKE_ASYNC(src, .proc/handle_automated_action) //ensure bot quickly responds - -/mob/living/simple_animal/bot/ed209/proc/back_to_hunt() - anchored = FALSE - frustration = 0 - mode = BOT_HUNT - INVOKE_ASYNC(src, .proc/handle_automated_action) //ensure bot quickly responds - -// look for a criminal in view of the bot - -/mob/living/simple_animal/bot/ed209/proc/look_for_perp() - if(disabled) - return - anchored = FALSE - threatlevel = 0 - var/judgment_criteria = judgment_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(judgment_criteria, lasercolor, 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(src, pick('sound/voice/ed209_20sec.ogg', 'sound/voice/edplaceholder.ogg'), 50, FALSE) - visible_message("[src] points at [C.name]!") - mode = BOT_HUNT - spawn(0) - handle_automated_action() // ensure bot quickly responds to a perp - break - else - continue - -/mob/living/simple_animal/bot/ed209/proc/check_for_weapons(var/obj/item/slot_item) - if(slot_item && (slot_item.item_flags & NEEDS_PERMIT)) - return 1 - return 0 - -/mob/living/simple_animal/bot/ed209/explode() - SSmove_manager.stop_looping(src) - visible_message("[src] blows apart!") - var/atom/Tsec = drop_location() - - var/obj/item/bot_assembly/ed209/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(cell_type, Tsec) - - if(!lasercolor) - var/obj/item/gun/energy/disabler/G = new (Tsec) - G.cell.charge = 0 - G.update_icon() - else if(lasercolor == "b") - var/obj/item/gun/energy/laser/bluetag/G = new (Tsec) - G.cell.charge = 0 - G.update_icon() - else if(lasercolor == "r") - var/obj/item/gun/energy/laser/redtag/G = new (Tsec) - G.cell.charge = 0 - G.update_icon() - - if(prob(50)) - new /obj/item/bodypart/l_leg/robot(Tsec) - if(prob(25)) - new /obj/item/bodypart/r_leg/robot(Tsec) - if(prob(25))//50% chance for a helmet OR vest - if(prob(50)) - new /obj/item/clothing/head/helmet(Tsec) - else - if(!lasercolor) - drop_part(vest_type, Tsec) - if(lasercolor == "b") - new /obj/item/clothing/suit/bluetag(Tsec) - if(lasercolor == "r") - new /obj/item/clothing/suit/redtag(Tsec) - - do_sparks(3, TRUE, src) - - new /obj/effect/decal/cleanable/oil(loc) ..() -/mob/living/simple_animal/bot/ed209/proc/set_weapon() //used to update the projectile type and firing sound +/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(lasercolor) - projectile = /obj/item/projectile/beam/lasertag - else - projectile = /obj/item/projectile/beam + projectile = /obj/item/projectile/beam else - if(!lasercolor) - shoot_sound = 'sound/weapons/laser.ogg' - projectile = /obj/item/projectile/beam/disabler - else if(lasercolor == "b") - projectile = /obj/item/projectile/beam/lasertag/bluetag - else if(lasercolor == "r") - projectile = /obj/item/projectile/beam/lasertag/redtag + projectile = /obj/item/projectile/beam/disabler -/mob/living/simple_animal/bot/ed209/proc/shootAt(mob/target) +/mob/living/simple_animal/bot/secbot/ed209/proc/shootAt(mob/target) if(world.time <= lastfired + shot_delay) return lastfired = world.time @@ -452,14 +85,7 @@ Auto Patrol[]"}, A.preparePixelProjectile(target, src) A.fire() -/mob/living/simple_animal/bot/ed209/attack_alien(mob/living/carbon/alien/user) - ..() - if(!isalien(target)) - target = user - mode = BOT_HUNT - - -/mob/living/simple_animal/bot/ed209/emp_act(severity) +/mob/living/simple_animal/bot/secbot/ed209/emp_act(severity) if(severity == 2 && prob(70)) severity = 1 . = ..() @@ -492,93 +118,7 @@ Auto Patrol[]"}, target = toarrest mode = BOT_HUNT - -/mob/living/simple_animal/bot/ed209/bullet_act(obj/item/projectile/Proj) - if(!disabled) - var/lasertag_check = 0 - if((lasercolor == "b")) - if(istype(Proj, /obj/item/projectile/beam/lasertag/redtag)) - lasertag_check++ - else if((lasercolor == "r")) - if(istype(Proj, /obj/item/projectile/beam/lasertag/bluetag)) - lasertag_check++ - if(lasertag_check) - icon_state = "[lasercolor]ed2090" - disabled = TRUE - target = null - addtimer(CALLBACK(src, .proc/reenable), 100) - return BULLET_ACT_HIT - else - . = ..() - else - . = ..() - -/mob/living/simple_animal/bot/ed209/proc/reenable() - disabled = FALSE - icon_state = "[lasercolor]ed2091" - -/mob/living/simple_animal/bot/ed209/bluetag - lasercolor = "b" - -/mob/living/simple_animal/bot/ed209/redtag - lasercolor = "r" - -/mob/living/simple_animal/bot/ed209/UnarmedAttack(atom/A) - if(!on) - return - if(iscarbon(A)) - var/mob/living/carbon/C = A - if(!C.IsStun() || !C.IsParalyzed() || arrest_type) - stun_attack(A) - else if(C.canBeHandcuffed() && !C.handcuffed) - cuff(A) - else - ..() - -/mob/living/simple_animal/bot/ed209/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum) - 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/ed209/RangedAttack(atom/A) +/mob/living/simple_animal/bot/secbot/ed209/RangedAttack(atom/A) if(!on) return shootAt(A) - -/mob/living/simple_animal/bot/ed209/proc/stun_attack(mob/living/carbon/C) - playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1) - icon_state = "[lasercolor]ed209-c" - spawn(2) - icon_state = "[lasercolor]ed209[on]" - var/threat = 5 - C.Paralyze(100) - C.stuttering = 5 - if(ishuman(C)) - var/mob/living/carbon/human/H = C - var/judgment_criteria = judgment_criteria() - threat = H.assess_threat(judgment_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/ed209/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/ed209/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() diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm index 1fd31e7064b38..eb41e5d288074 100644 --- a/code/modules/mob/living/simple_animal/bot/honkbot.dm +++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm @@ -101,7 +101,7 @@ Maintenance panel panel is [open ? "opened" : "closed"]"}, "[auto_patrol ? "On" : "Off"]" ) return dat -/mob/living/simple_animal/bot/honkbot/proc/judgment_criteria() +/mob/living/simple_animal/bot/honkbot/proc/judgement_criteria() var/final = NONE if(check_records) final = final|JUDGE_RECORDCHECK @@ -110,8 +110,8 @@ Maintenance panel panel is [open ? "opened" : "closed"]"}, return final /mob/living/simple_animal/bot/honkbot/proc/retaliate(mob/living/carbon/human/H) - var/judgment_criteria = judgment_criteria() - threatlevel = H.assess_threat(judgment_criteria) + var/judgement_criteria = judgement_criteria() + threatlevel = H.assess_threat(judgement_criteria) threatlevel += 6 if(threatlevel >= 4) target = H @@ -206,8 +206,8 @@ Maintenance panel panel is [open ? "opened" : "closed"]"}, if(client) //prevent spam from players.. spam_flag = TRUE if (emagged <= 1) //HONK once, then leave - var/judgment_criteria = judgment_criteria() - threatlevel = H.assess_threat(judgment_criteria) + 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 @@ -302,8 +302,8 @@ Maintenance panel panel is [open ? "opened" : "closed"]"}, if((C.name == oldtarget_name) && (world.time < last_found + 100)) continue - var/judgment_criteria = judgment_criteria() - threatlevel = C.assess_threat(judgment_criteria) + var/judgement_criteria = judgement_criteria() + threatlevel = C.assess_threat(judgement_criteria) if(threatlevel <= 3 && get_dist(C, src) <= 4 && !spam_flag) bike_horn() diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index fb8276ae9472b..6a7f3c42332fe 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -33,6 +33,7 @@ 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 /mob/living/simple_animal/bot/secbot/beepsky name = "Officer Beep O'sky" @@ -156,24 +157,26 @@ Auto Patrol: []"}, update_controls() /mob/living/simple_animal/bot/secbot/proc/retaliate(mob/living/carbon/human/H) - var/judgment_criteria = judgment_criteria() - threatlevel = H.assess_threat(judgment_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) + 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/judgment_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/judgement_criteria() + var/final = FALSE + if(idcheck) + final |= JUDGE_IDCHECK + if(check_records) + final |= JUDGE_RECORDCHECK + if(weaponscheck) + final |= JUDGE_WEAPONCHECK + if(emagged == 2) + final |= JUDGE_EMAGGED + if(ranged) + final |= JUDGE_IGNOREMONKEYS + 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 @@ -254,7 +257,7 @@ Auto Patrol: []"}, var/mob/living/carbon/human/H = C if(H.check_shields(src, 0)) return - var/judgment_criteria = judgment_criteria() + var/judgement_criteria = judgement_criteria() playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1) icon_state = "[initial(icon_state)]-c" addtimer(CALLBACK(src, /atom/.proc/update_icon), 2) @@ -263,11 +266,11 @@ Auto Patrol: []"}, C.stuttering = 5 C.Paralyze(100) var/mob/living/carbon/human/H = C - threat = H.assess_threat(judgment_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) + threat = H.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) else C.Paralyze(100) C.stuttering = 5 - threat = C.assess_threat(judgment_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) + threat = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) log_combat(src,C,"stunned") if(declare_arrests) @@ -381,7 +384,7 @@ Auto Patrol: []"}, /mob/living/simple_animal/bot/secbot/proc/look_for_perp() anchored = FALSE - var/judgment_criteria = judgment_criteria() + 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 @@ -389,7 +392,7 @@ Auto Patrol: []"}, if((C.name == oldtarget_name) && (world.time < last_found + 100)) continue - threatlevel = C.assess_threat(judgment_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) + threatlevel = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) if(!threatlevel) continue @@ -398,7 +401,10 @@ Auto Patrol: []"}, 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) + if(ranged) + 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("[src] points at [C.name]!") mode = BOT_HUNT INVOKE_ASYNC(src, .proc/handle_automated_action) @@ -414,17 +420,34 @@ Auto Patrol: []"}, /mob/living/simple_animal/bot/secbot/explode() 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) - if(!noloot) + if(ranged) + var/obj/item/bot_assembly/ed209/Sa = new (Tsec) + Sa.build_step = 1 + Sa.add_overlay("hs_hole") + Sa.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_icon() + if(prob(50)) + new /obj/item/bodypart/l_leg/robot(Tsec) + if(prob(25)) + new /obj/item/bodypart/r_leg/robot(Tsec) + if(prob(25))//50% chance for a helmet OR vest + if(prob(50)) + new /obj/item/clothing/head/helmet(Tsec) + 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 + new /obj/item/assembly/prox_sensor(Tsec) drop_part(baton_type, Tsec) - if(prob(50)) - drop_part(robot_arm, Tsec) + if(prob(50)) + drop_part(robot_arm, Tsec) do_sparks(3, TRUE, src) diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm index a892d7ca7cc83..0e1a8ffbab310 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -194,7 +194,7 @@ . += "" -/mob/living/simple_animal/drone/assess_threat(judgment_criteria, lasercolor = "", datum/callback/weaponcheck=null) //Secbots won't hunt maintenance drones. +/mob/living/simple_animal/drone/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) //Secbots won't hunt maintenance drones. return -10 diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 9606ad3af1779..fe55770d9690c 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -861,7 +861,7 @@ /mob/proc/activate_hand(selhand) return -/mob/proc/assess_threat(judgment_criteria, lasercolor = "", datum/callback/weaponcheck=null) //For sec bot threat assessment +/mob/proc/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) //For sec bot threat assessment return 0 ///Get the ghost of this mob (from the mind) diff --git a/code/modules/spells/spell_types/conjure.dm b/code/modules/spells/spell_types/conjure.dm index 27bc19621c28e..e55e2d3750c68 100644 --- a/code/modules/spells/spell_types/conjure.dm +++ b/code/modules/spells/spell_types/conjure.dm @@ -54,10 +54,10 @@ name = "Dispense Wizard Justice" desc = "This spell dispenses wizard justice." - summon_type = list(/mob/living/simple_animal/bot/ed209) + summon_type = list(/mob/living/simple_animal/bot/secbot/ed209) summon_amt = 10 range = 3 - newVars = list("emagged" = 2, "remote_disabled" = 1,"shoot_sound" = 'sound/weapons/laser.ogg',"projectile" = /obj/item/projectile/beam/laser, "declare_arrests" = 0,"name" = "Wizard's Justicebot") + newVars = list("emagged" = 2, "remote_disabled" = 1, "projectile" = /obj/item/projectile/beam/laser, "declare_arrests" = 0,"name" = "Wizard's Justicebot") /obj/effect/proc_holder/spell/aoe_turf/conjure/linkWorlds name = "Link Worlds" diff --git a/code/modules/spells/spell_types/shapeshift.dm b/code/modules/spells/spell_types/shapeshift.dm index b18131f951f83..908e4d23f194b 100644 --- a/code/modules/spells/spell_types/shapeshift.dm +++ b/code/modules/spells/spell_types/shapeshift.dm @@ -20,7 +20,7 @@ var/list/possible_shapes = list(/mob/living/simple_animal/mouse,\ /mob/living/simple_animal/pet/dog/corgi,\ /mob/living/simple_animal/hostile/carp/ranged/chaos,\ - /mob/living/simple_animal/bot/ed209,\ + /mob/living/simple_animal/bot/secbot/ed209,\ /mob/living/simple_animal/hostile/poison/giant_spider/hunter/viper/wizard,\ /mob/living/simple_animal/hostile/construct/armored) From 9fd76927eba94ba79e5b3f3220f91bdb5a58a405 Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Thu, 16 Feb 2023 13:09:38 -0500 Subject: [PATCH 02/20] requested --- .../antagonists/devil/true_devil/_true_devil.dm | 2 +- code/modules/mob/living/carbon/alien/alien.dm | 2 +- code/modules/mob/living/carbon/human/human.dm | 10 +++++----- code/modules/mob/living/carbon/monkey/monkey.dm | 8 ++++---- code/modules/mob/living/silicon/silicon.dm | 2 +- .../mob/living/simple_animal/bot/SuperBeepsky.dm | 4 ++-- .../mob/living/simple_animal/bot/ed209bot.dm | 4 ++-- .../mob/living/simple_animal/bot/honkbot.dm | 14 +++++++------- .../mob/living/simple_animal/bot/secbot.dm | 16 ++++++++-------- .../simple_animal/friendly/drone/_drone.dm | 2 +- code/modules/mob/mob.dm | 2 +- 11 files changed, 33 insertions(+), 33 deletions(-) diff --git a/code/modules/antagonists/devil/true_devil/_true_devil.dm b/code/modules/antagonists/devil/true_devil/_true_devil.dm index 4d53ad3931ada..58659ec13d9f1 100644 --- a/code/modules/antagonists/devil/true_devil/_true_devil.dm +++ b/code/modules/antagonists/devil/true_devil/_true_devil.dm @@ -103,7 +103,7 @@ return FALSE return TRUE -/mob/living/carbon/true_devil/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) +/mob/living/carbon/true_devil/assess_threat(judgment_criteria, lasercolor = "", datum/callback/weaponcheck=null) return 666 /mob/living/carbon/true_devil/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0) diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index 322ba19a12fb9..6d6396d172fc1 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -38,7 +38,7 @@ internal_organs += new /obj/item/organ/ears return ..() -/mob/living/carbon/alien/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) // beepsky won't hunt aliums +/mob/living/carbon/alien/assess_threat(judgment_criteria, lasercolor = "", datum/callback/weaponcheck=null) // beepsky won't hunt aliums return -10 /mob/living/carbon/alien/handle_environment(datum/gas_mixture/environment) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index e3545514ff8d2..b3b35ad5d61c6 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -448,8 +448,8 @@ return FALSE return TRUE -/mob/living/carbon/human/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) - if(judgement_criteria & JUDGE_EMAGGED) +/mob/living/carbon/human/assess_threat(judgment_criteria, lasercolor = "", datum/callback/weaponcheck=null) + if(judgment_criteria & JUDGE_EMAGGED) return 10 //Everyone is a criminal! var/threatcount = 0 @@ -476,11 +476,11 @@ //Check for ID var/obj/item/card/id/idcard = get_idcard(FALSE) - if( (judgement_criteria & JUDGE_IDCHECK) && !idcard && name=="Unknown") + if( (judgment_criteria & JUDGE_IDCHECK) && !idcard && name=="Unknown") threatcount += 4 //Check for weapons - if( (judgement_criteria & JUDGE_WEAPONCHECK) && weaponcheck) + if( (judgment_criteria & JUDGE_WEAPONCHECK) && weaponcheck) if(!idcard || !(ACCESS_WEAPONS in idcard.access)) for(var/obj/item/I in held_items) //if they're holding a gun if(weaponcheck.Invoke(I)) @@ -489,7 +489,7 @@ threatcount += 2 //not enough to trigger look_for_perp() on it's own unless they also have criminal status. //Check for arrest warrant - if(judgement_criteria & JUDGE_RECORDCHECK) + if(judgment_criteria & JUDGE_RECORDCHECK) var/perpname = get_face_name(get_id_name()) var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.security) if(R && R.fields["criminal"]) diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index eda101d4c41d8..83725e88b04f7 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -121,14 +121,14 @@ GLOBAL_LIST_INIT(strippable_monkey_items, create_strippable_list(list( /mob/living/carbon/monkey/canBeHandcuffed() return TRUE -/mob/living/carbon/monkey/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) - if(judgement_criteria & JUDGE_EMAGGED) +/mob/living/carbon/monkey/assess_threat(judgment_criteria, lasercolor = "", datum/callback/weaponcheck=null) + if(judgment_criteria & JUDGE_EMAGGED) return 10 //Everyone is a criminal! var/threatcount = 0 //Securitrons can't identify monkeys - if( !(judgement_criteria & JUDGE_IGNOREMONKEYS) && (judgement_criteria & JUDGE_IDCHECK) ) + if( !(judgment_criteria & JUDGE_IGNOREMONKEYS) && (judgment_criteria & JUDGE_IDCHECK) ) threatcount += 4 //Lasertag bullshit @@ -144,7 +144,7 @@ GLOBAL_LIST_INIT(strippable_monkey_items, create_strippable_list(list( return threatcount //Check for weapons - if( (judgement_criteria & JUDGE_WEAPONCHECK) && weaponcheck ) + if( (judgment_criteria & JUDGE_WEAPONCHECK) && weaponcheck ) for(var/obj/item/I in held_items) //if they're holding a gun if(weaponcheck.Invoke(I)) threatcount += 4 diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index a98694f11b091..8f214bcd7dfdf 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -433,7 +433,7 @@ return 0 -/mob/living/silicon/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) //Secbots won't hunt silicon units +/mob/living/silicon/assess_threat(judgment_criteria, lasercolor = "", datum/callback/weaponcheck=null) //Secbots won't hunt silicon units return -10 /mob/living/silicon/proc/remove_sensors() diff --git a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm index bab7bc405a5e7..e61cb0a0f0044 100644 --- a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm +++ b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm @@ -111,7 +111,7 @@ /mob/living/simple_animal/bot/secbot/grievous/look_for_perp() anchored = FALSE - var/judgement_criteria = judgement_criteria() + var/judgment_criteria = judgment_criteria() for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal if((C.stat) || (C.handcuffed)) continue @@ -119,7 +119,7 @@ if((C.name == oldtarget_name) && (world.time < last_found + 100)) continue - threatlevel = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) + threatlevel = C.assess_threat(judgment_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) if(!threatlevel) continue diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm index 5ab772db396e5..deed50be2f07c 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -39,13 +39,13 @@ set_weapon() /mob/living/simple_animal/bot/secbot/ed209/handle_automated_action() - var/judgement_criteria = judgement_criteria() + var/judgment_criteria = judgment_criteria() var/list/targets = list() for(var/mob/living/carbon/C in view(7,src)) //Let's find us a target var/threatlevel = 0 if(C.incapacitated()) continue - threatlevel = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) + threatlevel = C.assess_threat(judgment_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) //speak(C.real_name + text(": threat: []", threatlevel)) if(threatlevel < 4 ) continue diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm index eb41e5d288074..1fd31e7064b38 100644 --- a/code/modules/mob/living/simple_animal/bot/honkbot.dm +++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm @@ -101,7 +101,7 @@ Maintenance panel panel is [open ? "opened" : "closed"]"}, "[auto_patrol ? "On" : "Off"]" ) return dat -/mob/living/simple_animal/bot/honkbot/proc/judgement_criteria() +/mob/living/simple_animal/bot/honkbot/proc/judgment_criteria() var/final = NONE if(check_records) final = final|JUDGE_RECORDCHECK @@ -110,8 +110,8 @@ Maintenance panel panel is [open ? "opened" : "closed"]"}, return final /mob/living/simple_animal/bot/honkbot/proc/retaliate(mob/living/carbon/human/H) - var/judgement_criteria = judgement_criteria() - threatlevel = H.assess_threat(judgement_criteria) + var/judgment_criteria = judgment_criteria() + threatlevel = H.assess_threat(judgment_criteria) threatlevel += 6 if(threatlevel >= 4) target = H @@ -206,8 +206,8 @@ Maintenance panel panel is [open ? "opened" : "closed"]"}, if(client) //prevent spam from players.. spam_flag = TRUE if (emagged <= 1) //HONK once, then leave - var/judgement_criteria = judgement_criteria() - threatlevel = H.assess_threat(judgement_criteria) + var/judgment_criteria = judgment_criteria() + threatlevel = H.assess_threat(judgment_criteria) threatlevel -= 6 target = oldtarget_name else // you really don't want to hit an emagged honkbot @@ -302,8 +302,8 @@ Maintenance panel panel is [open ? "opened" : "closed"]"}, if((C.name == oldtarget_name) && (world.time < last_found + 100)) continue - var/judgement_criteria = judgement_criteria() - threatlevel = C.assess_threat(judgement_criteria) + var/judgment_criteria = judgment_criteria() + threatlevel = C.assess_threat(judgment_criteria) if(threatlevel <= 3 && get_dist(C, src) <= 4 && !spam_flag) bike_horn() diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index 6a7f3c42332fe..a4e25f1c1dd8e 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -157,14 +157,14 @@ Auto Patrol: []"}, 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)) + var/judgment_criteria = judgment_criteria() + threatlevel = H.assess_threat(judgment_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() +/mob/living/simple_animal/bot/secbot/proc/judgment_criteria() var/final = FALSE if(idcheck) final |= JUDGE_IDCHECK @@ -257,7 +257,7 @@ Auto Patrol: []"}, var/mob/living/carbon/human/H = C if(H.check_shields(src, 0)) return - var/judgement_criteria = judgement_criteria() + var/judgment_criteria = judgment_criteria() playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1) icon_state = "[initial(icon_state)]-c" addtimer(CALLBACK(src, /atom/.proc/update_icon), 2) @@ -266,11 +266,11 @@ Auto Patrol: []"}, 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)) + threat = H.assess_threat(judgment_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)) + threat = C.assess_threat(judgment_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) log_combat(src,C,"stunned") if(declare_arrests) @@ -384,7 +384,7 @@ Auto Patrol: []"}, /mob/living/simple_animal/bot/secbot/proc/look_for_perp() anchored = FALSE - var/judgement_criteria = judgement_criteria() + var/judgment_criteria = judgment_criteria() for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal if((C.stat) || (C.handcuffed)) continue @@ -392,7 +392,7 @@ Auto Patrol: []"}, if((C.name == oldtarget_name) && (world.time < last_found + 100)) continue - threatlevel = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) + threatlevel = C.assess_threat(judgment_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) if(!threatlevel) continue diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm index 0e1a8ffbab310..a892d7ca7cc83 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -194,7 +194,7 @@ . += "" -/mob/living/simple_animal/drone/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) //Secbots won't hunt maintenance drones. +/mob/living/simple_animal/drone/assess_threat(judgment_criteria, lasercolor = "", datum/callback/weaponcheck=null) //Secbots won't hunt maintenance drones. return -10 diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index fe55770d9690c..9606ad3af1779 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -861,7 +861,7 @@ /mob/proc/activate_hand(selhand) return -/mob/proc/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) //For sec bot threat assessment +/mob/proc/assess_threat(judgment_criteria, lasercolor = "", datum/callback/weaponcheck=null) //For sec bot threat assessment return 0 ///Get the ghost of this mob (from the mind) From 8d36fd6fb972b4ce589e13c8414d36a5327d27bd Mon Sep 17 00:00:00 2001 From: RKz Date: Mon, 13 Mar 2023 13:18:57 -0400 Subject: [PATCH 03/20] oops proc --- code/modules/mob/living/simple_animal/bot/ed209bot.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm index deed50be2f07c..eadf8f6409b14 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -45,7 +45,7 @@ var/threatlevel = 0 if(C.incapacitated()) continue - threatlevel = C.assess_threat(judgment_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons)) + threatlevel = C.assess_threat(judgment_criteria, weaponcheck=CALLBACK(src, PROC_REF(check_for_weapons))) //speak(C.real_name + text(": threat: []", threatlevel)) if(threatlevel < 4 ) continue From f5846229177f00d8eafb37ce457711363962fc54 Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Fri, 20 Oct 2023 02:56:22 -0400 Subject: [PATCH 04/20] wow rkz you used to suck at coding --- .../mob/living/simple_animal/bot/ed209bot.dm | 10 +++++----- .../mob/living/simple_animal/bot/secbot.dm | 13 +++++++------ code/modules/spells/spell_types/conjure.dm | 8 +++++++- icons/mob/aibots.dmi | Bin 66054 -> 72675 bytes 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm index 8cc5ef81761e2..6bbba8dcd59d9 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -1,7 +1,7 @@ /mob/living/simple_animal/bot/secbot/ed209 name = "\improper ED-209 Security Robot" desc = "A security robot. He looks less than thrilled." - icon_state = "ed2090" + icon_state = "ed209" density = TRUE health = 100 maxHealth = 100 @@ -16,8 +16,8 @@ var/lastfired = 0 var/shot_delay = 15 var/shoot_sound = 'sound/weapons/laser.ogg' - var/projectile = /obj/item/projectile/beam/disabler - var/fair_market_projectile = /obj/item/projectile/bullet/c38 // For shooting the worst scumbags of all: the poor + var/projectile = /obj/projectile/beam/disabler + var/fair_market_projectile = /obj/projectile/bullet/c38 // For shooting the worst scumbags of all: the poor do_footstep = TRUE /mob/living/simple_animal/bot/secbot/ed209/Initialize(mapload) @@ -62,9 +62,9 @@ /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) - projectile = /obj/item/projectile/beam + projectile = /obj/projectile/beam else - projectile = /obj/item/projectile/beam/disabler + projectile = /obj/projectile/beam/disabler /mob/living/simple_animal/bot/secbot/ed209/proc/shootAt(mob/target) if(world.time <= lastfired + shot_delay) diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index ea13abdc3e379..03fad04c2826f 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -68,7 +68,8 @@ /mob/living/simple_animal/bot/secbot/Initialize(mapload) . = ..() - update_icon() + update_appearance(UPDATE_ICON) + var/datum/job/J = SSjob.GetJob(JOB_NAME_DETECTIVE) access_card.access = J.get_access() prev_access = access_card.access.Copy() @@ -81,11 +82,11 @@ ) AddElement(/datum/element/connect_loc, loc_connections) -/mob/living/simple_animal/bot/secbot/update_icon() +/mob/living/simple_animal/bot/secbot/update_icon_state() if(mode == BOT_HUNT) icon_state = "[initial(icon_state)]-c" return - ..() + return ..() /mob/living/simple_animal/bot/secbot/turn_off() ..() @@ -196,7 +197,7 @@ oldtarget_name = user.name audible_message("[src] buzzes oddly!") declare_arrests = FALSE - update_icon() + update_appearance() /mob/living/simple_animal/bot/secbot/bullet_act(obj/projectile/Proj) if(istype(Proj , /obj/projectile/beam)||istype(Proj, /obj/projectile/bullet)) @@ -239,7 +240,7 @@ if(!C.handcuffed) C.handcuffed = new /obj/item/restraints/handcuffs/cable/zipties/used(C) C.update_handcuffed() - playsound(src, "law", 50, 0) + playsound(src, "law", 50, FALSE) back_to_idle() /mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/C) @@ -267,7 +268,7 @@ log_combat(src, C, "stunned") playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1) icon_state = "[initial(icon_state)]-c" - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon)), 2) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_appearance)), 0.2 SECONDS) /mob/living/simple_animal/bot/secbot/handle_automated_action() if(!..()) diff --git a/code/modules/spells/spell_types/conjure.dm b/code/modules/spells/spell_types/conjure.dm index 9415f0a35cb1e..d1d2dd29f66a5 100644 --- a/code/modules/spells/spell_types/conjure.dm +++ b/code/modules/spells/spell_types/conjure.dm @@ -57,7 +57,13 @@ summon_type = list(/mob/living/simple_animal/bot/secbot/ed209) summon_amt = 10 range = 3 - newVars = list("emagged" = 2, "remote_disabled" = 1, "projectile" = /obj/item/projectile/beam/laser, "declare_arrests" = 0,"name" = "Wizard's Justicebot") + newVars = list( + "emagged" = 2, + "remote_disabled" = 1, + "projectile" = /obj/projectile/beam/laser, + "declare_arrests" = 0, + "name" = "Wizard's Justicebot" + ) /obj/effect/proc_holder/spell/aoe_turf/conjure/linkWorlds name = "Link Worlds" diff --git a/icons/mob/aibots.dmi b/icons/mob/aibots.dmi index 84deedc5c5c4b474bb1749ff915e1fc6014bea9e..710686d82e66d9bb7f4b55812426d4c41fe28be8 100644 GIT binary patch literal 72675 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

38l(V>@8UF+3*T55sk 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 From 0b185a1d452a9ebd15cbbbdf758be6fb3202a42c Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Sun, 22 Oct 2023 17:28:07 -0400 Subject: [PATCH 05/20] making ruko cry (funny) --- code/__DEFINES/robots.dm | 14 +++++++++----- .../mob/living/simple_animal/bot/construction.dm | 8 ++++---- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/code/__DEFINES/robots.dm b/code/__DEFINES/robots.dm index 0db4411562eb2..c4378cd4a9fb8 100644 --- a/code/__DEFINES/robots.dm +++ b/code/__DEFINES/robots.dm @@ -53,8 +53,12 @@ #define DISCONNECT 5 //Assembly defines -#define ASSEMBLY_FIRST_STEP 0 -#define ASSEMBLY_SECOND_STEP 1 -#define ASSEMBLY_THIRD_STEP 2 -#define ASSEMBLY_FOURTH_STEP 3 -#define ASSEMBLY_FIFTH_STEP 4 +#define ASSEMBLY_FIRST_STEP 0 +#define ASSEMBLY_SECOND_STEP 1 +#define ASSEMBLY_THIRD_STEP 2 +#define ASSEMBLY_FOURTH_STEP 3 +#define ASSEMBLY_FIFTH_STEP 4 +#define ASSEMBLY_SIXTH_STEP 5 +#define ASSEMBLY_SEVENTH_STEP 6 +#define ASSEMBLY_EIGHTH_STEP 7 +#define ASSEMBLY_NINTH_STEP 8 diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index e4cfebefcf263..e6f34831ed863 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -128,7 +128,7 @@ icon_state = "ed209_hat" build_step++ - if(5) + if(ASSEMBLY_SIXTH_STEP) if(isprox(W)) if(!user.temporarilyRemoveItemFromInventory(W)) return @@ -139,7 +139,7 @@ item_state = "ed209_prox" icon_state = "ed209_prox" - if(6) + if(ASSEMBLY_SEVENTH_STEP) if(istype(W, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/coil = W if(coil.get_amount() < 1) @@ -153,7 +153,7 @@ name = "wired ED-209 assembly" build_step++ - if(7) + if(ASSEMBLY_EIGHTH_STEP) if(istype(W, /obj/item/gun/energy/disabler)) if(!user.temporarilyRemoveItemFromInventory(W)) return @@ -164,7 +164,7 @@ qdel(W) build_step++ - if(8) + if(ASSEMBLY_NINTH_STEP) if(W.tool_behaviour == TOOL_SCREWDRIVER) to_chat(user, "You start attaching the gun to the frame...") if(W.use_tool(src, user, 40, volume=100)) From dc5fa9caf3f3ac794a0dd07cd315a56e4f84f50a Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Sun, 22 Oct 2023 17:38:07 -0400 Subject: [PATCH 06/20] the dumb alternative --- .../living/simple_animal/bot/construction.dm | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index e6f34831ed863..8c99680d176b8 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -168,10 +168,23 @@ if(W.tool_behaviour == TOOL_SCREWDRIVER) to_chat(user, "You start attaching the gun to the frame...") if(W.use_tool(src, user, 40, volume=100)) - var/mob/living/simple_animal/bot/secbot/ed209/B = new(drop_location()) - B.name = created_name - to_chat(user, "You complete the ED-209.") - qdel(src) + name = "armed [name]" + to_chat(user, "The gun is now securely fastened to the frame.") + build_step++ + + if(9) + if(istype(W, /obj/item/stock_parts/cell/high)) + if(!can_finish_build(W, user)) + return + var/mob/living/simple_animal/bot/secbot/ed209/B = new(drop_location()) + B.name = created_name + to_chat(user, "You complete the ED-209.") + B.cell_type = W.type + qdel(W) + B.vest_type = vest_type + qdel(src) + else if(istype(W, /obj/item/stock_parts/cell)) // dont waste bluespace cells on this, goofus + to_chat(user, "Under Nanotrasen safety regulations, this Model bot only accepts standard issue high-capacity power cells.") //Floorbot assemblies /obj/item/bot_assembly/floorbot From 2cbc1fd3a10a3c110cb1b10c3b3cbd0b23dc3131 Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Tue, 24 Oct 2023 10:50:59 -0400 Subject: [PATCH 07/20] fix --- code/modules/mob/living/simple_animal/bot/construction.dm | 4 ---- 1 file changed, 4 deletions(-) diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index 8c99680d176b8..360f1c2f6aada 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -179,10 +179,6 @@ var/mob/living/simple_animal/bot/secbot/ed209/B = new(drop_location()) B.name = created_name to_chat(user, "You complete the ED-209.") - B.cell_type = W.type - qdel(W) - B.vest_type = vest_type - qdel(src) else if(istype(W, /obj/item/stock_parts/cell)) // dont waste bluespace cells on this, goofus to_chat(user, "Under Nanotrasen safety regulations, this Model bot only accepts standard issue high-capacity power cells.") From d640444f301ab2085c22bcf7a0b04ec8ddfd2fac Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Tue, 24 Oct 2023 11:04:19 -0400 Subject: [PATCH 08/20] fix infinite spawning --- code/modules/mob/living/simple_animal/bot/construction.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index 360f1c2f6aada..da26bef1b1dbb 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -179,7 +179,8 @@ var/mob/living/simple_animal/bot/secbot/ed209/B = new(drop_location()) B.name = created_name to_chat(user, "You complete the ED-209.") - else if(istype(W, /obj/item/stock_parts/cell)) // dont waste bluespace cells on this, goofus + qdel(src) //make sure to delete the unfinished recipe when spawning in the actual mob + else if(istype(W, /obj/item/stock_parts/cell/bluespace)) // dont waste bluespace cells on this, goofus to_chat(user, "Under Nanotrasen safety regulations, this Model bot only accepts standard issue high-capacity power cells.") //Floorbot assemblies From 034c2a5f27eedb18f97bd280f671a8e9377f7484 Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Tue, 24 Oct 2023 11:21:24 -0400 Subject: [PATCH 09/20] warning span --- code/modules/mob/living/simple_animal/bot/construction.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index da26bef1b1dbb..1143894f74f9d 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -181,7 +181,7 @@ to_chat(user, "You complete the ED-209.") qdel(src) //make sure to delete the unfinished recipe when spawning in the actual mob else if(istype(W, /obj/item/stock_parts/cell/bluespace)) // dont waste bluespace cells on this, goofus - to_chat(user, "Under Nanotrasen safety regulations, this Model bot only accepts standard issue high-capacity power cells.") + to_chat(user, "Under Nanotrasen safety regulations, this Model bot only accepts standard issue high-capacity power cells.") //Floorbot assemblies /obj/item/bot_assembly/floorbot From 01d3e414a6c46df407c33b13d82ed9eb874f9e27 Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Tue, 24 Oct 2023 13:50:56 -0400 Subject: [PATCH 10/20] . --- code/modules/mob/living/simple_animal/bot/construction.dm | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index 1143894f74f9d..2a58ad5b932c3 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -173,15 +173,13 @@ build_step++ if(9) - if(istype(W, /obj/item/stock_parts/cell/high)) + if(istype(W, /obj/item/stock_parts/cell)) if(!can_finish_build(W, user)) return var/mob/living/simple_animal/bot/secbot/ed209/B = new(drop_location()) B.name = created_name to_chat(user, "You complete the ED-209.") qdel(src) //make sure to delete the unfinished recipe when spawning in the actual mob - else if(istype(W, /obj/item/stock_parts/cell/bluespace)) // dont waste bluespace cells on this, goofus - to_chat(user, "Under Nanotrasen safety regulations, this Model bot only accepts standard issue high-capacity power cells.") //Floorbot assemblies /obj/item/bot_assembly/floorbot From 9b17ba22cb42df5f7cf0751ab505eb449d81252d Mon Sep 17 00:00:00 2001 From: RKz Date: Wed, 25 Oct 2023 09:33:50 -0400 Subject: [PATCH 11/20] https://github.com/tgstation/tgstation/pull/62510 --- code/__DEFINES/robots.dm | 93 ++++- code/datums/wires/robot.dm | 6 +- code/game/machinery/transformer.dm | 2 +- code/game/objects/buckling.dm | 6 +- code/game/objects/items/robot/robot_parts.dm | 4 +- .../objects/items/robot/robot_upgrades.dm | 4 +- code/modules/admin/verbs/borgpanel.dm | 4 +- code/modules/jobs/job_types/cyborg.dm | 7 +- code/modules/mob/dead/observer/login.dm | 2 +- .../modules/mob/living/silicon/robot/robot.dm | 14 +- .../mob/living/silicon/robot/robot_modules.dm | 2 +- code/modules/mob/living/silicon/silicon.dm | 2 +- .../living/simple_animal/bot/SuperBeepsky.dm | 15 +- .../mob/living/simple_animal/bot/bot.dm | 49 +-- .../mob/living/simple_animal/bot/cleanbot.dm | 16 +- .../living/simple_animal/bot/construction.dm | 4 +- .../mob/living/simple_animal/bot/ed209bot.dm | 88 ++--- .../mob/living/simple_animal/bot/firebot.dm | 6 +- .../mob/living/simple_animal/bot/floorbot.dm | 15 +- .../mob/living/simple_animal/bot/honkbot.dm | 94 +++--- .../mob/living/simple_animal/bot/medbot.dm | 26 +- .../mob/living/simple_animal/bot/secbot.dm | 319 +++++++++--------- .../simple_animal/friendly/drone/_drone.dm | 2 +- code/modules/mob/mob_defines.dm | 2 +- code/modules/mob/transform_procs.dm | 2 +- code/modules/projectiles/projectile/magic.dm | 2 +- code/modules/spells/spell_types/conjure.dm | 13 +- 27 files changed, 438 insertions(+), 361 deletions(-) diff --git a/code/__DEFINES/robots.dm b/code/__DEFINES/robots.dm index c4378cd4a9fb8..792406916575f 100644 --- a/code/__DEFINES/robots.dm +++ b/code/__DEFINES/robots.dm @@ -1,15 +1,81 @@ -/*ALL DEFINES FOR AIS, CYBORGS, AND SIMPLE ANIMAL BOTS*/ +/** AI defines */ #define DEFAULT_AI_LAWID "default" +//AI notification defines +///Alert when a new Cyborg is created. +#define AI_NOTIFICATION_NEW_BORG 1 +///Alert when a Cyborg selects a model. +#define AI_NOTIFICATION_NEW_MODEL 2 +///Alert when a Cyborg changes their name. +#define AI_NOTIFICATION_CYBORG_RENAMED 3 +///Alert when an AI disconnects themselves from their shell. +#define AI_NOTIFICATION_AI_SHELL 4 +///Alert when a Cyborg gets disconnected from their AI. +#define AI_NOTIFICATION_CYBORG_DISCONNECTED 5 + +/** Cyborg defines */ + +/// Special value to reset cyborg's lamp_cooldown +#define BORG_LAMP_CD_RESET -1 + +//Module slot define +///The third module slots is disabed. +#define BORG_MODULE_THREE_DISABLED (1<<0) +///The second module slots is disabed. +#define BORG_MODULE_TWO_DISABLED (1<<1) +///All modules slots are disabled. +#define BORG_MODULE_ALL_DISABLED (1<<2) + +//Cyborg module selection +///First Borg module slot. +#define BORG_CHOOSE_MODULE_ONE 1 +///Second Borg module slot. +#define BORG_CHOOSE_MODULE_TWO 2 +///Third Borg module slot. +#define BORG_CHOOSE_MODULE_THREE 3 + +#define SKIN_ICON "skin_icon" +#define SKIN_ICON_STATE "skin_icon_state" +#define SKIN_PIXEL_X "skin_pixel_x" +#define SKIN_PIXEL_Y "skin_pixel_y" +#define SKIN_LIGHT_KEY "skin_light_key" +#define SKIN_HAT_OFFSET "skin_hat_offset" +#define SKIN_TRAITS "skin_traits" + +/** Simple Animal BOT defines */ + //Bot defines, placed here so they can be read by other things! #define BOT_STEP_DELAY 4 //Delay between movemements #define BOT_STEP_MAX_RETRIES 5 //Maximum times a bot will retry to step from its position -#define DEFAULT_SCAN_RANGE 7 //default view range for finding targets. +#define DEFAULT_SCAN_RANGE 7 //default view range for finding targets. + +//Bot types +/// Secutritrons (Beepsky) +#define SEC_BOT (1<<0) +/// ED-209s +#define ADVANCED_SEC_BOT (1<<1) +/// MULEbots +#define MULE_BOT (1<<2) +/// Floorbots +#define FLOOR_BOT (1<<3) +/// Cleanbots +#define CLEAN_BOT (1<<4) +/// Medibots +#define MED_BOT (1<<5) +/// Honkbots & ED-Honks +#define HONK_BOT (1<<6) +/// Firebots +#define FIRE_BOT (1<<7) +/// Hygienebots +#define HYGIENE_BOT (1<<8) +/// Vibe bots +#define VIBE_BOT (1<<9) //Mode defines -#define BOT_IDLE 0 //! idle +/// Idle +#define BOT_IDLE 0 #define BOT_HUNT 1 //! found target, hunting #define BOT_PREP_ARREST 2 //! at target, preparing to arrest #define BOT_ARREST 3 //! arresting target @@ -28,14 +94,17 @@ #define BOT_WAIT_FOR_NAV 16 //! waiting for nav computation #define BOT_NO_ROUTE 17 //! no destination beacon found (or no route) -//Bot types -#define SEC_BOT (1<<0) //! Secutritrons (Beepsky) and ED-209s -#define MULE_BOT (1<<1) //! MULEbots -#define FLOOR_BOT (1<<2) //! Floorbots -#define CLEAN_BOT (1<<3) //! Cleanbots -#define MED_BOT (1<<4) //! Medibots -#define HONK_BOT (1<<5) //! Honkbots & ED-Honks -#define FIRE_BOT (1<<6) //! Firebots +//SecBOT defines on arresting +///Whether arrests should be broadcasted over the Security radio +#define SECBOT_DECLARE_ARRESTS (1<<0) +///Will arrest people who lack an ID card +#define SECBOT_CHECK_IDS (1<<1) +///Will check for weapons, taking Weapons access into account +#define SECBOT_CHECK_WEAPONS (1<<2) +///Will check Security record on whether to arrest +#define SECBOT_CHECK_RECORDS (1<<3) +///Whether we will stun & cuff or endlessly stun +#define SECBOT_HANDCUFF_TARGET (1<<4) //transfer_ai() defines. Main proc in ai_core.dm ///Downloading AI to InteliCard @@ -52,6 +121,8 @@ #define AI_SHELL 4 #define DISCONNECT 5 +/** Misc Robot defines */ + //Assembly defines #define ASSEMBLY_FIRST_STEP 0 #define ASSEMBLY_SECOND_STEP 1 diff --git a/code/datums/wires/robot.dm b/code/datums/wires/robot.dm index 37a5b4b5abce3..2dfac76e34e4c 100644 --- a/code/datums/wires/robot.dm +++ b/code/datums/wires/robot.dm @@ -36,13 +36,13 @@ new_ai = select_active_ai(user) else new_ai = select_active_ai(R) - R.notify_ai(DISCONNECT) + R.notify_ai(AI_NOTIFICATION_CYBORG_DISCONNECTED) if(new_ai && (new_ai != R.connected_ai)) log_combat(usr, R, "synced cyborg [R.connected_ai ? "from [ADMIN_LOOKUP(R.connected_ai)]": "false"] to [ADMIN_LOOKUP(new_ai)]") R.connected_ai = new_ai if(R.shell) R.undeploy() //If this borg is an AI shell, disconnect the controlling AI and assign ti to a new AI - R.notify_ai(AI_SHELL) + R.notify_ai(AI_NOTIFICATION_AI_SHELL) else R.notify_ai(TRUE) if(WIRE_CAMERA) // Pulse to disable the camera. @@ -71,7 +71,7 @@ switch(wire) if(WIRE_AI) // Cut the AI wire to reset AI control. if(!mend) - R.notify_ai(DISCONNECT) + R.notify_ai(AI_NOTIFICATION_AI_SHELL) log_combat(usr, R, "cut AI wire on cyborg[R.connected_ai ? " and disconnected from [ADMIN_LOOKUP(R.connected_ai)]": ""]") if(R.shell) R.undeploy() diff --git a/code/game/machinery/transformer.dm b/code/game/machinery/transformer.dm index e9884d629b4e9..4b0f0a0bf191e 100644 --- a/code/game/machinery/transformer.dm +++ b/code/game/machinery/transformer.dm @@ -107,4 +107,4 @@ sleep(30) if(R) R.SetLockdown(FALSE) - R.notify_ai(NEW_BORG) + R.notify_ai(AI_NOTIFICATION_NEW_BORG) diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm index 6ff54ceb0814e..b475bcb3229eb 100644 --- a/code/game/objects/buckling.dm +++ b/code/game/objects/buckling.dm @@ -25,11 +25,11 @@ if(user_unbuckle_mob(buckled_mobs[1],user)) return TRUE -/atom/movable/attackby(obj/item/W, mob/user, params) - if(!can_buckle || !istype(W, /obj/item/riding_offhand) || !user.Adjacent(src)) +/atom/movable/attackby(obj/item/attacking_item, mob/user, params) + if(!can_buckle || !istype(attacking_item, /obj/item/riding_offhand) || !user.Adjacent(src)) return ..() - var/obj/item/riding_offhand/riding_item = W + var/obj/item/riding_offhand/riding_item = attacking_item var/mob/living/carried_mob = riding_item.rider if(carried_mob == user) //Piggyback user. return diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index ea09a028e6856..5aa643bbfa994 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -293,7 +293,7 @@ lawsync = 0 O.connected_ai = null else - O.notify_ai(NEW_BORG) + O.notify_ai(AI_NOTIFICATION_NEW_BORG) if(forced_ai) O.connected_ai = forced_ai if(!lawsync) @@ -355,7 +355,7 @@ else if(forced_ai) O.connected_ai = forced_ai - O.notify_ai(AI_SHELL) + O.notify_ai(AI_NOTIFICATION_AI_SHELL) if(!lawsync) O.lawupdate = FALSE O.make_laws() diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 10f26f65e92f3..4fe8d4710852a 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -53,7 +53,7 @@ R.custom_name = heldname R.updatename() if(oldname == R.real_name) - R.notify_ai(RENAME, oldname, R.real_name) + R.notify_ai(AI_NOTIFICATION_CYBORG_RENAMED, oldname, R.real_name) log_game("[key_name(user)] have used a cyborg reclassification board to rename [oldkeyname] to [key_name(R)] at [loc_name(user)]") /obj/item/borg/upgrade/restart @@ -566,7 +566,7 @@ if (.) if(R.shell) R.undeploy() - R.notify_ai(AI_SHELL) + R.notify_ai(AI_NOTIFICATION_AI_SHELL) /obj/item/borg/upgrade/expand name = "borg expander" diff --git a/code/modules/admin/verbs/borgpanel.dm b/code/modules/admin/verbs/borgpanel.dm index 77e2b5acb12bc..e30c6e4e3bfaf 100644 --- a/code/modules/admin/verbs/borgpanel.dm +++ b/code/modules/admin/verbs/borgpanel.dm @@ -200,7 +200,7 @@ if ("slavetoai") var/mob/living/silicon/ai/newai = locate(params["slavetoai"]) in GLOB.ai_list if (newai && newai != borg.connected_ai) - borg.notify_ai(DISCONNECT) + borg.notify_ai(AI_NOTIFICATION_CYBORG_DISCONNECTED) if(borg.shell) borg.undeploy() borg.connected_ai = newai @@ -208,7 +208,7 @@ message_admins("[key_name_admin(user)] slaved [ADMIN_LOOKUPFLW(borg)] to the AI [ADMIN_LOOKUPFLW(newai)].") log_admin("[key_name(user)] slaved [key_name(borg)] to the AI [key_name(newai)].") else if (params["slavetoai"] == "null") - borg.notify_ai(DISCONNECT) + borg.notify_ai(AI_NOTIFICATION_CYBORG_DISCONNECTED) if(borg.shell) borg.undeploy() borg.connected_ai = null diff --git a/code/modules/jobs/job_types/cyborg.dm b/code/modules/jobs/job_types/cyborg.dm index 3a46423433e18..e732bca9677a6 100644 --- a/code/modules/jobs/job_types/cyborg.dm +++ b/code/modules/jobs/job_types/cyborg.dm @@ -24,11 +24,12 @@ CRASH("dynamic preview is unsupported") return H.Robotize(FALSE, latejoin) -/datum/job/cyborg/after_spawn(mob/living/silicon/robot/R, mob/M, latejoin = FALSE, client/preference_source, on_dummy = FALSE) +/datum/job/cyborg/after_spawn(mob/living/silicon/robot/spawned_robot, mob/M, latejoin = FALSE, client/preference_source, on_dummy = FALSE) if(!M.client || on_dummy) return - R.updatename(M.client) - R.gender = NEUTER + spawned_robot.updatename(M.client) + spawned_robot.gender = NEUTER + spawned_robot.notify_ai(AI_NOTIFICATION_NEW_BORG) /datum/job/cyborg/radio_help_message(mob/M) to_chat(M, "Prefix your message with :b to speak with other cyborgs and AI.") diff --git a/code/modules/mob/dead/observer/login.dm b/code/modules/mob/dead/observer/login.dm index 9bb48f0c46380..6374b269b6a7b 100644 --- a/code/modules/mob/dead/observer/login.dm +++ b/code/modules/mob/dead/observer/login.dm @@ -6,7 +6,7 @@ var/preferred_form = null if(IsAdminGhost(src)) - has_unlimited_silicon_privilege = 1 + has_unlimited_silicon_privilege = TRUE if(client.prefs.unlock_content) preferred_form = client.prefs.read_player_preference(/datum/preference/choiced/ghost_form) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index b81a34347cedc..cf027b5f9c989 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -920,15 +920,15 @@ if(!connected_ai) return switch(notifytype) - if(NEW_BORG) //New Cyborg + if(AI_NOTIFICATION_NEW_BORG) //New Cyborg to_chat(connected_ai, "

NOTICE - New cyborg connection detected: [name]
") - if(NEW_MODULE) //New Module + if(AI_NOTIFICATION_NEW_MODEL) //New Model to_chat(connected_ai, "

NOTICE - Cyborg module change detected: [name] has loaded the [designation] module.
") - if(RENAME) //New Name + if(AI_NOTIFICATION_CYBORG_RENAMED) //New Name to_chat(connected_ai, "

NOTICE - Cyborg reclassification detected: [oldname] is now designated as [newname].
") - if(AI_SHELL) //New Shell + if(AI_NOTIFICATION_AI_SHELL) //New Shell to_chat(connected_ai, "

NOTICE - New cyborg shell detected: [name]
") - if(DISCONNECT) //Tampering with the wires + if(AI_NOTIFICATION_CYBORG_DISCONNECTED) //Tampering with the wires to_chat(connected_ai, "

NOTICE - Remote telemetry lost with [name].
") /mob/living/silicon/robot/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE) @@ -1030,14 +1030,14 @@ builtInCamera.toggle_cam(src,0) if(admin_revive) locked = TRUE - notify_ai(NEW_BORG) + notify_ai(AI_NOTIFICATION_NEW_BORG) wires.ui_update() . = 1 /mob/living/silicon/robot/fully_replace_character_name(oldname, newname) ..() if(oldname != real_name) - notify_ai(RENAME, oldname, newname) + notify_ai(AI_NOTIFICATION_CYBORG_RENAMED, oldname, newname) if(!QDELETED(builtInCamera)) builtInCamera.c_tag = real_name modularInterface.saved_identification = real_name diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index faa7cffbacbd7..19e4c715974ee 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -238,7 +238,7 @@ R.anchored = FALSE R.notransform = FALSE R.update_icons() - R.notify_ai(NEW_MODULE) + R.notify_ai(AI_NOTIFICATION_NEW_MODEL) if(R.hud_used) R.hud_used.update_robot_modules_display() SSblackbox.record_feedback("tally", "cyborg_modules", 1, R.module) diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 4ed9a04c30f0d..511bbc43d4a84 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -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" diff --git a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm index 671f5bf797887..5eb00e7273ba8 100644 --- a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm +++ b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm @@ -5,9 +5,8 @@ icon_state = "grievous" health = 150 maxHealth = 150 - baton_type = /obj/item/melee/transforming/energy/sword/saber + weapon = /obj/item/melee/transforming/energy/sword/saber base_speed = 4 //he's a fast fucker - var/obj/item/weapon var/block_chance = 50 noloot = FALSE @@ -17,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 /mob/living/simple_animal/bot/secbot/grievous/nullcrate name = "General Griefsky" @@ -44,8 +43,8 @@ /mob/living/simple_animal/bot/secbot/grievous/Initialize(mapload) . = ..() - weapon = new baton_type(src) - weapon.attack_self(src) + weapon = new weapon(src) + INVOKE_ASYNC(weapon, /obj/item.proc/attack_self, src) /mob/living/simple_animal/bot/secbot/grievous/Destroy() QDEL_NULL(weapon) @@ -111,7 +110,7 @@ /mob/living/simple_animal/bot/secbot/grievous/look_for_perp() anchored = FALSE - var/judgment_criteria = judgment_criteria() + 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 @@ -119,7 +118,7 @@ if((C.name == oldtarget_name) && (world.time < last_found + 100)) continue - threatlevel = C.assess_threat(judgment_criteria, weaponcheck=CALLBACK(src, PROC_REF(check_for_weapons))) + threatlevel = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, PROC_REF(check_for_weapons))) if(!threatlevel) continue @@ -157,6 +156,6 @@ do_sparks(3, TRUE, src) if(!noloot) for(var/IS = 0 to 4) - drop_part(baton_type, Tsec) + drop_part(weapon, Tsec) new /obj/effect/decal/cleanable/oil(Tsec) qdel(src) diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 1d3fe678c2d54..585f28bf86ab7 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -10,7 +10,7 @@ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 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 verb_say = "states" @@ -48,7 +48,8 @@ var/boot_delay = 4 SECONDS //how long the bot takes to turn on from the control panel 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. @@ -61,7 +62,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 @@ -87,7 +88,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. var/list/mode_name = list("In Pursuit","Preparing to Arrest", "Arresting", \ @@ -247,8 +248,8 @@ to_chat(user, "You bypass [src]'s controls.") return //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. @@ -293,15 +294,15 @@ ignorelistcleanuptimer++ if(!on || client) - return + return FALSE 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 by PDA bot_summon() - return + return FALSE return TRUE //Successful completion. Used to prevent child process() continuing if this one is ended early. @@ -332,29 +333,29 @@ else to_chat(user, "Access denied.") -/mob/living/simple_animal/bot/attackby(obj/item/W, mob/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, "The maintenance panel is now [open ? "opened" : "closed"].") else to_chat(user, "The maintenance panel is locked.") - else if(istype(W, /obj/item/card/id) || istype(W, /obj/item/modular_computer/tablet/pda)) + else if(istype(attacking_item, /obj/item/card/id) || istype(attacking_item, /obj/item/modular_computer/tablet/pda)) togglelock(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, "Close the access panel before manipulating the personality slot!") else to_chat(user, "You attempt to pull [paicard] free...") if(do_after(user, 30, target = src)) if (paicard) - user.visible_message("[user] uses [W] to pull [paicard] out of [bot_name]!","You pull [paicard] out of [bot_name] with [W].") + user.visible_message("[user] uses [attacking_item] to pull [paicard] out of [bot_name]!","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.a_intent != INTENT_HARM) + if(attacking_item.tool_behaviour == TOOL_WELDER && user.a_intent != INTENT_HARM) if(health >= maxHealth) to_chat(user, "[src] does not need a repair!") return @@ -362,11 +363,11 @@ to_chat(user, "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("[user] repairs [src]!","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) ..() @@ -778,7 +779,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) @@ -944,8 +945,8 @@ Pass a positive integer as an argument to override a bot's default speed. if("hack") if(!issilicon(usr) && !IsAdminGhost(usr)) return TRUE - if(emagged != 2) - emagged = 2 + if(!emagged) + emagged = TRUE hacked = TRUE locked = TRUE to_chat(usr, "[text_hack]") @@ -1009,7 +1010,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) && !IsAdminGhost(user)) //Bot is hacked, so only silicons and admins are allowed access. @@ -1019,7 +1020,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) || IsAdminGhost(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?"]
" + hack += "[emagged ? "Software compromised! Unit may exhibit dangerous or erratic behavior." : "Unit operating normally. Release safety lock?"]
" hack += "Harm Prevention Safety System: [emagged ? "DANGER" : "Engaged"]
" 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: [remote_disabled ? "Disconnected" : "Connected"]
" diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm index 316551de4f536..8bbd8cd20dc5a 100644 --- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm +++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm @@ -85,9 +85,10 @@ /mob/living/simple_animal/bot/cleanbot/on_emag(atom/target, mob/user) ..() - if(emagged == 2) - if(user) - to_chat(user, "[src] buzzes and beeps.") + if(!emagged) + return + if(user) + to_chat(user, "[src] buzzes and beeps.") /mob/living/simple_animal/bot/cleanbot/process_scan(atom/A) if(iscarbon(A)) @@ -104,9 +105,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 @@ -123,7 +123,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. @@ -227,7 +227,7 @@ M.death() 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 @@ -341,7 +341,7 @@ M.death() 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 diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index 2a58ad5b932c3..bfc9bf2641b4f 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -304,7 +304,7 @@ to_chat(user, "You add the [I] to [src]! Honk!") var/mob/living/simple_animal/bot/honkbot/S = new(drop_location()) S.name = created_name - S.spam_flag = TRUE // only long enough to hear the first ping. + S.limiting_spam = TRUE // only long enough to hear the first ping. addtimer(CALLBACK (S, TYPE_PROC_REF(/mob/living/simple_animal/bot/honkbot, react_ping)), 5) S.bikehorn = I.type qdel(I) @@ -378,7 +378,7 @@ to_chat(user, "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) diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm index 6bbba8dcd59d9..8da2e75545d31 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -10,14 +10,13 @@ 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' var/projectile = /obj/projectile/beam/disabler - var/fair_market_projectile = /obj/projectile/bullet/c38 // For shooting the worst scumbags of all: the poor do_footstep = TRUE /mob/living/simple_animal/bot/secbot/ed209/Initialize(mapload) @@ -39,34 +38,33 @@ set_weapon() /mob/living/simple_animal/bot/secbot/ed209/handle_automated_action() - var/judgment_criteria = judgment_criteria() + 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(judgment_criteria, weaponcheck=CALLBACK(src, PROC_REF(check_for_weapons))) - //speak(C.real_name + text(": threat: []", threatlevel)) + threatlevel = nearby_carbon.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, PROC_REF(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 @@ -80,10 +78,10 @@ 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)) @@ -91,34 +89,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) diff --git a/code/modules/mob/living/simple_animal/bot/firebot.dm b/code/modules/mob/living/simple_animal/bot/firebot.dm index d3d56fbdb8ed8..716fabfc4dc3d 100644 --- a/code/modules/mob/living/simple_animal/bot/firebot.dm +++ b/code/modules/mob/living/simple_animal/bot/firebot.dm @@ -122,7 +122,7 @@ /mob/living/simple_animal/bot/firebot/on_emag(atom/target, mob/user) ..() - if(emagged == 2) + if(emagged) if(user) to_chat(user, "[src] buzzes and beeps.") audible_message("[src] buzzes oddly!") @@ -158,7 +158,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)) @@ -206,7 +206,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!") diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm index 54a1cd0b48476..e532f58ff9509 100644 --- a/code/modules/mob/living/simple_animal/bot/floorbot.dm +++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm @@ -131,9 +131,10 @@ /mob/living/simple_animal/bot/floorbot/on_emag(atom/target, mob/user) ..() - if(emagged == 2) - if(user) - to_chat(user, "[src] buzzes and beeps.") + if(!emagged) + return + if(user) + to_chat(user, "[src] buzzes and beeps.") /mob/living/simple_animal/bot/floorbot/Topic(href, href_list) if(..()) @@ -185,7 +186,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 @@ -210,7 +211,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) @@ -232,9 +233,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 anchored = TRUE mode = BOT_REPAIRING diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm index ba476701562af..ad929bf04c80b 100644 --- a/code/modules/mob/living/simple_animal/bot/honkbot.dm +++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm @@ -21,7 +21,7 @@ path_image_color = "#FF69B4" var/honksound = 'sound/items/bikehorn.ogg' //customizable sound - var/spam_flag = FALSE + var/limiting_spam = FALSE var/cooldowntime = 30 var/cooldowntimehorn = 10 var/mob/living/carbon/target @@ -51,8 +51,8 @@ ) AddElement(/datum/element/connect_loc, loc_connections) -/mob/living/simple_animal/bot/honkbot/proc/spam_flag_false() //used for addtimer - spam_flag = FALSE +/mob/living/simple_animal/bot/honkbot/proc/limiting_spam_false() //used for addtimer + limiting_spam = FALSE /mob/living/simple_animal/bot/honkbot/proc/sensor_blink() icon_state = "honkbot-c" @@ -61,9 +61,9 @@ //honkbots react with sounds. /mob/living/simple_animal/bot/honkbot/proc/react_ping() playsound(src, 'sound/machines/ping.ogg', 50, TRUE, -1) //the first sound upon creation! - spam_flag = TRUE + limiting_spam = TRUE sensor_blink() - addtimer(CALLBACK(src, PROC_REF(spam_flag_false)), 18) // calibrates before starting the honk + addtimer(CALLBACK(src, PROC_REF(limiting_spam_false)), 18) // calibrates before starting the honk /mob/living/simple_animal/bot/honkbot/proc/react_buzz() playsound(src, 'sound/machines/buzz-sigh.ogg', 50, TRUE, -1) @@ -76,7 +76,7 @@ anchored = FALSE SSmove_manager.stop_looping(src) last_found = world.time - spam_flag = FALSE + limiting_spam = FALSE /mob/living/simple_animal/bot/honkbot/set_custom_texts() @@ -98,17 +98,17 @@ dat += "
Auto Patrol: [auto_patrol ? "On" : "Off"]" return dat -/mob/living/simple_animal/bot/honkbot/proc/judgment_criteria() +/mob/living/simple_animal/bot/honkbot/proc/judgement_criteria() var/final = NONE if(check_records) final = final|JUDGE_RECORDCHECK - if(emagged == 2) + if(emagged) final = final|JUDGE_EMAGGED return final /mob/living/simple_animal/bot/honkbot/proc/retaliate(mob/living/carbon/human/H) - var/judgment_criteria = judgment_criteria() - threatlevel = H.assess_threat(judgment_criteria) + var/judgement_criteria = judgement_criteria() + threatlevel = H.assess_threat(judgement_criteria) threatlevel += 6 if(threatlevel >= 4) target = H @@ -129,13 +129,14 @@ /mob/living/simple_animal/bot/honkbot/on_emag(atom/target, mob/user) ..() - if(emagged == 2) - if(user) - user << "You short out [src]'s sound control system. It gives out an evil laugh!!" - oldtarget_name = user.name - audible_message("[src] gives out an evil laugh!") - playsound(src, 'sound/machines/honkbot_evil_laugh.ogg', 75, 1, -1) // evil laughter - update_icon() + if(!emagged) + return + if(user) + to_chat(user,"You short out [src]'s sound control system. It gives out an evil laugh!!") + oldtarget_name = user.name + audible_message("[src] gives out an evil laugh!") + playsound(src, 'sound/machines/honkbot_evil_laugh.ogg', 75, 1, -1) // evil laughter + update_icon() /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))) @@ -147,13 +148,13 @@ return if(iscarbon(A)) var/mob/living/carbon/C = A - if (emagged <= 1) + if(emagged) honk_attack(A) else if(!C.IsParalyzed() || arrest_type) stun_attack(A) ..() - else if (!spam_flag) //honking at the ground + else if (!limiting_spam) //honking at the ground bike_horn(A) @@ -168,32 +169,32 @@ ..() /mob/living/simple_animal/bot/honkbot/proc/bike_horn() //use bike_horn - if (emagged <= 1) - if (!spam_flag) - playsound(src, honksound, 50, TRUE, -1) - spam_flag = TRUE //prevent spam - sensor_blink() - addtimer(CALLBACK(src, PROC_REF(spam_flag_false)), cooldowntimehorn) - else if (emagged == 2) //emagged honkbots will spam short and memorable sounds. - if (!spam_flag) + if (emagged) //emagged honkbots will spam short and memorable sounds. + if (!limiting_spam) playsound(src, "honkbot_e", 50, 0) - spam_flag = TRUE // prevent spam + limiting_spam = TRUE // prevent spam icon_state = "honkbot-e" addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon)), 30, TIMER_OVERRIDE|TIMER_UNIQUE) - addtimer(CALLBACK(src, PROC_REF(spam_flag_false)), cooldowntimehorn) + addtimer(CALLBACK(src, PROC_REF(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_REF(limiting_spam_false), cooldowntimehorn)) /mob/living/simple_animal/bot/honkbot/proc/honk_attack(mob/living/carbon/C) // horn attack - if(!spam_flag) + if(!limiting_spam) playsound(loc, honksound, 50, TRUE, -1) - spam_flag = TRUE // prevent spam + limiting_spam = TRUE // prevent spam sensor_blink() - addtimer(CALLBACK(src, PROC_REF(spam_flag_false)), cooldowntimehorn) + addtimer(CALLBACK(src, PROC_REF(limiting_spam_false)), cooldowntimehorn) /mob/living/simple_animal/bot/honkbot/proc/stun_attack(mob/living/carbon/C) // airhorn stun - if(!spam_flag) + if(!limiting_spam) playsound(src, 'sound/items/AirHorn.ogg', 100, TRUE, -1) //HEEEEEEEEEEEENK!! sensor_blink() - if(spam_flag == 0) + if(limiting_spam == 0) if(ishuman(C)) C.stuttering = 20 C.adjustEarDamage(0, 5) //far less damage than the H.O.N.K. @@ -201,15 +202,16 @@ C.Paralyze(60) var/mob/living/carbon/human/H = C if(client) //prevent spam from players.. - spam_flag = TRUE - if (emagged <= 1) //HONK once, then leave - var/judgment_criteria = judgment_criteria() - threatlevel = H.assess_threat(judgment_criteria) + limiting_spam = TRUE + 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_REF(spam_flag_false)), cooldowntime) + addtimer(CALLBACK(src, PROC_REF(limiting_spam_false)), cooldowntime) log_combat(src,C,"honked") @@ -218,7 +220,7 @@ else C.stuttering = 20 C.Paralyze(80) - addtimer(CALLBACK(src, PROC_REF(spam_flag_false)), cooldowntime) + addtimer(CALLBACK(src, PROC_REF(limiting_spam_false)), cooldowntime) /mob/living/simple_animal/bot/honkbot/handle_automated_action() @@ -299,17 +301,17 @@ if((C.name == oldtarget_name) && (world.time < last_found + 100)) continue - var/judgment_criteria = judgment_criteria() - threatlevel = C.assess_threat(judgment_criteria) + var/judgement_criteria = judgement_criteria() + threatlevel = C.assess_threat(judgement_criteria) - if(threatlevel <= 3 && get_dist(C, src) <= 4 && !spam_flag) + if(threatlevel <= 3 && get_dist(C, src) <= 4 && !limiting_spam) bike_horn() else if(threatlevel >= 10) bike_horn() //just spam the shit outta this else if(threatlevel >= 4) - if(!spam_flag) + if(!limiting_spam) target = C oldtarget_name = C.name bike_horn() diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm index 95ae8ca007059..5e6acc9bc1fc0 100644 --- a/code/modules/mob/living/simple_animal/bot/medbot.dm +++ b/code/modules/mob/living/simple_animal/bot/medbot.dm @@ -219,15 +219,16 @@ GLOBAL_VAR(medibot_unique_id_gen) /mob/living/simple_animal/bot/medbot/on_emag(atom/target, mob/user) ..() - if(emagged == 2) - declare_crit = 0 - if(user) - to_chat(user, "You short out [src]'s reagent synthesis circuits.") - audible_message("[src] buzzes oddly!") - flick("medibot_spark", src) - playsound(src, "sparks", 75, TRUE) - if(user) - oldpatient = user + if(!emagged) + return + declare_crit = FALSE + if(user) + to_chat(user, "You short out [src]'s reagent synthesis circuits.") + audible_message("[src] buzzes oddly!") + flick("medibot_spark", src) + playsound(src, "sparks", 75, 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) @@ -427,8 +428,7 @@ GLOBAL_VAR(medibot_unique_id_gen) if(istype(C.dna.species, /datum/species/ipc)) return FALSE - if(emagged == 2) //Everyone needs our medicine. (Our medicine is toxins) - return TRUE + if(emagged) //Everyone needs our medicine. (Our medicine is toxins) if(HAS_TRAIT(C,TRAIT_MEDIBOTCOMINGTHROUGH) && !HAS_TRAIT_FROM(C,TRAIT_MEDIBOTCOMINGTHROUGH,medibot_counter)) //someone is healing them already sweetie return FALSE @@ -530,7 +530,7 @@ GLOBAL_VAR(medibot_unique_id_gen) else if(C.getToxLoss() >= heal_threshold) treatment_method = TOX - 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.health < heal_threshold) to_chat(src, "[C] is healthy! Your programming prevents you from injecting anyone without at least [heal_threshold] damage of any one type ([heal_threshold + 5] for oxygen damage.)") var/list/messagevoice = list("All patched up!" = 'sound/voice/medbot/patchedup.ogg',"An apple a day keeps me away." = 'sound/voice/medbot/apple.ogg',"Feel better soon!" = 'sound/voice/medbot/feelbetter.ogg') @@ -551,7 +551,7 @@ GLOBAL_VAR(medibot_unique_id_gen) healies *= 1.5 if(treatment_method == TOX && HAS_TRAIT(patient, TRAIT_TOXINLOVER)) healies *= -1.5 - 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)") diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index 03fad04c2826f..2f111325dd741 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -23,26 +23,38 @@ boot_delay = 8 SECONDS var/noloot = FALSE - var/baton_type = /obj/item/melee/baton + ///The tool this Secbot will use to make arrests + var/obj/item/weapon = /obj/item/melee/baton + ///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 + + ///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 + + /// Force of the harmbaton used on them + var/weapon_force = 20 + ///The department the secbot will deposit collected money into /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/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 Officer Beep O'sky's smaller, just-as aggressive cousin, Pipsqueak." @@ -52,20 +64,19 @@ resize = 0.8 update_transform() +/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/S = new(Tsec) - S.reagents.add_reagent(/datum/reagent/consumable/ethanol/whiskey, 15) - S.on_reagent_change(ADD_REAGENT) + var/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass/drinking_oil = new(Tsec) + drinking_oil.reagents.add_reagent(/datum/reagent/consumable/ethanol/whiskey, 15) + drinking_oil.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 = RADIO_CHANNEL_AI_PRIVATE - /mob/living/simple_animal/bot/secbot/Initialize(mapload) . = ..() update_appearance(UPDATE_ICON) @@ -117,56 +128,56 @@ if(!locked || issilicon(user) || IsAdminGhost(user)) dat += "
" - dat += "
Arrest Unidentifiable Persons: [idcheck ? "Yes" : "No"]" - dat += "
Arrest for Unauthorized Weapons: [weaponscheck ? "Yes" : "No"]" - dat += "
Arrest for Warrant: [check_records ? "Yes" : "No"]" - dat += "
Operating Mode: [arrest_type ? "Detain" : "Arrest"]" - dat += "
Report Arrests [declare_arrests ? "Yes" : "No"]" + dat += "
Arrest Unidentifiable Persons: [security_mode_flags & SECBOT_CHECK_IDS ? "Yes" : "No"]" + dat += "
Arrest for Unauthorized Weapons: [security_mode_flags & SECBOT_CHECK_WEAPONS ? "Yes" : "No"]" + dat += "
Arrest for Warrant: [security_mode_flags & SECBOT_CHECK_RECORDS ? "Yes" : "No"]" + dat += "
Operating Mode: [security_mode_flags & SECBOT_HANDCUFF_TARGET ? "Arrest" : "Detain"]" + dat += "
Report Arrests [security_mode_flags & SECBOT_DECLARE_ARRESTS ? "Yes" : "No"]" dat += "
Auto Patrol: [auto_patrol ? "On" : "Off"]" return dat /mob/living/simple_animal/bot/secbot/Topic(href, href_list) - if(..()) + . = ..() + if(.) return TRUE + if(!issilicon(usr) && !IsAdminGhost(usr) && !(bot_core.allowed(usr) || !locked)) 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 + + update_controls() -/mob/living/simple_animal/bot/secbot/proc/retaliate(mob/living/carbon/human/H) - var/judgment_criteria = judgment_criteria() - threatlevel = H.assess_threat(judgment_criteria, weaponcheck=CALLBACK(src, PROC_REF(check_for_weapons))) +/mob/living/simple_animal/bot/secbot/proc/retaliate(mob/living/carbon/human/attacking_human) + var/judgement_criteria = judgement_criteria() + threatlevel = attacking_human.assess_threat(judgement_criteria, weaponcheck = CALLBACK(src, PROC_REF(check_for_weapons))) threatlevel += 6 if(threatlevel >= 4) - target = H + target = attacking_human mode = BOT_HUNT -/mob/living/simple_animal/bot/secbot/proc/judgment_criteria() +/mob/living/simple_animal/bot/secbot/proc/judgement_criteria() var/final = FALSE - if(idcheck) + if(emagged) + final |= JUDGE_EMAGGED + if(bot_type == ADVANCED_SEC_BOT) + final |= JUDGE_IGNOREMONKEYS + if(security_mode_flags & SECBOT_CHECK_IDS) final |= JUDGE_IDCHECK - if(check_records) + if(security_mode_flags & SECBOT_CHECK_RECORDS) final |= JUDGE_RECORDCHECK - if(weaponscheck) + if(security_mode_flags & SECBOT_CHECK_WEAPONS) final |= JUDGE_WEAPONCHECK - if(emagged == 2) - final |= JUDGE_EMAGGED - if(ranged) - final |= JUDGE_IGNOREMONKEYS return final /mob/living/simple_animal/bot/secbot/proc/special_retaliate_after_attack(mob/user) //allows special actions to take place after being attacked. @@ -180,24 +191,24 @@ return ..() -/mob/living/simple_animal/bot/secbot/attackby(obj/item/W, mob/user, params) +/mob/living/simple_animal/bot/secbot/attackby(obj/item/attacking_item, mob/user, params) ..() - if(W.tool_behaviour == TOOL_WELDER && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry. + if(attacking_item.tool_behaviour == TOOL_WELDER && user.a_intent != INTENT_HARM) // 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/on_emag(atom/target, 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_appearance() + if(!emagged) + return + if(user) + to_chat(user, "You short out [src]'s target assessment circuits.") + oldtarget_name = user.name + audible_message("[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)) @@ -206,127 +217,123 @@ retaliate(Proj.firer) return ..() -/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/A) +/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers) if(!on) return - if(iscarbon(A)) - var/mob/living/carbon/C = A - if(!C.IsParalyzed() || arrest_type) - 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, 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) + if(!iscarbon(attack_target)) + return ..() + var/mob/living/carbon/carbon_target = attack_target + if(!carbon_target.IsParalyzed() || !(security_mode_flags & SECBOT_HANDCUFF_TARGET)) + 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/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("[src] is trying to put zipties on [C]!",\ + current_target.visible_message("[src] is trying to put zipties on [current_target]!",\ "[src] is trying to put zipties on you!") - addtimer(CALLBACK(src, PROC_REF(attempt_handcuff), C), 60) + addtimer(CALLBACK(src, PROC_REF(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.handcuffed = new /obj/item/restraints/handcuffs/cable/zipties/used(C) - C.update_handcuffed() + if(!current_target.handcuffed) + current_target.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) - var/judgment_criteria = judgment_criteria() +/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/current_target) + var/judgement_criteria = judgement_criteria() var/threat = 5 - if(ishuman(C)) - var/mob/living/carbon/human/H = C - if(H.check_shields(src, 0)) + if(ishuman(current_target)) + var/mob/living/carbon/human/human_target = current_target + if(human_target.check_shields(src, 0)) return - threat = H.assess_threat(judgment_criteria, weaponcheck=CALLBACK(src, PROC_REF(check_for_weapons))) + threat = human_target.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, PROC_REF(check_for_weapons))) else - threat = C.assess_threat(judgment_criteria, weaponcheck=CALLBACK(src, PROC_REF(check_for_weapons))) - if(declare_arrests) + threat = current_target.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, PROC_REF(check_for_weapons))) + if(security_mode_flags & SECBOT_DECLARE_ARRESTS) var/area/location = get_area(src) - speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag [C] in [location].", radio_channel) + speak("[security_mode_flags & SECBOT_HANDCUFF_TARGET ? "Arresting" : "Detaining"] level [threat] scumbag [current_target] in [location].", radio_channel) - var/armor_block = C.run_armor_check(BODY_ZONE_CHEST, "stamina") - C.apply_damage(85, STAMINA, BODY_ZONE_CHEST, armor_block) - C.apply_effect(EFFECT_STUTTER, 50) - C.visible_message( - "[src] has stunned [C]!",\ + var/armor_block = current_target.run_armor_check(BODY_ZONE_CHEST, "stamina") + current_target.apply_damage(85, STAMINA, BODY_ZONE_CHEST, armor_block) + current_target.apply_effect(EFFECT_STUTTER, 50) + current_target.visible_message( + "[src] has stunned [current_target]!",\ "[src] has stunned you!" ) - log_combat(src, C, "stunned") + log_combat(src, target, "stunned") playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1) icon_state = "[initial(icon_state)]-c" addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_appearance)), 0.2 SECONDS) /mob/living/simple_animal/bot/secbot/handle_automated_action() - if(!..()) + . = ..() + if(!.) return switch(mode) - if(BOT_IDLE) // idle - + if(BOT_IDLE) // idle SSmove_manager.stop_looping(src) 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(BOT_HUNT) // hunting for perp // if can't reach perp for long enough, go idle if(frustration >= 8) SSmove_manager.stop_looping(src) back_to_idle() return - if(target) // make sure target exists - if(Adjacent(target) && isturf(target.loc)) // if right next to perp - stun_attack(target) + if(!target) // make sure target exists + back_to_idle() + return + 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 + mode = BOT_PREP_ARREST + anchored = TRUE + target_lastloc = target.loc + return - else // not next to perp - var/turf/olddist = get_dist(src, target) - SSmove_manager.move_to(src, target, 1, 4) - if((get_dist(src, target)) >= (olddist)) - frustration++ - else - frustration = 0 + // not next to perp + var/turf/olddist = get_dist(src, target) + SSmove_manager.move_to(src, target, 1, 4) + if((get_dist(src, target)) >= (olddist)) + frustration++ else - back_to_idle() - - if(BOT_PREP_ARREST) // preparing to arrest target + 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.getStaminaLoss() < 100) + if(!Adjacent(target) || !isturf(target.loc) || target.getStaminaLoss() < 100) 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) @@ -355,9 +362,6 @@ look_for_perp() bot_patrol() - - return - /mob/living/simple_animal/bot/secbot/proc/back_to_idle() anchored = FALSE mode = BOT_IDLE @@ -375,33 +379,31 @@ /mob/living/simple_animal/bot/secbot/proc/look_for_perp() anchored = FALSE - var/judgment_criteria = judgment_criteria() - for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal - if((C.stat) || (C.handcuffed)) + var/judgement_criteria = judgement_criteria() + 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(judgment_criteria, weaponcheck=CALLBACK(src, PROC_REF(check_for_weapons))) + threatlevel = nearby_carbons.assess_threat(judgement_criteria, weaponcheck = CALLBACK(src, PROC_REF(check_for_weapons))) if(!threatlevel) continue else if(threatlevel >= 4) - target = C - oldtarget_name = C.name + 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("[src] points at [C.name]!") + visible_message("[src] points at [nearby_carbons.name]!") mode = BOT_HUNT INVOKE_ASYNC(src, PROC_REF(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)) @@ -411,15 +413,15 @@ /mob/living/simple_animal/bot/secbot/explode() visible_message("[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_icon() + 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)) @@ -430,12 +432,12 @@ 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) @@ -459,7 +461,6 @@ if(!istype(C) || !C || in_range(src, target)) return knockOver(C) - return /obj/machinery/bot_core/secbot req_access = list(ACCESS_SECURITY) diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm index 9ab732c688f15..f69b7bed8e58d 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -40,7 +40,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 diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 6deecca18e823..b10c6544f5712 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -175,7 +175,7 @@ var/image/digitaldisguise = null /// 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 diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index d8720c5cd408c..f2417b399b360 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -547,7 +547,7 @@ R.mmi.brainmob.name = real_name R.job = JOB_NAME_CYBORG - R.notify_ai(NEW_BORG) + R.notify_ai(AI_NOTIFICATION_NEW_BORG) . = R if(R.ckey && is_banned_from(R.ckey, JOB_NAME_CYBORG)) diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index bddd7878e4d8b..72ed9f0f2a968 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -175,7 +175,7 @@ Robot.undeploy() // disconnect any AI shells first if(Robot.mmi) qdel(Robot.mmi) - Robot.notify_ai(NEW_BORG) + Robot.notify_ai(AI_NOTIFICATION_NEW_BORG) else for(var/obj/item/W in contents) if(!M.dropItemToGround(W)) diff --git a/code/modules/spells/spell_types/conjure.dm b/code/modules/spells/spell_types/conjure.dm index d1d2dd29f66a5..4aa6beff3de24 100644 --- a/code/modules/spells/spell_types/conjure.dm +++ b/code/modules/spells/spell_types/conjure.dm @@ -10,7 +10,7 @@ var/summon_ignore_density = FALSE //if set to TRUE, adds dense tiles to possible spawn places var/summon_ignore_prev_spawn_points = TRUE //if set to TRUE, each new object is summoned on a new spawn point - var/list/newVars = list() //vars of the summoned objects will be replaced with those where they meet + var/list/new_vars = list() //vars of the summoned objects will be replaced with those where they meet //should have format of list("emagged" = 1,"name" = "Wizard's Justicebot"), for example var/cast_sound = 'sound/items/welder.ogg' @@ -38,9 +38,9 @@ else var/atom/summoned_object = new summoned_object_type(spawn_place) - for(var/varName in newVars) - if(varName in newVars) - summoned_object.vv_edit_var(varName, newVars[varName]) + for(var/varName in new_vars) + if(varName in new_vars) + summoned_object.vv_edit_var(varName, new_vars[varName]) summoned_object.flags_1 |= ADMIN_SPAWNED_1 if(summon_lifespan) QDEL_IN(summoned_object, summon_lifespan) @@ -57,11 +57,12 @@ summon_type = list(/mob/living/simple_animal/bot/secbot/ed209) summon_amt = 10 range = 3 - newVars = list( + new_vars = list( "emagged" = 2, "remote_disabled" = 1, + "shoot_sound" = 'sound/weapons/laser.ogg', "projectile" = /obj/projectile/beam/laser, - "declare_arrests" = 0, + "security_mode_flags" = ~(SECBOT_DECLARE_ARRESTS), "name" = "Wizard's Justicebot" ) From c5ca6068506456bc123d328956f4dffbba2a8088 Mon Sep 17 00:00:00 2001 From: RKz Date: Wed, 25 Oct 2023 09:34:50 -0400 Subject: [PATCH 12/20] map changes --- _maps/map_files/BoxStation/BoxStation.dmm | 9 +-------- _maps/map_files/CorgStation/CorgStation.dmm | 9 +-------- _maps/map_files/FlandStation/FlandStation.dmm | 9 +-------- _maps/map_files/MetaStation/MetaStation.dmm | 9 +-------- _maps/map_files/RadStation/RadStation.dmm | 9 +-------- 5 files changed, 5 insertions(+), 40 deletions(-) diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm index 0b70bd6d4a71c..0b49ecd309e48 100644 --- a/_maps/map_files/BoxStation/BoxStation.dmm +++ b/_maps/map_files/BoxStation/BoxStation.dmm @@ -8294,14 +8294,7 @@ /area/maintenance/disposal) "bkA" = ( /obj/effect/landmark/event_spawn, -/mob/living/simple_animal/bot/secbot{ - arrest_type = 1; - health = 45; - icon_state = "secbot1"; - idcheck = 1; - name = "Sergeant-at-Armsky"; - weaponscheck = 1 - }, +/mob/living/simple_animal/bot/secbot/beepsky/armsky, /turf/open/floor/plasteel, /area/ai_monitored/security/armory) "bkB" = ( diff --git a/_maps/map_files/CorgStation/CorgStation.dmm b/_maps/map_files/CorgStation/CorgStation.dmm index 5f380a2841e01..487959af2e797 100644 --- a/_maps/map_files/CorgStation/CorgStation.dmm +++ b/_maps/map_files/CorgStation/CorgStation.dmm @@ -43,14 +43,7 @@ dir = 1 }, /obj/effect/turf_decal/stripes/line, -/mob/living/simple_animal/bot/secbot{ - arrest_type = 1; - health = 45; - icon_state = "secbot1"; - idcheck = 1; - name = "Sergeant-at-Armsky"; - weaponscheck = 1 - }, +/mob/living/simple_animal/bot/secbot/beepsky/armsky, /turf/open/floor/plasteel/dark, /area/ai_monitored/security/armory) "aaf" = ( diff --git a/_maps/map_files/FlandStation/FlandStation.dmm b/_maps/map_files/FlandStation/FlandStation.dmm index d66ca745c74da..09585f3b4487f 100644 --- a/_maps/map_files/FlandStation/FlandStation.dmm +++ b/_maps/map_files/FlandStation/FlandStation.dmm @@ -89463,14 +89463,7 @@ /obj/effect/turf_decal/trimline/red/filled/corner{ dir = 8 }, -/mob/living/simple_animal/bot/secbot{ - arrest_type = 1; - health = 45; - icon_state = "secbot1"; - idcheck = 1; - name = "Sergeant-at-Armsky"; - weaponscheck = 1 - }, +/mob/living/simple_animal/bot/secbot/beepsky/armsky, /turf/open/floor/plasteel/dark, /area/ai_monitored/security/armory) "wAI" = ( diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index a2f5e91b7f00a..d7fa696ca062f 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -37124,14 +37124,7 @@ /turf/open/floor/plasteel, /area/hallway/primary/port) "gLe" = ( -/mob/living/simple_animal/bot/secbot{ - arrest_type = 1; - health = 45; - icon_state = "secbot1"; - idcheck = 1; - name = "Sergeant-at-Armsky"; - weaponscheck = 1 - }, +/mob/living/simple_animal/bot/secbot/beepsky/armsky, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer4{ dir = 8 }, diff --git a/_maps/map_files/RadStation/RadStation.dmm b/_maps/map_files/RadStation/RadStation.dmm index 88828a54e40a7..e7476e993dba3 100644 --- a/_maps/map_files/RadStation/RadStation.dmm +++ b/_maps/map_files/RadStation/RadStation.dmm @@ -17668,14 +17668,7 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ dir = 4 }, -/mob/living/simple_animal/bot/secbot{ - arrest_type = 1; - health = 45; - icon_state = "secbot1"; - idcheck = 1; - name = "Sergeant-at-Armsky"; - weaponscheck = 1 - }, +/mob/living/simple_animal/bot/secbot/beepsky/armsky, /obj/structure/cable/yellow{ icon_state = "4-8" }, From e9eda30697686bf8e583091195678e587bec26fa Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 26 Oct 2023 15:57:22 -0400 Subject: [PATCH 13/20] cleanup --- .../mob/living/simple_animal/bot/SuperBeepsky.dm | 13 +++++++------ .../mob/living/simple_animal/bot/ed209bot.dm | 2 +- code/modules/mob/living/simple_animal/bot/secbot.dm | 12 +++++++++--- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm index 5eb00e7273ba8..b83dc49dc5e2e 100644 --- a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm +++ b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm @@ -5,7 +5,8 @@ icon_state = "grievous" health = 150 maxHealth = 150 - weapon = /obj/item/melee/transforming/energy/sword/saber + + baton_type = /obj/item/melee/transforming/energy/sword/saber base_speed = 4 //he's a fast fucker var/block_chance = 50 noloot = FALSE @@ -16,7 +17,7 @@ desc = "An adorable looking secbot with four toy swords taped to its arms" health = 50 maxHealth = 50 - weapon = /obj/item/toy/sword + baton_type = /obj/item/toy/sword /mob/living/simple_animal/bot/secbot/grievous/nullcrate name = "General Griefsky" @@ -44,7 +45,7 @@ /mob/living/simple_animal/bot/secbot/grievous/Initialize(mapload) . = ..() weapon = new weapon(src) - INVOKE_ASYNC(weapon, /obj/item.proc/attack_self, src) + INVOKE_ASYNC(weapon, TYPE_PROC_REF(/obj/item, attack_self), src) /mob/living/simple_animal/bot/secbot/grievous/Destroy() QDEL_NULL(weapon) @@ -70,14 +71,14 @@ if(!on) return switch(mode) - if(BOT_IDLE) // idle - update_icon() + if(BOT_IDLE) // idle + update_appearance() SSmove_manager.stop_looping(src) 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 - update_icon() + update_appearance() playsound(src,'sound/effects/beepskyspinsabre.ogg',100,TRUE,-1) // general beepsky doesn't give up so easily, jedi scum if(frustration >= 20) diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm index 8da2e75545d31..8dd9d576641c7 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -13,6 +13,7 @@ bot_type = ADVANCED_SEC_BOT window_id = "autoed209" window_name = "Automatic Security Unit v2.6" + var/lastfired = 0 var/shot_delay = 15 var/shoot_sound = 'sound/weapons/laser.ogg' @@ -74,7 +75,6 @@ return if(!isturf(T)) return - if(!projectile) return diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index 2f111325dd741..55a447c6769b9 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -23,8 +23,9 @@ boot_delay = 8 SECONDS var/noloot = FALSE - ///The tool this Secbot will use to make arrests - var/obj/item/weapon = /obj/item/melee/baton + var/baton_type = /obj/item/melee/baton + ///The weapon (from baton_type) that will be used to make arrests. + var/obj/item/weapon ///Their current target var/mob/living/carbon/target ///Name of their last target to prevent spamming @@ -79,6 +80,7 @@ /mob/living/simple_animal/bot/secbot/Initialize(mapload) . = ..() + weapon = new baton_type() update_appearance(UPDATE_ICON) var/datum/job/J = SSjob.GetJob(JOB_NAME_DETECTIVE) @@ -93,6 +95,10 @@ ) AddElement(/datum/element/connect_loc, loc_connections) +/mob/living/simple_animal/bot/secbot/Destroy() + QDEL_NULL(weapon) + return ..() + /mob/living/simple_animal/bot/secbot/update_icon_state() if(mode == BOT_HUNT) icon_state = "[initial(icon_state)]-c" @@ -437,7 +443,7 @@ secbot_assembly.add_overlay("hs_hole") secbot_assembly.created_name = name new /obj/item/assembly/prox_sensor(Tsec) - drop_part(weapon, Tsec) + drop_part(baton_type, Tsec) if(prob(50)) drop_part(robot_arm, Tsec) From e75ff3ab90fdae7aaa13b2fbce3e9cc0c291e067 Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 26 Oct 2023 16:39:53 -0400 Subject: [PATCH 14/20] clean up drop_part --- .../living/simple_animal/bot/SuperBeepsky.dm | 5 +--- .../mob/living/simple_animal/bot/atmosbot.dm | 3 --- .../mob/living/simple_animal/bot/bot.dm | 25 ++++++++++--------- .../mob/living/simple_animal/bot/cleanbot.dm | 5 ---- .../mob/living/simple_animal/bot/firebot.dm | 3 --- .../mob/living/simple_animal/bot/floorbot.dm | 3 --- .../mob/living/simple_animal/bot/honkbot.dm | 3 +-- .../mob/living/simple_animal/bot/medbot.dm | 6 ++--- .../mob/living/simple_animal/bot/secbot.dm | 4 +-- 9 files changed, 18 insertions(+), 39 deletions(-) diff --git a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm index b83dc49dc5e2e..fd6ae783e8cae 100644 --- a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm +++ b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm @@ -141,7 +141,7 @@ /mob/living/simple_animal/bot/secbot/grievous/explode() - + ..() visible_message("[src] lets out a huge cough as it blows apart!") var/atom/Tsec = drop_location() @@ -151,9 +151,6 @@ Sa.created_name = name new /obj/item/assembly/prox_sensor(Tsec) - if(prob(50)) - drop_part(robot_arm, Tsec) - do_sparks(3, TRUE, src) if(!noloot) for(var/IS = 0 to 4) diff --git a/code/modules/mob/living/simple_animal/bot/atmosbot.dm b/code/modules/mob/living/simple_animal/bot/atmosbot.dm index 6a42640d86618..2e830bcb8058d 100644 --- a/code/modules/mob/living/simple_animal/bot/atmosbot.dm +++ b/code/modules/mob/living/simple_animal/bot/atmosbot.dm @@ -383,8 +383,5 @@ if(deployed_holobarrier) qdel(deployed_holobarrier.resolve()) - if(prob(50)) - drop_part(robot_arm, Tsec) - do_sparks(3, TRUE, src) ..() diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 585f28bf86ab7..98495539a450a 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -223,6 +223,9 @@ /mob/living/simple_animal/bot/proc/explode() qdel(src) + var/atom/location_destroyed = drop_location() + if(prob(50)) + drop_part(robot_arm, location_destroyed) /mob/living/simple_animal/bot/proc/should_emag(atom/target, mob/user) SIGNAL_HANDLER @@ -427,26 +430,24 @@ return REDUCE_RANGE /mob/living/simple_animal/bot/proc/drop_part(obj/item/drop_item, dropzone) - var/obj/item/dropped_item if(ispath(drop_item)) - dropped_item = new drop_item(dropzone) + new drop_item(dropzone) else - dropped_item = drop_item - dropped_item.forceMove(dropzone) + drop_item.forceMove(dropzone) - if(istype(dropped_item, /obj/item/stock_parts/cell)) - var/obj/item/stock_parts/cell/dropped_cell = dropped_item + if(istype(drop_item, /obj/item/stock_parts/cell)) + var/obj/item/stock_parts/cell/dropped_cell = drop_item dropped_cell.charge = 0 - dropped_cell.update_icon() + dropped_cell.update_appearance() - else if(istype(dropped_item, /obj/item/storage)) - var/obj/item/storage/S = dropped_item + else if(istype(drop_item, /obj/item/storage)) + var/obj/item/storage/S = drop_item S.contents = list() - else if(istype(dropped_item, /obj/item/gun/energy)) - var/obj/item/gun/energy/dropped_gun = dropped_item + else if(istype(drop_item, /obj/item/gun/energy)) + var/obj/item/gun/energy/dropped_gun = drop_item dropped_gun.cell.charge = 0 - dropped_gun.update_icon() + dropped_gun.update_appearance() //Generalized behavior code, override where needed! diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm index 8bbd8cd20dc5a..37fda4e3c47e1 100644 --- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm +++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm @@ -275,9 +275,6 @@ new /obj/item/assembly/prox_sensor(Tsec) - if(prob(50)) - drop_part(robot_arm, Tsec) - do_sparks(3, TRUE, src) ..() @@ -408,8 +405,6 @@ new /obj/item/larryframe(Tsec) new /obj/item/assembly/prox_sensor(Tsec) - if(prob(50)) - drop_part(robot_arm, Tsec) if(knife && prob(50)) new knife(Tsec) diff --git a/code/modules/mob/living/simple_animal/bot/firebot.dm b/code/modules/mob/living/simple_animal/bot/firebot.dm index 716fabfc4dc3d..f9b9b85428f39 100644 --- a/code/modules/mob/living/simple_animal/bot/firebot.dm +++ b/code/modules/mob/living/simple_animal/bot/firebot.dm @@ -312,9 +312,6 @@ var/turf/open/theturf = T theturf.MakeSlippery(TURF_WET_WATER, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS) - if(prob(50)) - drop_part(robot_arm, Tsec) - do_sparks(3, TRUE, src) ..() diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm index e532f58ff9509..9273232699613 100644 --- a/code/modules/mob/living/simple_animal/bot/floorbot.dm +++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm @@ -382,9 +382,6 @@ if(specialtiles && tiletype != null) empty_tiles() - if(prob(50)) - drop_part(robot_arm, Tsec) - new /obj/item/stack/tile/plasteel(Tsec, 1) do_sparks(3, TRUE, src) diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm index ad929bf04c80b..cc2babb610675 100644 --- a/code/modules/mob/living/simple_animal/bot/honkbot.dm +++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm @@ -324,11 +324,10 @@ continue /mob/living/simple_animal/bot/honkbot/explode() + visible_message("[src] blows apart!") var/atom/Tsec = drop_location() //doesn't drop cardboard nor its assembly, since its a very frail material. - if(prob(50)) - drop_part(robot_arm, Tsec) new bikehorn(Tsec) new /obj/item/assembly/prox_sensor(Tsec) diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm index 5e6acc9bc1fc0..991aa584dbc54 100644 --- a/code/modules/mob/living/simple_animal/bot/medbot.dm +++ b/code/modules/mob/living/simple_animal/bot/medbot.dm @@ -429,8 +429,9 @@ GLOBAL_VAR(medibot_unique_id_gen) return FALSE if(emagged) //Everyone needs our medicine. (Our medicine is toxins) + return TRUE - if(HAS_TRAIT(C,TRAIT_MEDIBOTCOMINGTHROUGH) && !HAS_TRAIT_FROM(C,TRAIT_MEDIBOTCOMINGTHROUGH,medibot_counter)) //someone is healing them already sweetie + if(HAS_TRAIT(C, TRAIT_MEDIBOTCOMINGTHROUGH) && !HAS_TRAIT_FROM(C, TRAIT_MEDIBOTCOMINGTHROUGH, medibot_counter)) //someone is healing them already sweetie return FALSE if(ishuman(C)) @@ -581,9 +582,6 @@ GLOBAL_VAR(medibot_unique_id_gen) new /obj/item/assembly/prox_sensor(Tsec) drop_part(healthanalyzer, Tsec) - if(prob(50)) - drop_part(robot_arm, Tsec) - if(emagged && prob(25)) playsound(src, 'sound/voice/medbot/insult.ogg', 50) diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index 55a447c6769b9..f55beea8648ca 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -417,6 +417,7 @@ return FALSE /mob/living/simple_animal/bot/secbot/explode() + visible_message("[src] blows apart!") var/atom/Tsec = drop_location() if(bot_type == ADVANCED_SEC_BOT) @@ -445,9 +446,6 @@ 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) From 62005399334da5b7050a0e087e5693c42417ad52 Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 26 Oct 2023 16:45:42 -0400 Subject: [PATCH 15/20] cleanup defines --- code/__DEFINES/robots.dm | 82 +++++++++++++------ .../mob/living/simple_animal/bot/bot.dm | 7 +- .../mob/living/simple_animal/bot/secbot.dm | 2 +- 3 files changed, 61 insertions(+), 30 deletions(-) diff --git a/code/__DEFINES/robots.dm b/code/__DEFINES/robots.dm index 792406916575f..d319f733726af 100644 --- a/code/__DEFINES/robots.dm +++ b/code/__DEFINES/robots.dm @@ -46,10 +46,13 @@ /** Simple Animal BOT defines */ //Bot defines, placed here so they can be read by other things! -#define BOT_STEP_DELAY 4 //Delay between movemements -#define BOT_STEP_MAX_RETRIES 5 //Maximum times a bot will retry to step from its position +/// Delay between movemements +#define BOT_STEP_DELAY 4 +/// Maximum times a bot will retry to step from its position +#define BOT_STEP_MAX_RETRIES 5 -#define DEFAULT_SCAN_RANGE 7 //default view range for finding targets. +/// Default view range for finding targets. +#define DEFAULT_SCAN_RANGE 7 //Bot types /// Secutritrons (Beepsky) @@ -69,30 +72,52 @@ /// Firebots #define FIRE_BOT (1<<7) /// Hygienebots -#define HYGIENE_BOT (1<<8) +//#define HYGIENE_BOT (1<<8) /// Vibe bots #define VIBE_BOT (1<<9) //Mode defines /// Idle #define BOT_IDLE 0 -#define BOT_HUNT 1 //! found target, hunting -#define BOT_PREP_ARREST 2 //! at target, preparing to arrest -#define BOT_ARREST 3 //! arresting target -#define BOT_START_PATROL 4 //! start patrol -#define BOT_PATROL 5 //! patrolling -#define BOT_SUMMON 6 //! summoned by PDA -#define BOT_CLEANING 7 //! cleaning (cleanbots) -#define BOT_REPAIRING 8 //! repairing hull breaches (floorbots) -#define BOT_MOVING 9 //! for clean/floor/med bots, when moving. -#define BOT_HEALING 10 //! healing people (medbots) -#define BOT_RESPONDING 11 //! responding to a call from the AI -#define BOT_DELIVER 12 //! moving to deliver -#define BOT_GO_HOME 13 //! returning to home -#define BOT_BLOCKED 14 //! blocked -#define BOT_NAV 15 //! computing navigation -#define BOT_WAIT_FOR_NAV 16 //! waiting for nav computation -#define BOT_NO_ROUTE 17 //! no destination beacon found (or no route) +/// Found target, hunting +#define BOT_HUNT 1 +/// Currently tipped over. +#define BOT_TIPPED 2 +/// Start patrol +#define BOT_START_PATROL 3 +/// Patrolling +#define BOT_PATROL 4 +/// Summoned to a location +#define BOT_SUMMON 5 +/// Currently moving +#define BOT_MOVING 6 +/// Secbot - At target, preparing to arrest +#define BOT_PREP_ARREST 7 +/// Secbot - Arresting target +#define BOT_ARREST 8 + +/// Cleanbot - Cleaning +#define BOT_CLEANING 9 +/// Hygienebot - Cleaning unhygienic humans +//#define BOT_SHOWERSTANCE 10 +/// Floorbots - Repairing hull breaches +#define BOT_REPAIRING 11 +/// Medibots - Healing people +#define BOT_HEALING 12 +/// Responding to a call from the AI +#define BOT_RESPONDING 13 +/// MULEbot - Moving to deliver +#define BOT_DELIVER 14 +/// MULEbot - Returning to home +#define BOT_GO_HOME 15 +/// MULEbot - Blocked +#define BOT_BLOCKED 16 +/// MULEbot - Computing navigation +#define BOT_NAV 17 +/// MULEbot - Waiting for nav computation +#define BOT_WAIT_FOR_NAV 18 +/// MULEbot - No destination beacon found (or no route) +#define BOT_NO_ROUTE 19 //SecBOT defines on arresting ///Whether arrests should be broadcasted over the Security radio @@ -115,11 +140,16 @@ #define AI_MECH_HACK 3 //AI notification defines -#define NEW_BORG 1 -#define NEW_MODULE 2 -#define RENAME 3 -#define AI_SHELL 4 -#define DISCONNECT 5 +///Alert when a new Cyborg is created. +#define NEW_BORG 1 +///Alert when a Cyborg selects a model. +#define NEW_MODULE 2 +///Alert when a Cyborg changes their name. +#define RENAME 3 +///Alert when an AI disconnects themselves from their shell. +#define AI_SHELL 4 +///Alert when a Cyborg gets disconnected from their AI. +#define DISCONNECT 5 /** Misc Robot defines */ diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 98495539a450a..90a2cdec96aa2 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -37,7 +37,8 @@ var/window_width = 0 //0 for default size var/window_height = 0 var/obj/item/paicard/paicard // Inserted pai card. - var/allow_pai = 1 // Are we even allowed to insert a pai card. + ///If a pAI is allowed to be inserted into this bot. + var/allow_pai = TRUE var/bot_name var/list/player_access = list() //Additonal access the bots gets when player controlled @@ -300,10 +301,10 @@ return FALSE switch(mode) //High-priority overrides are processed first. Bots can do nothing else while under direct command. - if(BOT_RESPONDING) //Called by the AI. + if(BOT_RESPONDING) //Called by the AI. call_mode() return FALSE - if(BOT_SUMMON) //Called by PDA + if(BOT_SUMMON) //Called to a location bot_summon() return FALSE return TRUE //Successful completion. Used to prevent child process() continuing if this one is ended early. diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index f55beea8648ca..9886bf0c08cb3 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -17,7 +17,7 @@ bot_core_type = /obj/machinery/bot_core/secbot window_id = "autosec" window_name = "Automatic Security Unit v1.6" - allow_pai = 0 + allow_pai = FALSE data_hud_type = DATA_HUD_SECURITY_ADVANCED path_image_color = "#FF0000" boot_delay = 8 SECONDS From e423687c72cdd612ff40e52299a973e0940890e8 Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 26 Oct 2023 17:16:35 -0400 Subject: [PATCH 16/20] cleanup defines --- code/__DEFINES/robots.dm | 32 +++++++++++-------- code/datums/ai_laws.dm | 8 ----- .../living/simple_animal/bot/construction.dm | 2 +- 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/code/__DEFINES/robots.dm b/code/__DEFINES/robots.dm index d319f733726af..498359757d303 100644 --- a/code/__DEFINES/robots.dm +++ b/code/__DEFINES/robots.dm @@ -1,6 +1,13 @@ /** AI defines */ #define DEFAULT_AI_LAWID "default" +#define LAW_VALENTINES "valentines" +#define LAW_DEVIL "devil" +#define LAW_ZEROTH "zeroth" +#define LAW_INHERENT "inherent" +#define LAW_SUPPLIED "supplied" +#define LAW_ION "ion" +#define LAW_HACKED "hacked" //AI notification defines ///Alert when a new Cyborg is created. @@ -45,12 +52,22 @@ /** Simple Animal BOT defines */ +//Assembly defines +#define ASSEMBLY_FIRST_STEP 0 +#define ASSEMBLY_SECOND_STEP 1 +#define ASSEMBLY_THIRD_STEP 2 +#define ASSEMBLY_FOURTH_STEP 3 +#define ASSEMBLY_FIFTH_STEP 4 +#define ASSEMBLY_SIXTH_STEP 5 +#define ASSEMBLY_SEVENTH_STEP 6 +#define ASSEMBLY_EIGHTH_STEP 7 +#define ASSEMBLY_NINTH_STEP 8 + //Bot defines, placed here so they can be read by other things! /// Delay between movemements #define BOT_STEP_DELAY 4 /// Maximum times a bot will retry to step from its position #define BOT_STEP_MAX_RETRIES 5 - /// Default view range for finding targets. #define DEFAULT_SCAN_RANGE 7 @@ -150,16 +167,3 @@ #define AI_SHELL 4 ///Alert when a Cyborg gets disconnected from their AI. #define DISCONNECT 5 - -/** Misc Robot defines */ - -//Assembly defines -#define ASSEMBLY_FIRST_STEP 0 -#define ASSEMBLY_SECOND_STEP 1 -#define ASSEMBLY_THIRD_STEP 2 -#define ASSEMBLY_FOURTH_STEP 3 -#define ASSEMBLY_FIFTH_STEP 4 -#define ASSEMBLY_SIXTH_STEP 5 -#define ASSEMBLY_SEVENTH_STEP 6 -#define ASSEMBLY_EIGHTH_STEP 7 -#define ASSEMBLY_NINTH_STEP 8 diff --git a/code/datums/ai_laws.dm b/code/datums/ai_laws.dm index 2d2b6344ccf2d..83b8711b397ea 100644 --- a/code/datums/ai_laws.dm +++ b/code/datums/ai_laws.dm @@ -1,11 +1,3 @@ -#define LAW_VALENTINES "valentines" -#define LAW_DEVIL "devil" -#define LAW_ZEROTH "zeroth" -#define LAW_INHERENT "inherent" -#define LAW_SUPPLIED "supplied" -#define LAW_ION "ion" -#define LAW_HACKED "hacked" - /datum/ai_laws var/name = "Unknown Laws" diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index bfc9bf2641b4f..cefbcea041807 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -147,7 +147,7 @@ return to_chat(user, "You start to wire [src]...") if(do_after(user, 40, target = src)) - if(coil.get_amount() >= 1 && build_step == 6) + if(coil.get_amount() >= 1 && build_step == ASSEMBLY_SEVENTH_STEP) coil.use(1) to_chat(user, "You wire [src].") name = "wired ED-209 assembly" From fb8a06d2f62fe37adf24d5e16d248b3e0373b63b Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 26 Oct 2023 17:58:41 -0400 Subject: [PATCH 17/20] fixes bad init on grievous secbots --- .../mob/living/simple_animal/bot/SuperBeepsky.dm | 13 ++++++------- code/modules/mob/living/simple_animal/bot/secbot.dm | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm index fd6ae783e8cae..ec45e060c6025 100644 --- a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm +++ b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm @@ -44,7 +44,6 @@ /mob/living/simple_animal/bot/secbot/grievous/Initialize(mapload) . = ..() - weapon = new weapon(src) INVOKE_ASYNC(weapon, TYPE_PROC_REF(/obj/item, attack_self), src) /mob/living/simple_animal/bot/secbot/grievous/Destroy() @@ -75,9 +74,9 @@ update_appearance() SSmove_manager.stop_looping(src) 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(!mode && auto_patrol) // still idle, and set to patrol + mode = BOT_START_PATROL // switch to patrol mode + if(BOT_HUNT) // hunting for perp update_appearance() playsound(src,'sound/effects/beepskyspinsabre.ogg',100,TRUE,-1) // general beepsky doesn't give up so easily, jedi scum @@ -85,13 +84,13 @@ SSmove_manager.stop_looping(src) back_to_idle() return - if(target) // make sure target exists - if(Adjacent(target) && isturf(target.loc)) // if right next to perp + if(target) // make sure target exists + if(Adjacent(target) && isturf(target.loc)) // if right next to perp target_lastloc = target.loc //stun_attack() can clear the target if they're dead, so this needs to be set first stun_attack(target) anchored = TRUE return - else // not next to perp + else // not next to perp var/turf/olddist = get_dist(src, target) SSmove_manager.move_to(src, target, 1, 4) if((get_dist(src, target)) >= (olddist)) diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index 9886bf0c08cb3..d515e02bb0b26 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -1,6 +1,6 @@ /mob/living/simple_animal/bot/secbot name = "\improper Securitron" - desc = "A little security robot. He looks less than thrilled." + desc = "A little security robot. He looks less than thrilled." icon = 'icons/mob/aibots.dmi' icon_state = "secbot" density = FALSE From b4d72cac854d5735ce9dab53e60f97f3919c2ed1 Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 26 Oct 2023 18:23:35 -0400 Subject: [PATCH 18/20] remove grievous nullcrate bot, fix grievous loot --- .../living/simple_animal/bot/SuperBeepsky.dm | 31 +++---------------- .../mob/living/simple_animal/bot/secbot.dm | 1 - 2 files changed, 4 insertions(+), 28 deletions(-) diff --git a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm index ec45e060c6025..6e8cd2bec4950 100644 --- a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm +++ b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm @@ -9,8 +9,6 @@ baton_type = /obj/item/melee/transforming/energy/sword/saber base_speed = 4 //he's a fast fucker var/block_chance = 50 - noloot = FALSE - /mob/living/simple_animal/bot/secbot/grievous/toy //A toy version of general beepsky! name = "Genewul Bweepskee" @@ -19,17 +17,6 @@ maxHealth = 50 baton_type = /obj/item/toy/sword -/mob/living/simple_animal/bot/secbot/grievous/nullcrate - name = "General Griefsky" - desc = "The Syndicate sends their regards." - emagged = 2 - noloot = TRUE - faction = list(FACTION_SYNDICATE) - -/mob/living/simple_animal/bot/secbot/grievous/nullcrate/ComponentInitialize() - . = ..() - AddElement(/datum/element/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_CONTENTS | EMP_PROTECT_WIRES) - /mob/living/simple_animal/bot/secbot/grievous/bullet_act(obj/projectile/P) visible_message("[src] deflects [P] with its energy swords!") playsound(src, 'sound/weapons/blade1.ogg', 50, TRUE) @@ -129,7 +116,7 @@ speak("Level [threatlevel] infraction alert!") playsound(src, pick('sound/voice/beepsky/criminal.ogg', 'sound/voice/beepsky/justice.ogg', 'sound/voice/beepsky/freeze.ogg'), 50, FALSE) playsound(src,'sound/weapons/saberon.ogg',50,TRUE,-1) - visible_message("[src] ignites his energy swords!") + visible_message("[src] ignites his energy swords!") icon_state = "grievous-c" visible_message("[src] points at [C.name]!") mode = BOT_HUNT @@ -143,16 +130,6 @@ ..() visible_message("[src] lets out a huge cough as it 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) - - do_sparks(3, TRUE, src) - if(!noloot) - for(var/IS = 0 to 4) - drop_part(weapon, Tsec) - new /obj/effect/decal/cleanable/oil(Tsec) - qdel(src) + //Parent is dropping the weapon, so let's drop 3 more to make up for it. + for(var/IS = 0 to 3) + drop_part(weapon, Tsec) diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index d515e02bb0b26..b972e39d65514 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -22,7 +22,6 @@ path_image_color = "#FF0000" boot_delay = 8 SECONDS - var/noloot = FALSE var/baton_type = /obj/item/melee/baton ///The weapon (from baton_type) that will be used to make arrests. var/obj/item/weapon From cbea39beea58aecc9438ba7a50eefc4e16ef805c Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 26 Oct 2023 18:33:24 -0400 Subject: [PATCH 19/20] fixes toy grievous --- code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm | 3 +++ code/modules/mob/living/simple_animal/bot/secbot.dm | 1 + 2 files changed, 4 insertions(+) diff --git a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm index 6e8cd2bec4950..225a34b609911 100644 --- a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm +++ b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm @@ -8,6 +8,8 @@ baton_type = /obj/item/melee/transforming/energy/sword/saber base_speed = 4 //he's a fast fucker + weapon_force = 30 + var/block_chance = 50 /mob/living/simple_animal/bot/secbot/grievous/toy //A toy version of general beepsky! @@ -16,6 +18,7 @@ health = 50 maxHealth = 50 baton_type = /obj/item/toy/sword + weapon_force = 0 /mob/living/simple_animal/bot/secbot/grievous/bullet_act(obj/projectile/P) visible_message("[src] deflects [P] with its energy swords!") diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index b972e39d65514..08bd299541550 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -22,6 +22,7 @@ path_image_color = "#FF0000" boot_delay = 8 SECONDS + ///The type of baton this Secbot will use var/baton_type = /obj/item/melee/baton ///The weapon (from baton_type) that will be used to make arrests. var/obj/item/weapon From aba9e054405c52e3f074ba9b029c792fa8ed69ae Mon Sep 17 00:00:00 2001 From: RKz Date: Thu, 26 Oct 2023 18:46:58 -0400 Subject: [PATCH 20/20] kilo-specific warden armsky --- _maps/map_files/KiloStation/KiloStation.dmm | 9 +-------- code/modules/mob/living/simple_animal/bot/secbot.dm | 6 ++++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm index c97481150b60e..470b178e4dd41 100644 --- a/_maps/map_files/KiloStation/KiloStation.dmm +++ b/_maps/map_files/KiloStation/KiloStation.dmm @@ -78801,14 +78801,7 @@ /obj/structure/cable/yellow{ icon_state = "1-2" }, -/mob/living/simple_animal/bot/secbot{ - arrest_type = 1; - health = 45; - icon_state = "secbot1"; - idcheck = 1; - name = "Warden Armsky"; - weaponscheck = 1 - }, +/mob/living/simple_animal/bot/secbot/beepsky/armsky/warden, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer2{ dir = 1 }, diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index 08bd299541550..59f83f911a4d0 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -56,6 +56,12 @@ auto_patrol = FALSE security_mode_flags = SECBOT_DECLARE_ARRESTS | SECBOT_CHECK_IDS | SECBOT_CHECK_RECORDS +/mob/living/simple_animal/bot/secbot/beepsky/armsky/warden + name = "Warden 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 Officer Beep O'sky's smaller, just-as aggressive cousin, Pipsqueak."