diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm index 7879b992b238e..2fa79e0611c0d 100644 --- a/_maps/map_files/BoxStation/BoxStation.dmm +++ b/_maps/map_files/BoxStation/BoxStation.dmm @@ -8297,14 +8297,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 56e6ad1257c2a..259ac7ee7fbae 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 179620e1fe6b3..56cbb62c7c5a7 100644 --- a/_maps/map_files/FlandStation/FlandStation.dmm +++ b/_maps/map_files/FlandStation/FlandStation.dmm @@ -89471,14 +89471,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/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/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 4f3ed05d19d57..e1186e1d7991e 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -37136,14 +37136,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 c3c12a8d19479..5046180a68878 100644 --- a/_maps/map_files/RadStation/RadStation.dmm +++ b/_maps/map_files/RadStation/RadStation.dmm @@ -17678,14 +17678,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" }, diff --git a/code/__DEFINES/robots.dm b/code/__DEFINES/robots.dm index 0db4411562eb2..498359757d303 100644 --- a/code/__DEFINES/robots.dm +++ b/code/__DEFINES/robots.dm @@ -1,41 +1,152 @@ -/*ALL DEFINES FOR AIS, CYBORGS, AND SIMPLE ANIMAL BOTS*/ +/** 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. +#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 */ + +//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! -#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 +/// Default view range for finding targets. +#define DEFAULT_SCAN_RANGE 7 -#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 -#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) +/// Idle +#define BOT_IDLE 0 +/// 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 -//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 +/// 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 +#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 @@ -46,15 +157,13 @@ #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 - -//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 +///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 diff --git a/code/controllers/subsystem/traumas.dm b/code/controllers/subsystem/traumas.dm index b2708f99042f3..99818cc05f7df 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/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/datums/components/crafting/recipes.dm b/code/datums/components/crafting/recipes.dm index 64c2a5ce940f0..129af4f1284e7 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/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 1434c998ed1e5..e2da919b498f2 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 d593e23866fdd..056a2289e10ac 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) @@ -354,7 +354,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 9094c2668aa7e..8e458a26aaf8c 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 @@ -564,7 +564,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 9f38adbc636d0..a08a8abf89877 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -933,15 +933,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) @@ -1043,14 +1043,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..225a34b609911 100644 --- a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm +++ b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm @@ -5,12 +5,12 @@ icon_state = "grievous" health = 150 maxHealth = 150 + baton_type = /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 + weapon_force = 30 + var/block_chance = 50 /mob/living/simple_animal/bot/secbot/grievous/toy //A toy version of general beepsky! name = "Genewul Bweepskee" @@ -18,17 +18,7 @@ health = 50 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) + weapon_force = 0 /mob/living/simple_animal/bot/secbot/grievous/bullet_act(obj/projectile/P) visible_message("[src] deflects [P] with its energy swords!") @@ -44,8 +34,7 @@ /mob/living/simple_animal/bot/secbot/grievous/Initialize(mapload) . = ..() - weapon = new baton_type(src) - weapon.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) @@ -71,27 +60,27 @@ 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() + 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 if(frustration >= 20) 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)) @@ -111,7 +100,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 +108,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 @@ -130,7 +119,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 @@ -141,22 +130,9 @@ /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() - - 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(prob(50)) - drop_part(robot_arm, Tsec) - - do_sparks(3, TRUE, src) - if(!noloot) - for(var/IS = 0 to 4) - drop_part(baton_type, 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/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 458afe1cceac6..0202b5b405504 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" @@ -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 @@ -48,7 +49,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 +63,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 +89,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", \ @@ -222,6 +224,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 @@ -247,8 +252,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 +298,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. + if(BOT_RESPONDING) //Called by the AI. call_mode() - return - if(BOT_SUMMON) //Called by PDA + return FALSE + if(BOT_SUMMON) //Called to a location bot_summon() - return + return FALSE return TRUE //Successful completion. Used to prevent child process() continuing if this one is ended early. @@ -332,29 +337,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 +367,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) ..() @@ -426,26 +431,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! @@ -778,7 +781,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 +947,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 +1012,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 +1022,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..37fda4e3c47e1 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 @@ -275,9 +275,6 @@ new /obj/item/assembly/prox_sensor(Tsec) - if(prob(50)) - drop_part(robot_arm, Tsec) - do_sparks(3, TRUE, src) ..() @@ -341,7 +338,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 @@ -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/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index effb609e29453..cefbcea041807 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,29 +118,17 @@ 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(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(!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(5) + if(ASSEMBLY_SIXTH_STEP) if(isprox(W)) if(!user.temporarilyRemoveItemFromInventory(W)) return @@ -155,10 +136,10 @@ 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(ASSEMBLY_SEVENTH_STEP) if(istype(W, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/coil = W if(coil.get_amount() < 1) @@ -166,35 +147,24 @@ 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" 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(ASSEMBLY_EIGHTH_STEP) + 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++ - - if(8) + 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(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)) @@ -206,13 +176,10 @@ 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) + 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) - + qdel(src) //make sure to delete the unfinished recipe when spawning in the actual mob //Floorbot assemblies /obj/item/bot_assembly/floorbot @@ -337,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) @@ -411,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 9ac10801ed956..8dd9d576641c7 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -1,430 +1,71 @@ -/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' - icon_state = "ed2090" + desc = "A security robot. He looks less than thrilled." + icon_state = "ed209" 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 + bot_type = ADVANCED_SEC_BOT window_id = "autoed209" window_name = "Automatic Security Unit v2.6" - allow_pai = 0 - data_hud_type = DATA_HUD_SECURITY_ADVANCED - path_image_color = "#FF0000" - carryable = FALSE 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/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/projectile/beam/disabler 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/J = SSjob.GetJob(JOB_NAME_DETECTIVE) - access_card.access = J.get_access() - prev_access = access_card.access.Copy() - 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 += "Security Unit v2.6 controls
" - dat += "
Status: [on ? "On" : "Off"]" - dat += "
Behaviour controls are [locked ? "locked" : "unlocked"]" - dat += "
Maintenance panel panel is [open ? "opened" : "closed"]" - - if(!locked || issilicon(user)|| IsAdminGhost(user)) - if(!lasercolor) - 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 += "
Auto Patrol [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_REF(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/projectile/Proj) - if(istype(Proj , /obj/projectile/beam/laser)||istype(Proj, /obj/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 + 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, lasercolor, weaponcheck=CALLBACK(src, PROC_REF(check_for_weapons))) - //speak(C.real_name + ": 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.mobility_flags & MOBILITY_STAND) && !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_REF(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_REF(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_REF(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) + 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/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/projectile/beam/lasertag - else - projectile = /obj/projectile/beam + if(emagged) + projectile = /obj/projectile/beam else - if(!lasercolor) - shoot_sound = 'sound/weapons/laser.ogg' - projectile = /obj/projectile/beam/disabler - else if(lasercolor == "b") - projectile = /obj/projectile/beam/lasertag/bluetag - else if(lasercolor == "r") - projectile = /obj/projectile/beam/lasertag/redtag + projectile = /obj/projectile/beam/disabler -/mob/living/simple_animal/bot/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 @@ -434,142 +75,50 @@ return if(!isturf(T)) return - if(!projectile) return - var/obj/projectile/A = new projectile (loc) + var/obj/projectile/fired_bullet = new projectile(loc) playsound(src, shoot_sound, 50, TRUE) - A.preparePixelProjectile(target, src) - A.fire() - -/mob/living/simple_animal/bot/ed209/attack_alien(mob/living/carbon/alien/user) - ..() - if(!isalien(target)) - target = user - mode = BOT_HUNT - + fired_bullet.preparePixelProjectile(target, src) + fired_bullet.fire() -/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 . = ..() 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(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 - - -/mob/living/simple_animal/bot/ed209/bullet_act(obj/projectile/Proj) - if(!disabled) - var/lasertag_check = 0 - if((lasercolor == "b")) - if(istype(Proj, /obj/projectile/beam/lasertag/redtag)) - lasertag_check++ - else if((lasercolor == "r")) - if(istype(Proj, /obj/projectile/beam/lasertag/bluetag)) - lasertag_check++ - if(lasertag_check) - icon_state = "[lasercolor]ed2090" - disabled = TRUE - target = null - addtimer(CALLBACK(src, PROC_REF(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) + if(severity <= 1) 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) - if(!on) + 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 - 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_REF(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_REF(attempt_handcuff), C), 60) + 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) + var/mob/to_arrest = pick(targets) + if(to_arrest) + target = to_arrest + mode = BOT_HUNT -/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. +/mob/living/simple_animal/bot/secbot/ed209/RangedAttack(atom/A) + if(!on) 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() + 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..f9b9b85428f39 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!") @@ -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 54a1cd0b48476..9273232699613 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 @@ -381,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 ba476701562af..cc2babb610675 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() @@ -322,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 95ae8ca007059..991aa584dbc54 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,10 +428,10 @@ 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) + 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)) @@ -530,7 +531,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 +552,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)") @@ -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 a53a04f99a3e2..59f83f911a4d0 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 @@ -17,31 +17,51 @@ 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 - var/noloot = FALSE + ///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 + ///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 + ///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/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." @@ -51,23 +71,24 @@ 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_icon() + weapon = new baton_type() + 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() @@ -80,11 +101,15 @@ ) AddElement(/datum/element/connect_loc, loc_connections) -/mob/living/simple_animal/bot/secbot/update_icon() +/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" return - ..() + return ..() /mob/living/simple_animal/bot/secbot/turn_off() ..() @@ -115,55 +140,57 @@ 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() - 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(emagged) + final |= JUDGE_EMAGGED + if(bot_type == ADVANCED_SEC_BOT) + final |= JUDGE_IGNOREMONKEYS + if(security_mode_flags & SECBOT_CHECK_IDS) + final |= JUDGE_IDCHECK + if(security_mode_flags & SECBOT_CHECK_RECORDS) + final |= JUDGE_RECORDCHECK + if(security_mode_flags & SECBOT_CHECK_WEAPONS) + final |= JUDGE_WEAPONCHECK + return final /mob/living/simple_animal/bot/secbot/proc/special_retaliate_after_attack(mob/user) //allows special actions to take place after being attacked. return @@ -176,24 +203,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_icon() + 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)) @@ -202,127 +229,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() - playsound(src, "law", 50, 0) + 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_icon)), 2) + 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) @@ -351,9 +374,6 @@ look_for_perp() bot_patrol() - - return - /mob/living/simple_animal/bot/secbot/proc/back_to_idle() anchored = FALSE mode = BOT_IDLE @@ -371,30 +391,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!") - playsound(loc, pick('sound/voice/beepsky/criminal.ogg', 'sound/voice/beepsky/justice.ogg', 'sound/voice/beepsky/freeze.ogg'), 50, FALSE) - visible_message("[src] points at [C.name]!") + 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 [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)) @@ -402,20 +423,35 @@ return FALSE /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(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/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)) + 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/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) - if(prob(50)) - drop_part(robot_arm, Tsec) - do_sparks(3, TRUE, src) new /obj/effect/decal/cleanable/oil(loc) @@ -435,7 +471,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 ab40fc979c7db..3d513a1aa0269 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -540,7 +540,7 @@ if(R.mmi) R.mmi.transfer_identity(src) - 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 91bd35daf915d..158c9779d4aa2 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 b705d6c3b776a..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) @@ -54,10 +54,17 @@ 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/projectile/beam/laser, "declare_arrests" = 0,"name" = "Wizard's Justicebot") + new_vars = list( + "emagged" = 2, + "remote_disabled" = 1, + "shoot_sound" = 'sound/weapons/laser.ogg', + "projectile" = /obj/projectile/beam/laser, + "security_mode_flags" = ~(SECBOT_DECLARE_ARRESTS), + "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 f924410198597..dd68ad4ec034b 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) diff --git a/icons/mob/aibots.dmi b/icons/mob/aibots.dmi index 84deedc5c5c4b..710686d82e66d 100644 Binary files a/icons/mob/aibots.dmi and b/icons/mob/aibots.dmi differ