diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 4de01402991..a22d6d2e408 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -523,6 +523,9 @@ #define COMPONENT_BLOCK_SWAP (1<<0) ///from base of /mob/verb/pointed: (atom/A) #define COMSIG_MOB_POINTED "mob_pointed" +///Mob is trying to open the wires of a target [/atom], from /datum/wires/interactable(): (atom/target) +#define COMSIG_TRY_WIRES_INTERACT "try_wires_interact" + #define COMPONENT_CANT_INTERACT_WIRES (1<<0) ///from /obj/structure/door/crush(): (mob/living/crushed, /obj/machinery/door/crushing_door) #define COMSIG_LIVING_DOORCRUSHED "living_doorcrush" @@ -702,7 +705,10 @@ ///from /obj/machinery/can_interact(mob/user): Called on user when attempting to interact with a machine (obj/machinery/machine) #define COMSIG_TRY_USE_MACHINE "try_use_machine" - #define COMPONENT_CANT_USE_MACHINE (1<<0) + /// Can't interact with the machine + #define COMPONENT_CANT_USE_MACHINE_INTERACT (1<<0) + /// Can't use tools on the machine + #define COMPONENT_CANT_USE_MACHINE_TOOLS (1<<1) ///from obj/machinery/iv_drip/IV_attach(target, usr) : (attachee) #define COMSIG_IV_ATTACH "iv_attach" diff --git a/code/__DEFINES/devices.dm b/code/__DEFINES/devices.dm new file mode 100644 index 00000000000..412e5d416d7 --- /dev/null +++ b/code/__DEFINES/devices.dm @@ -0,0 +1,20 @@ +// PDA defines // +#define CART_SECURITY (1<<0) +#define CART_ENGINE (1<<1) +#define CART_ATMOS (1<<2) +#define CART_MEDICAL (1<<3) +#define CART_MANIFEST (1<<4) +#define CART_CLOWN (1<<5) +#define CART_MIME (1<<6) +#define CART_JANITOR (1<<7) +#define CART_REAGENT_SCANNER (1<<8) +#define CART_NEWSCASTER (1<<9) +#define CART_REMOTE_DOOR (1<<10) +#define CART_STATUS_DISPLAY (1<<11) +#define CART_QUARTERMASTER (1<<12) +#define CART_HYDROPONICS (1<<13) +#define CART_DRONEPHONE (1<<14) +#define CART_DRONEACCESS (1<<15) + +// Used by PDA and cartridge code to reduce repetitiveness of spritesheets +#define PDAIMG(what) {""} diff --git a/code/__DEFINES/machines.dm b/code/__DEFINES/machines.dm index da2b76853da..6ec17b1d52f 100644 --- a/code/__DEFINES/machines.dm +++ b/code/__DEFINES/machines.dm @@ -190,3 +190,11 @@ #define ORION_GAMER_PAMPHLET -1 //game begins to have a chance to warn sec and med #define ORION_GAMER_REPORT_THRESHOLD 2 + +// Air alarm [/obj/machinery/airalarm/buildstage] +/// Air alarm missing circuit +#define AIRALARM_BUILD_NO_CIRCUIT 0 +/// Air alarm has circuit but is missing wires +#define AIRALARM_BUILD_NO_WIRES 1 +/// Air alarm has all components but isn't completed +#define AIRALARM_BUILD_COMPLETE 2 diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 2030ba8bbe2..320ee46a68a 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -454,9 +454,6 @@ GLOBAL_LIST_INIT(pda_styles, sortList(list(MONO, VT, ORBITRON, SHARE))) #define EGG_LAYING_MESSAGES list("lays an egg.","squats down and croons.","begins making a huge racket.","begins clucking raucously.") -// Used by PDA and cartridge code to reduce repetitiveness of spritesheets -#define PDAIMG(what) {""} - /// Prepares a text to be used for maptext. Use this so it doesn't look hideous. #define MAPTEXT(text) {"[##text]"} diff --git a/code/__DEFINES/tools.dm b/code/__DEFINES/tools.dm index 78905562690..a1504265fa5 100644 --- a/code/__DEFINES/tools.dm +++ b/code/__DEFINES/tools.dm @@ -22,3 +22,13 @@ // If delay between the start and the end of tool operation is less than MIN_TOOL_SOUND_DELAY, // tool sound is only played when op is started. If not, it's played twice. #define MIN_TOOL_SOUND_DELAY 20 + +// tool_act chain flags + +/// When a tooltype_act proc is successful +#define TOOL_ACT_TOOLTYPE_SUCCESS (1<<0) +/// When [COMSIG_ATOM_TOOL_ACT] blocks the act +#define TOOL_ACT_SIGNAL_BLOCKING (1<<1) + +/// When [TOOL_ACT_TOOLTYPE_SUCCESS] or [TOOL_ACT_SIGNAL_BLOCKING] are set +#define TOOL_ACT_MELEE_CHAIN_BLOCKING (TOOL_ACT_TOOLTYPE_SUCCESS | TOOL_ACT_SIGNAL_BLOCKING) diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm index e0e6ed945c8..f67c4f68398 100644 --- a/code/_globalvars/misc.dm +++ b/code/_globalvars/misc.dm @@ -31,3 +31,6 @@ GLOBAL_PROTECT(poll_options) GLOBAL_VAR_INIT(internal_tick_usage, 0.2 * world.tick_lag) GLOBAL_VAR_INIT(glowshrooms, 0) + +/// If drones are blacklisted from certain sensitive machines +GLOBAL_VAR_INIT(drone_machine_blacklist_enabled, TRUE) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 9e76eb3805d..d3824b7dde4 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -2,7 +2,7 @@ * This is the proc that handles the order of an item_attack. * * The order of procs called is: - * * [/atom/proc/tool_act] on the target. If it returns TRUE, the chain will be stopped. + * * [/atom/proc/tool_act] on the target. If it returns TOOL_ACT_TOOLTYPE_SUCCESS or TOOL_ACT_SIGNAL_BLOCKING, the chain will be stopped. * * [/obj/item/proc/pre_attack] on src. If this returns TRUE, the chain will be stopped. * * [/atom/proc/attackby] on the target. If it returns TRUE, the chain will be stopped. * * [/obj/item/proc/afterattack]. The return value does not matter. @@ -11,7 +11,7 @@ var/is_right_clicking = LAZYACCESS(params2list(params), RIGHT_CLICK) - if(tool_behaviour && target.tool_act(user, src, tool_behaviour, is_right_clicking)) + if(tool_behaviour && (target.tool_act(user, src, tool_behaviour, is_right_clicking) & TOOL_ACT_MELEE_CHAIN_BLOCKING)) return TRUE var/pre_attack_result diff --git a/code/datums/components/technointrovert.dm b/code/datums/components/technointrovert.dm index f77443c49c6..59752b70edb 100644 --- a/code/datums/components/technointrovert.dm +++ b/code/datums/components/technointrovert.dm @@ -14,10 +14,11 @@ src.message = message /datum/component/technointrovert/RegisterWithParent() - RegisterSignal(parent, COMSIG_TRY_USE_MACHINE, .proc/is_in_whitelist) + RegisterSignal(parent, COMSIG_TRY_USE_MACHINE, .proc/on_try_use_machine) + RegisterSignal(parent, COMSIG_TRY_WIRES_INTERACT, .proc/on_try_wires_interact) /datum/component/technointrovert/UnregisterFromParent() - UnregisterSignal(parent, COMSIG_TRY_USE_MACHINE) + UnregisterSignal(parent, list(COMSIG_TRY_USE_MACHINE, COMSIG_TRY_WIRES_INTERACT)) /datum/component/technointrovert/PostTransfer() if(!ismob(parent)) @@ -29,8 +30,17 @@ message = friend.message /datum/component/technointrovert/proc/is_in_whitelist(datum/source, obj/machinery/machine) - SIGNAL_HANDLER if(!is_type_in_typecache(machine, whitelist)) to_chat(source, "[replacetext(message, "%TARGET", machine)]") - return COMPONENT_CANT_USE_MACHINE + return FALSE + return TRUE +/datum/component/technointrovert/proc/on_try_use_machine(datum/source, obj/machinery/machine) + SIGNAL_HANDLER + if(!is_in_whitelist(source, machine)) + return COMPONENT_CANT_USE_MACHINE_INTERACT | COMPONENT_CANT_USE_MACHINE_TOOLS + +/datum/component/technointrovert/proc/on_try_wires_interact(datum/source, atom/machine) + SIGNAL_HANDLER + if(ismachinery(machine) && !is_in_whitelist(source, machine)) + return COMPONENT_CANT_INTERACT_WIRES diff --git a/code/datums/components/technoshy.dm b/code/datums/components/technoshy.dm new file mode 100644 index 00000000000..c46830ddcc6 --- /dev/null +++ b/code/datums/components/technoshy.dm @@ -0,0 +1,55 @@ +/// You can't use machines when they've been touched within the last [unused_duration], unless it was by a mob in [whitelist] +/datum/component/technoshy + can_transfer = TRUE + /// How long in deciseconds the machine can be untouched for + var/unused_duration = (2 MINUTES) + /// Typecache of allowed last_users + var/list/whitelist + /// Message presented if the machine was used too recently + var/message = "The %TARGET is way too fresh dude. Since we're like, super retro, we gotta wait for it to exit the mainstream." + +/datum/component/technoshy/Initialize(unused_duration, message, whitelist) + if(!ismob(parent)) + return COMPONENT_INCOMPATIBLE + if(unused_duration) + src.unused_duration = unused_duration + if(message) + src.message = message + if(!whitelist) + whitelist = typecacheof(parent.type) + src.whitelist = whitelist + +/datum/component/technoshy/RegisterWithParent() + RegisterSignal(parent, COMSIG_TRY_USE_MACHINE, .proc/on_try_use_machine) + RegisterSignal(parent, COMSIG_TRY_WIRES_INTERACT, .proc/on_try_wires_interact) + +/datum/component/technoshy/UnregisterFromParent() + UnregisterSignal(parent, list(COMSIG_TRY_USE_MACHINE, COMSIG_TRY_WIRES_INTERACT)) + +/datum/component/technoshy/PostTransfer() + if(!ismob(parent)) + return COMPONENT_INCOMPATIBLE + +/datum/component/technoshy/InheritComponent(datum/component/technoshy/friend, i_am_original, list/arguments) + if(i_am_original) + whitelist = friend.whitelist + message = friend.message + +/datum/component/technoshy/proc/is_not_touched(datum/source, obj/machinery/machine) + var/time_since = world.time - machine.last_used_time + if(time_since < unused_duration && !isnull(machine.last_user_mobtype) && !is_type_in_typecache(machine.last_user_mobtype, whitelist)) + to_chat(source, "[replacetext(message, "%TARGET", machine)]") + return TRUE + +/datum/component/technoshy/proc/on_try_use_machine(datum/source, obj/machinery/machine) + SIGNAL_HANDLER + if(is_not_touched(source, machine)) + return COMPONENT_CANT_USE_MACHINE_INTERACT | COMPONENT_CANT_USE_MACHINE_TOOLS + +/datum/component/technoshy/proc/on_try_wires_interact(datum/source, atom/machine) + SIGNAL_HANDLER + if(!ismachinery(machine)) + return + else if(is_not_touched(source, machine)) + return COMPONENT_CANT_INTERACT_WIRES + diff --git a/code/datums/wires/_wires.dm b/code/datums/wires/_wires.dm index be50c12425f..70c5fd15686 100644 --- a/code/datums/wires/_wires.dm +++ b/code/datums/wires/_wires.dm @@ -207,6 +207,9 @@ // Overridable Procs /datum/wires/proc/interactable(mob/user) + SHOULD_CALL_PARENT(TRUE) + if((SEND_SIGNAL(user, COMSIG_TRY_WIRES_INTERACT, holder) & COMPONENT_CANT_INTERACT_WIRES)) + return FALSE return TRUE /datum/wires/proc/get_status() diff --git a/code/datums/wires/airalarm.dm b/code/datums/wires/airalarm.dm index 6afccd54766..8eb66466c39 100644 --- a/code/datums/wires/airalarm.dm +++ b/code/datums/wires/airalarm.dm @@ -12,6 +12,8 @@ ..() /datum/wires/airalarm/interactable(mob/user) + if(!..()) + return FALSE var/obj/machinery/airalarm/A = holder if(A.panel_open && A.buildstage == 2) return TRUE diff --git a/code/datums/wires/airlock.dm b/code/datums/wires/airlock.dm index a8cdd6948f3..ba506987e6c 100644 --- a/code/datums/wires/airlock.dm +++ b/code/datums/wires/airlock.dm @@ -62,6 +62,8 @@ return ..() /datum/wires/airlock/interactable(mob/user) + if(!..()) + return FALSE var/obj/machinery/door/airlock/A = holder if(!issilicon(user) && A.isElectrified()) var/mob/living/carbon/carbon_user = user diff --git a/code/datums/wires/apc.dm b/code/datums/wires/apc.dm index 83c527bebdc..38020f7bb99 100644 --- a/code/datums/wires/apc.dm +++ b/code/datums/wires/apc.dm @@ -11,6 +11,8 @@ ..() /datum/wires/apc/interactable(mob/user) + if(!..()) + return FALSE var/obj/machinery/power/apc/A = holder if(A.panel_open && !A.opened) return TRUE diff --git a/code/datums/wires/autolathe.dm b/code/datums/wires/autolathe.dm index 7f3519f3947..b26627f8282 100644 --- a/code/datums/wires/autolathe.dm +++ b/code/datums/wires/autolathe.dm @@ -11,6 +11,8 @@ ..() /datum/wires/autolathe/interactable(mob/user) + if(!..()) + return FALSE var/obj/machinery/autolathe/A = holder if(A.panel_open) return TRUE diff --git a/code/datums/wires/conveyor.dm b/code/datums/wires/conveyor.dm index 6aa9ad28854..b6458037e22 100644 --- a/code/datums/wires/conveyor.dm +++ b/code/datums/wires/conveyor.dm @@ -13,5 +13,7 @@ C.interact(fingerman) /datum/wires/conveyor/interactable(mob/user) + if(!..()) + return FALSE fingerman = user return TRUE diff --git a/code/datums/wires/explosive.dm b/code/datums/wires/explosive.dm index 89c6c24fef2..854791415fa 100644 --- a/code/datums/wires/explosive.dm +++ b/code/datums/wires/explosive.dm @@ -22,6 +22,8 @@ var/fingerprint /datum/wires/explosive/chem_grenade/interactable(mob/user) + if(!..()) + return FALSE var/obj/item/grenade/chem_grenade/G = holder if(G.stage == GRENADE_WIRED) return TRUE @@ -77,9 +79,6 @@ /datum/wires/explosive/c4 // Also includes X4 holder_type = /obj/item/grenade/c4 -/datum/wires/explosive/c4/interactable(mob/user) // No need to unscrew wire panels on plastic explosives - return TRUE - /datum/wires/explosive/c4/explode() var/obj/item/grenade/c4/P = holder P.detonate() @@ -95,6 +94,8 @@ ..() /datum/wires/explosive/pizza/interactable(mob/user) + if(!..()) + return FALSE var/obj/item/pizzabox/P = holder if(P.open && P.bomb) return TRUE diff --git a/code/datums/wires/microwave.dm b/code/datums/wires/microwave.dm index 8c74abfa46c..b89aef6f8c9 100644 --- a/code/datums/wires/microwave.dm +++ b/code/datums/wires/microwave.dm @@ -9,6 +9,8 @@ ..() /datum/wires/microwave/interactable(mob/user) + if(!..()) + return FALSE . = FALSE var/obj/machinery/microwave/M = holder if(M.panel_open) diff --git a/code/datums/wires/mulebot.dm b/code/datums/wires/mulebot.dm index 60721e9c449..ebb6273000e 100644 --- a/code/datums/wires/mulebot.dm +++ b/code/datums/wires/mulebot.dm @@ -13,6 +13,8 @@ ..() /datum/wires/mulebot/interactable(mob/user) + if(!..()) + return FALSE var/mob/living/simple_animal/bot/mulebot/M = holder if(M.open) return TRUE diff --git a/code/datums/wires/r_n_d.dm b/code/datums/wires/r_n_d.dm index eda9a2776e9..9e483b397c9 100644 --- a/code/datums/wires/r_n_d.dm +++ b/code/datums/wires/r_n_d.dm @@ -12,6 +12,8 @@ ..() /datum/wires/rnd/interactable(mob/user) + if(!..()) + return FALSE var/obj/machinery/rnd/R = holder if(R.panel_open) return TRUE diff --git a/code/datums/wires/radio.dm b/code/datums/wires/radio.dm index a1118da6d73..538685aca3a 100644 --- a/code/datums/wires/radio.dm +++ b/code/datums/wires/radio.dm @@ -10,6 +10,8 @@ ..() /datum/wires/radio/interactable(mob/user) + if(!..()) + return FALSE var/obj/item/radio/R = holder return R.unscrewed diff --git a/code/datums/wires/robot.dm b/code/datums/wires/robot.dm index fdb6cf97c38..1768f361274 100644 --- a/code/datums/wires/robot.dm +++ b/code/datums/wires/robot.dm @@ -13,6 +13,8 @@ ..() /datum/wires/robot/interactable(mob/user) + if(!..()) + return FALSE var/mob/living/silicon/robot/R = holder if(R.wiresexposed) return TRUE diff --git a/code/datums/wires/roulette.dm b/code/datums/wires/roulette.dm index 657d19d5846..4d0b08e6bf6 100644 --- a/code/datums/wires/roulette.dm +++ b/code/datums/wires/roulette.dm @@ -13,6 +13,8 @@ ..() /datum/wires/roulette/interactable(mob/user) + if(!..()) + return FALSE . = FALSE var/obj/machinery/roulette/R = holder if(R.machine_stat & MAINT) diff --git a/code/datums/wires/suit_storage_unit.dm b/code/datums/wires/suit_storage_unit.dm index eb7781203b2..be313dca17c 100644 --- a/code/datums/wires/suit_storage_unit.dm +++ b/code/datums/wires/suit_storage_unit.dm @@ -11,6 +11,8 @@ ..() /datum/wires/suit_storage_unit/interactable(mob/user) + if(!..()) + return FALSE var/obj/machinery/suit_storage_unit/SSU = holder if(SSU.panel_open) return TRUE diff --git a/code/datums/wires/syndicatebomb.dm b/code/datums/wires/syndicatebomb.dm index b5147a3c760..72d903e5b11 100644 --- a/code/datums/wires/syndicatebomb.dm +++ b/code/datums/wires/syndicatebomb.dm @@ -11,6 +11,8 @@ ..() /datum/wires/syndicatebomb/interactable(mob/user) + if(!..()) + return FALSE var/obj/machinery/syndicatebomb/P = holder if(P.open_panel) return TRUE diff --git a/code/datums/wires/vending.dm b/code/datums/wires/vending.dm index 6113eaaf307..ce10cf9d500 100644 --- a/code/datums/wires/vending.dm +++ b/code/datums/wires/vending.dm @@ -11,6 +11,8 @@ ..() /datum/wires/vending/interactable(mob/user) + if(!..()) + return FALSE var/obj/machinery/vending/V = holder if(!issilicon(user) && V.seconds_electrified && V.shock(user, 100)) return FALSE diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 7debaf962e6..4c0d3f13608 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1354,48 +1354,53 @@ * Must return parent proc ..() in the end if overridden */ /atom/proc/tool_act(mob/living/user, obj/item/I, tool_type, is_right_clicking) + var/act_result var/signal_result if(!is_right_clicking) // Left click first for sensibility var/list/processing_recipes = list() //List of recipes that can be mutated by sending the signal signal_result = SEND_SIGNAL(src, COMSIG_ATOM_TOOL_ACT(tool_type), user, I, processing_recipes) + if(signal_result & COMPONENT_BLOCK_TOOL_ATTACK) // The COMSIG_ATOM_TOOL_ACT signal is blocking the act + return TOOL_ACT_SIGNAL_BLOCKING if(processing_recipes.len) process_recipes(user, I, processing_recipes) if(QDELETED(I)) return TRUE switch(tool_type) if(TOOL_CROWBAR) - . = crowbar_act(user, I,) + act_result = crowbar_act(user, I,) if(TOOL_MULTITOOL) - . = multitool_act(user, I) + act_result = multitool_act(user, I) if(TOOL_SCREWDRIVER) - . = screwdriver_act(user, I) + act_result = screwdriver_act(user, I) if(TOOL_WRENCH) - . = wrench_act(user, I) + act_result = wrench_act(user, I) if(TOOL_WIRECUTTER) - . = wirecutter_act(user, I) + act_result = wirecutter_act(user, I) if(TOOL_WELDER) - . = welder_act(user, I) + act_result = welder_act(user, I) if(TOOL_ANALYZER) - . = analyzer_act(user, I) + act_result = analyzer_act(user, I) else signal_result = SEND_SIGNAL(src, COMSIG_ATOM_SECONDARY_TOOL_ACT(tool_type), user, I) + if(signal_result & COMPONENT_BLOCK_TOOL_ATTACK) // The COMSIG_ATOM_TOOL_ACT signal is blocking the act + return TOOL_ACT_SIGNAL_BLOCKING switch(tool_type) if(TOOL_CROWBAR) - . = crowbar_act_secondary(user, I,) + act_result = crowbar_act_secondary(user, I,) if(TOOL_MULTITOOL) - . = multitool_act_secondary(user, I) + act_result = multitool_act_secondary(user, I) if(TOOL_SCREWDRIVER) - . = screwdriver_act_secondary(user, I) + act_result = screwdriver_act_secondary(user, I) if(TOOL_WRENCH) - . = wrench_act_secondary(user, I) + act_result = wrench_act_secondary(user, I) if(TOOL_WIRECUTTER) - . = wirecutter_act_secondary(user, I) + act_result = wirecutter_act_secondary(user, I) if(TOOL_WELDER) - . = welder_act_secondary(user, I) + act_result = welder_act_secondary(user, I) if(TOOL_ANALYZER) - . = analyzer_act_secondary(user, I) - if(. || signal_result & COMPONENT_BLOCK_TOOL_ATTACK) //Either the proc or the signal handled the tool's events in some way. - return TRUE + act_result = analyzer_act_secondary(user, I) + if(act_result) // A tooltype_act has completed successfully + return TOOL_ACT_TOOLTYPE_SUCCESS /atom/proc/process_recipes(mob/living/user, obj/item/I, list/processing_recipes) diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 57b98f95871..f5c16b40763 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -130,6 +130,10 @@ var/tgui_id // ID of TGUI interface ///Is this machine currently in the atmos machinery queue? var/atmos_processing = FALSE + /// world.time of last use by [/mob/living] + var/last_used_time = 0 + /// Mobtype of last user. Typecast to [/mob/living] for initial() usage + var/mob/living/last_user_mobtype /obj/machinery/Initialize() if(!armor) @@ -344,7 +348,7 @@ if(!isliving(user)) return FALSE //no ghosts in the machine allowed, sorry - if(SEND_SIGNAL(user, COMSIG_TRY_USE_MACHINE, src) & COMPONENT_CANT_USE_MACHINE) + if(SEND_SIGNAL(user, COMSIG_TRY_USE_MACHINE, src) & COMPONENT_CANT_USE_MACHINE_INTERACT) return FALSE var/mob/living/living_user = user @@ -422,10 +426,12 @@ /obj/machinery/interact(mob/user, special_state) if(interaction_flags_machine & INTERACT_MACHINE_SET_MACHINE) user.set_machine(src) + update_last_used(user) . = ..() /obj/machinery/ui_act(action, list/params) add_fingerprint(usr) + update_last_used(usr) return ..() /obj/machinery/Topic(href, href_list) @@ -435,6 +441,7 @@ if(!usr.canUseTopic(src)) return TRUE add_fingerprint(usr) + update_last_used(usr) return FALSE //////////////////////////////////////////////////////////////////////////////////////////// @@ -479,10 +486,30 @@ else return _try_interact(user) +/obj/machinery/attackby(obj/item/weapon, mob/user, params) + . = ..() + if(.) + return + update_last_used(user) + +/obj/machinery/attackby_secondary(obj/item/weapon, mob/user, params) + . = ..() + if(.) + return + update_last_used(user) + +/obj/machinery/tool_act(mob/living/user, obj/item/tool, tool_type) + if(SEND_SIGNAL(user, COMSIG_TRY_USE_MACHINE, src) & COMPONENT_CANT_USE_MACHINE_TOOLS) + return TOOL_ACT_MELEE_CHAIN_BLOCKING + . = ..() + if(. & TOOL_ACT_SIGNAL_BLOCKING) + return + update_last_used(user) + /obj/machinery/_try_interact(mob/user) if((interaction_flags_machine & INTERACT_MACHINE_WIRES_IF_OPEN) && panel_open && (attempt_wire_interaction(user) == WIRE_INTERACTION_BLOCK)) return TRUE - if(SEND_SIGNAL(user, COMSIG_TRY_USE_MACHINE, src) & COMPONENT_CANT_USE_MACHINE) + if(SEND_SIGNAL(user, COMSIG_TRY_USE_MACHINE, src) & COMPONENT_CANT_USE_MACHINE_INTERACT) return TRUE return ..() @@ -779,3 +806,8 @@ var/alertstr = "Network Alert: Hacking attempt detected[get_area(src)?" in [get_area_name(src, TRUE)]":". Unable to pinpoint location"]." for(var/mob/living/silicon/ai/AI in GLOB.player_list) to_chat(AI, alertstr) + +/obj/machinery/proc/update_last_used(mob/user) + if(isliving(user)) + last_used_time = world.time + last_user_mobtype = user.type diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 7996183ede3..a49dd97338d 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -325,6 +325,9 @@ GLOBAL_LIST_EMPTY(PDAs) dat += "
  • [PDAIMG(rdoor)]Toggle Remote Door
  • " if (cartridge.access & CART_DRONEPHONE) dat += "
  • [PDAIMG(dronephone)]Drone Phone
  • " + if (cartridge.access & CART_DRONEACCESS) + var/blacklist_state = GLOB.drone_machine_blacklist_enabled + dat += "
  • [PDAIMG(droneblacklist)][blacklist_state ? "Disable" : "Enable"] Drone Blacklist
  • " dat += "
  • [PDAIMG(atmos)]Atmospheric Scan
  • " dat += "
  • [PDAIMG(flashlight)][light_on ? "Disable" : "Enable"] Flashlight
  • " if (pai) @@ -589,6 +592,15 @@ GLOBAL_LIST_EMPTY(PDAs) to_chat(U, msg) if(!silent) playsound(src, 'sound/machines/terminal_success.ogg', 15, TRUE) + if("Drone Access") + var/mob/living/simple_animal/drone/drone_user = U + if(isdrone(U) && drone_user.shy) + to_chat(U, "Your laws prevent this action.") + return + var/new_state = text2num(href_list["drone_blacklist"]) + GLOB.drone_machine_blacklist_enabled = new_state + if(!silent) + playsound(src, 'sound/machines/terminal_select.ogg', 15, TRUE) //NOTEKEEPER FUNCTIONS=================================== diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm index ea9f00921c5..b32f7120f34 100644 --- a/code/game/objects/items/devices/PDA/cart.dm +++ b/code/game/objects/items/devices/PDA/cart.dm @@ -1,21 +1,3 @@ - -#define CART_SECURITY (1<<0) -#define CART_ENGINE (1<<1) -#define CART_ATMOS (1<<2) -#define CART_MEDICAL (1<<3) -#define CART_MANIFEST (1<<4) -#define CART_CLOWN (1<<5) -#define CART_MIME (1<<6) -#define CART_JANITOR (1<<7) -#define CART_REAGENT_SCANNER (1<<8) -#define CART_NEWSCASTER (1<<9) -#define CART_REMOTE_DOOR (1<<10) -#define CART_STATUS_DISPLAY (1<<11) -#define CART_QUARTERMASTER (1<<12) -#define CART_HYDROPONICS (1<<13) -#define CART_DRONEPHONE (1<<14) - - /obj/item/cartridge name = "generic cartridge" desc = "A data cartridge for portable microcomputers." @@ -160,7 +142,7 @@ /obj/item/cartridge/ce name = "\improper Power-On DELUXE cartridge" icon_state = "cart-ce" - access = CART_MANIFEST | CART_STATUS_DISPLAY | CART_ENGINE | CART_ATMOS | CART_DRONEPHONE + access = CART_MANIFEST | CART_STATUS_DISPLAY | CART_ENGINE | CART_ATMOS | CART_DRONEPHONE | CART_DRONEACCESS bot_access_flags = FLOOR_BOT | FIRE_BOT /obj/item/cartridge/cmo diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm index ebe4f6dfad9..4b0713257a9 100644 --- a/code/modules/asset_cache/asset_list_items.dm +++ b/code/modules/asset_cache/asset_list_items.dm @@ -90,7 +90,8 @@ "skills" = 'icons/pda_icons/pda_skills.png', "status" = 'icons/pda_icons/pda_status.png', "dronephone" = 'icons/pda_icons/pda_dronephone.png', - "emoji" = 'icons/pda_icons/pda_emoji.png' + "emoji" = 'icons/pda_icons/pda_emoji.png', + "droneblacklist" = 'icons/pda_icons/pda_droneblacklist.png', ) /datum/asset/spritesheet/simple/paper diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm index 70023c9e721..babdcd62ede 100644 --- a/code/modules/atmospherics/machinery/airalarm.dm +++ b/code/modules/atmospherics/machinery/airalarm.dm @@ -77,7 +77,7 @@ var/locked = TRUE var/aidisabled = 0 var/shorted = 0 - var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone + var/buildstage = AIRALARM_BUILD_COMPLETE // 2 = complete, 1 = no wires, 0 = circuit gone var/frequency = FREQ_ATMOS_CONTROL var/alarm_frequency = FREQ_ATMOS_ALARMS @@ -219,7 +219,7 @@ setDir(ndir) if(nbuild) - buildstage = 0 + buildstage = AIRALARM_BUILD_NO_CIRCUIT panel_open = TRUE pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24) pixel_y = (dir & 3)? (dir == 1 ? -24 : 24) : 0 @@ -244,11 +244,11 @@ /obj/machinery/airalarm/examine(mob/user) . = ..() switch(buildstage) - if(0) + if(AIRALARM_BUILD_NO_CIRCUIT) . += "It is missing air alarm electronics." - if(1) + if(AIRALARM_BUILD_NO_WIRES) . += "It is missing wiring." - if(2) + if(AIRALARM_BUILD_COMPLETE) . += "Alt-click to [locked ? "unlock" : "lock"] the interface." /obj/machinery/airalarm/ui_status(mob/user) @@ -391,7 +391,7 @@ /obj/machinery/airalarm/ui_act(action, params) . = ..() - if(. || buildstage != 2) + if(. || buildstage != AIRALARM_BUILD_COMPLETE) return if((locked && !usr.has_unlimited_silicon_privilege) || (usr.has_unlimited_silicon_privilege && aidisabled)) return @@ -644,11 +644,11 @@ /obj/machinery/airalarm/update_icon_state() if(panel_open) switch(buildstage) - if(2) + if(AIRALARM_BUILD_COMPLETE) icon_state = "alarmx" - if(1) + if(AIRALARM_BUILD_NO_WIRES) icon_state = "alarm_b2" - if(0) + if(AIRALARM_BUILD_NO_CIRCUIT) icon_state = "alarm_b1" return ..() @@ -737,42 +737,62 @@ update_appearance() +/obj/machinery/airalarm/crowbar_act(mob/living/user, obj/item/tool) + if(buildstage != AIRALARM_BUILD_NO_WIRES) + return + user.visible_message("[user.name] removes the electronics from [name].", \ + "You start prying out the circuit...") + tool.play_tool_sound(src) + if (tool.use_tool(src, user, 20)) + if (buildstage == AIRALARM_BUILD_NO_WIRES) + to_chat(user, "You remove the air alarm electronics.") + new /obj/item/electronics/airalarm(drop_location()) + playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) + buildstage = AIRALARM_BUILD_NO_CIRCUIT + update_appearance() + return TRUE + +/obj/machinery/airalarm/screwdriver_act(mob/living/user, obj/item/tool) + if(buildstage != AIRALARM_BUILD_COMPLETE) + return + tool.play_tool_sound(src) + panel_open = !panel_open + to_chat(user, "The wires have been [panel_open ? "exposed" : "unexposed"].") + update_appearance() + return TRUE + +/obj/machinery/airalarm/wirecutter_act(mob/living/user, obj/item/tool) + if(!(buildstage == AIRALARM_BUILD_COMPLETE && panel_open && wires.is_all_cut())) + return + tool.play_tool_sound(src) + to_chat(user, "You cut the final wires.") + var/obj/item/stack/cable_coil/cables = new(drop_location(), 5) + user.put_in_hands(cables) + buildstage = AIRALARM_BUILD_NO_WIRES + update_appearance() + return TRUE + +/obj/machinery/airalarm/wrench_act(mob/living/user, obj/item/tool) + if(buildstage != AIRALARM_BUILD_NO_CIRCUIT) + return + to_chat(user, "You detach \the [src] from the wall.") + tool.play_tool_sound(src) + var/obj/item/wallframe/airalarm/alarm_frame = new(drop_location()) + user.put_in_hands(alarm_frame) + qdel(src) + return TRUE + /obj/machinery/airalarm/attackby(obj/item/W, mob/user, params) + update_last_used(user) switch(buildstage) - if(2) - if(W.tool_behaviour == TOOL_WIRECUTTER && panel_open && wires.is_all_cut()) - W.play_tool_sound(src) - to_chat(user, "You cut the final wires.") - new /obj/item/stack/cable_coil(loc, 5) - buildstage = 1 - update_appearance() - return - else if(W.tool_behaviour == TOOL_SCREWDRIVER) // Opening that Air Alarm up. - W.play_tool_sound(src) - panel_open = !panel_open - to_chat(user, "The wires have been [panel_open ? "exposed" : "unexposed"].") - update_appearance() - return - else if(W.GetID())// trying to unlock the interface with an ID card + if(AIRALARM_BUILD_COMPLETE) + if(W.GetID())// trying to unlock the interface with an ID card togglelock(user) return else if(panel_open && is_wire_tool(W)) wires.interact(user) return - if(1) - if(W.tool_behaviour == TOOL_CROWBAR) - user.visible_message("[user.name] removes the electronics from [src.name].", \ - "You start prying out the circuit...") - W.play_tool_sound(src) - if (W.use_tool(src, user, 20)) - if (buildstage == 1) - to_chat(user, "You remove the air alarm electronics.") - new /obj/item/electronics/airalarm( src.loc ) - playsound(src.loc, 'sound/items/deconstruct.ogg', 50, TRUE) - buildstage = 0 - update_appearance() - return - + if(AIRALARM_BUILD_NO_WIRES) if(istype(W, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/cable = W if(cable.get_amount() < 5) @@ -781,7 +801,7 @@ user.visible_message("[user.name] wires the air alarm.", \ "You start wiring the air alarm...") if (do_after(user, 20, target = src)) - if (cable.get_amount() >= 5 && buildstage == 1) + if (cable.get_amount() >= 5 && buildstage == AIRALARM_BUILD_NO_WIRES) cable.use(5) to_chat(user, "You wire the air alarm.") wires.repair() @@ -790,14 +810,14 @@ mode = 1 shorted = 0 post_alert(0) - buildstage = 2 + buildstage = AIRALARM_BUILD_COMPLETE update_appearance() return - if(0) + if(AIRALARM_BUILD_NO_CIRCUIT) if(istype(W, /obj/item/electronics/airalarm)) if(user.temporarilyRemoveItemFromInventory(W)) to_chat(user, "You insert the circuit.") - buildstage = 1 + buildstage = AIRALARM_BUILD_NO_WIRES update_appearance() qdel(W) return @@ -808,21 +828,14 @@ return user.visible_message("[user] fabricates a circuit and places it into [src].", \ "You adapt an air alarm circuit and slot it into the assembly.") - buildstage = 1 + buildstage = AIRALARM_BUILD_NO_WIRES update_appearance() return - if(W.tool_behaviour == TOOL_WRENCH) - to_chat(user, "You detach \the [src] from the wall.") - W.play_tool_sound(src) - new /obj/item/wallframe/airalarm( user.loc ) - qdel(src) - return - return ..() /obj/machinery/airalarm/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) - if((buildstage == 0) && (the_rcd.upgrade & RCD_UPGRADE_SIMPLE_CIRCUITS)) + if((buildstage == AIRALARM_BUILD_NO_CIRCUIT) && (the_rcd.upgrade & RCD_UPGRADE_SIMPLE_CIRCUITS)) return list("mode" = RCD_UPGRADE_SIMPLE_CIRCUITS, "delay" = 20, "cost" = 1) return FALSE @@ -831,7 +844,7 @@ if(RCD_UPGRADE_SIMPLE_CIRCUITS) user.visible_message("[user] fabricates a circuit and places it into [src].", \ "You adapt an air alarm circuit and slot it into the assembly.") - buildstage = 1 + buildstage = AIRALARM_BUILD_NO_WIRES update_appearance() return TRUE return FALSE diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm index 76dc368dbc2..abc8a99babf 100644 --- a/code/modules/awaymissions/corpse.dm +++ b/code/modules/awaymissions/corpse.dm @@ -88,7 +88,7 @@ if(!random || newname) if(newname) M.real_name = newname - else + else if(!M.unique_name) M.real_name = mob_name ? mob_name : M.name if(!mob_gender) mob_gender = pick(MALE, FEMALE) diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm index a11d7c47037..67a7f78dc4c 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -122,27 +122,35 @@ " - Interacting with living beings (communication, attacking, healing, etc.)\n"+\ " - Interacting with non-living beings (dragging bodies, looting bodies, etc.)\n"+\ "These rules are at admin discretion and will be heavily enforced.\n"+\ - "If you do not have the regular drone laws, follow your laws to the best of your ability." + "If you do not have the regular drone laws, follow your laws to the best of your ability.\n"+\ + "Prefix your message with :b to speak in Drone Chat.\n" /// blacklisted drone areas, direct var/list/drone_area_blacklist_flat = list(/area/engineering/atmos, /area/engineering/atmospherics_engine) /// blacklisted drone areas, recursive/includes descendants var/list/drone_area_blacklist_recursive = list(/area/engineering/supermatter) - /// whitelisted drone machines, direct - var/list/drone_machinery_whitelist_flat - /// whitelisted drone machines, recursive/includes descendants - var/list/drone_machinery_whitelist_recursive = list( - /obj/machinery/atmospherics, - /obj/machinery/autolathe, - /obj/machinery/cell_charger, - /obj/machinery/disposal, - /obj/machinery/drone_dispenser, - /obj/machinery/light, - /obj/machinery/pipedispenser, - /obj/machinery/recharger, - /obj/machinery/rnd/production, + /// blacklisted drone machines, direct + var/list/drone_machinery_blacklist_flat + /// blacklisted drone machines, recursive/includes descendants + var/list/drone_machinery_blacklist_recursive = list( + /obj/machinery/airalarm, + /obj/machinery/computer, + /obj/machinery/modular_computer, ) + /// cancels out blacklisted machines, direct + var/list/drone_machinery_whitelist_flat + /// cancels out blacklisted machines, recursive/includes descendants + var/list/drone_machinery_whitelist_recursive = list( + /obj/machinery/computer/arcade, + /obj/machinery/computer/monitor, + /obj/machinery/computer/pod, + /obj/machinery/computer/station_alert, + /obj/machinery/computer/teleporter, + ) + /// blacklisted drone machine typecache, compiled from [var/drone_machinery_blacklist_flat], [var/list/drone_machinery_blacklist_recursive], negated by their whitelist counterparts + var/list/drone_machinery_blacklist_compiled /// whitelisted drone items, direct var/list/drone_item_whitelist_flat = list( + /obj/item/chisel, /obj/item/crowbar/drone, /obj/item/screwdriver/drone, /obj/item/wrench/drone, @@ -166,6 +174,7 @@ /obj/item/stack/tile, /obj/item/stock_parts, /obj/item/toner, + /obj/item/wallframe, /obj/item/clothing/head, /obj/item/clothing/mask, ) @@ -360,26 +369,47 @@ if(cleared) to_chat(src, "--- [class] alarm in [A.name] has been cleared.") +/mob/living/simple_animal/drone/proc/blacklist_on_try_use_machine(datum/source, obj/machinery/machine) + SIGNAL_HANDLER + if(GLOB.drone_machine_blacklist_enabled && is_type_in_typecache(machine, drone_machinery_blacklist_compiled)) + to_chat(src, "Using [machine] could break your laws.") + return COMPONENT_CANT_USE_MACHINE_INTERACT | COMPONENT_CANT_USE_MACHINE_TOOLS + +/mob/living/simple_animal/drone/proc/blacklist_on_try_wires_interact(datum/source, atom/machine) + SIGNAL_HANDLER + if(GLOB.drone_machine_blacklist_enabled && is_type_in_typecache(machine, drone_machinery_blacklist_compiled)) + to_chat(src, "Using [machine] could break your laws.") + return COMPONENT_CANT_INTERACT_WIRES + + /mob/living/simple_animal/drone/proc/set_shy(new_shy) shy = new_shy shy_update() /mob/living/simple_animal/drone/proc/shy_update() var/list/drone_bad_areas = make_associative(drone_area_blacklist_flat) + typecacheof(drone_area_blacklist_recursive) - var/list/drone_good_machines = make_associative(drone_machinery_whitelist_flat) + typecacheof(drone_machinery_whitelist_recursive) var/list/drone_good_items = make_associative(drone_item_whitelist_flat) + typecacheof(drone_item_whitelist_recursive) + + var/list/drone_bad_machinery = make_associative(drone_machinery_blacklist_flat) + typecacheof(drone_machinery_blacklist_recursive) + var/list/drone_good_machinery = LAZYCOPY(drone_machinery_whitelist_flat) + typecacheof(drone_machinery_whitelist_recursive) // not a valid typecache, only intended for negation against drone_bad_machinery + drone_machinery_blacklist_compiled = drone_bad_machinery - drone_good_machinery + + var/static/list/not_shy_of = typecacheof(list(/mob/living/simple_animal/drone, /mob/living/simple_animal/bot)) if(shy) ADD_TRAIT(src, TRAIT_PACIFISM, DRONE_SHY_TRAIT) - LoadComponent(/datum/component/shy, typecacheof(/mob/living/simple_animal/drone), 4, "Your laws prevent this action near %TARGET.", TRUE) + LoadComponent(/datum/component/shy, not_shy_of, 4, "Your laws prevent this action near %TARGET.", TRUE) LoadComponent(/datum/component/shy_in_room, drone_bad_areas, "Touching anything in %ROOM could break your laws.") - LoadComponent(/datum/component/technointrovert, drone_good_machines, "Using %TARGET could break your laws.") + LoadComponent(/datum/component/technoshy, 5 MINUTES, "%TARGET was touched by a being recently, using it could break your laws.") LoadComponent(/datum/component/itempicky, drone_good_items, "Using %TARGET could break your laws.") + RegisterSignal(src, COMSIG_TRY_USE_MACHINE, .proc/blacklist_on_try_use_machine) + RegisterSignal(src, COMSIG_TRY_WIRES_INTERACT, .proc/blacklist_on_try_wires_interact) else REMOVE_TRAIT(src, TRAIT_PACIFISM, DRONE_SHY_TRAIT) qdel(GetComponent(/datum/component/shy)) qdel(GetComponent(/datum/component/shy_in_room)) - qdel(GetComponent(/datum/component/technointrovert)) + qdel(GetComponent(/datum/component/technoshy)) qdel(GetComponent(/datum/component/itempicky)) + UnregisterSignal(src, list(COMSIG_TRY_USE_MACHINE, COMSIG_TRY_WIRES_INTERACT)) /mob/living/simple_animal/drone/handle_temperature_damage() return diff --git a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm index 6c7923c3e0c..bc308319b4b 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm @@ -42,6 +42,10 @@ return ..() var/required_role = CONFIG_GET(string/drone_required_role) var/required_playtime = CONFIG_GET(number/drone_role_playtime) * 60 + if(CONFIG_GET(flag/use_exp_restrictions_admin_bypass) && check_rights_for(user.client, R_ADMIN)) + return ..() + if(user?.client?.prefs.db_flags & DB_FLAG_EXEMPT) + return ..() if(required_playtime <= 0) return ..() var/current_playtime = user_client?.calc_exp_type(required_role) diff --git a/icons/pda_icons/pda_droneblacklist.png b/icons/pda_icons/pda_droneblacklist.png new file mode 100644 index 00000000000..98fd4a444ef Binary files /dev/null and b/icons/pda_icons/pda_droneblacklist.png differ diff --git a/tgstation.dme b/tgstation.dme index b6db99aa883..424104c2471 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -48,6 +48,7 @@ #include "code\__DEFINES\construction.dm" #include "code\__DEFINES\cooldowns.dm" #include "code\__DEFINES\cult.dm" +#include "code\__DEFINES\devices.dm" #include "code\__DEFINES\diseases.dm" #include "code\__DEFINES\DNA.dm" #include "code\__DEFINES\do_afters.dm" @@ -556,6 +557,7 @@ #include "code\datums\components\tackle.dm" #include "code\datums\components\tactical.dm" #include "code\datums\components\technointrovert.dm" +#include "code\datums\components\technoshy.dm" #include "code\datums\components\tether.dm" #include "code\datums\components\thermite.dm" #include "code\datums\components\twohanded.dm"