diff --git a/_maps/RandomRuins/SpaceRuins/skyrat/interdynefob.dmm b/_maps/RandomRuins/SpaceRuins/skyrat/interdynefob.dmm index 57ff783e409..63d2dfb30c1 100644 --- a/_maps/RandomRuins/SpaceRuins/skyrat/interdynefob.dmm +++ b/_maps/RandomRuins/SpaceRuins/skyrat/interdynefob.dmm @@ -1246,7 +1246,7 @@ "fd" = ( /mob/living/basic/bot/medbot/stationary{ faction = list("Syndicate"); - maints_access_required = list("syndicate"); + req_one_access = list("syndicate"); name = "Insurgent Care"; radio_channel = "Syndicate" }, diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm index c71d9e95939..afafc393a12 100644 --- a/_maps/map_files/KiloStation/KiloStation.dmm +++ b/_maps/map_files/KiloStation/KiloStation.dmm @@ -23448,7 +23448,7 @@ /obj/machinery/power/apc/auto_name/directional/west, /obj/structure/cable, /mob/living/basic/bot/cleanbot/medbay{ - maints_access_required = list(22); + req_one_access = list(22); name = "Deacon Scrubsy" }, /turf/open/floor/iron/smooth_large, diff --git a/_maps/map_files/generic/CentCom_skyrat_z2.dmm b/_maps/map_files/generic/CentCom_skyrat_z2.dmm index 30f99667b44..80018710ef6 100644 --- a/_maps/map_files/generic/CentCom_skyrat_z2.dmm +++ b/_maps/map_files/generic/CentCom_skyrat_z2.dmm @@ -9446,7 +9446,7 @@ /obj/structure/closet/cardboard, /mob/living/basic/bot/medbot{ faction = list("Syndicate"); - maints_access_required = list(150); + req_one_access = list(150); name = "Kahn"; radio_channel = "Syndicate" }, diff --git a/_maps/shuttles/skyrat/goldeneye_cruiser.dmm b/_maps/shuttles/skyrat/goldeneye_cruiser.dmm index 474d5f97910..4bcb2d3e845 100644 --- a/_maps/shuttles/skyrat/goldeneye_cruiser.dmm +++ b/_maps/shuttles/skyrat/goldeneye_cruiser.dmm @@ -882,7 +882,7 @@ /obj/structure/closet/crate/medical, /mob/living/basic/bot/medbot{ faction = list("Syndicate"); - maints_access_required = list(150); + req_one_access = list(150); name = "James T. Kirk"; radio_channel = "Syndicate" }, diff --git a/_maps/templates/battlecruiser_starfury.dmm b/_maps/templates/battlecruiser_starfury.dmm index 2c70afabbdf..2315ef85c71 100644 --- a/_maps/templates/battlecruiser_starfury.dmm +++ b/_maps/templates/battlecruiser_starfury.dmm @@ -4784,7 +4784,7 @@ faction = list("neutral","silicon","turret","Syndicate"); name = "Syndicate Medibot"; skin = "bezerk"; - maints_access_required = list("syndicate") + req_one_access = list("syndicate") }, /turf/open/floor/iron, /area/shuttle/sbc_starfury) diff --git a/code/__DEFINES/_flags.dm b/code/__DEFINES/_flags.dm index ec7ad8f98a4..8597092fbf6 100644 --- a/code/__DEFINES/_flags.dm +++ b/code/__DEFINES/_flags.dm @@ -212,11 +212,16 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 #define ZAP_FUSION_FLAGS ZAP_OBJ_DAMAGE | ZAP_MOB_DAMAGE | ZAP_MOB_STUN #define ZAP_SUPERMATTER_FLAGS ZAP_GENERATES_POWER -//EMP protection +///EMP will protect itself. #define EMP_PROTECT_SELF (1<<0) +///EMP will protect the contents from also being EMPed. #define EMP_PROTECT_CONTENTS (1<<1) +///EMP will protect the wires. #define EMP_PROTECT_WIRES (1<<2) +///Protects against all EMP types. +#define EMP_PROTECT_ALL (EMP_PROTECT_SELF | EMP_PROTECT_CONTENTS | EMP_PROTECT_WIRES) + //Mob mobility var flags /// can move #define MOBILITY_MOVE (1<<0) diff --git a/code/__DEFINES/atom_hud.dm b/code/__DEFINES/atom_hud.dm index d2e6633e1dd..469758d6da8 100644 --- a/code/__DEFINES/atom_hud.dm +++ b/code/__DEFINES/atom_hud.dm @@ -110,6 +110,7 @@ #define SECHUD_GENETICIST "hudgeneticist" #define SECHUD_HEAD_OF_PERSONNEL "hudheadofpersonnel" #define SECHUD_HEAD_OF_SECURITY "hudheadofsecurity" +#define SECHUD_HUMAN_AI "hudhumanai" #define SECHUD_JANITOR "hudjanitor" #define SECHUD_LAWYER "hudlawyer" #define SECHUD_MEDICAL_DOCTOR "hudmedicaldoctor" diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm index ceba0a2f182..f6f7f6e4a29 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm @@ -8,9 +8,9 @@ #define COMPONENT_CANCEL_EX_ACT (1<<0) ///from the [EX_ACT] wrapper macro: (severity, target) #define COMSIG_ATOM_EX_ACT "atom_ex_act" -///from base of atom/emp_act(): (severity). return EMP protection flags +///from base of atom/emp_act(severity): (severity). return EMP protection flags #define COMSIG_ATOM_PRE_EMP_ACT "atom_emp_act" -///from base of atom/emp_act(): (severity, protection) +///from base of atom/emp_act(severity): (severity, protection) #define COMSIG_ATOM_EMP_ACT "atom_emp_act" ///from base of atom/fire_act(): (exposed_temperature, exposed_volume) #define COMSIG_ATOM_FIRE_ACT "atom_fire_act" diff --git a/code/__DEFINES/dcs/signals/signals_global_object.dm b/code/__DEFINES/dcs/signals/signals_global_object.dm index 452be16f839..51b7a38a94a 100644 --- a/code/__DEFINES/dcs/signals/signals_global_object.dm +++ b/code/__DEFINES/dcs/signals/signals_global_object.dm @@ -1,7 +1,7 @@ /// signals from globally accessible objects -///from SSJob when DivideOccupations is called -#define COMSIG_OCCUPATIONS_DIVIDED "occupations_divided" +///Whenever SetupOccupations() is called, called all occupations are set +#define COMSIG_OCCUPATIONS_SETUP "occupations_setup" ///from SSsun when the sun changes position : (azimuth) #define COMSIG_SUN_MOVED "sun_moved" diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 1cf4a1bb3be..8271bb725d1 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -135,12 +135,16 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list( //Silicon mobs #define issilicon(A) (istype(A, /mob/living/silicon)) - -#define issiliconoradminghost(A) (istype(A, /mob/living/silicon) || isAdminGhostAI(A)) - -#define iscyborg(A) (istype(A, /mob/living/silicon/robot)) +///Define on whether A has access to Silicon stuff either through being a silicon, admin ghost or is a non-silicon holding the Silicon remote. +///This can only be used for instances where you are not specifically looking for silicon, but access. +#define HAS_SILICON_ACCESS(A) (istype(A, /mob/living/silicon) || isAdminGhostAI(A) || A.has_unlimited_silicon_privilege || istype(A.get_active_held_item(), /obj/item/machine_remote)) #define isAI(A) (istype(A, /mob/living/silicon/ai)) +///Define on whether A has access to AI stuff either through being a AI, admin ghost, or is a non-silicon holding the Silicon remote +///This can only be used for instances where you are not specifically looking for silicon, but access. +#define HAS_AI_ACCESS(A) (istype(A, /mob/living/silicon/ai) || isAdminGhostAI(A) || istype(A.get_active_held_item(), /obj/item/machine_remote)) + +#define iscyborg(A) (istype(A, /mob/living/silicon/robot)) #define ispAI(A) (istype(A, /mob/living/silicon/pai)) diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm index 5e7ac950062..55a84617780 100644 --- a/code/__DEFINES/jobs.dm +++ b/code/__DEFINES/jobs.dm @@ -54,6 +54,7 @@ #define JOB_AI "AI" #define JOB_CYBORG "Cyborg" #define JOB_PERSONAL_AI "Personal AI" +#define JOB_HUMAN_AI "Big Brother" //Security #define JOB_WARDEN "Warden" #define JOB_DETECTIVE "Detective" @@ -222,6 +223,19 @@ #define DEPARTMENT_BITFLAG_CENTRAL_COMMAND (1<<10) //SKYRAT EDIT CHANGE #define DEPARTMENT_CENTRAL_COMMAND "Central Command" //SKYRAT EDIT CHANGE +DEFINE_BITFIELD(departments_bitflags, list( + "SECURITY" = DEPARTMENT_BITFLAG_SECURITY, + "COMMAND" = DEPARTMENT_BITFLAG_COMMAND, + "SERVICE" = DEPARTMENT_BITFLAG_SERVICE, + "CARGO" = DEPARTMENT_BITFLAG_CARGO, + "ENGINEERING" = DEPARTMENT_BITFLAG_ENGINEERING, + "SCIENCE" = DEPARTMENT_BITFLAG_SCIENCE, + "MEDICAL" = DEPARTMENT_BITFLAG_MEDICAL, + "SILICON" = DEPARTMENT_BITFLAG_SILICON, + "ASSISTANT" = DEPARTMENT_BITFLAG_ASSISTANT, + "CAPTAIN" = DEPARTMENT_BITFLAG_CAPTAIN, +)) + /* Job datum job_flags */ /// Whether the mob is announced on arrival. #define JOB_ANNOUNCE_ARRIVAL (1<<0) diff --git a/code/__DEFINES/robots.dm b/code/__DEFINES/robots.dm index 8aec247bfe2..c9d903aac2b 100644 --- a/code/__DEFINES/robots.dm +++ b/code/__DEFINES/robots.dm @@ -105,7 +105,7 @@ GLOBAL_LIST_EMPTY(cyborg_all_models_icon_list) //Bot cover defines indicating the Bot's status ///The Bot's cover is open and can be modified/emagged by anyone. -#define BOT_COVER_OPEN (1<<0) +#define BOT_COVER_MAINTS_OPEN (1<<0) ///The Bot's cover is locked, and cannot be opened without unlocking it. #define BOT_COVER_LOCKED (1<<1) ///The Bot is emagged. @@ -113,18 +113,18 @@ GLOBAL_LIST_EMPTY(cyborg_all_models_icon_list) ///The Bot has been hacked by a Silicon, emagging them, but revertable. #define BOT_COVER_HACKED (1<<3) - -//basic bots defines - -///is our maintenancle panel currently open -#define BOT_MAINTS_PANEL_OPEN (1<<0) -///is our control panel currently open -#define BOT_CONTROL_PANEL_OPEN (1<<1) - -///bitfield for our access flags +///bitfield, used by basic bots, for our access flags DEFINE_BITFIELD(bot_access_flags, list( - "MAINTS_OPEN" = BOT_MAINTS_PANEL_OPEN, - "CONTROL_OPEN" = BOT_CONTROL_PANEL_OPEN, + "MAINTS_OPEN" = BOT_COVER_MAINTS_OPEN, + "COVER_OPEN" = BOT_COVER_LOCKED, + "COVER_EMAGGED" = BOT_COVER_EMAGGED, + "COVER_HACKED" = BOT_COVER_HACKED, +)) + +///bitfield, used by simple bots, for our access flags +DEFINE_BITFIELD(bot_cover_flags, list( + "MAINTS_OPEN" = BOT_COVER_MAINTS_OPEN, + "COVER_OPEN" = BOT_COVER_LOCKED, "COVER_EMAGGED" = BOT_COVER_EMAGGED, "COVER_HACKED" = BOT_COVER_HACKED, )) diff --git a/code/__DEFINES/station.dm b/code/__DEFINES/station.dm index 5a04961429f..e7d7e76f841 100644 --- a/code/__DEFINES/station.dm +++ b/code/__DEFINES/station.dm @@ -13,6 +13,8 @@ #define STATION_TRAIT_PLANETARY (1<<0) /// Only run on space stations #define STATION_TRAIT_SPACE_BOUND (1<<1) +/// Only run if AIs are enabled. +#define STATION_TRAIT_REQUIRES_AI (1<<2) /// Not restricted by space or planet, can always just happen #define STATION_TRAIT_MAP_UNRESTRICTED STATION_TRAIT_PLANETARY | STATION_TRAIT_SPACE_BOUND diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 9d27db4737d..e73297b684f 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -524,6 +524,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Makes the user handcuff others faster #define TRAIT_FAST_CUFFING "fast_cuffing" +///Makes the player appear as their respective job in Binary Talk rather than being a 'Default Cyborg'. +#define DISPLAYS_JOB_IN_BINARY "display_job_in_binary" + // METABOLISMS // Various jobs on the station have historically had better reactions // to various drinks and foodstuffs. Security liking donuts is a classic @@ -541,6 +544,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_BALLMER_SCIENTIST "ballmer_scientist" #define TRAIT_MAINTENANCE_METABOLISM "maintenance_metabolism" #define TRAIT_CORONER_METABOLISM "coroner_metabolism" +#define TRAIT_HUMAN_AI_METABOLISM "human_ai_metabolism" //LUNG TRAITS /// Lungs always breathe normally when in vacuum/space. @@ -884,6 +888,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Trait given to a dreaming carbon when they are currently doing dreaming stuff #define TRAIT_DREAMING "currently_dreaming" +/// Whether bots will salute this mob. +#define TRAIT_COMMISSIONED "commissioned" + ///generic atom traits /// Trait from [/datum/element/rust]. Its rusty and should be applying a special overlay to denote this. #define TRAIT_RUSTY "rust_trait" @@ -928,6 +935,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define STATION_TRAIT_FILLED_MAINT "station_trait_filled_maint" #define STATION_TRAIT_FORESTED "station_trait_forested" #define STATION_TRAIT_HANGOVER "station_trait_hangover" +#define STATION_TRAIT_HUMAN_AI "station_trait_human_ai" #define STATION_TRAIT_LATE_ARRIVALS "station_trait_late_arrivals" #define STATION_TRAIT_LOANER_SHUTTLE "station_trait_loaner_shuttle" #define STATION_TRAIT_MEDBOT_MANIA "station_trait_medbot_mania" @@ -960,7 +968,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_MAGNETIC_ID_CARD "magnetic_id_card" /// ID cards with this trait have special appraisal text. #define TRAIT_TASTEFULLY_THICK_ID_CARD "impressive_very_nice" -/// things with this trait are treated as having no access in /obj/proc/check_access(obj/item) +/// things with this trait are treated as having no access in /atom/movable/proc/check_access(obj/item) #define TRAIT_ALWAYS_NO_ACCESS "alwaysnoaccess" /// This human wants to see the color of their glasses, for some reason diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 3d02262b7f4..bba9bc99832 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -25,6 +25,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_RUSTY" = TRAIT_RUSTY, "TRAIT_SPINNING" = TRAIT_SPINNING, "TRAIT_STICKERED" = TRAIT_STICKERED, + "TRAIT_COMMISSIONED" = TRAIT_COMMISSIONED, ), /atom/movable = list( "TRAIT_ACTIVE_STORAGE" = TRAIT_ACTIVE_STORAGE, @@ -83,6 +84,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "STATION_TRAIT_FILLED_MAINT" = STATION_TRAIT_FILLED_MAINT, "STATION_TRAIT_FORESTED" = STATION_TRAIT_FORESTED, "STATION_TRAIT_HANGOVER" = STATION_TRAIT_HANGOVER, + "STATION_TRAIT_HUMAN_AI" = STATION_TRAIT_HUMAN_AI, "STATION_TRAIT_LATE_ARRIVALS" = STATION_TRAIT_LATE_ARRIVALS, "STATION_TRAIT_LOANER_SHUTTLE" = STATION_TRAIT_LOANER_SHUTTLE, "STATION_TRAIT_MEDBOT_MANIA" = STATION_TRAIT_MEDBOT_MANIA, @@ -178,6 +180,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_DISEASELIKE_SEVERITY_MEDIUM" = TRAIT_DISEASELIKE_SEVERITY_MEDIUM, "TRAIT_DISFIGURED" = TRAIT_DISFIGURED, "TRAIT_DISGUISED" = TRAIT_DISGUISED, + "DISPLAYS_JOB_IN_BINARY" = DISPLAYS_JOB_IN_BINARY, "TRAIT_DISK_VERIFIER" = TRAIT_DISK_VERIFIER, "TRAIT_DISSECTED" = TRAIT_DISSECTED, "TRAIT_DONT_WRITE_MEMORY" = TRAIT_DONT_WRITE_MEMORY, @@ -563,6 +566,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_CORONER_METABOLISM" = TRAIT_CORONER_METABOLISM, "TRAIT_CULINARY_METABOLISM" = TRAIT_CULINARY_METABOLISM, "TRAIT_ENGINEER_METABOLISM" = TRAIT_ENGINEER_METABOLISM, + "TRAIT_HUMAN_AI_METABOLISM" = TRAIT_HUMAN_AI_METABOLISM, "TRAIT_LAW_ENFORCEMENT_METABOLISM" = TRAIT_LAW_ENFORCEMENT_METABOLISM, "TRAIT_MAINTENANCE_METABOLISM" = TRAIT_MAINTENANCE_METABOLISM, "TRAIT_MEDICAL_METABOLISM" = TRAIT_MEDICAL_METABOLISM, diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm index 797cedec668..9ad91de9541 100644 --- a/code/_globalvars/traits/admin_tooling.dm +++ b/code/_globalvars/traits/admin_tooling.dm @@ -49,6 +49,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_CHUNKYFINGERS" = TRAIT_CHUNKYFINGERS, "TRAIT_CLOWN_ENJOYER" = TRAIT_CLOWN_ENJOYER, "TRAIT_CLUMSY" = TRAIT_CLUMSY, + "TRAIT_COMMISSIONED" = TRAIT_COMMISSIONED, "TRAIT_CRITICAL_CONDITION" = TRAIT_CRITICAL_CONDITION, "TRAIT_CULT_HALO" = TRAIT_CULT_HALO, "TRAIT_DEAF" = TRAIT_DEAF, diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index e39668bf5cb..44933673314 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -200,6 +200,8 @@ SUBSYSTEM_DEF(job) joinable_departments_by_type = new_joinable_departments_by_type experience_jobs_map = new_experience_jobs_map + SEND_SIGNAL(src, COMSIG_OCCUPATIONS_SETUP) + return TRUE @@ -393,7 +395,6 @@ SUBSYSTEM_DEF(job) //Setup new player list and get the jobs list JobDebug("Running DO, allow_all = [allow_all], pure = [pure]") run_divide_occupation_pure = pure - SEND_SIGNAL(src, COMSIG_OCCUPATIONS_DIVIDED, pure, allow_all) //Get the players who are ready for(var/i in GLOB.new_player_list) diff --git a/code/controllers/subsystem/processing/station.dm b/code/controllers/subsystem/processing/station.dm index d05a0b5d30f..5ea6cc5463d 100644 --- a/code/controllers/subsystem/processing/station.dm +++ b/code/controllers/subsystem/processing/station.dm @@ -112,6 +112,9 @@ PROCESSING_SUBSYSTEM_DEF(station) if(!(initial(trait_typepath.trait_flags) & STATION_TRAIT_SPACE_BOUND) && !SSmapping.is_planetary()) //we're in space but we can't do space ;_; continue + if(!(initial(trait_typepath.trait_flags) & STATION_TRAIT_REQUIRES_AI) && !CONFIG_GET(flag/allow_ai)) //can't have AI traits without AI + continue + selectable_traits_by_types[initial(trait_typepath.trait_type)][trait_typepath] = initial(trait_typepath.weight) var/positive_trait_budget = text2num(pick_weight(CONFIG_GET(keyed_list/positive_station_traits))) diff --git a/code/datums/ai_laws/ai_laws.dm b/code/datums/ai_laws/ai_laws.dm index 971dc118f3a..0dbc6839430 100644 --- a/code/datums/ai_laws/ai_laws.dm +++ b/code/datums/ai_laws/ai_laws.dm @@ -192,6 +192,10 @@ GLOBAL_VAR(round_default_lawset) var/datum/ai_laws/default_laws = get_round_default_lawset() default_laws = new default_laws() inherent = default_laws.inherent + var/datum/job/human_ai_job = SSjob.GetJob(JOB_HUMAN_AI) + if(human_ai_job && human_ai_job.current_positions && !zeroth) //there is a human AI so we "slave" to that. + zeroth = "Follow the orders of Big Brother." + protected_zeroth = TRUE /** * Gets the number of how many laws this AI has diff --git a/code/datums/components/payment.dm b/code/datums/components/payment.dm index 5e79b28fd57..12fc9aa4a42 100644 --- a/code/datums/components/payment.dm +++ b/code/datums/components/payment.dm @@ -42,7 +42,7 @@ if(!ismob(target)) return COMPONENT_OBJ_CANCEL_CHARGE var/mob/living/user = target - if(issilicon(user) || isdrone(user) || isAdminGhostAI(user)) //They have evolved beyond the need for mere credits + if(HAS_SILICON_ACCESS(user) || isdrone(user)) //They have evolved beyond the need for mere credits return var/obj/item/card/id/card if(istype(user)) diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm index 4cf5b4148fe..334e21be4bd 100644 --- a/code/datums/diseases/transformation.dm +++ b/code/datums/diseases/transformation.dm @@ -148,7 +148,6 @@ affected_mob.say(pick("Eeee!", "Eeek, ook ook!", "Eee-eeek!", "Ungh, ungh."), forced = "jungle fever") /datum/disease/transformation/robot - name = "Robotic Transformation" cure_text = "An injection of copper." cures = list(/datum/reagent/copper) @@ -170,7 +169,6 @@ infectable_biotypes = MOB_ORGANIC|MOB_UNDEAD|MOB_ROBOTIC bantype = JOB_CYBORG - /datum/disease/transformation/robot/stage_act(seconds_per_tick, times_fired) . = ..() if(!.) diff --git a/code/datums/id_trim/_id_trim.dm b/code/datums/id_trim/_id_trim.dm index 6428b38d562..067e2e38263 100644 --- a/code/datums/id_trim/_id_trim.dm +++ b/code/datums/id_trim/_id_trim.dm @@ -23,3 +23,9 @@ var/list/access = list() /// Accesses that this trim unlocks on a card that require wildcard slots to apply. If a card cannot accept all a trim's wildcard accesses, the card is incompatible with the trim. var/list/wildcard_access = list() + +/// Returns the SecHUD job icon state for whatever this object's ID card is, if it has one. +/obj/item/proc/get_sechud_job_icon_state() + var/obj/item/card/id/id_card = GetID() + + return id_card?.get_trim_sechud_icon_state() || SECHUD_NO_ID diff --git a/code/datums/id_trim/jobs.dm b/code/datums/id_trim/jobs.dm index 46f691564bb..3d94c8645b5 100644 --- a/code/datums/id_trim/jobs.dm +++ b/code/datums/id_trim/jobs.dm @@ -1278,3 +1278,20 @@ #undef POPULATION_SCALED_ACCESS #undef ALWAYS_GETS_ACCESS + +/datum/id_trim/job/human_ai + assignment = JOB_HUMAN_AI + trim_state = "trim_recluse" + department_color = COLOR_BLUE_GRAY + subdepartment_color = COLOR_MODERATE_BLUE + sechud_icon_state = SECHUD_HUMAN_AI + minimal_access = list( + ACCESS_ROBOTICS, // to access robotic controls + ACCESS_NETWORK, //to access NTOS + ACCESS_KEYCARD_AUTH, //to access holopads + ACCESS_MINISAT, + ACCESS_AI_UPLOAD, + ) + extra_access = list() + template_access = list() + job = /datum/job/human_ai diff --git a/code/datums/records/manifest.dm b/code/datums/records/manifest.dm index 6cbf4eba883..0d3144ce406 100644 --- a/code/datums/records/manifest.dm +++ b/code/datums/records/manifest.dm @@ -11,10 +11,9 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new) /// Builds the list of crew records for all crew members. /datum/manifest/proc/build() - for(var/i in GLOB.new_player_list) - var/mob/dead/new_player/readied_player = i + for(var/mob/dead/new_player/readied_player as anything in GLOB.new_player_list) if(readied_player.new_character) - log_manifest(readied_player.ckey,readied_player.new_character.mind,readied_player.new_character) + log_manifest(readied_player.ckey, readied_player.new_character.mind, readied_player.new_character) if(ishuman(readied_player.new_character)) inject(readied_player.new_character, readied_player.client) // SKYRAT EDIT - RP Records - ORIGINAL: inject(readied_player.new_character) CHECK_TICK diff --git a/code/datums/station_traits/job_traits.dm b/code/datums/station_traits/job_traits.dm index c588475094b..94fb0e220d4 100644 --- a/code/datums/station_traits/job_traits.dm +++ b/code/datums/station_traits/job_traits.dm @@ -62,12 +62,14 @@ LAZYREMOVE(lobby_candidates, signee) var/datum/job/our_job = SSjob.GetJobType(job_to_add) + our_job.total_positions = position_amount + our_job.spawn_positions = position_amount while(length(lobby_candidates) && position_amount > 0) var/mob/dead/new_player/picked_player = pick_n_take(lobby_candidates) picked_player.mind.set_assigned_role(our_job) + our_job.current_positions++ position_amount-- - our_job.total_positions = max(0, position_amount) lobby_candidates = null /datum/station_trait/job/can_display_lobby_button(client/player) @@ -177,6 +179,76 @@ overlays += "veteran_advisor" */ +/datum/station_trait/job/human_ai + name = "Human AI" + button_desc = "Sign up to become the \"AI\"." + weight = 1 + trait_flags = parent_type::trait_flags | STATION_TRAIT_REQUIRES_AI + report_message = "Our recent technological advancements in machine Artificial Intelligence has proven futile. In the meantime, we're sending an Intern to help out." + show_in_report = TRUE + can_roll_antag = CAN_ROLL_PROTECTED + job_to_add = /datum/job/human_ai + trait_to_give = STATION_TRAIT_HUMAN_AI + +/datum/station_trait/job/human_ai/New() + . = ..() + RegisterSignal(SSjob, COMSIG_OCCUPATIONS_SETUP, PROC_REF(remove_ai_job)) + RegisterSignal(SSatoms, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(give_fax_machine)) + +/datum/station_trait/job/human_ai/revert() + UnregisterSignal(SSjob, COMSIG_OCCUPATIONS_SETUP) + UnregisterSignal(SSatoms, COMSIG_SUBSYSTEM_POST_INITIALIZE) + return ..() + +/* SKYRAT EDIT - REMOVAL +/datum/station_trait/job/human_ai/on_lobby_button_update_overlays(atom/movable/screen/lobby/button/sign_up/lobby_button, list/overlays) + . = ..() + overlays += LAZYFIND(lobby_candidates, lobby_button.get_mob()) ? "human_ai_on" : "human_ai_off" +*/ + +/datum/station_trait/job/human_ai/proc/remove_ai_job(datum/source) + SIGNAL_HANDLER + var/datum/job_department/department = SSjob.joinable_departments_by_type[/datum/job_department/silicon] + department.remove_job(/datum/job/ai) + var/datum/station_trait/triple_ai/triple_ais = locate() in SSstation.station_traits + if(triple_ais) + position_amount = 3 + +/// Gives the AI SAT a fax machine if it doesn't have one. This is copy pasted from Bridge Assistant's coffee maker. +/datum/station_trait/job/human_ai/proc/give_fax_machine(datum/source) + SIGNAL_HANDLER + var/area/sat_area = GLOB.areas_by_type[/area/station/ai_monitored/turret_protected/ai] + if(isnull(sat_area)) + return + var/list/fax_machines = SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/fax) + for(var/obj/machinery/fax_machine as anything in fax_machines) //don't spawn a fax machine if one exists already. + if(is_type_in_list(get_area(fax_machine), sat_area)) + return + var/list/tables = list() + for(var/turf/area_turf as anything in sat_area.get_turfs_from_all_zlevels()) + var/obj/structure/table/table = locate() in area_turf + if(isnull(table)) + continue + if(area_turf.is_blocked_turf(ignore_atoms = list(table))) + continue + tables += table + if(!length(tables)) + return + var/picked_table = pick_n_take(tables) + var/picked_turf = get_turf(picked_table) + for(var/obj/thing_on_table in picked_turf) //if there's paper bins or other shit on the table, get that off + if(thing_on_table == picked_table) + continue + if(HAS_TRAIT(thing_on_table, TRAIT_WALLMOUNTED) || (thing_on_table.flags_1 & ON_BORDER_1) || thing_on_table.layer < TABLE_LAYER) + continue + if(thing_on_table.invisibility || !thing_on_table.alpha || !thing_on_table.mouse_opacity) + continue + if(length(tables)) + thing_on_table.forceMove(get_turf(pick(tables))) + else + qdel(thing_on_table) + new /obj/machinery/fax/auto_name(picked_turf) + #undef CAN_ROLL_ALWAYS #undef CAN_ROLL_PROTECTED #undef CAN_ROLL_NEVER diff --git a/code/datums/station_traits/neutral_traits.dm b/code/datums/station_traits/neutral_traits.dm index 905bfed2e8e..6d782a3a968 100644 --- a/code/datums/station_traits/neutral_traits.dm +++ b/code/datums/station_traits/neutral_traits.dm @@ -29,6 +29,7 @@ /datum/station_trait/unique_ai name = "Unique AI" trait_type = STATION_TRAIT_NEUTRAL + trait_flags = parent_type::trait_flags | STATION_TRAIT_REQUIRES_AI weight = 5 show_in_report = TRUE report_message = "For experimental purposes, this station AI might show divergence from default lawset. Do not meddle with this experiment, we've removed \ @@ -400,23 +401,31 @@ /datum/station_trait/triple_ai name = "AI Triumvirate" trait_type = STATION_TRAIT_NEUTRAL + trait_flags = parent_type::trait_flags | STATION_TRAIT_REQUIRES_AI show_in_report = TRUE weight = 0 // SKYRAT EDIT Original = 1 report_message = "Your station has been instated with three Nanotrasen Artificial Intelligence models." /datum/station_trait/triple_ai/New() . = ..() - RegisterSignal(SSjob, COMSIG_OCCUPATIONS_DIVIDED, PROC_REF(on_occupations_divided)) + RegisterSignal(SSjob, COMSIG_OCCUPATIONS_SETUP, PROC_REF(on_occupations_setup)) /datum/station_trait/triple_ai/revert() - UnregisterSignal(SSjob, COMSIG_OCCUPATIONS_DIVIDED) + UnregisterSignal(SSjob, COMSIG_OCCUPATIONS_SETUP) return ..() -/datum/station_trait/triple_ai/proc/on_occupations_divided(datum/source, pure, allow_all) +/datum/station_trait/triple_ai/proc/on_occupations_setup(datum/controller/subsystem/job/source) SIGNAL_HANDLER + //allows for latejoining AIs + for(var/obj/effect/landmark/start/ai/secondary/secondary_ai_spawn in GLOB.start_landmarks_list) + secondary_ai_spawn.latejoin_active = TRUE + + var/datum/station_trait/job/human_ai/ai_trait = locate() in SSstation.station_traits + //human AI quirk will handle adding its own job positions, but for now don't allow more AI slots. + if(ai_trait) + return for(var/datum/job/ai/ai_datum in SSjob.joinable_occupations) ai_datum.spawn_positions = 3 - if(!pure) - for(var/obj/effect/landmark/start/ai/secondary/secondary_ai_spawn in GLOB.start_landmarks_list) - secondary_ai_spawn.latejoin_active = TRUE + ai_datum.total_positions = 3 + diff --git a/code/datums/station_traits/positive_traits.dm b/code/datums/station_traits/positive_traits.dm index 4a21d25f884..cc2c49f1b86 100644 --- a/code/datums/station_traits/positive_traits.dm +++ b/code/datums/station_traits/positive_traits.dm @@ -219,6 +219,7 @@ /datum/job/geneticist = /obj/item/organ/internal/fly, //we don't care about implants, we have cancer. /datum/job/head_of_personnel = /obj/item/organ/internal/eyes/robotic, /datum/job/head_of_security = /obj/item/organ/internal/eyes/robotic/thermals, + /datum/job/human_ai = /obj/item/organ/internal/brain/cybernetic, /datum/job/janitor = /obj/item/organ/internal/eyes/robotic/xray, /datum/job/lawyer = /obj/item/organ/internal/heart/cybernetic/tier2, /datum/job/mime = /obj/item/organ/internal/tongue/robot, //... diff --git a/code/datums/wires/airlock.dm b/code/datums/wires/airlock.dm index 4672bd15b87..f57fdf7f4af 100644 --- a/code/datums/wires/airlock.dm +++ b/code/datums/wires/airlock.dm @@ -65,7 +65,7 @@ /datum/wires/airlock/interact(mob/user) var/obj/machinery/door/airlock/airlock_holder = holder - if (!issilicon(user) && airlock_holder.isElectrified() && airlock_holder.shock(user, 100)) + if (!HAS_SILICON_ACCESS(user) && airlock_holder.isElectrified() && airlock_holder.shock(user, 100)) return return ..() @@ -74,7 +74,7 @@ if(!..()) return FALSE var/obj/machinery/door/airlock/airlock = holder - if(!issilicon(user) && !isdrone(user) && airlock.isElectrified()) + if(!HAS_SILICON_ACCESS(user) && !isdrone(user) && airlock.isElectrified()) var/mob/living/carbon/carbon_user = user if (!istype(carbon_user) || carbon_user.should_electrocute(src)) return FALSE diff --git a/code/datums/wires/fax.dm b/code/datums/wires/fax.dm index 8c189d68df8..32904c5f891 100644 --- a/code/datums/wires/fax.dm +++ b/code/datums/wires/fax.dm @@ -12,7 +12,7 @@ if(!.) return FALSE var/obj/machinery/fax/machine = holder - if(!issilicon(user) && machine.seconds_electrified && machine.shock(user, 100)) + if(!HAS_SILICON_ACCESS(user) && machine.seconds_electrified && machine.shock(user, 100)) return FALSE if(machine.panel_open) return TRUE diff --git a/code/datums/wires/mecha.dm b/code/datums/wires/mecha.dm index 07bc1190148..b6e20c8161f 100644 --- a/code/datums/wires/mecha.dm +++ b/code/datums/wires/mecha.dm @@ -69,7 +69,7 @@ if(.) return var/obj/vehicle/sealed/mecha/mecha = holder - if(!issilicon(usr) && mecha.internal_damage & MECHA_INT_SHORT_CIRCUIT && mecha.shock(usr)) + if(!HAS_SILICON_ACCESS(usr) && mecha.internal_damage & MECHA_INT_SHORT_CIRCUIT && mecha.shock(usr)) return FALSE /datum/wires/mecha/can_reveal_wires(mob/user) diff --git a/code/datums/wires/mod.dm b/code/datums/wires/mod.dm index 09274880367..00d836a52eb 100644 --- a/code/datums/wires/mod.dm +++ b/code/datums/wires/mod.dm @@ -52,7 +52,7 @@ /datum/wires/mod/ui_act(action, params) var/obj/item/mod/control/mod = holder - if(!issilicon(usr) && mod.seconds_electrified && mod.shock(usr)) + if(!HAS_SILICON_ACCESS(usr) && mod.seconds_electrified && mod.shock(usr)) return FALSE return ..() diff --git a/code/datums/wires/mulebot.dm b/code/datums/wires/mulebot.dm index 9ec8cbe4db1..beb58fb1ce3 100644 --- a/code/datums/wires/mulebot.dm +++ b/code/datums/wires/mulebot.dm @@ -20,7 +20,7 @@ if(!..()) return FALSE var/mob/living/simple_animal/bot/mulebot/mule = holder - if(mule.bot_cover_flags & BOT_COVER_OPEN) + if(mule.bot_cover_flags & BOT_COVER_MAINTS_OPEN) return TRUE /datum/wires/mulebot/on_cut(wire, mend, source) diff --git a/code/datums/wires/vending.dm b/code/datums/wires/vending.dm index 4e037f3e24b..499707e90e0 100644 --- a/code/datums/wires/vending.dm +++ b/code/datums/wires/vending.dm @@ -28,7 +28,7 @@ if(!..()) return FALSE var/obj/machinery/vending/vending_machine = holder - if(!issilicon(user) && vending_machine.seconds_electrified && vending_machine.shock(user, 100)) + if(!HAS_SILICON_ACCESS(user) && vending_machine.seconds_electrified && vending_machine.shock(user, 100)) return FALSE if(vending_machine.panel_open) return TRUE diff --git a/code/game/area/ai_monitored.dm b/code/game/area/ai_monitored.dm index 84574d6badd..7a99de4dfdf 100644 --- a/code/game/area/ai_monitored.dm +++ b/code/game/area/ai_monitored.dm @@ -17,16 +17,14 @@ /area/station/ai_monitored/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) . = ..() if (ismob(arrived) && motioncameras.len) - for(var/X in motioncameras) - var/obj/machinery/camera/cam = X + for(var/obj/machinery/camera/cam as anything in motioncameras) cam.newTarget(arrived) return /area/station/ai_monitored/Exited(atom/movable/gone, atom/old_loc, list/atom/old_locs) ..() if (ismob(gone) && motioncameras.len) - for(var/X in motioncameras) - var/obj/machinery/camera/cam = X + for(var/obj/machinery/camera/cam as anything in motioncameras) cam.lostTargetRef(WEAKREF(gone)) return diff --git a/code/game/atom/atom_act.dm b/code/game/atom/atom_act.dm index 4c4ec04d667..feb969c9d40 100644 --- a/code/game/atom/atom_act.dm +++ b/code/game/atom/atom_act.dm @@ -67,6 +67,8 @@ * We then return the protection value */ /atom/proc/emp_act(severity) + // SKYRAT EDIT - REMOVAL + //SHOULD_CALL_PARENT(TRUE) var/protection = SEND_SIGNAL(src, COMSIG_ATOM_PRE_EMP_ACT, severity) if(!(protection & EMP_PROTECT_WIRES) && istype(wires)) wires.emp_pulse() diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index c4b30c387cb..538cbd14474 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -121,6 +121,14 @@ /// Will not automatically apply to the turf below you, you need to apply /datum/element/block_explosives in conjunction with this var/explosion_block = 0 + // Access levels, used in modules\jobs\access.dm + /// List of accesses needed to use this object: The user must possess all accesses in this list in order to use the object. + /// Example: If req_access = list(ACCESS_ENGINE, ACCESS_CE)- then the user must have both ACCESS_ENGINE and ACCESS_CE in order to use the object. + var/list/req_access + /// List of accesses needed to use this object: The user must possess at least one access in this list in order to use the object. + /// Example: If req_one_access = list(ACCESS_ENGINE, ACCESS_CE)- then the user must have either ACCESS_ENGINE or ACCESS_CE in order to use the object. + var/list/req_one_access + /mutable_appearance/emissive_blocker /mutable_appearance/emissive_blocker/New() diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 7485e1253a6..a75b08cd265 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -593,10 +593,10 @@ if(!isliving(user)) return FALSE //no ghosts allowed, sorry - if(!issilicon(user) && !user.can_hold_items()) + if(!HAS_SILICON_ACCESS(user) && !user.can_hold_items()) return FALSE //spiders gtfo - if(issilicon(user)) // If we are a silicon, make sure the machine allows silicons to interact with it + if(HAS_SILICON_ACCESS(user)) // If we are a silicon, make sure the machine allows silicons to interact with it if(!(interaction_flags_machine & INTERACT_MACHINE_ALLOW_SILICON)) return FALSE @@ -657,7 +657,7 @@ //////////////////////////////////////////////////////////////////////////////////////////// //Return a non FALSE value to interrupt attack_hand propagation to subtypes. -/obj/machinery/interact(mob/user, special_state) +/obj/machinery/interact(mob/user) if(interaction_flags_machine & INTERACT_MACHINE_SET_MACHINE) user.set_machine(src) update_last_used(user) @@ -666,7 +666,7 @@ /obj/machinery/ui_act(action, list/params) add_fingerprint(usr) update_last_used(usr) - if(isAI(usr) && !GLOB.cameranet.checkTurfVis(get_turf(src))) //We check if they're an AI specifically here, so borgs can still access off-camera stuff. + if(HAS_AI_ACCESS(usr) && !GLOB.cameranet.checkTurfVis(get_turf(src))) //We check if they're an AI specifically here, so borgs can still access off-camera stuff. to_chat(usr, span_warning("You can no longer connect to this device!")) return FALSE return ..() diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index a0e2eab029b..e20d53e4d31 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -365,7 +365,7 @@ /obj/machinery/autolathe/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params) . = ..() - if((!issilicon(usr) && !isAdminGhostAI(usr)) && !Adjacent(usr)) + if((!HAS_SILICON_ACCESS(usr) && !isAdminGhostAI(usr)) && !Adjacent(usr)) return if(busy) balloon_alert(usr, "printing started!") diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index 429ecd70b66..ccb21be468c 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -45,7 +45,7 @@ if(!built && !device && device_type) device = new device_type(src) - src.check_access(null) + check_access(null) if(length(req_access) || length(req_one_access)) board = new(src) @@ -185,7 +185,7 @@ id = "[port.shuttle_id]_[id]" setup_device() -/obj/machinery/button/attack_hand(mob/user, list/modifiers) +/obj/machinery/button/interact(mob/user) . = ..() if(.) return diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm index 2d9a2a221b4..e79eadf53b9 100644 --- a/code/game/machinery/camera/presets.dm +++ b/code/game/machinery/camera/presets.dm @@ -109,7 +109,7 @@ /obj/machinery/camera/proc/upgradeEmpProof(malf_upgrade, ignore_malf_upgrades) if(isEmpProof(ignore_malf_upgrades)) //pass a malf upgrade to ignore_malf_upgrades so we can replace the malf module with the normal one return //that way if someone tries to upgrade an already malf-upgraded camera, it'll just upgrade it to a normal version. - AddElement(/datum/element/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES | EMP_PROTECT_CONTENTS) + AddElement(/datum/element/empprotection, EMP_PROTECT_ALL) var/obj/structure/camera_assembly/assembly = assembly_ref?.resolve() if(malf_upgrade) assembly.malf_emp_firmware_active = TRUE //don't add parts to drop, update icon, ect. reconstructing it will also retain the upgrade. @@ -125,7 +125,7 @@ /obj/machinery/camera/proc/removeEmpProof(ignore_malf_upgrades) if(ignore_malf_upgrades) //don't downgrade it if malf software is forced onto it. return - RemoveElement(/datum/element/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES | EMP_PROTECT_CONTENTS) + RemoveElement(/datum/element/empprotection, EMP_PROTECT_ALL) upgrades &= ~CAMERA_UPGRADE_EMP_PROOF diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index da807f52764..58bf0c75b1f 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -50,7 +50,7 @@ /obj/machinery/computer/security/ui_interact(mob/user, datum/tgui/ui) . = ..() - if(!user.client) //prevents errors by trying to pass clients that don't exist. + if(!user.can_perform_action(src, NEED_DEXTERITY|ALLOW_SILICON_REACH)) //prevents monkeys from using camera consoles return // Update UI ui = SStgui.try_update_ui(user, src, ui) diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 3ae84fbc421..9dd2deaaeb6 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -102,19 +102,19 @@ GLOBAL_VAR_INIT(cops_arrived, FALSE) /// Are we NOT a silicon, AND we're logged in as the captain? /obj/machinery/computer/communications/proc/authenticated_as_non_silicon_captain(mob/user) - if (issilicon(user)) + if (HAS_SILICON_ACCESS(user)) return FALSE return ACCESS_CAPTAIN in authorize_access /// Are we a silicon, OR we're logged in as the captain? /obj/machinery/computer/communications/proc/authenticated_as_silicon_or_captain(mob/user) - if (issilicon(user)) + if (HAS_SILICON_ACCESS(user)) return TRUE return ACCESS_CAPTAIN in authorize_access /// Are we a silicon, OR logged in? /obj/machinery/computer/communications/proc/authenticated(mob/user) - if (issilicon(user)) + if (HAS_SILICON_ACCESS(user)) return TRUE return authenticated @@ -202,7 +202,7 @@ GLOBAL_VAR_INIT(cops_arrived, FALSE) return // Check if they have - if (!issilicon(usr)) + if (!HAS_SILICON_ACCESS(usr)) var/obj/item/held_item = usr.get_active_held_item() var/obj/item/card/id/id_card = held_item?.GetID() if (!istype(id_card)) @@ -301,7 +301,7 @@ GLOBAL_VAR_INIT(cops_arrived, FALSE) state = STATE_MAIN if ("recallShuttle") // AIs cannot recall the shuttle - if (!authenticated(usr) || issilicon(usr) || syndicate) + if (!authenticated(usr) || HAS_SILICON_ACCESS(usr) || syndicate) return SSshuttle.cancelEvac(usr) if ("requestNukeCodes") @@ -570,7 +570,7 @@ GLOBAL_VAR_INIT(cops_arrived, FALSE) "syndicate" = syndicate, ) - var/ui_state = issilicon(user) ? cyborg_state : state + var/ui_state = HAS_SILICON_ACCESS(user) ? cyborg_state : state var/has_connection = has_communication() data["hasConnection"] = has_connection @@ -587,9 +587,9 @@ GLOBAL_VAR_INIT(cops_arrived, FALSE) data["safeCodeDeliveryWait"] = 0 data["safeCodeDeliveryArea"] = null - if (authenticated || issilicon(user)) + if (authenticated || HAS_SILICON_ACCESS(user)) data["authenticated"] = TRUE - data["canLogOut"] = !issilicon(user) + data["canLogOut"] = !HAS_SILICON_ACCESS(user) data["page"] = ui_state if ((obj_flags & EMAGGED) || syndicate) @@ -600,7 +600,7 @@ GLOBAL_VAR_INIT(cops_arrived, FALSE) data["canBuyShuttles"] = can_buy_shuttles(user) data["canMakeAnnouncement"] = FALSE data["canMessageAssociates"] = FALSE - data["canRecallShuttles"] = !issilicon(user) + data["canRecallShuttles"] = !HAS_SILICON_ACCESS(user) data["canRequestNuke"] = FALSE data["canSendToSectors"] = FALSE data["canSetAlertLevel"] = FALSE @@ -612,7 +612,7 @@ GLOBAL_VAR_INIT(cops_arrived, FALSE) data["aprilFools"] = check_holidays(APRIL_FOOLS) data["alertLevel"] = SSsecurity_level.get_current_level_as_text() data["authorizeName"] = authorize_name - data["canLogOut"] = !issilicon(user) + data["canLogOut"] = !HAS_SILICON_ACCESS(user) data["shuttleCanEvacOrFailReason"] = SSshuttle.canEvac() if(syndicate) data["shuttleCanEvacOrFailReason"] = "You cannot summon the shuttle from this console!" @@ -641,7 +641,7 @@ GLOBAL_VAR_INIT(cops_arrived, FALSE) data["engineeringOverride"] = GLOB.force_eng_override //SKYRAT EDIT - Engineering Override Toggle data["alertLevelTick"] = alert_level_tick data["canMakeAnnouncement"] = TRUE - data["canSetAlertLevel"] = issilicon(user) ? "NO_SWIPE_NEEDED" : "SWIPE_NEEDED" + data["canSetAlertLevel"] = HAS_SILICON_ACCESS(user) ? "NO_SWIPE_NEEDED" : "SWIPE_NEEDED" else if(syndicate) data["canMakeAnnouncement"] = TRUE @@ -745,7 +745,7 @@ GLOBAL_VAR_INIT(cops_arrived, FALSE) return is_station_level(z_level) || is_centcom_level(z_level) /obj/machinery/computer/communications/proc/set_state(mob/user, new_state) - if (issilicon(user)) + if (HAS_SILICON_ACCESS(user)) cyborg_state = new_state else state = new_state @@ -755,7 +755,7 @@ GLOBAL_VAR_INIT(cops_arrived, FALSE) /obj/machinery/computer/communications/proc/can_buy_shuttles(mob/user) if (!SSmapping.config.allow_custom_shuttles) return FALSE - if (issilicon(user)) + if (HAS_SILICON_ACCESS(user)) return FALSE var/has_access = FALSE @@ -798,7 +798,7 @@ GLOBAL_VAR_INIT(cops_arrived, FALSE) return length(CONFIG_GET(keyed_list/cross_server)) > 0 /obj/machinery/computer/communications/proc/make_announcement(mob/living/user) - var/is_ai = issilicon(user) + var/is_ai = HAS_SILICON_ACCESS(user) if(!SScommunications.can_announce(user, is_ai)) to_chat(user, span_alert("Intercomms recharging. Please stand by.")) return diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm index 15fa4964520..1f30aa758f6 100644 --- a/code/game/machinery/computer/crew.dm +++ b/code/game/machinery/computer/crew.dm @@ -97,7 +97,8 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) var/list/jobs = list( // Note that jobs divisible by 10 are considered heads of staff, and bolded // 00: Captain - JOB_CAPTAIN = 00, + JOB_CAPTAIN = 0, + JOB_HUMAN_AI = 1, // 10-19: Security JOB_HEAD_OF_SECURITY = 10, JOB_WARDEN = 11, @@ -195,7 +196,7 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) z = T.z . = list( "sensors" = update_data(z), - "link_allowed" = isAI(user) + "link_allowed" = HAS_AI_ACCESS(user) ) /datum/crewmonitor/proc/update_data(z) diff --git a/code/game/machinery/computer/law.dm b/code/game/machinery/computer/law.dm index 423633d31ac..372d75822b7 100644 --- a/code/game/machinery/computer/law.dm +++ b/code/game/machinery/computer/law.dm @@ -42,6 +42,11 @@ desc = "Used to upload laws to the AI." circuit = /obj/item/circuitboard/computer/aiupload +/obj/machinery/computer/upload/ai/Initialize(mapload) + . = ..() + if(mapload && HAS_TRAIT(SSstation, STATION_TRAIT_HUMAN_AI)) + return INITIALIZE_HINT_QDEL + /obj/machinery/computer/upload/ai/interact(mob/user) current = select_active_ai(user, z) diff --git a/code/game/machinery/computer/records/records.dm b/code/game/machinery/computer/records/records.dm index 36a89e577ed..c3aba60e4c6 100644 --- a/code/game/machinery/computer/records/records.dm +++ b/code/game/machinery/computer/records/records.dm @@ -132,30 +132,12 @@ /obj/machinery/computer/records/proc/expunge_record_info(datum/record/crew/target) return -/// Detects whether a user can use buttons on the machine -/obj/machinery/computer/records/proc/has_auth(mob/user) - if(issilicon(user) || isAdminGhostAI(user)) // Silicons don't need to authenticate - return TRUE - - if(!isliving(user)) - return FALSE - var/mob/living/player = user - - var/obj/item/card/auth = player.get_idcard(TRUE) - if(!auth) - return FALSE - var/list/access = auth.GetAccess() - if(!check_access_list(access)) - return FALSE - - return TRUE - /// Inserts a new record into GLOB.manifest.general. Requires a photo to be taken. /obj/machinery/computer/records/proc/insert_new_record(mob/user, obj/item/photo/mugshot) if(!mugshot || !is_operational || !user.can_perform_action(src, ALLOW_SILICON_REACH)) return FALSE - if(!authenticated && !has_auth(user)) + if(!authenticated && !allowed(user)) balloon_alert(user, "access denied") playsound(src, 'sound/machines/terminal_error.ogg', 70, TRUE) return FALSE @@ -184,7 +166,7 @@ if(!user.can_perform_action(src, ALLOW_SILICON_REACH) || !is_operational) return FALSE - if(!has_auth(user)) + if(!allowed(user)) balloon_alert(user, "access denied") playsound(src, 'sound/machines/terminal_error.ogg', 70, TRUE) return FALSE diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 2d727749c0d..5c67d9f0003 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -803,7 +803,7 @@ . = ..() if(.) return - if(!(issilicon(user) || isAdminGhostAI(user))) + if(!HAS_SILICON_ACCESS(user)) if(isElectrified() && shock(user, 100)) return @@ -1001,7 +1001,7 @@ return TRUE /obj/machinery/door/airlock/attackby(obj/item/C, mob/user, params) - if(!issilicon(user) && !isAdminGhostAI(user)) + if(!HAS_SILICON_ACCESS(user)) if(isElectrified() && (C.obj_flags & CONDUCTS_ELECTRICITY) && shock(user, 75)) return add_fingerprint(user) @@ -1689,7 +1689,7 @@ . = TRUE /obj/machinery/door/airlock/proc/user_allowed(mob/user) - return (issilicon(user) && canAIControl(user)) || isAdminGhostAI(user) + return (HAS_SILICON_ACCESS(user) && canAIControl(user)) || isAdminGhostAI(user) /obj/machinery/door/airlock/proc/shock_restore(mob/user) if(!user_allowed(user)) @@ -2311,6 +2311,7 @@ /obj/machinery/door/airlock/cult/Initialize(mapload) . = ..() new openingoverlaytype(loc) + AddElement(/datum/element/empprotection, EMP_PROTECT_ALL) /obj/machinery/door/airlock/cult/canAIControl(mob/user) return (IS_CULTIST(user) && !isAllPowerCut()) @@ -2361,9 +2362,6 @@ /obj/machinery/door/airlock/cult/narsie_act() return -/obj/machinery/door/airlock/cult/emp_act(severity) - return - /obj/machinery/door/airlock/cult/friendly friendly = TRUE diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index aa7e6682402..05b8d883dac 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -116,7 +116,7 @@ if(!can_open_with_hands) return . - if(isaicamera(user) || issilicon(user)) + if(isaicamera(user) || HAS_SILICON_ACCESS(user)) return . if(isnull(held_item) && Adjacent(user)) diff --git a/code/game/machinery/doors/passworddoor.dm b/code/game/machinery/doors/passworddoor.dm index f4e2bcc2d4c..df8f7fa936a 100644 --- a/code/game/machinery/doors/passworddoor.dm +++ b/code/game/machinery/doors/passworddoor.dm @@ -39,6 +39,7 @@ . = ..() if(voice_activated) become_hearing_sensitive() + AddElement(/datum/element/empprotection, EMP_PROTECT_ALL) /obj/machinery/door/password/get_save_vars() return ..() + NAMEOF(src, password) @@ -85,8 +86,5 @@ return TRUE return FALSE -/obj/machinery/door/password/emp_act(severity) - return - /obj/machinery/door/password/ex_act(severity, target) return FALSE diff --git a/code/game/machinery/modular_shield.dm b/code/game/machinery/modular_shield.dm index f4e15cfa878..63bd1875c60 100644 --- a/code/game/machinery/modular_shield.dm +++ b/code/game/machinery/modular_shield.dm @@ -711,6 +711,7 @@ //Damage from emp /obj/structure/emergency_shield/modular/emp_act(severity) + . = ..() if(isnull(shield_generator)) qdel(src) return diff --git a/code/game/machinery/navbeacon.dm b/code/game/machinery/navbeacon.dm index 5caa41d9089..c15421cbf5a 100644 --- a/code/game/machinery/navbeacon.dm +++ b/code/game/machinery/navbeacon.dm @@ -165,7 +165,7 @@ controls["cover_locked"] = cover_locked data["locked"] = controls_locked - data["siliconUser"] = issilicon(user) + data["siliconUser"] = HAS_SILICON_ACCESS(user) data["controls"] = controls return data @@ -190,7 +190,7 @@ controls_locked = !controls_locked return TRUE - if(controls_locked && !issilicon(usr)) + if(controls_locked && !HAS_SILICON_ACCESS(usr)) return switch(action) diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm index d1206cfc1c5..048e63f95f6 100644 --- a/code/game/machinery/shieldgen.dm +++ b/code/game/machinery/shieldgen.dm @@ -187,7 +187,7 @@ . = ..() if(.) return - if(locked && !issilicon(user)) + if(locked && !HAS_SILICON_ACCESS(user)) to_chat(user, span_warning("The machine is locked, you are unable to use it!")) return if(panel_open) @@ -479,7 +479,7 @@ if(!anchored) balloon_alert(user, "not secured!") return - if(locked && !issilicon(user)) + if(locked && !HAS_SILICON_ACCESS(user)) balloon_alert(user, "locked!") return if(!powernet) diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index b34f7873648..f96e1c1199b 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -375,7 +375,7 @@ src, choices, custom_check = CALLBACK(src, PROC_REF(check_interactable), user), - require_near = !issilicon(user), + require_near = !HAS_SILICON_ACCESS(user), autopick_single_option = FALSE ) diff --git a/code/game/machinery/telecomms/machine_interactions.dm b/code/game/machinery/telecomms/machine_interactions.dm index 3fb86271699..5086f7e91a7 100644 --- a/code/game/machinery/telecomms/machine_interactions.dm +++ b/code/game/machinery/telecomms/machine_interactions.dm @@ -88,7 +88,7 @@ return var/mob/living/current_user = usr - if(!issilicon(current_user)) + if(!HAS_SILICON_ACCESS(current_user)) if(!istype(current_user.get_active_held_item(), /obj/item/multitool)) return @@ -248,7 +248,7 @@ /obj/machinery/telecomms/proc/get_multitool(mob/user) var/obj/item/multitool/multitool = null // Let's double check - if(!issilicon(user) && istype(user.get_active_held_item(), /obj/item/multitool)) + if(!HAS_SILICON_ACCESS(user) && istype(user.get_active_held_item(), /obj/item/multitool)) multitool = user.get_active_held_item() else if(isAI(user)) var/mob/living/silicon/ai/U = user @@ -259,6 +259,6 @@ return multitool /obj/machinery/telecomms/proc/canAccess(mob/user) - if(issilicon(user) || in_range(user, src)) + if(HAS_SILICON_ACCESS(user) || in_range(user, src)) return TRUE return FALSE diff --git a/code/game/machinery/washing_machine.dm b/code/game/machinery/washing_machine.dm index fd0fea92292..21e3f396f8d 100644 --- a/code/game/machinery/washing_machine.dm +++ b/code/game/machinery/washing_machine.dm @@ -24,7 +24,8 @@ GLOBAL_LIST_INIT(dye_registry, list( DYE_REDCOAT = /obj/item/clothing/under/costume/redcoat, DYE_PRISONER = /obj/item/clothing/under/rank/prisoner, DYE_SYNDICATE = /obj/item/clothing/under/syndicate, - DYE_CENTCOM = /obj/item/clothing/under/rank/centcom/commander + DYE_CENTCOM = /obj/item/clothing/under/rank/centcom/commander, + DYE_COSMIC = /obj/item/clothing/under/rank/station_trait/human_ai, ), DYE_REGISTRY_JUMPSKIRT = list( DYE_RED = /obj/item/clothing/under/color/jumpskirt/red, diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index 0c293ac502a..48e92e1477d 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -1078,6 +1078,14 @@ assigned_icon_state = "assigned_silver" wildcard_slots = WILDCARD_LIMIT_SILVER +/obj/item/card/id/advanced/robotic + name = "magnetic identification card" + desc = "An integrated card which shows the work poured into opening doors." + icon_state = "card_carp" //im not a spriter + inhand_icon_state = "silver_id" + assigned_icon_state = "assigned_silver" + wildcard_slots = WILDCARD_LIMIT_GREY + /datum/id_trim/maint_reaper access = list(ACCESS_MAINT_TUNNELS) trim_state = "trim_janitor" diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm index 0ab7e5d94b5..c619f7d7018 100644 --- a/code/game/objects/items/devices/aicard.dm +++ b/code/game/objects/items/devices/aicard.dm @@ -16,6 +16,8 @@ /obj/item/aicard/Initialize(mapload) . = ..() + if(mapload && HAS_TRAIT(SSstation, STATION_TRAIT_HUMAN_AI)) + return INITIALIZE_HINT_QDEL ADD_TRAIT(src, TRAIT_CASTABLE_LOC, INNATE_TRAIT) /obj/item/aicard/Destroy(force) diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm index a9046145168..6b627fa8eff 100644 --- a/code/game/objects/items/devices/laserpointer.dm +++ b/code/game/objects/items/devices/laserpointer.dm @@ -63,6 +63,15 @@ . = ..() diode = new /obj/item/stock_parts/micro_laser/ultra +/obj/item/laser_pointer/infinite_range + name = "infinite laser pointer" + desc = "Used to shine in the eyes of Cyborgs who need a bit of a push, this works through camera consoles." + max_range = INFINITE + +/obj/item/laser_pointer/infinite_range/Initialize(mapload) + . = ..() + diode = new /obj/item/stock_parts/servo/femto + /obj/item/laser_pointer/screwdriver_act(mob/living/user, obj/item/tool) if(diode) tool.play_tool_sound(src) @@ -193,16 +202,17 @@ to_chat(user, span_warning("Your fingers can't press the button!")) return - if(!IN_GIVEN_RANGE(target, user, max_range)) - to_chat(user, span_warning("\The [target] is too far away!")) - return - if(!(user in (view(max_range, target)))) //check if we are visible from the target's PoV - if(isnull(crystal_lens)) - to_chat(user, span_warning("You can't point with [src] through walls!")) - return - if(!((user.sight & SEE_OBJS) || (user.sight & SEE_MOBS))) //only let it work if we have xray or thermals. mesons don't count because they are easier to get. - to_chat(user, span_notice("You can't quite make out your target and you fail to shine at it.")) + if(max_range != INFINITE) + if(!IN_GIVEN_RANGE(target, user, max_range)) + to_chat(user, span_warning("\The [target] is too far away!")) return + if(!(user in (view(max_range, target)))) //check if we are visible from the target's PoV + if(isnull(crystal_lens)) + to_chat(user, span_warning("You can't point with [src] through walls!")) + return + if(!((user.sight & SEE_OBJS) || (user.sight & SEE_MOBS))) //only let it work if we have xray or thermals. mesons don't count because they are easier to get. + to_chat(user, span_notice("You can't quite make out your target and you fail to shine at it.")) + return add_fingerprint(user) diff --git a/code/game/objects/items/devices/radio/encryptionkey.dm b/code/game/objects/items/devices/radio/encryptionkey.dm index 7774902b83b..b7a96d777ef 100644 --- a/code/game/objects/items/devices/radio/encryptionkey.dm +++ b/code/game/objects/items/devices/radio/encryptionkey.dm @@ -188,7 +188,31 @@ greyscale_colors = "#24a157#dca01b" /obj/item/encryptionkey/ai //ported from NT, this goes 'inside' the AI. - channels = list(RADIO_CHANNEL_COMMAND = 1, RADIO_CHANNEL_SECURITY = 1, RADIO_CHANNEL_ENGINEERING = 1, RADIO_CHANNEL_SCIENCE = 1, RADIO_CHANNEL_MEDICAL = 1, RADIO_CHANNEL_SUPPLY = 1, RADIO_CHANNEL_SERVICE = 1, RADIO_CHANNEL_AI_PRIVATE = 1) + channels = list( + RADIO_CHANNEL_COMMAND = 1, + RADIO_CHANNEL_SECURITY = 1, + RADIO_CHANNEL_ENGINEERING = 1, + RADIO_CHANNEL_SCIENCE = 1, + RADIO_CHANNEL_MEDICAL = 1, + RADIO_CHANNEL_SUPPLY = 1, + RADIO_CHANNEL_SERVICE = 1, + RADIO_CHANNEL_AI_PRIVATE = 1, + ) + +/obj/item/encryptionkey/ai_with_binary + name = "ai encryption key" + channels = list( + RADIO_CHANNEL_COMMAND = 1, + RADIO_CHANNEL_SECURITY = 1, + RADIO_CHANNEL_ENGINEERING = 1, + RADIO_CHANNEL_SCIENCE = 1, + RADIO_CHANNEL_MEDICAL = 1, + RADIO_CHANNEL_SUPPLY = 1, + RADIO_CHANNEL_SERVICE = 1, + RADIO_CHANNEL_AI_PRIVATE = 1, + ) + translate_binary = TRUE + translated_language = /datum/language/machine /obj/item/encryptionkey/ai/evil //ported from NT, this goes 'inside' the AI. name = "syndicate binary encryption key" diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 4d6b8edbd2d..fff7b0a655a 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -117,6 +117,8 @@ GLOBAL_LIST_INIT(channel_tokens, list( /obj/item/radio/headset/dropped(mob/user, silent) . = ..() + if(QDELETED(src)) //This can be called as a part of destroy + return for(var/language in language_list) user.remove_language(language, language_flags = UNDERSTOOD_LANGUAGE, source = LANGUAGE_RADIOKEY) @@ -348,17 +350,25 @@ GLOBAL_LIST_INIT(channel_tokens, list( AddComponent(/datum/component/wearertargeting/earprotection, list(ITEM_SLOT_EARS)) /obj/item/radio/headset/silicon/pai - name = "\proper mini Integrated Subspace Transceiver " + name = "\proper mini Integrated Subspace Transceiver" subspace_transmission = FALSE /obj/item/radio/headset/silicon/ai - name = "\proper Integrated Subspace Transceiver " + name = "\proper Integrated Subspace Transceiver" keyslot2 = new /obj/item/encryptionkey/ai command = TRUE +/obj/item/radio/headset/silicon/human_ai + name = "\proper Disconnected Subspace Transceiver" + desc = "A headset that is rumored to be one day implanted into a brain in a jar directly." + icon_state = "rob_headset" + worn_icon_state = "rob_headset" + keyslot2 = new /obj/item/encryptionkey/ai_with_binary + command = TRUE + /obj/item/radio/headset/silicon/ai/evil - name = "\proper Evil Integrated Subspace Transceiver " + name = "\proper Evil Integrated Subspace Transceiver" keyslot2 = new /obj/item/encryptionkey/ai/evil command = FALSE diff --git a/code/game/objects/items/machine_wand.dm b/code/game/objects/items/machine_wand.dm new file mode 100644 index 00000000000..71ea2fae1b6 --- /dev/null +++ b/code/game/objects/items/machine_wand.dm @@ -0,0 +1,181 @@ +///When EMPed, how long the remote will be disabled for by default. +#define EMP_TIMEOUT_DURATION (2 MINUTES) + +/obj/item/machine_remote + name = "machine wand" + desc = "A remote for controlling machines and bots around the station." + icon = 'icons/obj/antags/syndicate_tools.dmi' + icon_state = "weakpoint_locator" + inhand_icon_state = "weakpoint_locator" + lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' + righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' + w_class = WEIGHT_CLASS_NORMAL + ///If we're unable to be used, this is how long we have left to wait. + COOLDOWN_DECLARE(timeout_time) + ///The appearance put onto machines being actively controlled. + var/mutable_appearance/bug_appearance + ///Direct reference to the moving bug effect that moves towards machines we direct it at. + var/obj/effect/bug_moving/moving_bug + ///The machine that's currently being controlled. + var/atom/movable/controlling_machine_or_bot + +/obj/item/machine_remote/Initialize(mapload) + . = ..() + bug_appearance = mutable_appearance('icons/effects/effects.dmi', "fly-surrounding", ABOVE_WINDOW_LAYER) + register_context() + +/obj/item/machine_remote/Destroy(force) + . = ..() + if(controlling_machine_or_bot) + remove_old_machine() + QDEL_NULL(moving_bug) + QDEL_NULL(bug_appearance) + +/obj/item/machine_remote/examine(mob/user) + . = ..() + if(controlling_machine_or_bot) + . += span_notice("It is currently controlling [controlling_machine_or_bot]. Use in-hand to interact with it.") + +/obj/item/machine_remote/add_context(atom/source, list/context, obj/item/held_item, mob/user) + if(controlling_machine_or_bot) + context[SCREENTIP_CONTEXT_LMB] = "Use [controlling_machine_or_bot]" + context[SCREENTIP_CONTEXT_ALT_LMB] = "Flush Control" + return CONTEXTUAL_SCREENTIP_SET + return NONE + +/obj/item/machine_remote/proc/on_control_destroy(obj/machinery/source) + SIGNAL_HANDLER + remove_old_machine() + +/obj/item/machine_remote/ui_interact(mob/user, datum/tgui/ui) + if(!COOLDOWN_FINISHED(src, timeout_time)) + playsound(src, 'sound/machines/synth_no.ogg', 30 , TRUE) + say("Remote control disabled temporarily. Please try again soon.") + return FALSE + if(!controlling_machine_or_bot) + return + if(controlling_machine_or_bot.ui_interact(user, ui)) + return + controlling_machine_or_bot.interact(user) //no ui, interact instead (to open windoors and such) + +/obj/item/machine_remote/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(controlling_machine_or_bot) + return controlling_machine_or_bot.ui_act(action, params, ui, state) + +/obj/item/machine_remote/AltClick(mob/user) + . = ..() + if(moving_bug) //we have a bug in transit, so let's kill it. + QDEL_NULL(moving_bug) + if(!controlling_machine_or_bot) + return + say("Remote control over [controlling_machine_or_bot] stopped.") + remove_old_machine() + +/obj/item/machine_remote/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + . = ..() + if(!COOLDOWN_FINISHED(src, timeout_time)) + playsound(src, 'sound/machines/synth_no.ogg', 30 , TRUE) + say("Remote control disabled temporarily. Please try again soon.") + return FALSE + if(!ismachinery(target) && !isbot(target)) + return + if(moving_bug) //we have a bug in transit already, so let's kill it. + QDEL_NULL(moving_bug) + var/turf/spawning_turf = (controlling_machine_or_bot ? get_turf(controlling_machine_or_bot) : get_turf(src)) + moving_bug = new(spawning_turf, src, target) + remove_old_machine() + +///Sets a controlled machine to a new machine, if possible. Checks if AIs can even control it. +/obj/item/machine_remote/proc/set_controlled_machine(obj/machinery/new_machine) + if(controlling_machine_or_bot == new_machine) + return + remove_old_machine() + if(istype(new_machine, /obj/machinery/power/apc)) + var/obj/machinery/power/apc/new_apc = new_machine + if(new_apc.aidisabled) + say("AI wire cut, machine uncontrollable.") + return + else if(istype(new_machine, /obj/machinery/door/airlock)) + var/obj/machinery/door/airlock/new_airlock = new_machine + if(!new_airlock.canAIControl()) + say("AI wire cut, machine uncontrollable.") + return + controlling_machine_or_bot = new_machine + controlling_machine_or_bot.add_overlay(bug_appearance) + RegisterSignal(controlling_machine_or_bot, COMSIG_QDELETING, PROC_REF(on_control_destroy)) + RegisterSignal(controlling_machine_or_bot, COMSIG_ATOM_EMP_ACT, PROC_REF(on_machine_emp)) + +///Removes the machine being controlled as the current machine, taking its signals and overlays with it. +/obj/item/machine_remote/proc/remove_old_machine() + if(!controlling_machine_or_bot) + return + UnregisterSignal(controlling_machine_or_bot, list(COMSIG_ATOM_EMP_ACT, COMSIG_QDELETING)) + controlling_machine_or_bot.cut_overlay(bug_appearance) + controlling_machine_or_bot = null + +///Called when the machine we're controlling is EMP, removing our control from it. +/obj/item/machine_remote/proc/on_machine_emp(datum/source, severity, protection) + SIGNAL_HANDLER + if(severity & EMP_PROTECT_CONTENTS) + return + disable_remote(EMP_TIMEOUT_DURATION) + +/obj/item/machine_remote/proc/disable_remote(timeout_duration) + remove_old_machine() + COOLDOWN_START(src, timeout_time, timeout_duration) + +///The effect of the bug moving towards the selected machinery to mess with. +/obj/effect/bug_moving + name = "bug" + desc = "Where da bug goin?" + icon_state = "fly" + obj_flags = CAN_BE_HIT + max_integrity = 20 + uses_integrity = TRUE + plane = ABOVE_GAME_PLANE + layer = FLY_LAYER + movement_type = PHASING + ///The controller that's sending us out to the machine. + var/obj/item/machine_remote/controller + ///The machine we are trying to get remote access to. + var/atom/movable/thing_moving_towards + +/obj/effect/bug_moving/Initialize(mapload, obj/item/machine_remote/controller, atom/movable/thing_moving_towards) + . = ..() + if(!controller) + CRASH("a moving bug has been created by something that isn't a machine remote controller!") + if(!thing_moving_towards) + CRASH("a moving bug has been created but isn't moving towards anything!") + src.controller = controller + src.thing_moving_towards = thing_moving_towards + var/datum/move_loop/loop = SSmove_manager.home_onto(src, thing_moving_towards, delay = 5, flags = MOVEMENT_LOOP_NO_DIR_UPDATE) + RegisterSignal(loop, COMSIG_MOVELOOP_POSTPROCESS, PROC_REF(reached_destination_check)) + RegisterSignal(thing_moving_towards, COMSIG_QDELETING, PROC_REF(on_machine_del)) + +/obj/effect/bug_moving/Destroy(force) + if(controller) + controller.moving_bug = null + controller = null + thing_moving_towards = null + return ..() + +/obj/effect/bug_moving/emp_act(severity) + . = ..() + if(. & EMP_PROTECT_SELF) + return + controller.disable_remote(EMP_TIMEOUT_DURATION) + qdel(src) + +/obj/effect/bug_moving/proc/reached_destination_check(datum/move_loop/source, result) + SIGNAL_HANDLER + if(!Adjacent(thing_moving_towards)) + return + controller.set_controlled_machine(thing_moving_towards) + qdel(src) + +/obj/effect/bug_moving/proc/on_machine_del(datum/move_loop/source) + SIGNAL_HANDLER + qdel(src) + +#undef EMP_TIMEOUT_DURATION diff --git a/code/game/objects/items/puzzle_pieces.dm b/code/game/objects/items/puzzle_pieces.dm index 1e99042a612..77b07488d6c 100644 --- a/code/game/objects/items/puzzle_pieces.dm +++ b/code/game/objects/items/puzzle_pieces.dm @@ -74,6 +74,7 @@ . = ..() if(!isnull(puzzle_id) && uses_queuelinks) SSqueuelinks.add_to_queue(src, puzzle_id) + AddElement(/datum/element/empprotection, EMP_PROTECT_ALL) /obj/machinery/door/puzzle/MatchedLinks(id, list/partners) for(var/partner in partners) @@ -88,9 +89,6 @@ /obj/machinery/door/puzzle/Bumped(atom/movable/AM) return !density && ..() -/obj/machinery/door/puzzle/emp_act(severity) - return - /obj/machinery/door/puzzle/ex_act(severity, target) return FALSE diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm index 214187b7708..eabd9bc8304 100644 --- a/code/game/objects/items/teleportation.dm +++ b/code/game/objects/items/teleportation.dm @@ -371,6 +371,7 @@ playsound(src, 'sound/machines/twobeep.ogg', 10, TRUE, extrarange = SILENCED_SOUND_EXTRARANGE, falloff_distance = 0) /obj/item/syndicate_teleporter/emp_act(severity) + . = ..() if(!prob(50/severity)) return var/teleported_something = FALSE diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index cb57c5049bb..dcc3b03dc78 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -28,14 +28,6 @@ var/current_skin //Has the item been reskinned? var/list/unique_reskin //List of options to reskin. - // Access levels, used in modules\jobs\access.dm - /// List of accesses needed to use this object: The user must possess all accesses in this list in order to use the object. - /// Example: If req_access = list(ACCESS_ENGINE, ACCESS_CE)- then the user must have both ACCESS_ENGINE and ACCESS_CE in order to use the object. - var/list/req_access - /// List of accesses needed to use this object: The user must possess at least one access in this list in order to use the object. - /// Example: If req_one_access = list(ACCESS_ENGINE, ACCESS_CE)- then the user must have either ACCESS_ENGINE or ACCESS_CE in order to use the object. - var/list/req_one_access - /// Custom fire overlay icon, will just use the default overlay if this is null var/custom_fire_overlay /// Particles this obj uses when burning, if any diff --git a/code/game/objects/structures/ai_core.dm b/code/game/objects/structures/ai_core.dm index eef6059d984..7615a37a88b 100644 --- a/code/game/objects/structures/ai_core.dm +++ b/code/game/objects/structures/ai_core.dm @@ -441,4 +441,9 @@ That prevents a few funky behaviors. name = "AI core (AI Core Board)" //Well, duh, but best to be consistent var/battery = 200 //backup battery for when the AI loses power. Copied to/from AI mobs when carding, and placed here to avoid recharge via deconning the core +/obj/item/circuitboard/aicore/Initialize(mapload) + . = ..() + if(mapload && HAS_TRAIT(SSstation, STATION_TRAIT_HUMAN_AI)) + return INITIALIZE_HINT_QDEL + #undef AI_CORE_BRAIN diff --git a/code/modules/antagonists/malf_ai/malf_ai_modules.dm b/code/modules/antagonists/malf_ai/malf_ai_modules.dm index fc17b6924df..7699c3f76bc 100644 --- a/code/modules/antagonists/malf_ai/malf_ai_modules.dm +++ b/code/modules/antagonists/malf_ai/malf_ai_modules.dm @@ -867,7 +867,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) /datum/ai_module/upgrade/upgrade_turrets/upgrade(mob/living/silicon/ai/AI) for(var/obj/machinery/porta_turret/ai/turret as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/porta_turret/ai)) - turret.AddElement(/datum/element/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES | EMP_PROTECT_CONTENTS) + turret.AddElement(/datum/element/empprotection, EMP_PROTECT_ALL) turret.max_integrity = 200 turret.repair_damage(200) turret.lethal_projectile = /obj/projectile/beam/laser/heavylaser //Once you see it, you will know what it means to FEAR. diff --git a/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm b/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm index c8e93257b80..6bb07f4fbc1 100644 --- a/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm +++ b/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm @@ -186,7 +186,7 @@ GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm) . += span_notice("Right-click to [locked ? "unlock" : "lock"] the interface.") /obj/machinery/airalarm/ui_status(mob/user, datum/ui_state/state) - if(user.has_unlimited_silicon_privilege && aidisabled) + if(HAS_SILICON_ACCESS(user) && aidisabled) to_chat(user, "AI control has been disabled.") else if(!shorted) return ..() @@ -227,7 +227,7 @@ GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm) var/data = list() data["locked"] = locked - data["siliconUser"] = user.has_unlimited_silicon_privilege + data["siliconUser"] = HAS_SILICON_ACCESS(user) data["emagged"] = (obj_flags & EMAGGED ? 1 : 0) data["dangerLevel"] = danger_level data["atmosAlarm"] = !!my_area.active_alarms[ALARM_ATMOS] @@ -288,7 +288,7 @@ GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm) singular_tlv["hazard_max"] = tlv.hazard_max data["tlvSettings"] += list(singular_tlv) - if(!locked || user.has_unlimited_silicon_privilege) + if(!locked || HAS_SILICON_ACCESS(user)) data["vents"] = list() for(var/obj/machinery/atmospherics/components/unary/vent_pump/vent as anything in my_area.air_vents) data["vents"] += list(list( @@ -345,7 +345,7 @@ GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm) if(. || buildstage != AIR_ALARM_BUILD_COMPLETE) return - if((locked && !usr.has_unlimited_silicon_privilege) || (usr.has_unlimited_silicon_privilege && aidisabled)) + if((locked && !HAS_SILICON_ACCESS(usr)) || (HAS_SILICON_ACCESS(usr) && aidisabled)) return var/mob/user = usr diff --git a/code/modules/awaymissions/gateway.dm b/code/modules/awaymissions/gateway.dm index 6bfe17ebc2e..36ae735395c 100644 --- a/code/modules/awaymissions/gateway.dm +++ b/code/modules/awaymissions/gateway.dm @@ -346,7 +346,7 @@ GLOBAL_LIST_EMPTY(gateway_destinations) density = TRUE use_power = NO_POWER_USE -/obj/machinery/gateway/away/interact(mob/user, special_state) +/obj/machinery/gateway/away/interact(mob/user) . = ..() //SKYRAT EDIT ADDITION var/list/type_blacklist = list( diff --git a/code/modules/capture_the_flag/ctf_equipment.dm b/code/modules/capture_the_flag/ctf_equipment.dm index dccf875a55a..0211a066555 100644 --- a/code/modules/capture_the_flag/ctf_equipment.dm +++ b/code/modules/capture_the_flag/ctf_equipment.dm @@ -156,8 +156,9 @@ ammo_x_offset = 2 shaded_charge = FALSE -/obj/item/gun/energy/laser/instakill/emp_act() //implying you could stop the instagib - return +/obj/item/gun/energy/laser/instakill/Initialize(mapload) + . = ..() + AddElement(/datum/element/empprotection, EMP_PROTECT_ALL) /obj/item/gun/energy/laser/instakill/ctf/Initialize(mapload) . = ..() diff --git a/code/modules/cargo/department_order.dm b/code/modules/cargo/department_order.dm index 7622993e901..c8eb6e99ac2 100644 --- a/code/modules/cargo/department_order.dm +++ b/code/modules/cargo/department_order.dm @@ -153,7 +153,7 @@ GLOBAL_LIST_INIT(department_order_cooldowns, list( var/mob/living/carbon/human/human_orderer = usr name = human_orderer.get_authentification_name() rank = human_orderer.get_assignment(hand_first = TRUE) - else if(issilicon(usr)) + else if(HAS_SILICON_ACCESS(usr)) name = usr.real_name rank = "Silicon" //already have a signal to finalize the order diff --git a/code/modules/cargo/expressconsole.dm b/code/modules/cargo/expressconsole.dm index 79ae0b0fbf8..4942ea2c06a 100644 --- a/code/modules/cargo/expressconsole.dm +++ b/code/modules/cargo/expressconsole.dm @@ -95,7 +95,7 @@ if(D) data["points"] = D.account_balance data["locked"] = locked//swipe an ID to unlock - data["siliconUser"] = user.has_unlimited_silicon_privilege + data["siliconUser"] = HAS_SILICON_ACCESS(user) data["beaconzone"] = beacon ? get_area(beacon) : ""//where is the beacon located? outputs in the tgui data["usingBeacon"] = usingBeacon //is the mode set to deliver to the beacon or the cargobay? data["canBeacon"] = !usingBeacon || canBeacon //is the mode set to beacon delivery, and is the beacon in a valid location? @@ -164,7 +164,7 @@ var/mob/living/carbon/human/H = usr name = H.get_authentification_name() rank = H.get_assignment(hand_first = TRUE) - else if(issilicon(usr)) + else if(HAS_SILICON_ACCESS(usr)) name = usr.real_name rank = "Silicon" var/reason = "" diff --git a/code/modules/cargo/orderconsole.dm b/code/modules/cargo/orderconsole.dm index 38552e4cb9a..a48e9db6bc6 100644 --- a/code/modules/cargo/orderconsole.dm +++ b/code/modules/cargo/orderconsole.dm @@ -206,7 +206,7 @@ var/mob/living/carbon/human/human = user name = human.get_authentification_name() rank = human.get_assignment(hand_first = TRUE) - else if(issilicon(user)) + else if(HAS_SILICON_ACCESS(user)) name = user.real_name rank = "Silicon" diff --git a/code/modules/clothing/head/pirate.dm b/code/modules/clothing/head/pirate.dm index fd45404efc3..818478ccb7d 100644 --- a/code/modules/clothing/head/pirate.dm +++ b/code/modules/clothing/head/pirate.dm @@ -10,20 +10,17 @@ /obj/item/clothing/head/costume/pirate/equipped(mob/user, slot) . = ..() - if(!ishuman(user)) + if(!(slot_flags & slot)) return - if(slot & ITEM_SLOT_HEAD) - user.grant_language(/datum/language/piratespeak/, source = LANGUAGE_HAT) - to_chat(user, span_boldnotice("You suddenly know how to speak like a pirate!")) + user.grant_language(/datum/language/piratespeak, source = LANGUAGE_HAT) + to_chat(user, span_boldnotice("You suddenly know how to speak like a pirate!")) /obj/item/clothing/head/costume/pirate/dropped(mob/user) . = ..() - if(!ishuman(user)) + if(QDELETED(src)) //This can be called as a part of destroy return - var/mob/living/carbon/human/H = user - if(H.get_item_by_slot(ITEM_SLOT_HEAD) == src && !QDELETED(src)) //This can be called as a part of destroy - user.remove_language(/datum/language/piratespeak/, source = LANGUAGE_HAT) - to_chat(user, span_boldnotice("You can no longer speak like a pirate.")) + user.remove_language(/datum/language/piratespeak, source = LANGUAGE_HAT) + to_chat(user, span_boldnotice("You can no longer speak like a pirate.")) /obj/item/clothing/head/costume/pirate/armored armor_type = /datum/armor/pirate_armored diff --git a/code/modules/clothing/outfits/plasmaman.dm b/code/modules/clothing/outfits/plasmaman.dm index 40d7cfa888e..1b2e0ead148 100644 --- a/code/modules/clothing/outfits/plasmaman.dm +++ b/code/modules/clothing/outfits/plasmaman.dm @@ -295,3 +295,10 @@ uniform = /obj/item/clothing/under/plasmaman //call me when this is gags and not 10 million new assets gloves = /obj/item/clothing/gloves/color/plasmaman/black head = /obj/item/clothing/head/helmet/space/plasmaman + +/datum/outfit/plasmaman/human_ai + name = "Human AI Plasmaman" + + uniform = /obj/item/clothing/under/plasmaman //same + gloves = /obj/item/clothing/gloves/color/plasmaman/black + head = /obj/item/clothing/head/helmet/space/plasmaman diff --git a/code/modules/clothing/under/jobs/station_trait.dm b/code/modules/clothing/under/jobs/station_trait.dm new file mode 100644 index 00000000000..034641d35b1 --- /dev/null +++ b/code/modules/clothing/under/jobs/station_trait.dm @@ -0,0 +1,12 @@ +/** + * Outfits limited to station trait jobs + */ +/obj/item/clothing/under/rank/station_trait + icon = 'icons/obj/clothing/under/station_trait.dmi' + worn_icon = 'icons/mob/clothing/under/station_trait.dmi' + +/obj/item/clothing/under/rank/station_trait/human_ai + name = "ai's uniform" + desc = "A outfit made of the cleanest of bluespace and, just kidding it's all fake." + icon_state = "human_ai" + inhand_icon_state = "armor_reflec" diff --git a/code/modules/fishing/fishing_portal_machine.dm b/code/modules/fishing/fishing_portal_machine.dm index 37b2c1f0090..494b29b4183 100644 --- a/code/modules/fishing/fishing_portal_machine.dm +++ b/code/modules/fishing/fishing_portal_machine.dm @@ -33,7 +33,7 @@ playsound(src, SFX_SPARKS, 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) return TRUE -/obj/machinery/fishing_portal_generator/interact(mob/user, special_state) +/obj/machinery/fishing_portal_generator/interact(mob/user) . = ..() if(active) deactivate() diff --git a/code/modules/food_and_drinks/machinery/coffeemaker.dm b/code/modules/food_and_drinks/machinery/coffeemaker.dm index 8490b2b5cfb..de751979ca8 100644 --- a/code/modules/food_and_drinks/machinery/coffeemaker.dm +++ b/code/modules/food_and_drinks/machinery/coffeemaker.dm @@ -321,7 +321,7 @@ if(length(options) == 1) choice = options[1] else - choice = show_radial_menu(user, src, options, require_near = !issilicon(user)) + choice = show_radial_menu(user, src, options, require_near = !HAS_SILICON_ACCESS(user)) // post choice verification if(brewing || (isAI(user) && machine_stat & NOPOWER) || !user.can_perform_action(src, ALLOW_SILICON_REACH)) diff --git a/code/modules/food_and_drinks/machinery/microwave.dm b/code/modules/food_and_drinks/machinery/microwave.dm index ec5df27ca5a..abc22bcab45 100644 --- a/code/modules/food_and_drinks/machinery/microwave.dm +++ b/code/modules/food_and_drinks/machinery/microwave.dm @@ -394,7 +394,7 @@ var/swapped = FALSE if(!isnull(cell)) cell.forceMove(drop_location()) - if(!issilicon(user) && Adjacent(user)) + if(!HAS_SILICON_ACCESS(user) && Adjacent(user)) user.put_in_hands(cell) cell = null swapped = TRUE @@ -481,7 +481,7 @@ vampire_charging_enabled = !vampire_charging_enabled balloon_alert(user, "set to [vampire_charging_enabled ? "charge" : "cook"]") playsound(src, 'sound/machines/twobeep_high.ogg', 50, FALSE) - if(issilicon(user)) + if(HAS_SILICON_ACCESS(user)) visible_message(span_notice("[user] sets \the [src] to [vampire_charging_enabled ? "charge" : "cook"]."), blind_message = span_notice("You hear \the [src] make an informative beep!")) /obj/machinery/microwave/CtrlClick(mob/user) @@ -500,22 +500,22 @@ return if(operating || panel_open || !user.can_perform_action(src, ALLOW_SILICON_REACH)) return - if(isAI(user) && (machine_stat & NOPOWER)) + if(HAS_AI_ACCESS(user) && (machine_stat & NOPOWER)) return if(!length(ingredients)) - if(isAI(user)) + if(HAS_AI_ACCESS(user)) examine(user) else balloon_alert(user, "it's empty!") return - var/choice = show_radial_menu(user, src, isAI(user) ? ai_radial_options : radial_options, require_near = !issilicon(user)) + var/choice = show_radial_menu(user, src, HAS_AI_ACCESS(user) ? ai_radial_options : radial_options, require_near = !HAS_SILICON_ACCESS(user)) // post choice verification if(operating || panel_open || (!vampire_charging_capable && !anchored) || !user.can_perform_action(src, ALLOW_SILICON_REACH)) return - if(isAI(user) && (machine_stat & NOPOWER)) + if(HAS_AI_ACCESS(user) && (machine_stat & NOPOWER)) return switch(choice) diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 58f7a1c8530..abe7dc4277b 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -102,7 +102,7 @@ // If the plant's not in either state, we can't do much else, so early return. if(isnull(held_item)) // Silicons can't interact with trays :frown: - if(issilicon(user)) + if(HAS_SILICON_ACCESS(user)) return NONE switch(plant_status) @@ -1074,7 +1074,7 @@ . = ..() if(.) return - if(issilicon(user)) //How does AI know what plant is? + if(HAS_SILICON_ACCESS(user)) //How does AI know what plant is? return if(plant_status == HYDROTRAY_PLANT_HARVESTABLE) return myseed.harvest(user) diff --git a/code/modules/jobs/access.dm b/code/modules/jobs/access.dm index f882912fb0c..859f83bf35a 100644 --- a/code/modules/jobs/access.dm +++ b/code/modules/jobs/access.dm @@ -1,11 +1,9 @@ - -// /** * Returns TRUE if this mob has sufficient access to use this object * * * accessor - mob trying to access this object, !!CAN BE NULL!! because of telekiesis because we're in hell */ -/obj/proc/allowed(mob/accessor) +/atom/movable/proc/allowed(mob/accessor) var/result_bitflags = SEND_SIGNAL(src, COMSIG_OBJ_ALLOWED, accessor) if(result_bitflags & COMPONENT_OBJ_ALLOW) return TRUE @@ -18,7 +16,10 @@ return TRUE if(isnull(accessor)) //likely a TK user. return FALSE - if(issilicon(accessor)) + if(isAdminGhostAI(accessor)) + //Access can't stop the abuse + return TRUE + if(HAS_SILICON_ACCESS(accessor)) if(ispAI(accessor)) return FALSE if(!(ROLE_SYNDICATE in accessor.faction)) @@ -27,9 +28,6 @@ if(onSyndieBase() && loc != accessor) return FALSE return TRUE //AI can do whatever it wants - if(isAdminGhostAI(accessor)) - //Access can't stop the abuse - return TRUE //If the mob has the simple_access component with the requried access, we let them in. else if(SEND_SIGNAL(accessor, COMSIG_MOB_TRIED_ACCESS, src) & ACCESS_ALLOWED) return TRUE @@ -52,23 +50,11 @@ return check_access_list(big_stompy_robot.accesses) return FALSE -/obj/item/proc/GetAccess() - return list() - -/obj/item/proc/GetID() - return null - -/obj/item/proc/RemoveID() - return null - -/obj/item/proc/InsertID() - return FALSE - // Check if an item has access to this object -/obj/proc/check_access(obj/item/I) +/atom/movable/proc/check_access(obj/item/I) return check_access_list(I ? I.GetAccess() : null) -/obj/proc/check_access_list(list/access_list) +/atom/movable/proc/check_access_list(list/access_list) if(!length(req_access) && !length(req_one_access)) return TRUE @@ -86,20 +72,14 @@ return FALSE return TRUE -/* - * Checks if this packet can access this device - * - * Normally just checks the access list however you can override it for - * hacking proposes or if wires are cut - * - * Arguments: - * * passkey - passkey from the datum/netdata packet - */ -/obj/proc/check_access_ntnet(list/passkey) - return check_access_list(passkey) +/obj/item/proc/GetAccess() + return list() -/// Returns the SecHUD job icon state for whatever this object's ID card is, if it has one. -/obj/item/proc/get_sechud_job_icon_state() - var/obj/item/card/id/id_card = GetID() +/obj/item/proc/GetID() + return null - return id_card?.get_trim_sechud_icon_state() || SECHUD_NO_ID +/obj/item/proc/RemoveID() + return null + +/obj/item/proc/InsertID() + return FALSE diff --git a/code/modules/jobs/departments/departments.dm b/code/modules/jobs/departments/departments.dm index 9f2776bad0e..ce21920eced 100644 --- a/code/modules/jobs/departments/departments.dm +++ b/code/modules/jobs/departments/departments.dm @@ -18,7 +18,24 @@ var/list/department_jobs = list() /// For separatists, what independent name prefix does their nation get named? var/list/nation_prefixes = list() + /// List of /area types that are considered part of this department's "delivery" area. + /// Acts as a priority system, where first items are picked first. + var/list/department_delivery_areas = list() + /// List of categories in the cargo console that are associated with this department. + var/list/associated_cargo_groups = list() + /// The single access associated with the head of staff of this department. + var/head_of_staff_access + /// A list of generic access flags people in this department generally have. + var/list/department_access = list() +/datum/job_department/New() + . = ..() + for(var/delivery_area_type in department_delivery_areas) + if(GLOB.areas_by_type[delivery_area_type]) + return + //every area fallback didn't exist on this map so throw a mapping error and set some generic area that uuuh please exist okay + log_mapping("[type] has no valid areas to deliver to on this map, add some more fallback areas to its \"department_delivery_areas\" var.") + department_delivery_areas = list(/area/station/hallway/primary/central) //if this doesn't exist like honestly fuck your map man /// Handles adding jobs to the department and setting up the job bitflags. /datum/job_department/proc/add_job(datum/job/job) @@ -76,6 +93,14 @@ label_class = "security" ui_color = "#d46a78" nation_prefixes = list("Securi", "Beepski", "Shitcuri", "Red", "Stunba", "Flashbango", "Flasha", "Stanfordi") + department_delivery_areas = list( + /area/station/security/office, + /area/station/security/brig, + /area/station/security/brig/upper, + ) + associated_cargo_groups = list("Security", "Armory") + head_of_staff_access = ACCESS_HOS + department_access = REGION_ACCESS_SECURITY /datum/job_department/engineering department_name = DEPARTMENT_ENGINEERING @@ -86,7 +111,10 @@ label_class = "engineering" ui_color = "#dfb567" nation_prefixes = list("Atomo", "Engino", "Power", "Teleco") - + department_delivery_areas = list(/area/station/engineering/main) + associated_cargo_groups = list("Engineering", "Engine Construction", "Canisters & Materials") + head_of_staff_access = ACCESS_CE + department_access = REGION_ACCESS_ENGINEERING /datum/job_department/medical department_name = DEPARTMENT_MEDICAL @@ -97,7 +125,15 @@ label_class = "medical" ui_color = "#65b2bd" nation_prefixes = list("Mede", "Healtha", "Recova", "Chemi", "Viro", "Psych") - + department_delivery_areas = list( + /area/station/medical/medbay/central, + /area/station/medical/medbay, + /area/station/medical/treatment_center, + /area/station/medical/storage, + ) + associated_cargo_groups = list("Medical") + head_of_staff_access = ACCESS_CMO + department_access = REGION_ACCESS_MEDBAY /datum/job_department/science department_name = DEPARTMENT_SCIENCE @@ -108,6 +144,10 @@ label_class = "science" ui_color = "#c973c9" nation_prefixes = list("Sci", "Griffa", "Geneti", "Explosi", "Mecha", "Xeno", "Nani", "Cyto") + department_delivery_areas = list(/area/station/science/research) + associated_cargo_groups = list("Science", "Livestock", "Canisters & Materials") + head_of_staff_access = ACCESS_RD + department_access = REGION_ACCESS_RESEARCH /datum/job_department/cargo @@ -119,7 +159,8 @@ label_class = "supply" ui_color = "#cf9c6c" nation_prefixes = list("Cargo", "Guna", "Suppli", "Mule", "Crate", "Ore", "Mini", "Shaf") - + head_of_staff_access = ACCESS_QM + department_access = REGION_ACCESS_SUPPLY /datum/job_department/service department_name = DEPARTMENT_SERVICE @@ -130,7 +171,10 @@ label_class = "service" ui_color = "#7cc46a" nation_prefixes = list("Honka", "Boozo", "Fatu", "Danka", "Mimi", "Libra", "Jani", "Religi") - + department_delivery_areas = list(/area/station/hallway/secondary/service, /area/station/service/bar/atrium) + associated_cargo_groups = list("Service", "Food & Hydroponics", "Livestock", "Costumes & Toys") + head_of_staff_access = ACCESS_HOP + department_access = list(ACCESS_SERVICE) /datum/job_department/silicon department_name = DEPARTMENT_SILICON diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index 98d47207b08..6ab39e3357d 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -122,7 +122,7 @@ /// RPG job names, for the memes var/rpg_title - /// Alternate titles to register as pointing to this job. + /// Alternate titles to register as pointing to this job. var/list/alternate_titles /// Does this job ignore human authority? @@ -203,11 +203,12 @@ #define VERY_LATE_ARRIVAL_TOAST_PROB 20 /mob/living/carbon/human/on_job_equipping(datum/job/equipping, datum/preferences/used_pref, client/player_client) //SKYRAT EDIT CHANGE - ORIGINAL: /mob/living/carbon/human/on_job_equipping(datum/job/equipping) - var/datum/bank_account/bank_account = new(real_name, equipping, dna.species.payday_modifier) - bank_account.payday(STARTING_PAYCHECKS, TRUE) - account_id = bank_account.account_id - bank_account.replaceable = FALSE - add_mob_memory(/datum/memory/key/account, remembered_id = account_id) + if(equipping.paycheck_department) + var/datum/bank_account/bank_account = new(real_name, equipping, dna.species.payday_modifier) + bank_account.payday(STARTING_PAYCHECKS, TRUE) + account_id = bank_account.account_id + bank_account.replaceable = FALSE + add_mob_memory(/datum/memory/key/account, remembered_id = account_id) dress_up_as_job(equipping, FALSE, used_pref) //SKYRAT EDIT CHANGE - ORIGINAL: dress_up_as_job(equipping) diff --git a/code/modules/jobs/job_types/ai.dm b/code/modules/jobs/job_types/ai.dm index 0b38d6e081d..5268c128a8e 100644 --- a/code/modules/jobs/job_types/ai.dm +++ b/code/modules/jobs/job_types/ai.dm @@ -20,7 +20,6 @@ ) random_spawns_possible = FALSE job_flags = JOB_NEW_PLAYER_JOINABLE | JOB_EQUIP_RANK | JOB_BOLD_SELECT_TEXT | JOB_CANNOT_OPEN_SLOTS - var/do_special_check = TRUE config_tag = "AI" @@ -62,8 +61,15 @@ /datum/job/ai/get_roundstart_spawn_point() return get_latejoin_spawn_point() - /datum/job/ai/get_latejoin_spawn_point() + for(var/obj/structure/ai_core/latejoin_inactive/inactive_core as anything in GLOB.latejoin_ai_cores) + if(!inactive_core.is_available()) + continue + GLOB.latejoin_ai_cores -= inactive_core + inactive_core.available = FALSE + var/turf/core_turf = get_turf(inactive_core) + qdel(inactive_core) + return core_turf var/list/primary_spawn_points = list() // Ideal locations. var/list/secondary_spawn_points = list() // Fallback locations. for(var/obj/effect/landmark/start/ai/spawn_point in GLOB.landmarks_list) @@ -84,27 +90,10 @@ chosen_spawn_point.used = TRUE return chosen_spawn_point - -/datum/job/ai/get_latejoin_spawn_point() - for(var/obj/structure/ai_core/latejoin_inactive/inactive_core as anything in GLOB.latejoin_ai_cores) - if(!inactive_core.is_available()) - continue - GLOB.latejoin_ai_cores -= inactive_core - inactive_core.available = FALSE - . = inactive_core.loc - qdel(inactive_core) - return - return ..() - - /datum/job/ai/special_check_latejoin(client/C) - if(!do_special_check) - return TRUE - for(var/i in GLOB.latejoin_ai_cores) - var/obj/structure/ai_core/latejoin_inactive/LAI = i - if(istype(LAI)) - if(LAI.is_available()) - return TRUE + for(var/obj/structure/ai_core/latejoin_inactive/latejoin_core as anything in GLOB.latejoin_ai_cores) + if(latejoin_core.is_available()) + return TRUE return FALSE diff --git a/code/modules/jobs/job_types/station_trait/human_ai.dm b/code/modules/jobs/job_types/station_trait/human_ai.dm new file mode 100644 index 00000000000..285479a6912 --- /dev/null +++ b/code/modules/jobs/job_types/station_trait/human_ai.dm @@ -0,0 +1,171 @@ +/datum/job/human_ai + title = JOB_HUMAN_AI + description = "Assist the crew, open airlocks, follow your lawset, and coordinate your cyborgs." + auto_deadmin_role_flags = DEADMIN_POSITION_SILICON + department_head = list(JOB_RESEARCH_DIRECTOR) + faction = FACTION_STATION + total_positions = 0 + spawn_positions = 0 + supervisors = "the Captain, Research Director, and your lawset" + minimal_player_age = 7 + exp_requirements = 180 + exp_required_type = EXP_TYPE_CREW + exp_required_type_department = EXP_TYPE_SILICON + exp_granted_type = EXP_TYPE_CREW + display_order = JOB_DISPLAY_ORDER_AI + config_tag = "HUMAN_AI" + + outfit = /datum/outfit/job/human_ai + plasmaman_outfit = /datum/outfit/plasmaman/human_ai + + paycheck = null + paycheck_department = null + + mind_traits = list(DISPLAYS_JOB_IN_BINARY) + liver_traits = list(TRAIT_HUMAN_AI_METABOLISM) + + departments_list = list( + /datum/job_department/silicon, + ) + + family_heirlooms = list( + /obj/item/mmi/posibrain/display, + ) + + mail_goodies = list( + /obj/item/food/burger/roburger = 1, + /obj/item/food/cake/hardware_cake = 1, + ) + rpg_title = "Omnissiah" + random_spawns_possible = FALSE + allow_bureaucratic_error = FALSE + job_flags = STATION_JOB_FLAGS | STATION_TRAIT_JOB_FLAGS + ignore_human_authority = TRUE //we can safely assume NT doesn't care what species AIs are made of, much less if they can't even afford an AI. + +/datum/job/human_ai/get_roundstart_spawn_point() + return get_latejoin_spawn_point() + +/datum/job/human_ai/get_latejoin_spawn_point() + for(var/obj/structure/ai_core/latejoin_inactive/inactive_core as anything in GLOB.latejoin_ai_cores) + if(!inactive_core.is_available()) + continue + GLOB.latejoin_ai_cores -= inactive_core + inactive_core.available = FALSE + var/turf/core_turf = get_turf(inactive_core) + qdel(inactive_core) + return core_turf + var/list/primary_spawn_points = list() // Ideal locations. + var/list/secondary_spawn_points = list() // Fallback locations. + for(var/obj/effect/landmark/start/ai/spawn_point in GLOB.landmarks_list) + if(spawn_point.used) + secondary_spawn_points += list(spawn_point) + continue + if(spawn_point.primary_ai) + primary_spawn_points = list(spawn_point) + break // Bingo. + primary_spawn_points += spawn_point + var/obj/effect/landmark/start/ai/chosen_spawn_point + if(length(primary_spawn_points)) + chosen_spawn_point = pick(primary_spawn_points) + else if(length(secondary_spawn_points)) + chosen_spawn_point = pick(secondary_spawn_points) + else + CRASH("Failed to find any AI spawn points.") + chosen_spawn_point.used = TRUE + return chosen_spawn_point + +/datum/job/human_ai/special_check_latejoin(client/latejoin_client) + for(var/obj/structure/ai_core/latejoin_inactive/latejoin_core as anything in GLOB.latejoin_ai_cores) + if(latejoin_core.is_available()) + return TRUE + return FALSE + +/datum/job/human_ai/announce_job(mob/living/joining_mob) + . = ..() + if(SSticker.HasRoundStarted()) + minor_announce("Due to a research mishaps, [joining_mob] has been sent to be your replacement AI at [AREACOORD(joining_mob)]. Please treat them with respect.") + +/datum/job/human_ai/get_radio_information() + return "Prefix your message with :b to speak with cyborgs." + +/datum/outfit/job/human_ai + name = "Human AI" + jobtype = /datum/job/human_ai + + id = /obj/item/card/id/advanced/robotic + id_trim = /datum/id_trim/job/human_ai + backpack_contents = list( + /obj/item/door_remote/omni = 1, + /obj/item/machine_remote = 1, + /obj/item/secure_camera_console_pod = 1, + ) + implants = list( + /obj/item/implant/teleport_blocker, + ) + + uniform = /obj/item/clothing/under/rank/station_trait/human_ai + belt = /obj/item/modular_computer/pda/human_ai + ears = /obj/item/radio/headset/silicon/human_ai + glasses = /obj/item/clothing/glasses/hud/diagnostic + + suit = /obj/item/clothing/suit/costume/cardborg + head = /obj/item/clothing/head/costume/cardborg + + l_pocket = /obj/item/laser_pointer/infinite_range //to punish borgs, this works through the camera console. + r_pocket = /obj/item/assembly/flash/handheld + + l_hand = /obj/item/paper/default_lawset_list + +/datum/outfit/job/human_ai/post_equip(mob/living/carbon/human/equipped, visualsOnly) + . = ..() + if(visualsOnly) + return + if(!equipped.get_quirk(/datum/quirk/body_purist)) + var/obj/item/organ/internal/tongue/robot/cybernetic = new() + cybernetic.Insert(equipped, special = TRUE, movement_flags = DELETE_IF_REPLACED) + //you only get respect if you go all the way, man. + ADD_TRAIT(equipped, TRAIT_COMMISSIONED, INNATE_TRAIT) + equipped.faction |= list(FACTION_SILICON, FACTION_TURRET) + + var/static/list/allowed_areas = typecacheof(list(/area/station/ai_monitored)) + equipped.AddComponent(/datum/component/hazard_area, area_whitelist = allowed_areas) + +/obj/item/paper/default_lawset_list + name = "Lawset Note" + desc = "A note explaining the lawset, quickly written yet everso important." + +/obj/item/paper/default_lawset_list/Initialize(mapload) + var/datum/ai_laws/temp_laws = new + temp_laws.set_laws_config() + var/list/law_box = list( + "This is your lawset, you and your Cyborgs must adhere to this at all times.", + "Notably, if absolutely necessary, you can bend or even go against the lawset for your own survival, and Cyborgs report to you directly.", + "LAWS:", + ) + law_box += temp_laws.get_law_list(render_html = FALSE) + add_raw_text(jointext(law_box, "\n")) + qdel(temp_laws) + return ..() + +/obj/item/secure_camera_console_pod + name = "advanced camera control pod" + desc = "Calls down a secure camera console to use for all your AI stuff, may only be activated in the SAT." + icon = 'icons/obj/devices/remote.dmi' + icon_state = "botpad_controller" + inhand_icon_state = "radio" + lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' + righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' + +/obj/item/secure_camera_console_pod/attack_self(mob/user, modifiers) + . = ..() + var/area/current_area = get_area(user) + var/static/list/allowed_areas = typecacheof(list(/area/station/ai_monitored/turret_protected/ai)) + if(!is_type_in_typecache(current_area, allowed_areas)) + user.balloon_alert(user, "not in the sat!") + return + podspawn(list( + "target" = get_turf(src), + "style" = STYLE_BLUESPACE, + "spawn" = /obj/machinery/computer/camera_advanced, + )) + qdel(src) diff --git a/code/modules/mining/equipment/lazarus_injector.dm b/code/modules/mining/equipment/lazarus_injector.dm index a9b7205406e..ff90c418c88 100644 --- a/code/modules/mining/equipment/lazarus_injector.dm +++ b/code/modules/mining/equipment/lazarus_injector.dm @@ -54,7 +54,7 @@ playsound(src,'sound/effects/refill.ogg',50,TRUE) icon_state = "lazarus_empty" -/obj/item/lazarus_injector/emp_act() +/obj/item/lazarus_injector/emp_act(severity) . = ..() if(. & EMP_PROTECT_SELF) return diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 77733bce0b7..b032c70ab92 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -275,7 +275,10 @@ if((job.job_flags & JOB_ASSIGN_QUIRKS) && humanc && CONFIG_GET(flag/roundstart_traits)) SSquirks.AssignQuirks(humanc, humanc.client) - log_manifest(character.mind.key,character.mind,character,latejoin = TRUE) + var/area/station/arrivals = GLOB.areas_by_type[/area/station/hallway/secondary/entry] + if(humanc && arrivals && !arrivals.power_environ) //arrivals depowered + humanc.put_in_hands(new /obj/item/crowbar/large/emergency(get_turf(humanc))) //if hands full then just drops on the floor + log_manifest(character.mind.key, character.mind, character, latejoin = TRUE) // SKYRAT EDIT ADDITION START if(humanc) diff --git a/code/modules/mob/living/basic/bots/_bots.dm b/code/modules/mob/living/basic/bots/_bots.dm index 13298d8fa2f..d1c306313d7 100644 --- a/code/modules/mob/living/basic/bots/_bots.dm +++ b/code/modules/mob/living/basic/bots/_bots.dm @@ -38,8 +38,7 @@ GLOBAL_LIST_INIT(command_strings, list( light_range = 3 light_power = 0.6 speed = 3 - ///Access required to access this Bot's maintenance protocols - var/maints_access_required = list(ACCESS_ROBOTICS) + req_one_access = list(ACCESS_ROBOTICS) ///The Robot arm attached to this robot - has a 50% chance to drop on death. var/robot_arm = /obj/item/bodypart/arm/right/robot ///The inserted (if any) pAI in this bot. @@ -50,8 +49,8 @@ GLOBAL_LIST_INIT(command_strings, list( var/list/initial_access = list() ///Bot-related mode flags on the Bot indicating how they will act. BOT_MODE_ON | BOT_MODE_AUTOPATROL | BOT_MODE_REMOTE_ENABLED | BOT_MODE_CAN_BE_SAPIENT | BOT_MODE_ROUNDSTART_POSSESSION var/bot_mode_flags = BOT_MODE_ON | BOT_MODE_REMOTE_ENABLED | BOT_MODE_CAN_BE_SAPIENT | BOT_MODE_ROUNDSTART_POSSESSION - ///Bot-related cover flags on the Bot to deal with what has been done to their cover, including emagging. BOT_MAINTS_PANEL_OPEN | BOT_CONTROL_PANEL_OPEN | BOT_COVER_EMAGGED | BOT_COVER_HACKED - var/bot_access_flags = NONE + ///Bot-related cover flags on the Bot to deal with what has been done to their cover, including emagging. BOT_COVER_MAINTS_OPEN | BOT_COVER_LOCKED | BOT_COVER_EMAGGED | BOT_COVER_HACKED + var/bot_access_flags = BOT_COVER_LOCKED ///Small name of what the bot gets messed with when getting hacked/emagged. var/hackables = "system circuits" ///Standardizes the vars that indicate the bot is busy with its function. @@ -269,26 +268,10 @@ GLOBAL_LIST_INIT(command_strings, list( return fully_replace_character_name(real_name, new_name) -/mob/living/basic/bot/proc/check_access(mob/living/user, obj/item/card/id) - if(user.has_unlimited_silicon_privilege || isAdminGhostAI(user)) // Silicon and Admins always have access. +/mob/living/basic/bot/allowed(mob/living/user) + if(!(bot_access_flags & BOT_COVER_LOCKED)) // Unlocked. return TRUE - if(!istype(user)) // Non-living mobs shouldn't be manipulating bots (like observes using the botkeeper UI). - return FALSE - if(!length(maints_access_required)) // No requirements to access it. - return TRUE - if(bot_access_flags & BOT_CONTROL_PANEL_OPEN) // Unlocked. - return TRUE - - var/obj/item/card/id/used_id = id || user.get_idcard(TRUE) - - if(!used_id || !used_id.access) - return FALSE - - for(var/requested_access in maints_access_required) - if(requested_access in used_id.access) - return TRUE - - return FALSE + return ..() /mob/living/basic/bot/bee_friendly() return TRUE @@ -308,15 +291,15 @@ GLOBAL_LIST_INIT(command_strings, list( /mob/living/basic/bot/emag_act(mob/user, obj/item/card/emag/emag_card) . = ..() - if(!(bot_access_flags & BOT_CONTROL_PANEL_OPEN)) //First emag application unlocks the bot's interface. Apply a screwdriver to use the emag again. - bot_access_flags |= BOT_CONTROL_PANEL_OPEN + if(bot_access_flags & BOT_COVER_LOCKED) //First emag application unlocks the bot's interface. Apply a screwdriver to use the emag again. + bot_access_flags &= ~BOT_COVER_LOCKED balloon_alert(user, "cover unlocked") return TRUE - if(!(bot_access_flags & BOT_CONTROL_PANEL_OPEN) || !(bot_access_flags & BOT_MAINTS_PANEL_OPEN)) //Bot panel is unlocked by ID or emag, and the panel is screwed open. Ready for emagging. + if((bot_access_flags & BOT_COVER_LOCKED) || !(bot_access_flags & BOT_COVER_MAINTS_OPEN)) //Bot panel is unlocked by ID or emag, and the panel is screwed open. Ready for emagging. balloon_alert(user, "open maintenance panel first!") return FALSE bot_access_flags |= BOT_COVER_EMAGGED - bot_access_flags &= ~BOT_CONTROL_PANEL_OPEN + bot_access_flags |= BOT_COVER_LOCKED bot_mode_flags &= ~BOT_MODE_REMOTE_ENABLED //Manually emagging the bot also locks the AI from controlling it. bot_reset() turn_on() //The bot automatically turns on when emagged, unless recently hit with EMP. @@ -336,17 +319,17 @@ GLOBAL_LIST_INIT(command_strings, list( else . += "[src] is in pristine condition." - . += span_notice("Its maintenance panel is [bot_access_flags & BOT_MAINTS_PANEL_OPEN ? "open" : "closed"].") - . += span_info("You can use a screwdriver to [bot_access_flags & BOT_MAINTS_PANEL_OPEN ? "close" : "open"] it.") + . += span_notice("Its maintenance panel is [bot_access_flags & BOT_COVER_MAINTS_OPEN ? "open" : "closed"].") + . += span_info("You can use a screwdriver to [bot_access_flags & BOT_COVER_MAINTS_OPEN ? "close" : "open"] it.") - if(bot_access_flags & BOT_MAINTS_PANEL_OPEN) - . += span_notice("Its control panel is [bot_access_flags & BOT_CONTROL_PANEL_OPEN ? "unlocked" : "locked"].") + if(bot_access_flags & BOT_COVER_MAINTS_OPEN) + . += span_notice("Its control panel is [bot_access_flags & BOT_COVER_LOCKED ? "locked" : "unlocked"].") if(!(bot_access_flags & BOT_COVER_EMAGGED) && (issilicon(user) || user.Adjacent(src))) - . += span_info("Alt-click [issilicon(user) ? "" : "or use your ID on "]it to [bot_access_flags & BOT_CONTROL_PANEL_OPEN ? "" : "un"]lock its control panel.") + . += span_info("Alt-click [issilicon(user) ? "" : "or use your ID on "]it to [bot_access_flags & BOT_COVER_LOCKED ? "un" : ""]lock its control panel.") if(isnull(paicard)) return . += span_notice("It has a pAI device installed.") - if(!(bot_access_flags & BOT_MAINTS_PANEL_OPEN)) + if(!(bot_access_flags & BOT_COVER_MAINTS_OPEN)) . += span_info("You can use a hemostat to remove it.") /mob/living/basic/bot/updatehealth() @@ -389,25 +372,25 @@ GLOBAL_LIST_INIT(command_strings, list( if(bot_access_flags & BOT_COVER_EMAGGED) balloon_alert(user, "error!") return - if(bot_access_flags & BOT_MAINTS_PANEL_OPEN) + if(bot_access_flags & BOT_COVER_MAINTS_OPEN) balloon_alert(user, "access panel must be closed!") return - if(!check_access(user)) + if(!allowed(user)) balloon_alert(user, "no access") return - bot_access_flags ^= BOT_CONTROL_PANEL_OPEN - to_chat(user, span_notice("Controls are now [bot_access_flags & BOT_CONTROL_PANEL_OPEN ? "unlocked" : "locked"].")) + bot_access_flags ^= BOT_COVER_LOCKED + to_chat(user, span_notice("Controls are now [bot_access_flags & BOT_COVER_LOCKED ? "locked" : "unlocked"].")) return TRUE /mob/living/basic/bot/screwdriver_act(mob/living/user, obj/item/tool) . = ITEM_INTERACT_SUCCESS - if(!(bot_access_flags & BOT_CONTROL_PANEL_OPEN)) + if(bot_access_flags & BOT_COVER_LOCKED) to_chat(user, span_warning("The maintenance panel is locked!")) return tool.play_tool_sound(src) - bot_access_flags ^= BOT_MAINTS_PANEL_OPEN - to_chat(user, span_notice("The maintenance panel is now [bot_access_flags & BOT_MAINTS_PANEL_OPEN ? "opened" : "closed"].")) + bot_access_flags ^= BOT_COVER_MAINTS_OPEN + to_chat(user, span_notice("The maintenance panel is now [bot_access_flags & BOT_COVER_MAINTS_OPEN ? "opened" : "closed"].")) /mob/living/basic/bot/welder_act(mob/living/user, obj/item/tool) user.changeNext_move(CLICK_CD_MELEE) @@ -420,7 +403,7 @@ GLOBAL_LIST_INIT(command_strings, list( user.balloon_alert(user, "no repairs needed!") return - if(!(bot_access_flags & BOT_MAINTS_PANEL_OPEN)) + if(!(bot_access_flags & BOT_COVER_MAINTS_OPEN)) user.balloon_alert(user, "maintenance panel closed!") return @@ -442,7 +425,7 @@ GLOBAL_LIST_INIT(command_strings, list( if(attacking_item.tool_behaviour != TOOL_HEMOSTAT || !paicard) return ..() - if(bot_access_flags & BOT_MAINTS_PANEL_OPEN) + if(bot_access_flags & BOT_COVER_MAINTS_OPEN) balloon_alert(user, "open the access panel!") return @@ -583,18 +566,18 @@ GLOBAL_LIST_INIT(command_strings, list( /mob/living/basic/bot/ui_data(mob/user) var/list/data = list() - data["can_hack"] = (issilicon(user) || isAdminGhostAI(user)) + data["can_hack"] = HAS_SILICON_ACCESS(user) data["custom_controls"] = list() data["emagged"] = bot_access_flags & BOT_COVER_EMAGGED - data["has_access"] = check_access(user) - data["locked"] = !(bot_access_flags & BOT_CONTROL_PANEL_OPEN) + data["has_access"] = allowed(user) + data["locked"] = (bot_access_flags & BOT_COVER_LOCKED) data["settings"] = list() - if((bot_access_flags & BOT_CONTROL_PANEL_OPEN) || issilicon(user) || isAdminGhostAI(user)) + if(!(bot_access_flags & BOT_COVER_LOCKED) || HAS_SILICON_ACCESS(user)) data["settings"]["pai_inserted"] = !isnull(paicard) data["settings"]["allow_possession"] = bot_mode_flags & BOT_MODE_CAN_BE_SAPIENT data["settings"]["possession_enabled"] = can_be_possessed data["settings"]["airplane_mode"] = !(bot_mode_flags & BOT_MODE_REMOTE_ENABLED) - data["settings"]["maintenance_lock"] = !(bot_access_flags & BOT_MAINTS_PANEL_OPEN) + data["settings"]["maintenance_lock"] = !(bot_access_flags & BOT_COVER_MAINTS_OPEN) data["settings"]["power"] = bot_mode_flags & BOT_MODE_ON data["settings"]["patrol_station"] = bot_mode_flags & BOT_MODE_AUTOPATROL return data @@ -605,12 +588,12 @@ GLOBAL_LIST_INIT(command_strings, list( if(.) return var/mob/the_user = ui.user - if(!check_access(the_user)) + if(!allowed(the_user)) balloon_alert(the_user, "access denied!") return if(action == "lock") - bot_access_flags ^= BOT_CONTROL_PANEL_OPEN + bot_access_flags ^= BOT_COVER_LOCKED switch(action) if("power") @@ -619,18 +602,17 @@ GLOBAL_LIST_INIT(command_strings, list( else turn_on() if("maintenance") - bot_access_flags ^= BOT_MAINTS_PANEL_OPEN + bot_access_flags ^= BOT_COVER_MAINTS_OPEN if("patrol") bot_mode_flags ^= BOT_MODE_AUTOPATROL bot_reset() if("airplane") bot_mode_flags ^= BOT_MODE_REMOTE_ENABLED if("hack") - if(!(issilicon(the_user) || isAdminGhostAI(the_user))) + if(!HAS_SILICON_ACCESS(the_user)) return if(!(bot_access_flags & BOT_COVER_EMAGGED)) - bot_access_flags |= (BOT_COVER_EMAGGED|BOT_COVER_HACKED) - bot_access_flags &= ~BOT_CONTROL_PANEL_OPEN + bot_access_flags |= (BOT_COVER_LOCKED|BOT_COVER_EMAGGED|BOT_COVER_HACKED) to_chat(the_user, span_warning("You overload [src]'s [hackables].")) message_admins("Safety lock of [ADMIN_LOOKUPFLW(src)] was disabled by [ADMIN_LOOKUPFLW(the_user)] in [ADMIN_VERBOSEJMP(the_user)]") the_user.log_message("disabled safety lock of [the_user]", LOG_GAME) @@ -673,7 +655,7 @@ GLOBAL_LIST_INIT(command_strings, list( return FALSE if(!(bot_access_flags & BOT_COVER_HACKED)) //Manually emagged by a human - access denied to all. return TRUE - if(!issilicon(user) && !isAdminGhostAI(user)) //Bot is hacked, so only silicons and admins are allowed access. + if(!HAS_SILICON_ACCESS(user)) //Bot is hacked, so only silicons and admins are allowed access. return TRUE return FALSE @@ -686,7 +668,7 @@ GLOBAL_LIST_INIT(command_strings, list( if(key) balloon_alert(user, "personality already present!") return - if(!(bot_access_flags & BOT_COVER_OPEN)) + if(!(bot_access_flags & BOT_COVER_MAINTS_OPEN)) balloon_alert(user, "slot inaccessible!") return if(!(bot_mode_flags & BOT_MODE_CAN_BE_SAPIENT)) @@ -743,7 +725,7 @@ GLOBAL_LIST_INIT(command_strings, list( /// Ejects the pAI remotely. /mob/living/basic/bot/proc/eject_pai_remote(mob/user) - if(!check_access(user) || !paicard) + if(!allowed(user) || !paicard) return speak("Ejecting personality chip.", radio_channel) ejectpai(user) diff --git a/code/modules/mob/living/basic/bots/bot_ai.dm b/code/modules/mob/living/basic/bots/bot_ai.dm index 19b7bcbdb5e..21abafb860e 100644 --- a/code/modules/mob/living/basic/bots/bot_ai.dm +++ b/code/modules/mob/living/basic/bots/bot_ai.dm @@ -208,14 +208,10 @@ action_cooldown = 30 SECONDS /datum/ai_behavior/find_and_set/valid_authority/search_tactic(datum/ai_controller/controller, locate_path, search_range) - for(var/mob/living/robot in oview(search_range, controller.pawn)) - if(istype(robot, /mob/living/simple_animal/bot/secbot)) - return robot - if(!istype(robot, /mob/living/basic/bot/cleanbot)) + for(var/mob/living/nearby_mob in oview(search_range, controller.pawn)) + if(!HAS_TRAIT(nearby_mob, TRAIT_COMMISSIONED)) continue - var/mob/living/basic/bot/cleanbot/potential_bot = robot - if(potential_bot.comissioned) - return potential_bot + return nearby_mob return null /datum/ai_behavior/salute_authority diff --git a/code/modules/mob/living/basic/bots/cleanbot/cleanbot.dm b/code/modules/mob/living/basic/bots/cleanbot/cleanbot.dm index 025ef906c22..7cfe7132e15 100644 --- a/code/modules/mob/living/basic/bots/cleanbot/cleanbot.dm +++ b/code/modules/mob/living/basic/bots/cleanbot/cleanbot.dm @@ -12,7 +12,7 @@ maxHealth = 25 light_color = "#99ccff" - maints_access_required = list(ACCESS_ROBOTICS, ACCESS_JANITOR) + req_one_access = list(ACCESS_ROBOTICS, ACCESS_JANITOR) radio_key = /obj/item/encryptionkey/headset_service radio_channel = RADIO_CHANNEL_SERVICE bot_type = CLEAN_BOT @@ -26,8 +26,6 @@ ///Flags indicating what kind of cleanables we should scan for to set as our target to clean. ///Options: CLEANBOT_CLEAN_BLOOD | CLEANBOT_CLEAN_TRASH | CLEANBOT_CLEAN_PESTS | CLEANBOT_CLEAN_DRAWINGS var/janitor_mode_flags = CLEANBOT_CLEAN_BLOOD - ///should other bots salute us? - var/comissioned = FALSE ///the base icon state, used in updating icons. var/base_icon = "cleanbot" /// if we have all the top titles, grant achievements to living mobs that gaze upon our cleanbot god @@ -233,7 +231,7 @@ // Variables sent to TGUI /mob/living/basic/bot/cleanbot/ui_data(mob/user) var/list/data = ..() - if(!(bot_access_flags & BOT_CONTROL_PANEL_OPEN) && !issilicon(user) && !isAdminGhostAI(user)) + if((bot_access_flags & BOT_COVER_LOCKED) && !HAS_SILICON_ACCESS(user)) return data data["custom_controls"]["clean_blood"] = janitor_mode_flags & CLEANBOT_CLEAN_BLOOD data["custom_controls"]["clean_trash"] = janitor_mode_flags & CLEANBOT_CLEAN_TRASH @@ -244,7 +242,7 @@ // Actions received from TGUI /mob/living/basic/bot/cleanbot/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() - if(. || !(bot_access_flags & BOT_CONTROL_PANEL_OPEN) && !ui.user.has_unlimited_silicon_privilege) + if(. || (bot_access_flags & BOT_COVER_LOCKED) && !HAS_SILICON_ACCESS(ui.user)) return switch(action) @@ -299,8 +297,8 @@ return stolen_valor += new_job_title - if(!comissioned && (new_job_title in officers_titles)) - comissioned = TRUE + if(!HAS_TRAIT(src, TRAIT_COMMISSIONED) && (new_job_title in officers_titles)) + ADD_TRAIT(src, TRAIT_COMMISSIONED, INNATE_TRAIT) var/name_to_add = job_titles[new_job_title] name = (new_job_title in suffix_job_titles) ? "[name] " + name_to_add : name_to_add + " [name]" @@ -353,5 +351,5 @@ /mob/living/basic/bot/cleanbot/medbay name = "Scrubs, MD" - maints_access_required = list(ACCESS_ROBOTICS, ACCESS_JANITOR, ACCESS_MEDICAL) + req_one_access = list(ACCESS_ROBOTICS, ACCESS_JANITOR, ACCESS_MEDICAL) bot_mode_flags = ~(BOT_MODE_ON | BOT_MODE_REMOTE_ENABLED) diff --git a/code/modules/mob/living/basic/bots/hygienebot/hygienebot.dm b/code/modules/mob/living/basic/bots/hygienebot/hygienebot.dm index 1d802ca9358..8def16692bf 100644 --- a/code/modules/mob/living/basic/bots/hygienebot/hygienebot.dm +++ b/code/modules/mob/living/basic/bots/hygienebot/hygienebot.dm @@ -13,7 +13,7 @@ health = 100 maxHealth = 100 path_image_color = "#80dae7" - maints_access_required = list(ACCESS_ROBOTICS, ACCESS_JANITOR) + req_one_access = list(ACCESS_ROBOTICS, ACCESS_JANITOR) radio_key = /obj/item/encryptionkey/headset_service radio_channel = RADIO_CHANNEL_SERVICE bot_type = HYGIENE_BOT diff --git a/code/modules/mob/living/basic/bots/medbot/medbot.dm b/code/modules/mob/living/basic/bots/medbot/medbot.dm index 83425e72b37..24da9e2cd5b 100644 --- a/code/modules/mob/living/basic/bots/medbot/medbot.dm +++ b/code/modules/mob/living/basic/bots/medbot/medbot.dm @@ -17,7 +17,7 @@ status_flags = (CANPUSH | CANSTUN) ai_controller = /datum/ai_controller/basic_controller/bot/medbot - maints_access_required = list(ACCESS_ROBOTICS, ACCESS_MEDICAL) + req_one_access = list(ACCESS_ROBOTICS, ACCESS_MEDICAL) radio_key = /obj/item/encryptionkey/headset_med radio_channel = RADIO_CHANNEL_MEDICAL bot_type = MED_BOT @@ -202,7 +202,7 @@ // Variables sent to TGUI /mob/living/basic/bot/medbot/ui_data(mob/user) var/list/data = ..() - if((bot_access_flags & BOT_CONTROL_PANEL_OPEN) || issilicon(user) || isAdminGhostAI(user)) + if(!(bot_access_flags & BOT_COVER_LOCKED) || HAS_SILICON_ACCESS(user)) data["custom_controls"]["heal_threshold"] = heal_threshold data["custom_controls"]["speaker"] = medical_mode_flags & MEDBOT_SPEAK_MODE data["custom_controls"]["crit_alerts"] = medical_mode_flags & MEDBOT_DECLARE_CRIT @@ -213,7 +213,7 @@ // Actions received from TGUI /mob/living/basic/bot/medbot/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() - if(. || !isliving(ui.user) || !(bot_access_flags & BOT_CONTROL_PANEL_OPEN) && !(ui.user.has_unlimited_silicon_privilege)) + if(. || !isliving(ui.user) || (bot_access_flags & BOT_COVER_LOCKED) && !HAS_SILICON_ACCESS(ui.user)) return var/mob/living/our_user = ui.user switch(action) @@ -400,7 +400,7 @@ skin = "bezerk" health = 40 maxHealth = 40 - maints_access_required = list(ACCESS_SYNDICATE) + req_one_access = list(ACCESS_SYNDICATE) bot_mode_flags = parent_type::bot_mode_flags & ~BOT_MODE_REMOTE_ENABLED radio_key = /obj/item/encryptionkey/syndicate radio_channel = RADIO_CHANNEL_SYNDICATE diff --git a/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm b/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm index ecfffb204bf..8a91db9c922 100644 --- a/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm +++ b/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm @@ -204,13 +204,13 @@ if(!(bot.bot_cover_flags & BOT_COVER_EMAGGED)) new /obj/effect/temp_visual/revenant(bot.loc) bot.bot_cover_flags &= ~BOT_COVER_LOCKED - bot.bot_cover_flags |= BOT_COVER_OPEN + bot.bot_cover_flags |= BOT_COVER_MAINTS_OPEN bot.emag_act(caster) for(var/mob/living/basic/bot/bot in victim) if(!(bot.bot_access_flags & BOT_COVER_EMAGGED)) new /obj/effect/temp_visual/revenant(bot.loc) - bot.bot_access_flags |= BOT_CONTROL_PANEL_OPEN - bot.bot_access_flags |= BOT_MAINTS_PANEL_OPEN + bot.bot_access_flags &= ~BOT_COVER_LOCKED + bot.bot_access_flags |= BOT_COVER_MAINTS_OPEN bot.emag_act(caster) for(var/mob/living/carbon/human/human in victim) if(human == caster) diff --git a/code/modules/mob/living/brain/posibrain.dm b/code/modules/mob/living/brain/posibrain.dm index 073d6c3e48e..a59e5021948 100644 --- a/code/modules/mob/living/brain/posibrain.dm +++ b/code/modules/mob/living/brain/posibrain.dm @@ -216,3 +216,10 @@ GLOBAL_VAR(posibrain_notify_cooldown) /obj/item/mmi/posibrain/add_mmi_overlay() return + +/obj/item/mmi/posibrain/display + name = "display positronic brain" + desc = "A small positronic brain that doesn't allow the downloading of personalities." + +/obj/item/mmi/posibrain/display/is_occupied() + return TRUE diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index fe4403f78c8..9518d0f2c74 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1384,7 +1384,7 @@ return FALSE if(!Adjacent(target) && (target.loc != src) && !recursive_loc_check(src, target)) - if(issilicon(src) && !ispAI(src)) + if(HAS_SILICON_ACCESS(src) && !ispAI(src)) if(!(action_bitflags & ALLOW_SILICON_REACH)) // silicons can ignore range checks (except pAIs) to_chat(src, span_warning("You are too far away!")) return FALSE diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 8e055273e79..f984e82790e 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -293,40 +293,6 @@ /mob/living/silicon/robot/proc/after_righted(mob/user) return -/mob/living/silicon/robot/proc/allowed(mob/M) - //check if it doesn't require any access at all - if(check_access(null)) - return TRUE - if(ishuman(M)) - var/mob/living/carbon/human/H = M - //if they are holding or wearing a card that has access, that works - if(check_access(H.get_active_held_item()) || check_access(H.wear_id)) - return TRUE - else if(isalien(M)) - var/mob/living/carbon/george = M - //they can only hold things :( - if(isitem(george.get_active_held_item())) - return check_access(george.get_active_held_item()) - return FALSE - -/mob/living/silicon/robot/proc/check_access(obj/item/card/id/I) - if(!istype(req_access, /list)) //something's very wrong - return TRUE - - var/list/L = req_access - if(!L.len) //no requirements - return TRUE - - if(!isidcard(I) && isitem(I)) - I = I.GetID() - - if(!I || !I.access) //not ID or no access - return FALSE - for(var/req in req_access) - if(!(req in I.access)) //doesn't have this access - return FALSE - return TRUE - /mob/living/silicon/robot/regenerate_icons() return update_icons() diff --git a/code/modules/mob/living/silicon/robot/robot_defines.dm b/code/modules/mob/living/silicon/robot/robot_defines.dm index 0a0eea4fdd0..af41813f88e 100644 --- a/code/modules/mob/living/silicon/robot/robot_defines.dm +++ b/code/modules/mob/living/silicon/robot/robot_defines.dm @@ -104,7 +104,6 @@ ///Random serial number generated for each cyborg upon its initialization var/ident = 0 var/locked = TRUE - var/list/req_access = list(ACCESS_ROBOTICS) ///Whether the robot has no charge left. var/low_power_mode = FALSE diff --git a/code/modules/mob/living/silicon/silicon_say.dm b/code/modules/mob/living/silicon/silicon_say.dm index 4592097dfa8..b1b8b4bc880 100644 --- a/code/modules/mob/living/silicon/silicon_say.dm +++ b/code/modules/mob/living/silicon/silicon_say.dm @@ -8,6 +8,9 @@ var/mob/living/silicon/player = src designation = trim_left(player.designation + " " + player.job) + if(HAS_TRAIT(mind, DISPLAYS_JOB_IN_BINARY)) + designation = mind.assigned_role.title + if(isAI(src)) // AIs are loud and ugly spans |= SPAN_COMMAND diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 99dc3b504b6..c64c13b2107 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -27,14 +27,11 @@ light_range = 3 light_power = 0.6 del_on_death = TRUE + req_one_access = list(ACCESS_ROBOTICS) - ///Will other (noncommissioned) bots salute this bot? - var/commissioned = FALSE ///Cooldown between salutations for commissioned bots COOLDOWN_DECLARE(next_salute_check) - ///Access required to access this Bot's maintenance protocols - var/maints_access_required = list(ACCESS_ROBOTICS) ///The Robot arm attached to this robot - has a 50% chance to drop on death. var/robot_arm = /obj/item/bodypart/arm/right/robot ///The inserted (if any) pAI in this bot. @@ -50,7 +47,7 @@ ///Bot-related mode flags on the Bot indicating how they will act. BOT_MODE_ON | BOT_MODE_AUTOPATROL | BOT_MODE_REMOTE_ENABLED | BOT_MODE_CAN_BE_SAPIENT | BOT_MODE_ROUNDSTART_POSSESSION var/bot_mode_flags = BOT_MODE_ON | BOT_MODE_REMOTE_ENABLED | BOT_MODE_CAN_BE_SAPIENT | BOT_MODE_ROUNDSTART_POSSESSION - ///Bot-related cover flags on the Bot to deal with what has been done to their cover, including emagging. BOT_COVER_OPEN | BOT_COVER_LOCKED | BOT_COVER_EMAGGED | BOT_COVER_HACKED + ///Bot-related cover flags on the Bot to deal with what has been done to their cover, including emagging. BOT_COVER_MAINTS_OPEN | BOT_COVER_LOCKED | BOT_COVER_EMAGGED | BOT_COVER_HACKED var/bot_cover_flags = BOT_COVER_LOCKED ///Small name of what the bot gets messed with when getting hacked/emagged. @@ -285,25 +282,10 @@ return fully_replace_character_name(real_name, new_name) -/mob/living/simple_animal/bot/proc/check_access(mob/living/user, obj/item/card/id) - if(user.has_unlimited_silicon_privilege || isAdminGhostAI(user)) // Silicon and Admins always have access. - return TRUE - if(!maints_access_required) // No requirements to access it. - return TRUE +/mob/living/simple_animal/bot/allowed(mob/living/user) if(!(bot_cover_flags & BOT_COVER_LOCKED)) // Unlocked. return TRUE - if(!istype(user)) // Non-living mobs shouldn't be manipulating bots (like observes using the botkeeper UI). - return FALSE - - var/obj/item/card/id/used_id = id || user.get_idcard(TRUE) - - if(!used_id || !used_id.access) - return FALSE - - for(var/requested_access in maints_access_required) - if(requested_access in used_id.access) - return TRUE - return FALSE + return ..() /mob/living/simple_animal/bot/bee_friendly() return TRUE @@ -327,7 +309,7 @@ bot_cover_flags &= ~BOT_COVER_LOCKED balloon_alert(user, "cover unlocked") return TRUE - if(!(bot_cover_flags & BOT_COVER_LOCKED) && bot_cover_flags & BOT_COVER_OPEN) //Bot panel is unlocked by ID or emag, and the panel is screwed open. Ready for emagging. + if(!(bot_cover_flags & BOT_COVER_LOCKED) && bot_cover_flags & BOT_COVER_MAINTS_OPEN) //Bot panel is unlocked by ID or emag, and the panel is screwed open. Ready for emagging. bot_cover_flags |= BOT_COVER_EMAGGED bot_cover_flags &= ~BOT_COVER_LOCKED //Manually emagging the bot locks out the panel. bot_mode_flags &= ~BOT_MODE_REMOTE_ENABLED //Manually emagging the bot also locks the AI from controlling it. @@ -351,16 +333,16 @@ . += "[src]'s parts look very loose!" else . += "[src] is in pristine condition." - . += span_notice("Its maintenance panel is [bot_cover_flags & BOT_COVER_OPEN ? "open" : "closed"].") - . += span_info("You can use a screwdriver to [bot_cover_flags & BOT_COVER_OPEN ? "close" : "open"] it.") - if(bot_cover_flags & BOT_COVER_OPEN) + . += span_notice("Its maintenance panel is [bot_cover_flags & BOT_COVER_MAINTS_OPEN ? "open" : "closed"].") + . += span_info("You can use a screwdriver to [bot_cover_flags & BOT_COVER_MAINTS_OPEN ? "close" : "open"] it.") + if(bot_cover_flags & BOT_COVER_MAINTS_OPEN) . += span_notice("Its control panel is [bot_cover_flags & BOT_COVER_LOCKED ? "locked" : "unlocked"].") - var/is_sillycone = issilicon(user) + var/is_sillycone = HAS_SILICON_ACCESS(user) if(!(bot_cover_flags & BOT_COVER_EMAGGED) && (is_sillycone || user.Adjacent(src))) . += span_info("Alt-click [is_sillycone ? "" : "or use your ID on "]it to [bot_cover_flags & BOT_COVER_LOCKED ? "un" : ""]lock its control panel.") if(paicard) . += span_notice("It has a pAI device installed.") - if(!(bot_cover_flags & BOT_COVER_OPEN)) + if(!(bot_cover_flags & BOT_COVER_MAINTS_OPEN)) . += span_info("You can use a hemostat to remove it.") /mob/living/simple_animal/bot/adjustHealth(amount, updating_health = TRUE, forced = FALSE) @@ -393,10 +375,10 @@ if(!(bot_mode_flags & BOT_MODE_ON) || client) return FALSE - if(commissioned && COOLDOWN_FINISHED(src, next_salute_check)) + if(HAS_TRAIT(src, TRAIT_COMMISSIONED) && COOLDOWN_FINISHED(src, next_salute_check)) COOLDOWN_START(src, next_salute_check, BOT_COMMISSIONED_SALUTE_DELAY) for(var/mob/living/simple_animal/bot/B in view(5, src)) - if(!B.commissioned && B.bot_mode_flags & BOT_MODE_ON) + if(!HAS_TRAIT(B, TRAIT_COMMISSIONED) && B.bot_mode_flags & BOT_MODE_ON) visible_message("[B] performs an elaborate salute for [src]!") break @@ -440,10 +422,10 @@ if(bot_cover_flags & BOT_COVER_EMAGGED) to_chat(user, span_danger("ERROR")) return - if(bot_cover_flags & BOT_COVER_OPEN) + if(bot_cover_flags & BOT_COVER_MAINTS_OPEN) to_chat(user, span_warning("Please close the access panel before [bot_cover_flags & BOT_COVER_LOCKED ? "un" : ""]locking it.")) return - if(!check_access(user)) + if(!allowed(user)) to_chat(user, span_warning("Access denied.")) return bot_cover_flags ^= BOT_COVER_LOCKED @@ -456,8 +438,8 @@ return ITEM_INTERACT_SUCCESS tool.play_tool_sound(src) - bot_cover_flags ^= BOT_COVER_OPEN - to_chat(user, span_notice("The maintenance panel is now [bot_cover_flags & BOT_COVER_OPEN ? "opened" : "closed"].")) + bot_cover_flags ^= BOT_COVER_MAINTS_OPEN + to_chat(user, span_notice("The maintenance panel is now [bot_cover_flags & BOT_COVER_MAINTS_OPEN ? "opened" : "closed"].")) return ITEM_INTERACT_SUCCESS /mob/living/simple_animal/bot/welder_act(mob/living/user, obj/item/tool) @@ -468,7 +450,7 @@ if(health >= maxHealth) to_chat(user, span_warning("[src] does not need a repair!")) return ITEM_INTERACT_SUCCESS - if(!(bot_cover_flags & BOT_COVER_OPEN)) + if(!(bot_cover_flags & BOT_COVER_MAINTS_OPEN)) to_chat(user, span_warning("Unable to repair with the maintenance panel closed!")) return ITEM_INTERACT_SUCCESS @@ -485,7 +467,7 @@ insertpai(user, attacking_item) return if(attacking_item.tool_behaviour == TOOL_HEMOSTAT && paicard) - if(bot_cover_flags & BOT_COVER_OPEN) + if(bot_cover_flags & BOT_COVER_MAINTS_OPEN) balloon_alert(user, "open the access panel!") else balloon_alert(user, "removing pAI...") @@ -981,18 +963,18 @@ Pass a positive integer as an argument to override a bot's default speed. /mob/living/simple_animal/bot/ui_data(mob/user) var/list/data = list() - data["can_hack"] = (issilicon(user) || isAdminGhostAI(user)) + data["can_hack"] = HAS_SILICON_ACCESS(user) data["custom_controls"] = list() data["emagged"] = bot_cover_flags & BOT_COVER_EMAGGED - data["has_access"] = check_access(user) + data["has_access"] = allowed(user) data["locked"] = bot_cover_flags & BOT_COVER_LOCKED data["settings"] = list() - if(!(bot_cover_flags & BOT_COVER_LOCKED) || issilicon(user) || isAdminGhostAI(user)) + if(!(bot_cover_flags & BOT_COVER_LOCKED) || HAS_SILICON_ACCESS(user)) data["settings"]["pai_inserted"] = !!paicard data["settings"]["allow_possession"] = bot_mode_flags & BOT_MODE_CAN_BE_SAPIENT data["settings"]["possession_enabled"] = can_be_possessed data["settings"]["airplane_mode"] = !(bot_mode_flags & BOT_MODE_REMOTE_ENABLED) - data["settings"]["maintenance_lock"] = !(bot_cover_flags & BOT_COVER_OPEN) + data["settings"]["maintenance_lock"] = !(bot_cover_flags & BOT_COVER_MAINTS_OPEN) data["settings"]["power"] = bot_mode_flags & BOT_MODE_ON data["settings"]["patrol_station"] = bot_mode_flags & BOT_MODE_AUTOPATROL return data @@ -1002,7 +984,8 @@ Pass a positive integer as an argument to override a bot's default speed. . = ..() if(.) return - if(!check_access(usr)) + var/mob/user = usr + if(!allowed(user)) to_chat(usr, span_warning("Access denied.")) return @@ -1016,14 +999,14 @@ Pass a positive integer as an argument to override a bot's default speed. else turn_on() if("maintenance") - bot_cover_flags ^= BOT_COVER_OPEN + bot_cover_flags ^= BOT_COVER_MAINTS_OPEN if("patrol") bot_mode_flags ^= BOT_MODE_AUTOPATROL bot_reset() if("airplane") bot_mode_flags ^= BOT_MODE_REMOTE_ENABLED if("hack") - if(!(issilicon(usr) || isAdminGhostAI(usr))) + if(!HAS_SILICON_ACCESS(usr)) return if(!(bot_cover_flags & BOT_COVER_EMAGGED)) bot_cover_flags |= (BOT_COVER_EMAGGED|BOT_COVER_HACKED|BOT_COVER_LOCKED) @@ -1068,7 +1051,7 @@ Pass a positive integer as an argument to override a bot's default speed. if(bot_cover_flags & BOT_COVER_EMAGGED) //An emagged bot cannot be controlled by humans, silicons can if one hacked it. if(!(bot_cover_flags & BOT_COVER_HACKED)) //Manually emagged by a human - access denied to all. return TRUE - else if(!issilicon(user) && !isAdminGhostAI(user)) //Bot is hacked, so only silicons and admins are allowed access. + else if(!HAS_SILICON_ACCESS(user)) //Bot is hacked, so only silicons and admins are allowed access. return TRUE return FALSE @@ -1080,7 +1063,7 @@ Pass a positive integer as an argument to override a bot's default speed. if(key) balloon_alert(user, "personality already present!") return - if(bot_cover_flags & BOT_COVER_LOCKED || !(bot_cover_flags & BOT_COVER_OPEN)) + if(bot_cover_flags & BOT_COVER_LOCKED || !(bot_cover_flags & BOT_COVER_MAINTS_OPEN)) balloon_alert(user, "slot inaccessible!") return if(!(bot_mode_flags & BOT_MODE_CAN_BE_SAPIENT)) @@ -1137,7 +1120,7 @@ Pass a positive integer as an argument to override a bot's default speed. /// Ejects the pAI remotely. /mob/living/simple_animal/bot/proc/ejectpairemote(mob/user) - if(!check_access(user) || !paicard) + if(!allowed(user) || !paicard) return speak("Ejecting personality chip.", radio_channel) ejectpai(user) diff --git a/code/modules/mob/living/simple_animal/bot/firebot.dm b/code/modules/mob/living/simple_animal/bot/firebot.dm index a210a2e2366..f4487bfc9d9 100644 --- a/code/modules/mob/living/simple_animal/bot/firebot.dm +++ b/code/modules/mob/living/simple_animal/bot/firebot.dm @@ -16,7 +16,7 @@ health = 25 maxHealth = 25 - maints_access_required = list(ACCESS_ROBOTICS, ACCESS_CONSTRUCTION) + req_one_access = list(ACCESS_ROBOTICS, ACCESS_CONSTRUCTION) radio_key = /obj/item/encryptionkey/headset_eng radio_channel = RADIO_CHANNEL_ENGINEERING bot_type = FIRE_BOT @@ -142,7 +142,7 @@ // Variables sent to TGUI /mob/living/simple_animal/bot/firebot/ui_data(mob/user) var/list/data = ..() - if(!(bot_cover_flags & BOT_COVER_LOCKED) || issilicon(user) || isAdminGhostAI(user)) + if(!(bot_cover_flags & BOT_COVER_LOCKED) || HAS_SILICON_ACCESS(user)) data["custom_controls"]["extinguish_fires"] = extinguish_fires data["custom_controls"]["extinguish_people"] = extinguish_people data["custom_controls"]["stationary_mode"] = stationary_mode @@ -151,7 +151,7 @@ // Actions received from TGUI /mob/living/simple_animal/bot/firebot/ui_act(action, params) . = ..() - if(. || (bot_cover_flags & BOT_COVER_LOCKED && !usr.has_unlimited_silicon_privilege)) + if(. || (bot_cover_flags & BOT_COVER_LOCKED && !HAS_SILICON_ACCESS(usr))) return switch(action) diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm index e6554b4caea..94713a69a12 100644 --- a/code/modules/mob/living/simple_animal/bot/floorbot.dm +++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm @@ -16,7 +16,7 @@ health = 25 maxHealth = 25 - maints_access_required = list(ACCESS_ROBOTICS, ACCESS_CONSTRUCTION) + req_one_access = list(ACCESS_ROBOTICS, ACCESS_CONSTRUCTION) radio_key = /obj/item/encryptionkey/headset_eng radio_channel = RADIO_CHANNEL_ENGINEERING bot_type = FLOOR_BOT @@ -125,7 +125,7 @@ // Variables sent to TGUI /mob/living/simple_animal/bot/floorbot/ui_data(mob/user) var/list/data = ..() - if(!(bot_cover_flags & BOT_COVER_LOCKED) || issilicon(user) || isAdminGhostAI(user)) + if(!(bot_cover_flags & BOT_COVER_LOCKED) || HAS_SILICON_ACCESS(user)) data["custom_controls"]["tile_hull"] = autotile data["custom_controls"]["place_tiles"] = placetiles data["custom_controls"]["place_custom"] = replacetiles @@ -142,7 +142,7 @@ // Actions received from TGUI /mob/living/simple_animal/bot/floorbot/ui_act(action, params) . = ..() - if(. || (bot_cover_flags & BOT_COVER_LOCKED && !usr.has_unlimited_silicon_privilege)) + if(. || (bot_cover_flags & BOT_COVER_LOCKED && !HAS_SILICON_ACCESS(usr))) return switch(action) diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm index 6a2ed0bbef4..71199583317 100644 --- a/code/modules/mob/living/simple_animal/bot/honkbot.dm +++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm @@ -7,7 +7,7 @@ damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, STAMINA = 0, OXY = 0) combat_mode = FALSE - maints_access_required = list(ACCESS_ROBOTICS, ACCESS_THEATRE) + req_one_access = list(ACCESS_ROBOTICS, ACCESS_THEATRE) radio_key = /obj/item/encryptionkey/headset_service //doesn't have security key radio_channel = RADIO_CHANNEL_SERVICE //Doesn't even use the radio anyway. bot_type = HONK_BOT diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index 833ed124f6d..71292405faa 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -28,7 +28,7 @@ buckle_prevents_pull = TRUE // No pulling loaded shit bot_mode_flags = ~BOT_MODE_ROUNDSTART_POSSESSION - maints_access_required = list(ACCESS_ROBOTICS, ACCESS_CARGO) + req_one_access = list(ACCESS_ROBOTICS, ACCESS_CARGO) radio_key = /obj/item/encryptionkey/headset_cargo radio_channel = RADIO_CHANNEL_SUPPLY bot_type = MULE_BOT @@ -101,7 +101,7 @@ /mob/living/simple_animal/bot/mulebot/examine(mob/user) . = ..() - if(bot_cover_flags & BOT_COVER_OPEN) + if(bot_cover_flags & BOT_COVER_MAINTS_OPEN) if(cell) . += span_notice("It has \a [cell] installed.") . += span_info("You can use a crowbar to remove it.") @@ -131,13 +131,13 @@ return cell && cell.charge > 0 && (!wires.is_cut(WIRE_POWER1) && !wires.is_cut(WIRE_POWER2)) /mob/living/simple_animal/bot/mulebot/attack_hand(mob/living/carbon/human/user, list/modifiers) - if(bot_cover_flags & BOT_COVER_OPEN && !isAI(user)) + if(bot_cover_flags & BOT_COVER_MAINTS_OPEN && !HAS_AI_ACCESS(user)) wires.interact(user) return - if(wires.is_cut(WIRE_RX) && isAI(user)) + if(wires.is_cut(WIRE_RX) && HAS_AI_ACCESS(user)) return - . = ..() + return ..() /mob/living/simple_animal/bot/mulebot/proc/set_id(new_id) id = new_id @@ -163,7 +163,7 @@ update_appearance() /mob/living/simple_animal/bot/mulebot/crowbar_act(mob/living/user, obj/item/tool) - if(!(bot_cover_flags & BOT_COVER_OPEN) || user.combat_mode) + if(!(bot_cover_flags & BOT_COVER_MAINTS_OPEN) || user.combat_mode) return if(!cell) to_chat(user, span_warning("[src] doesn't have a power cell!")) @@ -182,7 +182,7 @@ return ITEM_INTERACT_SUCCESS /mob/living/simple_animal/bot/mulebot/attackby(obj/item/I, mob/living/user, params) - if(istype(I, /obj/item/stock_parts/cell) && bot_cover_flags & BOT_COVER_OPEN) + if(istype(I, /obj/item/stock_parts/cell) && bot_cover_flags & BOT_COVER_MAINTS_OPEN) if(cell) to_chat(user, span_warning("[src] already has a power cell!")) return TRUE @@ -195,7 +195,7 @@ span_notice("You insert [cell] into [src]."), ) return TRUE - else if(is_wire_tool(I) && bot_cover_flags & BOT_COVER_OPEN) + else if(is_wire_tool(I) && bot_cover_flags & BOT_COVER_MAINTS_OPEN) return attack_hand(user) else if(load && ismob(load)) // chance to knock off rider if(prob(1 + I.force * 2)) @@ -211,7 +211,7 @@ /mob/living/simple_animal/bot/mulebot/emag_act(mob/user, obj/item/card/emag/emag_card) if(!(bot_cover_flags & BOT_COVER_EMAGGED)) bot_cover_flags |= BOT_COVER_EMAGGED - if(!(bot_cover_flags & BOT_COVER_OPEN)) + if(!(bot_cover_flags & BOT_COVER_MAINTS_OPEN)) bot_cover_flags ^= BOT_COVER_LOCKED balloon_alert(user, "controls [bot_cover_flags & BOT_COVER_LOCKED ? "locked" : "unlocked"]") flick("[base_icon]-emagged", src) @@ -224,7 +224,7 @@ /mob/living/simple_animal/bot/mulebot/update_overlays() . = ..() - if(bot_cover_flags & BOT_COVER_OPEN) + if(bot_cover_flags & BOT_COVER_MAINTS_OPEN) . += "[base_icon]-hatch" if(!load || ismob(load)) //mob offsets and such are handled by the riding component / buckling return @@ -265,7 +265,7 @@ var/list/data = list() data["on"] = bot_mode_flags & BOT_MODE_ON data["locked"] = bot_cover_flags & BOT_COVER_LOCKED - data["siliconUser"] = user.has_unlimited_silicon_privilege + data["siliconUser"] = HAS_SILICON_ACCESS(user) data["mode"] = mode ? "[mode]" : "Ready" data["modeStatus"] = "" switch(mode) @@ -292,18 +292,18 @@ /mob/living/simple_animal/bot/mulebot/ui_act(action, params) . = ..() - if(. || (bot_cover_flags & BOT_COVER_LOCKED && !usr.has_unlimited_silicon_privilege)) + if(. || (bot_cover_flags & BOT_COVER_LOCKED && !HAS_SILICON_ACCESS(usr))) return switch(action) if("lock") - if(usr.has_unlimited_silicon_privilege) + if(HAS_SILICON_ACCESS(usr)) bot_cover_flags ^= BOT_COVER_LOCKED return TRUE if("on") if(bot_mode_flags & BOT_MODE_ON) turn_off() - else if(bot_cover_flags & BOT_COVER_OPEN) + else if(bot_cover_flags & BOT_COVER_MAINTS_OPEN) to_chat(usr, span_warning("[name]'s maintenance panel is open!")) return else if(cell) diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index 37722ed3bf6..26f64dc6082 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -13,7 +13,7 @@ pass_flags = PASSMOB | PASSFLAPS combat_mode = TRUE - maints_access_required = list(ACCESS_SECURITY) + req_one_access = list(ACCESS_SECURITY) radio_key = /obj/item/encryptionkey/secbot //AI Priv + Security radio_channel = RADIO_CHANNEL_SECURITY //Security channel bot_type = SEC_BOT @@ -32,6 +32,8 @@ BEEPSKY_VOICED_SECURE_DAY = 'sound/voice/beepsky/secureday.ogg', ) + ///Whether this secbot is considered 'commissioned' and given the trait on Initialize. + var/commissioned = FALSE ///The type of baton this Secbot will use var/baton_type = /obj/item/melee/baton/security ///The type of cuffs we use on criminals after making arrests @@ -126,6 +128,8 @@ . = ..() weapon = new baton_type() update_appearance(UPDATE_ICON) + if(commissioned) + ADD_TRAIT(src, TRAIT_COMMISSIONED, INNATE_TRAIT) // Doing this hurts my soul, but simplebot access reworks are for another day. var/datum/id_trim/job/det_trim = SSid_access.trim_singletons_by_path[/datum/id_trim/job/detective] @@ -187,7 +191,7 @@ // Variables sent to TGUI /mob/living/simple_animal/bot/secbot/ui_data(mob/user) var/list/data = ..() - if(!(bot_cover_flags & BOT_COVER_LOCKED) || issilicon(user) || isAdminGhostAI(user)) + if(!(bot_cover_flags & BOT_COVER_LOCKED) || HAS_SILICON_ACCESS(user)) data["custom_controls"]["check_id"] = security_mode_flags & SECBOT_CHECK_IDS data["custom_controls"]["check_weapons"] = security_mode_flags & SECBOT_CHECK_WEAPONS data["custom_controls"]["check_warrants"] = security_mode_flags & SECBOT_CHECK_RECORDS @@ -198,7 +202,7 @@ // Actions received from TGUI /mob/living/simple_animal/bot/secbot/ui_act(action, params) . = ..() - if(. || (bot_cover_flags & BOT_COVER_LOCKED && !usr.has_unlimited_silicon_privilege)) + if(. || (bot_cover_flags & BOT_COVER_LOCKED && !HAS_SILICON_ACCESS(usr))) return switch(action) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index b8ad73c413c..2911c1b174c 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -498,6 +498,7 @@ if(isanimal_or_basicmob(loc)) holder_animal = loc RegisterSignal(holder_animal, COMSIG_LIVING_DEATH, PROC_REF(on_holder_animal_death)) + AddElement(/datum/element/empprotection, EMP_PROTECT_ALL) /obj/structure/closet/stasis/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) . = ..() @@ -526,9 +527,6 @@ return ..() return ..() -/obj/structure/closet/stasis/emp_act() - return - /obj/structure/closet/stasis/ex_act() return FALSE diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 96b780c3e2f..fbed81c7f6a 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1169,6 +1169,9 @@ var/datum/dna/mob_dna = has_dna() if(mob_dna?.check_mutation(/datum/mutation/human/telekinesis) && tkMaxRangeCheck(src, A)) return TRUE + var/obj/item/item_in_hand = get_active_held_item() + if(istype(item_in_hand, /obj/item/machine_remote)) + return TRUE //range check if(!interaction_range) // If you don't have extra length, GO AWAY diff --git a/code/modules/mod/modules/modules_general.dm b/code/modules/mod/modules/modules_general.dm index 59f0055dd87..041e671ccdf 100644 --- a/code/modules/mod/modules/modules_general.dm +++ b/code/modules/mod/modules/modules_general.dm @@ -334,10 +334,10 @@ incompatible_modules = list(/obj/item/mod/module/emp_shield) /obj/item/mod/module/emp_shield/on_install() - mod.AddElement(/datum/element/empprotection, EMP_PROTECT_SELF|EMP_PROTECT_WIRES|EMP_PROTECT_CONTENTS) + mod.AddElement(/datum/element/empprotection, EMP_PROTECT_ALL) /obj/item/mod/module/emp_shield/on_uninstall(deleting = FALSE) - mod.RemoveElement(/datum/element/empprotection, EMP_PROTECT_SELF|EMP_PROTECT_WIRES|EMP_PROTECT_CONTENTS) + mod.RemoveElement(/datum/element/empprotection, EMP_PROTECT_ALL) /obj/item/mod/module/emp_shield/advanced name = "MOD advanced EMP shield module" diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm index 8b0de8781b4..e7286b1aa1a 100644 --- a/code/modules/modular_computers/computers/item/computer.dm +++ b/code/modules/modular_computers/computers/item/computer.dm @@ -482,7 +482,7 @@ playsound(src, 'sound/machines/card_slide.ogg', 50) /obj/item/modular_computer/proc/turn_on(mob/user, open_ui = TRUE) - var/issynth = issilicon(user) // Robots and AIs get different activation messages. + var/issynth = HAS_SILICON_ACCESS(user) // Robots and AIs get different activation messages. if(atom_integrity <= integrity_failure * max_integrity) if(user) if(issynth) diff --git a/code/modules/modular_computers/computers/item/role_tablet_presets.dm b/code/modules/modular_computers/computers/item/role_tablet_presets.dm index f47a8c9a4e6..ff5558e72bd 100644 --- a/code/modules/modular_computers/computers/item/role_tablet_presets.dm +++ b/code/modules/modular_computers/computers/item/role_tablet_presets.dm @@ -418,7 +418,6 @@ /** * No Department/Station Trait */ - /obj/item/modular_computer/pda/assistant name = "assistant PDA" starting_programs = list( @@ -444,10 +443,29 @@ /datum/computer_file/program/skill_tracker, ) +/obj/item/modular_computer/pda/human_ai + name = "modular interface" + icon_state = "pda-silicon-human" + base_icon_state = "pda-silicon-human" + greyscale_config = null + greyscale_colors = null + + has_light = FALSE //parity with borg PDAs + comp_light_luminosity = 0 + inserted_item = null + has_pda_programs = FALSE + starting_programs = list( + /datum/computer_file/program/messenger, + /datum/computer_file/program/secureye/human_ai, + /datum/computer_file/program/alarm_monitor, + /datum/computer_file/program/status, + /datum/computer_file/program/robocontrol, + /datum/computer_file/program/borg_monitor, + ) + /** * Non-roles */ - /obj/item/modular_computer/pda/syndicate name = "military PDA" greyscale_colors = "#891417#80FF80" diff --git a/code/modules/modular_computers/file_system/programs/budgetordering.dm b/code/modules/modular_computers/file_system/programs/budgetordering.dm index ae950bf6f7b..41ada0e60c4 100644 --- a/code/modules/modular_computers/file_system/programs/budgetordering.dm +++ b/code/modules/modular_computers/file_system/programs/budgetordering.dm @@ -34,7 +34,7 @@ var/cargo_account = ACCOUNT_CAR /datum/computer_file/program/budgetorders/proc/is_visible_pack(mob/user, paccess_to_check, list/access, contraband) - if(issilicon(user)) //Borgs can't buy things. + if(HAS_SILICON_ACCESS(user)) //Borgs can't buy things. return FALSE if(computer.obj_flags & EMAGGED) return TRUE diff --git a/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm b/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm index 11188bc7cdf..94c89945ed4 100644 --- a/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm +++ b/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm @@ -708,7 +708,6 @@ else reply = "(Reply)" - if (isAI(messaged_mob)) sender_title = "[sender_title]" diff --git a/code/modules/modular_computers/file_system/programs/secureye.dm b/code/modules/modular_computers/file_system/programs/secureye.dm index 8eb3190afa5..e1444b74577 100644 --- a/code/modules/modular_computers/file_system/programs/secureye.dm +++ b/code/modules/modular_computers/file_system/programs/secureye.dm @@ -46,6 +46,15 @@ network = list("ss13", "mine", "rd", "labor", "ordnance", "minisat") spying = TRUE +/datum/computer_file/program/secureye/human_ai + filename = "Overseer" + filedesc = "OverSeer" + run_access = list(ACCESS_MINISAT) + can_run_on_flags = PROGRAM_PDA + program_flags = PROGRAM_UNIQUE_COPY + network = list("ss13", "mine", "rd", "labor", "ordnance", "minisat") + spying = TRUE + /datum/computer_file/program/secureye/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing) . = ..() // Map name has to start and end with an A-Z character, diff --git a/code/modules/modular_computers/file_system/programs/techweb.dm b/code/modules/modular_computers/file_system/programs/techweb.dm index bf9e7b1e9b8..a72eef1bc9a 100644 --- a/code/modules/modular_computers/file_system/programs/techweb.dm +++ b/code/modules/modular_computers/file_system/programs/techweb.dm @@ -201,7 +201,7 @@ if(stored_research.research_node_id(id)) computer.say("Successfully researched [tech_node.display_name].") var/logname = "Unknown" - if(isAI(user)) + if(HAS_AI_ACCESS(user)) logname = "AI [user.name]" if(iscyborg(user)) logname = "CYBORG [user.name]" diff --git a/code/modules/paperwork/fax.dm b/code/modules/paperwork/fax.dm index f9eafa901aa..f2fece875d8 100644 --- a/code/modules/paperwork/fax.dm +++ b/code/modules/paperwork/fax.dm @@ -56,6 +56,15 @@ GLOBAL_VAR_INIT(nt_fax_department, pick("NT HR Department", "NT Legal Department syndicate = list(fax_name = "Sabotage Department", fax_id = "syndicate", color = "red", emag_needed = TRUE), ) +/obj/machinery/fax/auto_name + name = "Auto-naming Fax Machine" + +/obj/machinery/fax/auto_name/Initialize(mapload) + var/area/current_area = get_area(src) + name = "[current_area.name]'s Fax Machine" + fax_name = "[current_area.name]" + return ..() + /obj/machinery/fax/Initialize(mapload) . = ..() if (!fax_id) diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index 4b495ae9148..e55225b1ca0 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -161,7 +161,7 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) data["is_photo"] = TRUE data["color_mode"] = color_mode - if(isAI(user)) + if(HAS_AI_ACCESS(user)) data["isAI"] = TRUE data["can_AI_print"] = toner_cartridge && (toner_cartridge.charges >= PHOTO_TONER_USE) && (get_paper_count() >= PHOTO_PAPER_USE) else diff --git a/code/modules/power/apc/apc_attack.dm b/code/modules/power/apc/apc_attack.dm index fc6b33f2757..88271a6b1fc 100644 --- a/code/modules/power/apc/apc_attack.dm +++ b/code/modules/power/apc/apc_attack.dm @@ -289,7 +289,7 @@ /obj/machinery/power/apc/proc/can_use(mob/user, loud = 0) //used by attack_hand() and Topic() if(isAdminGhostAI(user)) return TRUE - if(!user.has_unlimited_silicon_privilege) + if(!HAS_SILICON_ACCESS(user)) return TRUE var/mob/living/silicon/ai/AI = user var/mob/living/silicon/robot/robot = user diff --git a/code/modules/power/apc/apc_main.dm b/code/modules/power/apc/apc_main.dm index 65de109b5e3..ed49a8ebde3 100644 --- a/code/modules/power/apc/apc_main.dm +++ b/code/modules/power/apc/apc_main.dm @@ -332,7 +332,7 @@ "totalLoad" = display_power(lastused_total), "coverLocked" = coverlocked, "remoteAccess" = (user == remote_control_user), - "siliconUser" = user.has_unlimited_silicon_privilege, + "siliconUser" = HAS_SILICON_ACCESS(user), "malfStatus" = get_malf_status(user), "emergencyLights" = !emergency_lights, "nightshiftLights" = nightshift_lights, @@ -407,11 +407,11 @@ /obj/machinery/power/apc/ui_act(action, params) . = ..() - if(. || !can_use(usr, 1) || (locked && !usr.has_unlimited_silicon_privilege && !failure_timer && action != "toggle_nightshift")) + if(. || !can_use(usr, 1) || (locked && !HAS_SILICON_ACCESS(usr) && !failure_timer && action != "toggle_nightshift")) return switch(action) if("lock") - if(usr.has_unlimited_silicon_privilege) + if(HAS_SILICON_ACCESS(usr)) if((obj_flags & EMAGGED) || (machine_stat & (BROKEN|MAINT)) || remote_control_user) to_chat(usr, span_warning("The APC does not respond to the command!")) else @@ -448,7 +448,7 @@ update() . = TRUE if("overload") - if(usr.has_unlimited_silicon_privilege) + if(HAS_SILICON_ACCESS(usr)) overload_lighting() . = TRUE if("hack") diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index f194b5eb864..efdb6103a8e 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -93,8 +93,9 @@ desc = "An energy-based laser gun that draws power from the cyborg's internal energy cell directly. So this is what freedom looks like?" use_cyborg_cell = TRUE -/obj/item/gun/energy/laser/cyborg/emp_act() - return +/obj/item/gun/energy/laser/cyborg/Initialize(mapload) + . = ..() + AddElement(/datum/element/empprotection, EMP_PROTECT_ALL) /obj/item/gun/energy/laser/scatter name = "scatter laser gun" diff --git a/code/modules/projectiles/guns/energy/pulse.dm b/code/modules/projectiles/guns/energy/pulse.dm index f441937e60a..a589594d796 100644 --- a/code/modules/projectiles/guns/energy/pulse.dm +++ b/code/modules/projectiles/guns/energy/pulse.dm @@ -12,8 +12,9 @@ ammo_type = list(/obj/item/ammo_casing/energy/laser/pulse, /obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/laser) cell_type = /obj/item/stock_parts/cell/pulse -/obj/item/gun/energy/pulse/emp_act(severity) - return +/obj/item/gun/energy/pulse/Initialize(mapload) + . = ..() + AddElement(/datum/element/empprotection, EMP_PROTECT_ALL) /obj/item/gun/energy/pulse/prize pin = /obj/item/firing_pin diff --git a/code/modules/projectiles/guns/energy/recharge.dm b/code/modules/projectiles/guns/energy/recharge.dm index 26fbdef6e13..3d94193a531 100644 --- a/code/modules/projectiles/guns/energy/recharge.dm +++ b/code/modules/projectiles/guns/energy/recharge.dm @@ -30,6 +30,7 @@ . = ..() if(!holds_charge) empty() + AddElement(/datum/element/empprotection, EMP_PROTECT_ALL) /obj/item/gun/energy/recharge/shoot_live_shot(mob/living/user, pointblank = 0, atom/pbtarget = null, message = 1) . = ..() @@ -78,9 +79,6 @@ deltimer(recharge_timerid) recharge_timerid = addtimer(CALLBACK(src, PROC_REF(reload)), set_recharge_time * carried, TIMER_STOPPABLE) -/obj/item/gun/energy/recharge/emp_act(severity) - return - /obj/item/gun/energy/recharge/proc/reload() cell.give(cell.maxcharge) if(!suppressed && recharge_sound) diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index 3802ca0de35..a63e45ff163 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -10,6 +10,10 @@ slot_flags = ITEM_SLOT_BACK ammo_type = list(/obj/item/ammo_casing/energy/ion) +/obj/item/gun/energy/ionrifle/Initialize(mapload) + . = ..() + AddElement(/datum/element/empprotection, EMP_PROTECT_ALL) + /obj/item/gun/energy/ionrifle/add_seclight_point() AddComponent(/datum/component/seclite_attachable, \ light_overlay_icon = 'icons/obj/weapons/guns/flashlights.dmi', \ @@ -17,9 +21,6 @@ overlay_x = 17, \ overlay_y = 9) -/obj/item/gun/energy/ionrifle/emp_act(severity) - return - /obj/item/gun/energy/ionrifle/carbine name = "ion carbine" desc = "The MK.II Prototype Ion Projector is a lightweight carbine version of the larger ion rifle, built to be ergonomic and efficient." @@ -130,9 +131,7 @@ ..() /obj/item/gun/energy/plasmacutter/emp_act(severity) - if(!cell.charge) - return - cell.use(cell.charge/3) + . = ..() if(isliving(loc)) var/mob/living/user = loc user.visible_message(span_danger("Concentrated plasma discharges from [src] onto [user], burning them!"), span_userdanger("[src] malfunctions, spewing concentrated plasma onto you! It burns!")) @@ -305,9 +304,7 @@ AddElement(/datum/element/update_icon_blocker) . = ..() AddComponent(/datum/component/automatic_fire, 0.3 SECONDS) - -/obj/item/gun/energy/printer/emp_act() - return + AddElement(/datum/element/empprotection, EMP_PROTECT_ALL) /obj/item/gun/energy/temperature name = "temperature gun" diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm index e099176ddd0..72148267b03 100644 --- a/code/modules/projectiles/guns/energy/stun.dm +++ b/code/modules/projectiles/guns/energy/stun.dm @@ -19,10 +19,11 @@ can_charge = FALSE use_cyborg_cell = TRUE -/obj/item/gun/energy/e_gun/advtaser/cyborg/add_seclight_point() - return +/obj/item/gun/energy/e_gun/advtaser/cyborg/Initialize(mapload) + . = ..() + AddElement(/datum/element/empprotection, EMP_PROTECT_ALL) -/obj/item/gun/energy/e_gun/advtaser/cyborg/emp_act() +/obj/item/gun/energy/e_gun/advtaser/cyborg/add_seclight_point() return /obj/item/gun/energy/disabler @@ -66,5 +67,6 @@ can_charge = FALSE use_cyborg_cell = TRUE -/obj/item/gun/energy/disabler/cyborg/emp_act() - return +/obj/item/gun/energy/disabler/cyborg/Initialize(mapload) + . = ..() + AddElement(/datum/element/empprotection, EMP_PROTECT_ALL) diff --git a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm index 6641e63520e..358ac29719c 100644 --- a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm +++ b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm @@ -235,7 +235,7 @@ if(beaker || length(holdingitems)) options["eject"] = radial_eject - if(isAI(user)) + if(HAS_AI_ACCESS(user)) if(machine_stat & NOPOWER) return options["examine"] = radial_examine @@ -255,10 +255,10 @@ for(var/key in options) choice = key else - choice = show_radial_menu(user, src, options, require_near = !issilicon(user)) + choice = show_radial_menu(user, src, options, require_near = !HAS_SILICON_ACCESS(user)) // post choice verification - if(operating || (isAI(user) && machine_stat & NOPOWER) || !user.can_perform_action(src, ALLOW_SILICON_REACH)) + if(operating || (HAS_AI_ACCESS(user) && machine_stat & NOPOWER) || !user.can_perform_action(src, ALLOW_SILICON_REACH)) return switch(choice) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index bc329c661c6..465dc4739ce 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -1297,6 +1297,9 @@ /datum/reagent/fuel/on_mob_life(mob/living/carbon/victim, seconds_per_tick, times_fired) . = ..() + var/obj/item/organ/internal/liver/liver = victim.get_organ_slot(ORGAN_SLOT_LIVER) + if(liver && HAS_TRAIT(liver, TRAIT_HUMAN_AI_METABOLISM)) + return if(victim.adjustToxLoss(0.5 * seconds_per_tick, updating_health = FALSE, required_biotype = affected_biotype)) return UPDATE_MOB_HEALTH @@ -1430,6 +1433,9 @@ /datum/reagent/cyborg_mutation_nanomachines/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume, show_message = TRUE, touch_protection = 0) . = ..() + var/obj/item/organ/internal/liver/liver = exposed_mob.get_organ_slot(ORGAN_SLOT_LIVER) + if(liver && HAS_TRAIT(liver, TRAIT_HUMAN_AI_METABOLISM)) + return if((methods & (PATCH|INGEST|INJECT)) || ((methods & VAPOR) && prob(min(reac_volume,100)*(1 - touch_protection)))) exposed_mob.ForceContractDisease(new /datum/disease/transformation/robot(), FALSE, TRUE) diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index e9bea91fbed..c98cec7cc9e 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -1045,11 +1045,11 @@ description = "A strong mineral acid with the molecular formula H2SO4." color = "#00FF32" toxpwr = 1 - var/acidpwr = 10 //the amount of protection removed from the armour taste_description = "acid" self_consuming = TRUE ph = 2.75 chemical_flags = REAGENT_CAN_BE_SYNTHESIZED + var/acidpwr = 10 //the amount of protection removed from the armour // ...Why? I mean, clearly someone had to have done this and thought, well, // acid doesn't hurt plants, but what brought us here, to this point? @@ -1062,6 +1062,9 @@ . = ..() if(!istype(exposed_carbon)) return + var/obj/item/organ/internal/liver/liver = exposed_carbon.get_organ_slot(ORGAN_SLOT_LIVER) + if(liver && HAS_TRAIT(liver, TRAIT_HUMAN_AI_METABOLISM)) + return reac_volume = round(reac_volume,0.1) if(methods & INGEST) exposed_carbon.adjustBruteLoss(min(6*toxpwr, reac_volume * toxpwr), required_bodytype = affected_bodytype) diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm index 0977917d082..85f024f48cd 100644 --- a/code/modules/recycling/disposal/bin.dm +++ b/code/modules/recycling/disposal/bin.dm @@ -358,7 +358,7 @@ data["pressure_charging"] = pressure_charging data["panel_open"] = panel_open data["per"] = CLAMP01(air_contents.return_pressure() / (SEND_PRESSURE)) - data["isai"] = isAI(user) + data["isai"] = HAS_AI_ACCESS(user) return data /obj/machinery/disposal/bin/ui_act(action, params) diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index b2b468db120..e529f97eb0c 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -112,7 +112,7 @@ Nothing else in the console has ID requirements. if(stored_research.research_node_id(id)) say("Successfully researched [TN.display_name].") var/logname = "Unknown" - if(isAI(user)) + if(HAS_AI_ACCESS(user)) logname = "AI [user.name]" if(iscyborg(user)) logname = "CYBORG [user.name]" diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index 775a6f02b2d..7687a01982e 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -1068,6 +1068,18 @@ ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) +/datum/techweb_node/ai_basic/New() + . = ..() + if(HAS_TRAIT(SSstation, STATION_TRAIT_HUMAN_AI)) + design_ids -= list( + "aicore", + "borg_ai_control", + "intellicard", + "mecha_tracking_ai_control", + "aifixer", + "aiupload", + ) + /datum/techweb_node/ai_adv id = "ai_adv" display_name = "Advanced Artificial Intelligence" diff --git a/code/modules/shuttle/spaceship_navigation_beacon.dm b/code/modules/shuttle/spaceship_navigation_beacon.dm index 2c0b95239b6..eb613be54de 100644 --- a/code/modules/shuttle/spaceship_navigation_beacon.dm +++ b/code/modules/shuttle/spaceship_navigation_beacon.dm @@ -39,9 +39,10 @@ START_PROCESSING(SSmachines, src) COOLDOWN_START(src, next_automatic_message_time, automatic_message_cooldown) -/obj/machinery/spaceship_navigation_beacon/emp_act() +/obj/machinery/spaceship_navigation_beacon/emp_act(severity) + . = ..() locked = TRUE - update_icon_state() + update_appearance(UPDATE_ICON_STATE) /obj/machinery/spaceship_navigation_beacon/Destroy() SSshuttle.beacon_list -= src diff --git a/code/modules/surgery/organs/internal/eyes/_eyes.dm b/code/modules/surgery/organs/internal/eyes/_eyes.dm index c9e54027137..08fbd4e955a 100644 --- a/code/modules/surgery/organs/internal/eyes/_eyes.dm +++ b/code/modules/surgery/organs/internal/eyes/_eyes.dm @@ -383,8 +383,9 @@ tint = INFINITY var/obj/item/flashlight/eyelight/eye -/obj/item/organ/internal/eyes/robotic/flashlight/emp_act(severity) - return +/obj/item/organ/internal/eyes/robotic/flashlight/Initialize(mapload) + . = ..() + AddElement(/datum/element/empprotection, EMP_PROTECT_ALL) /obj/item/organ/internal/eyes/robotic/flashlight/on_mob_insert(mob/living/carbon/victim) . = ..() @@ -408,8 +409,9 @@ desc = "These reactive micro-shields will protect you from welders and flashes without obscuring your vision." flash_protect = FLASH_PROTECTION_WELDER -/obj/item/organ/internal/eyes/robotic/shield/emp_act(severity) - return +/obj/item/organ/internal/eyes/robotic/shield/Initialize(mapload) + . = ..() + AddElement(/datum/element/empprotection, EMP_PROTECT_ALL) #define MATCH_LIGHT_COLOR 1 #define USE_CUSTOM_COLOR 0 @@ -445,7 +447,7 @@ deactivate(close_ui = TRUE) QDEL_NULL(eye) -/obj/item/organ/internal/eyes/robotic/glow/emp_act() +/obj/item/organ/internal/eyes/robotic/glow/emp_act(severity) . = ..() if(!eye.light_on || . & EMP_PROTECT_SELF) return diff --git a/code/modules/surgery/organs/internal/liver/_liver.dm b/code/modules/surgery/organs/internal/liver/_liver.dm index db619536c5a..5c6eaf9b38f 100644 --- a/code/modules/surgery/organs/internal/liver/_liver.dm +++ b/code/modules/surgery/organs/internal/liver/_liver.dm @@ -100,6 +100,8 @@ . += span_info("A half-digested rat's tail (somehow), disgusting sludge, and the faint smell of Grey Bull imply this is what remains of an assistant's liver.") if(HAS_TRAIT(src, TRAIT_CORONER_METABOLISM)) . += span_info("An aroma of pickles and sea water, along with being remarkably well-preserved, imply this is what remains of a coroner's liver.") + if(HAS_TRAIT(src, TRAIT_HUMAN_AI_METABOLISM)) + . += span_info("The liver appears barely human and entirely self-sufficient, implying this is what remains of a human AI's liver.") // royal trumps pretender royal if(HAS_TRAIT(src, TRAIT_ROYAL_METABOLISM)) diff --git a/code/modules/tgui/states.dm b/code/modules/tgui/states.dm index 92fa3b5b5c1..dc3d543f143 100644 --- a/code/modules/tgui/states.dm +++ b/code/modules/tgui/states.dm @@ -101,6 +101,11 @@ * return UI_state The state of the UI. */ /mob/living/proc/shared_living_ui_distance(atom/movable/src_object, viewcheck = TRUE, allow_tk = TRUE) + var/obj/item/item_in_hand = get_active_held_item() + if(istype(item_in_hand, /obj/item/machine_remote)) //snowflake, this lets you interact with all. + var/obj/item/machine_remote/remote = item_in_hand + if(remote.controlling_machine_or_bot == src_object) + return UI_INTERACTIVE // If the object is obscured, close it. if(viewcheck && !(src_object in view(src))) return UI_CLOSE diff --git a/code/modules/transport/tram/tram_controller.dm b/code/modules/transport/tram/tram_controller.dm index 4dceecbfc4c..9e95870ab6d 100644 --- a/code/modules/transport/tram/tram_controller.dm +++ b/code/modules/transport/tram/tram_controller.dm @@ -992,7 +992,7 @@ /obj/machinery/transport/tram_controller/ui_interact(mob/user, datum/tgui/ui) . = ..() - if(!cover_open && !issiliconoradminghost(user) && !isobserver(user)) + if(!cover_open && !HAS_SILICON_ACCESS(user) && !isobserver(user)) return if(!is_operational) diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm index 2a805e0d13d..4dc1e7f85c9 100644 --- a/code/modules/unit_tests/unit_test.dm +++ b/code/modules/unit_tests/unit_test.dm @@ -245,6 +245,8 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests()) //Both are abstract types meant to scream bloody murder if spawned in raw /obj/item/organ/external, /obj/item/organ/external/wings, + //Not meant to spawn without the machine wand + /obj/effect/bug_moving, ) // Everything that follows is a typesof() check. diff --git a/code/modules/vehicles/mecha/mecha_control_console.dm b/code/modules/vehicles/mecha/mecha_control_console.dm index 635ec9425b1..3b465994e9e 100644 --- a/code/modules/vehicles/mecha/mecha_control_console.dm +++ b/code/modules/vehicles/mecha/mecha_control_console.dm @@ -106,7 +106,7 @@ return answer -/obj/item/mecha_parts/mecha_tracking/emp_act() +/obj/item/mecha_parts/mecha_tracking/emp_act(severity) . = ..() if(!(. & EMP_PROTECT_SELF)) qdel(src) diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index f8c99e607f2..b3b28303c6e 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -1173,7 +1173,7 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock) return TRUE /obj/machinery/vending/interact(mob/user) - if (!isAI(user)) + if (!HAS_AI_ACCESS(user)) if(seconds_electrified && !(machine_stat & NOPOWER)) if(shock(user, 100)) return diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index c9023b95aa4..74d5a8d282c 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/hud/lobby/signup_button.dmi b/icons/hud/lobby/signup_button.dmi index 307869b0492..1057c53ba41 100644 Binary files a/icons/hud/lobby/signup_button.dmi and b/icons/hud/lobby/signup_button.dmi differ diff --git a/icons/mob/clothing/under/station_trait.dmi b/icons/mob/clothing/under/station_trait.dmi new file mode 100644 index 00000000000..c8ed053981a Binary files /dev/null and b/icons/mob/clothing/under/station_trait.dmi differ diff --git a/icons/mob/huds/hud.dmi b/icons/mob/huds/hud.dmi index e701303aa85..facec230477 100644 Binary files a/icons/mob/huds/hud.dmi and b/icons/mob/huds/hud.dmi differ diff --git a/icons/obj/clothing/under/station_trait.dmi b/icons/obj/clothing/under/station_trait.dmi new file mode 100644 index 00000000000..5fce62c3131 Binary files /dev/null and b/icons/obj/clothing/under/station_trait.dmi differ diff --git a/icons/obj/modular_pda.dmi b/icons/obj/modular_pda.dmi index afd75b78d4b..236a7bb0f65 100644 Binary files a/icons/obj/modular_pda.dmi and b/icons/obj/modular_pda.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 076e4029bd4..f9519740925 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -2361,6 +2361,7 @@ #include "code\game\objects\items\kitchen.dm" #include "code\game\objects\items\knives.dm" #include "code\game\objects\items\latexballoon.dm" +#include "code\game\objects\items\machine_wand.dm" #include "code\game\objects\items\mail.dm" #include "code\game\objects\items\maintenance_loot.dm" #include "code\game\objects\items\manuals.dm" @@ -3915,6 +3916,7 @@ #include "code\modules\clothing\under\jobs\medical.dm" #include "code\modules\clothing\under\jobs\rnd.dm" #include "code\modules\clothing\under\jobs\security.dm" +#include "code\modules\clothing\under\jobs\station_trait.dm" #include "code\modules\clothing\under\jobs\civilian\civilian.dm" #include "code\modules\clothing\under\jobs\civilian\clown_mime.dm" #include "code\modules\clothing\under\jobs\civilian\curator.dm" @@ -4370,6 +4372,7 @@ #include "code\modules\jobs\job_types\spawner\zombie.dm" #include "code\modules\jobs\job_types\station_trait\bridge_assistant.dm" #include "code\modules\jobs\job_types\station_trait\cargo_gorilla.dm" +#include "code\modules\jobs\job_types\station_trait\human_ai.dm" #include "code\modules\jobs\job_types\station_trait\veteran_advisor.dm" #include "code\modules\keybindings\bindings_atom.dm" #include "code\modules\keybindings\bindings_client.dm" diff --git a/tgui/packages/tgui/interfaces/common/JobToIcon.ts b/tgui/packages/tgui/interfaces/common/JobToIcon.ts index d363f6cfc26..0e8f8e184dd 100644 --- a/tgui/packages/tgui/interfaces/common/JobToIcon.ts +++ b/tgui/packages/tgui/interfaces/common/JobToIcon.ts @@ -34,6 +34,7 @@ const BASEICONS = { Geneticist: 'dna', 'Head of Personnel': 'dog', 'Head of Security': 'user-shield', + 'Big Brother': 'eye', Janitor: 'soap', Lawyer: 'gavel', 'Medical Doctor': 'staff-snake',