From 4756a4414186866b4c4401e9e5a716038505b9f1 Mon Sep 17 00:00:00 2001 From: Stonetear <89315023+Stonetear@users.noreply.github.com> Date: Sun, 7 Sep 2025 03:27:38 -0700 Subject: [PATCH] MODSuit procs now pass who clicked the UI button + misc code cleanup (#92424) ## About The Pull Request Most of these changes are centered around removing `mod.wearer` references in module function bubble alerts. However, I cleaned up a few other things that I thought were easy fixes. ~~This PR should be testmerged~~ nah send it. I think I did a pretty good job testing, but there might be a bug or two I missed. (debug modsuit should allow conflicting modules and have unlimited complexity btw) ### Track who clicks the activate button * Adds `mob/activator` to `on_select()`, `activate()`, `deactivate()`, `used()`, `on_activation()`, `on_deactivation()` and `on_use()` * `mod_ui` now passes `ui.user`, which is who actually clicked the button in the UI.1 * module action proc now passes the person clicking. * **Alert bubbles:** Modifies many module code bubbles to pass the activation bubble text to `mob/activator` instead of `mob.wearer` so that pAIs get feedback on why clicking the button isn't working. ### Cargo clamp * **Clamp code cleanup:** The cargo clamp now has a variable for the max creature weight it can support, and the logic is changed around a bit to support this. * The cargo clamp uses an `accepted_items` typecache. ### Code cleanup * **Button malfunction chance** is controlled by a `MOD_MALFUNCTION_PROB` define. * **Pathfinder runtime:** `mod_control`'s `GetAccess()` now checks if there is an access before returning it. (This previously caused runtimes when using the pathfinder module if you didn't swipe your ID) * **Pathfinder code tweaks:** Reworks the code for the pathfinder module a bit. Activation logic is now stored in the module instead of the implant. The suit is prevented from being recalled by pAIs, which is controlled by a variable. * Adds `MODULE_ALLOW_UNWORN`, which lets you activate modules in suits that aren't currently being worn. Module activation code now smoothly supports modules being activated while not worn. * Chameleon module now works when unworn. This will probably be a Part 1, with a Part 2 to follow. Actions are kinda funky and could probably be cleaned up a little better. Plus, I want to make selectable modules theoretically usable by the AI, even if I leave it disabled. ## Why It's Good For The Game This PR doesn't contain any balance changes, and I manually disabled any new serious functionality that pAIs might gain. (Such as being able to activate the pathfinder implant) They *can* use the chameleon module with no wearer- but I'm going to consider this a bug that they couldn't before. Paves the way for more pAI modsuit nonsense I'm doing downsteam. ## Changelog :cl: Stonetear refactor: MODsuit module code now knows who clicked the activation button. /:cl: --------- Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com> --- code/__DEFINES/ai/ai_blackboard.dm | 4 +- code/__DEFINES/mod.dm | 5 + code/datums/ai/objects/mod.dm | 14 +- code/modules/mod/mod_actions.dm | 4 +- code/modules/mod/mod_control.dm | 2 +- code/modules/mod/mod_ui.dm | 4 +- code/modules/mod/modules/_module.dm | 77 ++++---- code/modules/mod/modules/module_kinesis.dm | 2 +- code/modules/mod/modules/module_pathfinder.dm | 168 ++++++++++-------- code/modules/mod/modules/modules_antag.dm | 14 +- .../mod/modules/modules_engineering.dm | 8 +- code/modules/mod/modules/modules_general.dm | 24 +-- code/modules/mod/modules/modules_maint.dm | 18 +- code/modules/mod/modules/modules_ninja.dm | 12 +- code/modules/mod/modules/modules_science.dm | 12 +- code/modules/mod/modules/modules_security.dm | 22 +-- code/modules/mod/modules/modules_service.dm | 2 +- code/modules/mod/modules/modules_supply.dm | 40 +++-- code/modules/mod/modules/modules_timeline.dm | 21 +-- code/modules/mod/modules/modules_visor.dm | 12 +- 20 files changed, 256 insertions(+), 209 deletions(-) diff --git a/code/__DEFINES/ai/ai_blackboard.dm b/code/__DEFINES/ai/ai_blackboard.dm index 1b94abc95c1..ebcd71345ee 100644 --- a/code/__DEFINES/ai/ai_blackboard.dm +++ b/code/__DEFINES/ai/ai_blackboard.dm @@ -171,8 +171,8 @@ ///Mob the MOD is trying to attach to #define BB_MOD_TARGET "BB_mod_target" -///The implant the AI was created from -#define BB_MOD_IMPLANT "BB_mod_implant" +///The module the AI was created from +#define BB_MOD_MODULE "BB_mod_module" ///Range for a MOD AI controller. #define MOD_AI_RANGE 200 diff --git a/code/__DEFINES/mod.dm b/code/__DEFINES/mod.dm index 1a4bed1ca99..5760dc5a05f 100644 --- a/code/__DEFINES/mod.dm +++ b/code/__DEFINES/mod.dm @@ -7,6 +7,9 @@ /// Default time for a part of the suit to seal. #define MOD_ACTIVATION_STEP_TIME (1 SECONDS) +/// How likely the UI is to fail when malfunctioning +#define MOD_MALFUNCTION_PROB 75 + /// Passive module, just acts when put in naturally. #define MODULE_PASSIVE 0 /// Usable module, does something when you press a button. @@ -22,6 +25,8 @@ #define MODULE_ALLOW_INCAPACITATED (1<<1) /// This module can be used while the suit is off #define MODULE_ALLOW_INACTIVE (1<<2) +/// This module can be used (by button) while the suit is unworn +#define MODULE_ALLOW_UNWORN (1<<3) #define UNSEALED_LAYER "unsealed_layer" #define SEALED_LAYER "sealed_layer" diff --git a/code/datums/ai/objects/mod.dm b/code/datums/ai/objects/mod.dm index 2b4c1f7e2b0..46b41adb1c8 100644 --- a/code/datums/ai/objects/mod.dm +++ b/code/datums/ai/objects/mod.dm @@ -1,8 +1,8 @@ -/// An AI controller for the MODsuit pathfinder module. It's activated by implant and attaches itself to the user. +/// An AI controller for the MODsuit pathfinder module. It's activated by module and attaches itself to the user. /datum/ai_controller/mod blackboard = list( BB_MOD_TARGET, - BB_MOD_IMPLANT, + BB_MOD_MODULE, ) can_idle = FALSE max_target_distance = MOD_AI_RANGE //a little spicy but its one specific item that summons it, and it doesn't run otherwise @@ -25,7 +25,7 @@ /datum/ai_controller/mod/SelectBehaviors(seconds_per_tick) current_behaviors = list() - if(blackboard[BB_MOD_TARGET] && blackboard[BB_MOD_IMPLANT]) + if(blackboard[BB_MOD_TARGET] && blackboard[BB_MOD_MODULE]) queue_behavior(/datum/ai_behavior/mod_attach) /datum/ai_controller/mod/get_access() @@ -37,12 +37,12 @@ /datum/ai_behavior/mod_attach/perform(seconds_per_tick, datum/ai_controller/controller) if(!controller.pawn.Adjacent(controller.blackboard[BB_MOD_TARGET])) return AI_BEHAVIOR_DELAY - var/obj/item/implant/mod/implant = controller.blackboard[BB_MOD_IMPLANT] - implant.module.attach(controller.blackboard[BB_MOD_TARGET]) + var/obj/item/mod/module/pathfinder/module = controller.blackboard[BB_MOD_MODULE] + module.attach(controller.blackboard[BB_MOD_TARGET]) return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/mod_attach/finish_action(datum/ai_controller/controller, succeeded) . = ..() controller.clear_blackboard_key(BB_MOD_TARGET) - var/obj/item/implant/mod/implant = controller.blackboard[BB_MOD_IMPLANT] - implant.end_recall(succeeded) + var/obj/item/mod/module/pathfinder/module = controller.blackboard[BB_MOD_MODULE] + module.end_recall(succeeded) diff --git a/code/modules/mod/mod_actions.dm b/code/modules/mod/mod_actions.dm index d0424d9682d..8385b657671 100644 --- a/code/modules/mod/mod_actions.dm +++ b/code/modules/mod/mod_actions.dm @@ -32,7 +32,7 @@ /datum/action/item_action/mod/do_effect(trigger_flags) var/obj/item/mod/control/mod = target - if(mod.malfunctioning && prob(75)) + if(mod.malfunctioning && prob(MOD_MALFUNCTION_PROB)) mod.balloon_alert(usr, "button malfunctions!") return FALSE return TRUE @@ -182,7 +182,7 @@ . = ..() if(!.) return - module.on_select() + module.on_select(owner) /datum/action/item_action/mod/pinnable/module/apply_button_overlay(atom/movable/screen/movable/action_button/current_button, force) current_button.cut_overlays() diff --git a/code/modules/mod/mod_control.dm b/code/modules/mod/mod_control.dm index 883eee631d0..cb4689e81d0 100644 --- a/code/modules/mod/mod_control.dm +++ b/code/modules/mod/mod_control.dm @@ -378,7 +378,7 @@ return cell /obj/item/mod/control/GetAccess() - if(ai_controller) + if(ai_controller && req_access) return req_access.Copy() else return ..() diff --git a/code/modules/mod/mod_ui.dm b/code/modules/mod/mod_ui.dm index 9a8e77f7e8e..e25c3b2a836 100644 --- a/code/modules/mod/mod_ui.dm +++ b/code/modules/mod/mod_ui.dm @@ -86,7 +86,7 @@ . = ..() if(.) return - if(malfunctioning && prob(75)) + if(malfunctioning && prob(MOD_MALFUNCTION_PROB)) balloon_alert(ui.user, "button malfunctions!") return switch(action) @@ -108,7 +108,7 @@ var/obj/item/mod/module/module = locate(params["ref"]) in modules if(!module) return - module.on_select() + module.on_select(ui.user) // We can now if("configure") var/obj/item/mod/module/module = locate(params["ref"]) in modules if(!module) diff --git a/code/modules/mod/modules/_module.dm b/code/modules/mod/modules/_module.dm index 5f0be8207f9..57765677d46 100644 --- a/code/modules/mod/modules/_module.dm +++ b/code/modules/mod/modules/_module.dm @@ -105,32 +105,29 @@ return TRUE /// Called when the module is selected from the TGUI, radial or the action button -/obj/item/mod/module/proc/on_select() - if(!mod.wearer) - if(ismob(mod.loc)) - balloon_alert(mod.loc, "not equipped!") +/obj/item/mod/module/proc/on_select(mob/activator) + if(!mod.wearer && !(allow_flags & MODULE_ALLOW_UNWORN)) //No wearer and cannot be used unworn + balloon_alert(activator, "not equipped!") return - if(((!mod.active || mod.activating) && !(allow_flags & MODULE_ALLOW_INACTIVE)) || module_type == MODULE_PASSIVE) - if(mod.wearer) - balloon_alert(mod.wearer, "not active!") + if(((!mod.active || mod.activating) && !(allow_flags & (MODULE_ALLOW_INACTIVE | MODULE_ALLOW_UNWORN))) || module_type == MODULE_PASSIVE) // not active + balloon_alert(activator, "not active!") return - if(!has_required_parts(mod.mod_parts, need_active = TRUE)) - if(mod.wearer) - balloon_alert(mod.wearer, "required parts inactive!") - var/list/slot_strings = list() - for(var/slot in required_slots) - var/list/slot_list = parse_slot_flags(slot) - slot_strings += (length(slot_list) == 1 ? "" : "one of ") + english_list(slot_list, and_text = " or ") - to_chat(mod.wearer, span_warning("[src] requires these slots to be deployed: [english_list(slot_strings)]")) - playsound(src, 'sound/machines/scanner/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + if(!has_required_parts(mod.mod_parts, need_active = TRUE) && !(allow_flags & MODULE_ALLOW_UNWORN)) // Doesn't have parts + balloon_alert(activator, "required parts inactive!") + var/list/slot_strings = list() + for(var/slot in required_slots) + var/list/slot_list = parse_slot_flags(slot) + slot_strings += (length(slot_list) == 1 ? "" : "one of ") + english_list(slot_list, and_text = " or ") + to_chat(activator, span_warning("[src] requires these slots to be deployed: [english_list(slot_strings)]")) + playsound(src, 'sound/machines/scanner/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) return if(module_type != MODULE_USABLE) if(active) - deactivate() + deactivate(activator) else - activate() + activate(activator) else - used() + used(activator) SEND_SIGNAL(mod, COMSIG_MOD_MODULE_SELECTED, src) /// Apply a cooldown until this item can be used again @@ -141,16 +138,16 @@ SEND_SIGNAL(src, COMSIG_MODULE_COOLDOWN_STARTED, applied_cooldown) /// Called when the module is activated -/obj/item/mod/module/proc/activate() +/obj/item/mod/module/proc/activate(mob/activator) if(!COOLDOWN_FINISHED(src, cooldown_timer)) - balloon_alert(mod.wearer, "on cooldown!") + balloon_alert(activator, "on cooldown!") return FALSE if(!mod.active || mod.activating || !mod.get_charge()) - balloon_alert(mod.wearer, "unpowered!") + balloon_alert(activator, "unpowered!") return FALSE if(!(allow_flags & MODULE_ALLOW_PHASEOUT) && istype(mod.wearer.loc, /obj/effect/dummy/phased_mob)) //specifically a to_chat because the user is phased out. - to_chat(mod.wearer, span_warning("You cannot activate this right now.")) + to_chat(activator, span_warning("You cannot activate this right now.")) return FALSE if(SEND_SIGNAL(src, COMSIG_MODULE_TRIGGERED, mod.wearer) & MOD_ABORT_USE) return FALSE @@ -160,25 +157,25 @@ mod.selected_module = src if(device) if(mod.wearer.put_in_hands(device)) - balloon_alert(mod.wearer, "[device] extended") + balloon_alert(activator, "[device] extended") RegisterSignal(mod.wearer, COMSIG_ATOM_EXITED, PROC_REF(on_exit)) RegisterSignal(mod.wearer, COMSIG_KB_MOB_DROPITEM_DOWN, PROC_REF(dropkey)) else - balloon_alert(mod.wearer, "can't extend [device]!") + balloon_alert(activator, "can't extend [device]!") mod.wearer.transferItemToLoc(device, src, force = TRUE) return FALSE else var/used_button = mod.wearer.client?.prefs.read_preference(/datum/preference/choiced/mod_select) || MIDDLE_CLICK update_signal(used_button) - balloon_alert(mod.wearer, "[src] activated, [used_button]-click to use") + balloon_alert(mod.wearer, "[src] activated, [used_button]-click to use") // As of now, only wearers can "use" mods active = TRUE SEND_SIGNAL(src, COMSIG_MODULE_ACTIVATED) - on_activation() + on_activation(activator) update_clothing_slots() return TRUE /// Called when the module is deactivated -/obj/item/mod/module/proc/deactivate(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/proc/deactivate(mob/activator, display_message = TRUE, deleting = FALSE) active = FALSE if(module_type == MODULE_ACTIVE) mod.selected_module = null @@ -192,12 +189,15 @@ UnregisterSignal(mod.wearer, used_signal) used_signal = null SEND_SIGNAL(src, COMSIG_MODULE_DEACTIVATED, mod.wearer) - on_deactivation(display_message = TRUE, deleting = FALSE) + on_deactivation(activator, display_message = TRUE, deleting = FALSE) update_clothing_slots() return TRUE /// Call to update all slots visually affected by this module /obj/item/mod/module/proc/update_clothing_slots() + if(!mod.wearer) + return + var/updated_slots = mod.slot_flags if (mask_worn_overlay) for (var/obj/item/part as anything in mod.get_parts()) @@ -208,24 +208,25 @@ mod.wearer.update_clothing(updated_slots) /// Called when the module is used -/obj/item/mod/module/proc/used() +/obj/item/mod/module/proc/used(mob/activator) if(!COOLDOWN_FINISHED(src, cooldown_timer)) - balloon_alert(mod.wearer, "on cooldown!") + balloon_alert(activator, "on cooldown!") return FALSE if(!check_power(use_energy_cost)) - balloon_alert(mod.wearer, "not enough charge!") + balloon_alert(activator, "not enough charge!") return FALSE if(!(allow_flags & MODULE_ALLOW_PHASEOUT) && istype(mod.wearer.loc, /obj/effect/dummy/phased_mob)) //specifically a to_chat because the user is phased out. - to_chat(mod.wearer, span_warning("You cannot activate this right now.")) + to_chat(activator, span_warning("You cannot activate this right now.")) return FALSE if(SEND_SIGNAL(src, COMSIG_MODULE_TRIGGERED, mod.wearer) & MOD_ABORT_USE) return FALSE start_cooldown() - addtimer(CALLBACK(mod.wearer, TYPE_PROC_REF(/mob, update_clothing), mod.slot_flags), cooldown_time+1) //need to run it a bit after the cooldown starts to avoid conflicts + if(mod.wearer) + addtimer(CALLBACK(mod.wearer, TYPE_PROC_REF(/mob, update_clothing), mod.slot_flags), cooldown_time+1) //need to run it a bit after the cooldown starts to avoid conflicts update_clothing_slots() SEND_SIGNAL(src, COMSIG_MODULE_USED) - on_use() + on_use(activator) return TRUE /// Called when an activated module without a device is used @@ -257,15 +258,15 @@ return TRUE /// Called from the module's activate() -/obj/item/mod/module/proc/on_activation() +/obj/item/mod/module/proc/on_activation(mob/activator) return /// Called from the module's deactivate() -/obj/item/mod/module/proc/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/proc/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) return /// Called from the module's used() -/obj/item/mod/module/proc/on_use() +/obj/item/mod/module/proc/on_use(mob/activator) return /// Called on the MODsuit's process if it is an active module diff --git a/code/modules/mod/modules/module_kinesis.dm b/code/modules/mod/modules/module_kinesis.dm index 436d3dc9e87..f79701e7961 100644 --- a/code/modules/mod/modules/module_kinesis.dm +++ b/code/modules/mod/modules/module_kinesis.dm @@ -63,7 +63,7 @@ drain_power(use_energy_cost) grab_atom(target) -/obj/item/mod/module/anomaly_locked/kinesis/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/anomaly_locked/kinesis/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) clear_grab(playsound = !deleting) /obj/item/mod/module/anomaly_locked/kinesis/process(seconds_per_tick) diff --git a/code/modules/mod/modules/module_pathfinder.dm b/code/modules/mod/modules/module_pathfinder.dm index 9f1cec7e9fa..4b948d6ed07 100644 --- a/code/modules/mod/modules/module_pathfinder.dm +++ b/code/modules/mod/modules/module_pathfinder.dm @@ -15,12 +15,22 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 10 incompatible_modules = list(/obj/item/mod/module/pathfinder) required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) + allow_flags = list(MODULE_ALLOW_INACTIVE|MODULE_ALLOW_UNWORN) /// The pathfinding implant. var/obj/item/implant/mod/implant + /// Whether the implant has been used or not + var/implant_inside = TRUE + /// The jet icon we apply to the MOD. + var/image/jet_icon + /// Allow suit activation - Lets this module be recalled from the MOD. + var/allow_suit_activation = FALSE // I'm not here to argue about balance + /obj/item/mod/module/pathfinder/Initialize(mapload) . = ..() implant = new(src) + jet_icon = image(icon = 'icons/obj/clothing/modsuit/mod_modules.dmi', icon_state = "mod_jet", layer = LOW_ITEM_LAYER) + /obj/item/mod/module/pathfinder/Destroy() QDEL_NULL(implant) @@ -28,28 +38,28 @@ /obj/item/mod/module/pathfinder/Exited(atom/movable/gone, direction) if(gone == implant) - implant = null + implant_inside = FALSE update_icon_state() return ..() /obj/item/mod/module/pathfinder/update_icon_state() . = ..() - icon_state = implant ? "pathfinder" : "pathfinder_empty" + icon_state = implant_inside ? "pathfinder" : "pathfinder_empty" /obj/item/mod/module/pathfinder/examine(mob/user) . = ..() - if(implant) + if(implant_inside) . += span_notice("Use it on a human to implant them.") else . += span_warning("The implant is missing.") /obj/item/mod/module/pathfinder/attack(mob/living/target, mob/living/user, list/modifiers, list/attack_modifiers) - if(!ishuman(target) || !implant) + if(!ishuman(target) || !implant_inside) // Not human, or no implant in module return if(!do_after(user, 1.5 SECONDS, target = target)) balloon_alert(user, "interrupted!") return - if(!implant.implant(target, user)) + if(!implant.implant(target, user)) // If implant fails balloon_alert(user, "can't implant!") return if(target == user) @@ -57,21 +67,29 @@ else target.visible_message(span_notice("[user] implants [target]."), span_notice("[user] implants you with [implant].")) playsound(src, 'sound/effects/spray.ogg', 30, TRUE, -6) - module_type = MODULE_PASSIVE -/obj/item/mod/module/pathfinder/on_use() +/obj/item/mod/module/pathfinder/on_use(mob/activator) . = ..() - if (!ishuman(mod.wearer) || !implant) + if(mod.wearer && implant_inside) // implant them + try_implant(activator) + return + if(mod.wearer) + balloon_alert(activator, "suit already worn!") + else + recall(activator) + + +/// Assuming we have a wearer, attempt to implant them. +/obj/item/mod/module/pathfinder/proc/try_implant(mob/activator) + if(!ishuman(mod.wearer)) // Wearer isn't human return if(!implant.implant(mod.wearer, mod.wearer)) - balloon_alert(mod.wearer, "can't implant!") + balloon_alert(activator, "can't implant!") return - balloon_alert(mod.wearer, "implanted") + balloon_alert(activator, "implanted") + if(!(activator == mod.wearer)) // someone else implanted you + balloon_alert(mod.wearer, "pathfinder MOD tracker implanted!") playsound(src, 'sound/effects/spray.ogg', 30, TRUE, -6) - module_type = MODULE_PASSIVE - var/datum/action/item_action/mod/pinnable/module/existing_action = pinned_to[REF(mod.wearer)] - if(existing_action) - mod.remove_item_action(existing_action) /obj/item/mod/module/pathfinder/proc/attach(mob/living/user) if(!ishuman(user)) @@ -87,27 +105,86 @@ playsound(mod, 'sound/machines/ping.ogg', 50, TRUE) drain_power(use_energy_cost) +/obj/item/mod/module/pathfinder/proc/recall(mob/recaller) + if(!implant) + balloon_alert(recaller, "no target implant!") + return FALSE + if(recaller != implant.imp_in && !allow_suit_activation) // No pAI recalling + balloon_alert(recaller, "sector safety regulations prevent MOD-side recalling!") + return FALSE + if(mod.open) + balloon_alert(recaller, "cover open!") + return FALSE + if(mod.ai_controller) + balloon_alert(recaller, "already moving!") + return FALSE + if(ismob(get_atom_on_turf(mod))) + balloon_alert(recaller, "already on someone!") + return FALSE + if(mod.z != implant.imp_in.z || get_dist(implant.imp_in, mod) > MOD_AI_RANGE) + balloon_alert(recaller, "too far!") + return FALSE + var/datum/ai_controller/mod_ai = new /datum/ai_controller/mod(mod) + mod.ai_controller = mod_ai + mod_ai.set_movement_target(type, implant.imp_in) + mod_ai.set_blackboard_key(BB_MOD_TARGET, implant.imp_in) + mod_ai.set_blackboard_key(BB_MOD_MODULE, src) + mod.interaction_flags_item &= ~INTERACT_ITEM_ATTACK_HAND_PICKUP + mod.AddElement(/datum/element/movetype_handler) + ADD_TRAIT(mod, TRAIT_MOVE_FLYING, MOD_TRAIT) + animate(mod, 0.2 SECONDS, pixel_x = base_pixel_y, pixel_y = base_pixel_y) + mod.add_overlay(jet_icon) + RegisterSignal(mod, COMSIG_MOVABLE_MOVED, PROC_REF(on_move)) + balloon_alert(recaller, "suit recalled") + if(!(recaller == mod.wearer)) + balloon_alert(mod.wearer, "suit recalled") + return TRUE + +/obj/item/mod/module/pathfinder/proc/on_move(atom/movable/source, atom/old_loc, dir, forced) + SIGNAL_HANDLER + + var/matrix/mod_matrix = matrix() + mod_matrix.Turn(get_angle(source, implant.imp_in)) + source.transform = mod_matrix + +/obj/item/mod/module/pathfinder/proc/end_recall(successful = TRUE) + if(!mod) + return + QDEL_NULL(mod.ai_controller) + mod.interaction_flags_item |= INTERACT_ITEM_ATTACK_HAND_PICKUP + REMOVE_TRAIT(mod, TRAIT_MOVE_FLYING, MOD_TRAIT) + mod.RemoveElement(/datum/element/movetype_handler) + mod.cut_overlay(jet_icon) + mod.transform = matrix() + UnregisterSignal(mod, COMSIG_MOVABLE_MOVED) + if(!successful) + balloon_alert(implant.imp_in, "suit lost connection!") + +// ########### +// THE INPLANT +// ########### + + /obj/item/implant/mod name = "MOD pathfinder implant" desc = "Lets you recall a MODsuit to you at any time." actions_types = list(/datum/action/item_action/mod_recall) + allow_multiple = TRUE // Surgrey is annoying if you loose your MOD /// The pathfinder module we are linked to. var/obj/item/mod/module/pathfinder/module - /// The jet icon we apply to the MOD. - var/image/jet_icon + + /obj/item/implant/mod/Initialize(mapload) . = ..() if(!istype(loc, /obj/item/mod/module/pathfinder)) return INITIALIZE_HINT_QDEL module = loc - jet_icon = image(icon = 'icons/obj/clothing/modsuit/mod_modules.dmi', icon_state = "mod_jet", layer = LOW_ITEM_LAYER) /obj/item/implant/mod/Destroy() if(module?.mod?.ai_controller) - end_recall(successful = FALSE) + module.end_recall(successful = FALSE) module = null - jet_icon = null return ..() /obj/item/implant/mod/get_data() @@ -115,55 +192,6 @@ Name: Nakamura Engineering Pathfinder Implant
\ Implant Details: Allows for the recall of a Modular Outerwear Device by the implant owner at any time.
" -/obj/item/implant/mod/proc/recall() - if(!module?.mod) - balloon_alert(imp_in, "no connected unit!") - return FALSE - if(module.mod.open) - balloon_alert(imp_in, "cover open!") - return FALSE - if(module.mod.ai_controller) - balloon_alert(imp_in, "already moving!") - return FALSE - if(ismob(get_atom_on_turf(module.mod))) - balloon_alert(imp_in, "already on someone!") - return FALSE - if(module.z != z || get_dist(imp_in, module.mod) > MOD_AI_RANGE) - balloon_alert(imp_in, "too far!") - return FALSE - var/datum/ai_controller/mod_ai = new /datum/ai_controller/mod(module.mod) - module.mod.ai_controller = mod_ai - mod_ai.set_movement_target(type, imp_in) - mod_ai.set_blackboard_key(BB_MOD_TARGET, imp_in) - mod_ai.set_blackboard_key(BB_MOD_IMPLANT, src) - module.mod.interaction_flags_item &= ~INTERACT_ITEM_ATTACK_HAND_PICKUP - module.mod.AddElement(/datum/element/movetype_handler) - ADD_TRAIT(module.mod, TRAIT_MOVE_FLYING, MOD_TRAIT) - animate(module.mod, 0.2 SECONDS, pixel_x = base_pixel_y, pixel_y = base_pixel_y) - module.mod.add_overlay(jet_icon) - RegisterSignal(module.mod, COMSIG_MOVABLE_MOVED, PROC_REF(on_move)) - balloon_alert(imp_in, "suit recalled") - return TRUE - -/obj/item/implant/mod/proc/end_recall(successful = TRUE) - if(!module?.mod) - return - QDEL_NULL(module.mod.ai_controller) - module.mod.interaction_flags_item |= INTERACT_ITEM_ATTACK_HAND_PICKUP - REMOVE_TRAIT(module.mod, TRAIT_MOVE_FLYING, MOD_TRAIT) - module.mod.RemoveElement(/datum/element/movetype_handler) - module.mod.cut_overlay(jet_icon) - module.mod.transform = matrix() - UnregisterSignal(module.mod, COMSIG_MOVABLE_MOVED) - if(!successful) - balloon_alert(imp_in, "suit lost connection!") - -/obj/item/implant/mod/proc/on_move(atom/movable/source, atom/old_loc, dir, forced) - SIGNAL_HANDLER - - var/matrix/mod_matrix = matrix() - mod_matrix.Turn(get_angle(source, imp_in)) - source.transform = mod_matrix /datum/action/item_action/mod_recall name = "Recall MOD" @@ -185,7 +213,7 @@ /datum/action/item_action/mod_recall/do_effect(trigger_flags) var/obj/item/implant/mod/implant = target if(!COOLDOWN_FINISHED(src, recall_cooldown)) - implant.balloon_alert(implant.imp_in, "on cooldown!") + implant.balloon_alert(owner, "on cooldown!") return - if(implant.recall()) + if(implant.module.recall(owner)) // change this COOLDOWN_START(src, recall_cooldown, 15 SECONDS) diff --git a/code/modules/mod/modules/modules_antag.dm b/code/modules/mod/modules/modules_antag.dm index b190d872d39..32b11f23c59 100644 --- a/code/modules/mod/modules/modules_antag.dm +++ b/code/modules/mod/modules/modules_antag.dm @@ -292,7 +292,7 @@ complexity = 2 incompatible_modules = list(/obj/item/mod/module/chameleon) cooldown_time = 0.5 SECONDS - allow_flags = MODULE_ALLOW_INACTIVE + allow_flags = list(MODULE_ALLOW_INACTIVE|MODULE_ALLOW_UNWORN) /// A list of all the items the suit can disguise as. var/list/possible_disguises = list() /// The path of the item we're disguised as. @@ -314,17 +314,17 @@ return_look() possible_disguises = null -/obj/item/mod/module/chameleon/used() +/obj/item/mod/module/chameleon/used(mob/activator) if(mod.active || mod.activating) - balloon_alert(mod.wearer, "unit active!") + balloon_alert(activator, "unit active!") return FALSE return ..() -/obj/item/mod/module/chameleon/on_use() +/obj/item/mod/module/chameleon/on_use(mob/activator) if(current_disguise) return_look() return - var/picked_name = tgui_input_list(mod.wearer, "Select look to change into", "Chameleon Settings", possible_disguises) + var/picked_name = tgui_input_list(activator, "Select look to change into", "Chameleon Settings", possible_disguises) if(!possible_disguises[picked_name] || mod.active || mod.activating) return current_disguise = possible_disguises[picked_name] @@ -506,10 +506,10 @@ if(disrupted.on_saboteur(src, 1 MINUTES)) mod.add_charge(DEFAULT_CHARGE_DRAIN * 250) -/obj/item/mod/module/stealth/wraith/on_activation() +/obj/item/mod/module/stealth/wraith/on_activation(mob/activator) return // Don't activate stealth when the module is activated because the stealth portion of the module is fully passive -/obj/item/mod/module/stealth/wraith/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/stealth/wraith/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) . = ..() UnregisterSignal(mod.wearer, list(COMSIG_LIVING_MOB_BUMP, COMSIG_ATOM_BUMPED, COMSIG_MOB_FIRED_GUN)) diff --git a/code/modules/mod/modules/modules_engineering.dm b/code/modules/mod/modules/modules_engineering.dm index fa28e7aaee6..54c6f09b8b1 100644 --- a/code/modules/mod/modules/modules_engineering.dm +++ b/code/modules/mod/modules/modules_engineering.dm @@ -81,11 +81,11 @@ . = ..() UnregisterSignal(mod, COMSIG_MOD_UPDATE_SPEED) -/obj/item/mod/module/magboot/on_activation() +/obj/item/mod/module/magboot/on_activation(mob/activator) mod.wearer.add_traits(active_traits, REF(src)) mod.update_speed() -/obj/item/mod/module/magboot/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/magboot/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) mod.wearer.remove_traits(active_traits, REF(src)) mod.update_speed() @@ -140,7 +140,7 @@ if (key == "cut_tethers") SEND_SIGNAL(src, COMSIG_MOD_TETHER_SNAP) -/obj/item/mod/module/tether/on_deactivation(display_message, deleting) +/obj/item/mod/module/tether/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) SEND_SIGNAL(src, COMSIG_MOD_TETHER_SNAP) /obj/projectile/tether @@ -394,7 +394,7 @@ /obj/item/mod/module/constructor/on_part_deactivation(deleting = FALSE) REMOVE_TRAIT(mod.wearer, TRAIT_QUICK_BUILD, REF(src)) -/obj/item/mod/module/constructor/on_use() +/obj/item/mod/module/constructor/on_use(mob/activator) rcd_scan(src, fade_time = 10 SECONDS) drain_power(use_energy_cost) diff --git a/code/modules/mod/modules/modules_general.dm b/code/modules/mod/modules/modules_general.dm index da2440dec8f..c1fbaba91f0 100644 --- a/code/modules/mod/modules/modules_general.dm +++ b/code/modules/mod/modules/modules_general.dm @@ -171,12 +171,12 @@ return FALSE return TRUE -/obj/item/mod/module/jetpack/on_activation() +/obj/item/mod/module/jetpack/on_activation(mob/activator) mod.wearer.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/full_speed) if (!stabilize) ADD_TRAIT(mod.wearer, TRAIT_NOGRAV_ALWAYS_DRIFT, REF(src)) -/obj/item/mod/module/jetpack/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/jetpack/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) mod.wearer.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/full_speed) REMOVE_TRAIT(mod.wearer, TRAIT_NOGRAV_ALWAYS_DRIFT, REF(src)) @@ -206,9 +206,9 @@ incompatible_modules = list(/obj/item/mod/module/jump_jet) required_slots = list(ITEM_SLOT_BACK) -/obj/item/mod/module/jump_jet/on_use() +/obj/item/mod/module/jump_jet/on_use(mob/activator) if (DOING_INTERACTION(mod.wearer, mod.wearer)) - balloon_alert(mod.wearer, "busy!") + balloon_alert(activator, "busy!") return balloon_alert(mod.wearer, "launching...") mod.wearer.Shake(duration = 1 SECONDS) @@ -438,12 +438,12 @@ /// Maximum range we can set. var/max_range = 5 -/obj/item/mod/module/flashlight/on_activation() +/obj/item/mod/module/flashlight/on_activation(mob/activator) set_light_flags(light_flags | LIGHT_ATTACHED) set_light_on(active) active_power_cost = base_power * light_range -/obj/item/mod/module/flashlight/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/flashlight/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) set_light_flags(light_flags & ~LIGHT_ATTACHED) set_light_on(active) @@ -518,13 +518,13 @@ /// Time it takes for us to dispense. var/dispense_time = 0 SECONDS -/obj/item/mod/module/dispenser/on_use() +/obj/item/mod/module/dispenser/on_use(mob/activator) if(dispense_time && !do_after(mod.wearer, dispense_time, target = mod)) balloon_alert(mod.wearer, "interrupted!") return FALSE var/obj/item/dispensed = new dispense_type(mod.wearer.loc) mod.wearer.put_in_hands(dispensed) - balloon_alert(mod.wearer, "[dispensed] dispensed") + balloon_alert(activator, "[dispensed] dispensed") playsound(src, 'sound/machines/click.ogg', 100, TRUE) drain_power(use_energy_cost) return dispensed @@ -627,9 +627,9 @@ UnregisterSignal(mod, COMSIG_ATOM_EMP_ACT) UnregisterSignal(mod, COMSIG_ATOM_EMAG_ACT) -/obj/item/mod/module/dna_lock/on_use() +/obj/item/mod/module/dna_lock/on_use(mob/activator) dna = mod.wearer.dna.unique_enzymes - balloon_alert(mod.wearer, "dna updated") + balloon_alert(activator, "dna updated") drain_power(use_energy_cost) /obj/item/mod/module/dna_lock/emp_act(severity) @@ -855,11 +855,11 @@ container = null return ..() -/obj/item/mod/module/recycler/on_activation() +/obj/item/mod/module/recycler/on_activation(mob/activator) connector = AddComponent(/datum/component/connect_loc_behalf, mod.wearer, loc_connections) RegisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED, PROC_REF(on_wearer_moved)) -/obj/item/mod/module/recycler/on_deactivation(display_message, deleting = FALSE) +/obj/item/mod/module/recycler/on_deactivation(mob/activator, display_message, deleting = FALSE) QDEL_NULL(connector) UnregisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED, PROC_REF(on_wearer_moved)) diff --git a/code/modules/mod/modules/modules_maint.dm b/code/modules/mod/modules/modules_maint.dm index 17804dcd406..2e0b2dba3a0 100644 --- a/code/modules/mod/modules/modules_maint.dm +++ b/code/modules/mod/modules/modules_maint.dm @@ -136,12 +136,12 @@ QDEL_NULL(rave_screen) return ..() -/obj/item/mod/module/visor/rave/on_activation() +/obj/item/mod/module/visor/rave/on_activation(mob/activator) rave_screen = mod.wearer.add_client_colour(/datum/client_colour/rave, REF(src)) rave_screen.update_color(rainbow_order[rave_number]) music_player.start_music(mod.wearer) -/obj/item/mod/module/visor/rave/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/visor/rave/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) QDEL_NULL(rave_screen) if(isnull(music_player.active_song_sound)) return @@ -199,7 +199,7 @@ cooldown_time = 30 SECONDS required_slots = list(ITEM_SLOT_OCLOTHING|ITEM_SLOT_ICLOTHING) -/obj/item/mod/module/tanner/on_use() +/obj/item/mod/module/tanner/on_use(mob/activator) playsound(src, 'sound/machines/microwave/microwave-end.ogg', 50, TRUE) var/datum/reagents/holder = new() holder.add_reagent(/datum/reagent/spraytan, 10) @@ -223,7 +223,7 @@ var/blowing_time = 10 SECONDS var/oxygen_damage = 20 -/obj/item/mod/module/balloon/on_use() +/obj/item/mod/module/balloon/on_use(mob/activator) if(!do_after(mod.wearer, blowing_time, target = mod)) return FALSE mod.wearer.adjustOxyLoss(oxygen_damage) @@ -247,7 +247,7 @@ /// The total number of sheets created by this MOD. The more sheets, them more likely they set on fire. var/num_sheets_dispensed = 0 -/obj/item/mod/module/paper_dispenser/on_use() +/obj/item/mod/module/paper_dispenser/on_use(mob/activator) if(!do_after(mod.wearer, 1 SECONDS, target = mod)) return FALSE @@ -316,7 +316,7 @@ /// If you use the module on a planetary turf, you fly up. To the sky. var/you_fucked_up = FALSE -/obj/item/mod/module/atrocinator/on_activation() +/obj/item/mod/module/atrocinator/on_activation(mob/activator) playsound(src, 'sound/effects/curse/curseattack.ogg', 50) mod.wearer.AddElement(/datum/element/forced_gravity, NEGATIVE_GRAVITY) RegisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED, PROC_REF(check_upstairs)) @@ -325,13 +325,13 @@ passtable_on(mod.wearer, REF(src)) check_upstairs() //todo at some point flip your screen around -/obj/item/mod/module/atrocinator/deactivate(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/atrocinator/deactivate(mob/activator, display_message = TRUE, deleting = FALSE) if(you_fucked_up && !deleting) - to_chat(mod.wearer, span_danger("It's too late.")) + to_chat(activator, span_danger("It's too late.")) return FALSE return ..() -/obj/item/mod/module/atrocinator/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/atrocinator/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) if(!deleting) playsound(src, 'sound/effects/curse/curseattack.ogg', 50) qdel(mod.wearer.RemoveElement(/datum/element/forced_gravity, NEGATIVE_GRAVITY)) diff --git a/code/modules/mod/modules/modules_ninja.dm b/code/modules/mod/modules/modules_ninja.dm index 50fbda88467..e0674545004 100644 --- a/code/modules/mod/modules/modules_ninja.dm +++ b/code/modules/mod/modules/modules_ninja.dm @@ -19,7 +19,7 @@ /// The alpha applied when the cloak is on. var/stealth_alpha = 50 -/obj/item/mod/module/stealth/on_activation() +/obj/item/mod/module/stealth/on_activation(mob/activator) if(bumpoff) RegisterSignal(mod.wearer, COMSIG_LIVING_MOB_BUMP, PROC_REF(unstealth)) RegisterSignal(mod.wearer, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_unarmed_attack)) @@ -28,7 +28,7 @@ animate(mod.wearer, alpha = stealth_alpha, time = 1.5 SECONDS) drain_power(use_energy_cost) -/obj/item/mod/module/stealth/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/stealth/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) if(bumpoff) UnregisterSignal(mod.wearer, COMSIG_LIVING_MOB_BUMP) UnregisterSignal(mod.wearer, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_MOB_ITEM_ATTACK, COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_BULLET_ACT, COMSIG_ATOM_HITBY, COMSIG_ATOM_HULK_ATTACK, COMSIG_ATOM_ATTACK_PAW, COMSIG_CARBON_CUFF_ATTEMPTED)) @@ -72,11 +72,11 @@ cooldown_time = 3 SECONDS -/obj/item/mod/module/stealth/ninja/on_activation() +/obj/item/mod/module/stealth/ninja/on_activation(mob/activator) . = ..() ADD_TRAIT(mod.wearer, TRAIT_SILENT_FOOTSTEPS, REF(src)) -/obj/item/mod/module/stealth/ninja/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/stealth/ninja/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) . = ..() REMOVE_TRAIT(mod.wearer, TRAIT_SILENT_FOOTSTEPS, REF(src)) @@ -287,7 +287,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 10 cooldown_time = 8 SECONDS -/obj/item/mod/module/emp_shield/pulse/on_use() +/obj/item/mod/module/emp_shield/pulse/on_use(mob/activator) playsound(src, 'sound/effects/empulse.ogg', 60, TRUE) empulse(src, heavy_range = 4, light_range = 6) drain_power(use_energy_cost) @@ -420,7 +420,7 @@ return FALSE return ..() -/obj/item/mod/module/adrenaline_boost/on_use() +/obj/item/mod/module/adrenaline_boost/on_use(mob/activator) if(IS_SPACE_NINJA(mod.wearer)) mod.wearer.say(pick_list_replacements(NINJA_FILE, "lines"), forced = type) to_chat(mod.wearer, span_notice("You have used the adrenaline boost.")) diff --git a/code/modules/mod/modules/modules_science.dm b/code/modules/mod/modules/modules_science.dm index 8cb15d35370..8a41d449edf 100644 --- a/code/modules/mod/modules/modules_science.dm +++ b/code/modules/mod/modules/modules_science.dm @@ -13,10 +13,10 @@ incompatible_modules = list(/obj/item/mod/module/reagent_scanner) required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_EYES|ITEM_SLOT_MASK) -/obj/item/mod/module/reagent_scanner/on_activation() +/obj/item/mod/module/reagent_scanner/on_activation(mob/activator) ADD_TRAIT(mod.wearer, TRAIT_REAGENT_SCANNER, REF(src)) -/obj/item/mod/module/reagent_scanner/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/reagent_scanner/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) REMOVE_TRAIT(mod.wearer, TRAIT_REAGENT_SCANNER, REF(src)) /obj/item/mod/module/reagent_scanner/advanced @@ -29,12 +29,12 @@ removable = FALSE var/explosion_detection_dist = 21 -/obj/item/mod/module/reagent_scanner/advanced/on_activation() +/obj/item/mod/module/reagent_scanner/advanced/on_activation(mob/activator) . = ..() ADD_TRAIT(mod.wearer, TRAIT_RESEARCH_SCANNER, REF(src)) RegisterSignal(SSdcs, COMSIG_GLOB_EXPLOSION, PROC_REF(sense_explosion)) -/obj/item/mod/module/reagent_scanner/advanced/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/reagent_scanner/advanced/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) . = ..() REMOVE_TRAIT(mod.wearer, TRAIT_RESEARCH_SCANNER, REF(src)) UnregisterSignal(SSdcs, COMSIG_GLOB_EXPLOSION) @@ -61,13 +61,13 @@ accepted_anomalies = list(/obj/item/assembly/signaler/anomaly/grav) required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) -/obj/item/mod/module/anomaly_locked/antigrav/on_activation() +/obj/item/mod/module/anomaly_locked/antigrav/on_activation(mob/activator) if(mod.wearer.has_gravity()) new /obj/effect/temp_visual/mook_dust(get_turf(src)) mod.wearer.AddElement(/datum/element/forced_gravity, 0) playsound(src, 'sound/effects/gravhit.ogg', 50) -/obj/item/mod/module/anomaly_locked/antigrav/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/anomaly_locked/antigrav/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) mod.wearer.RemoveElement(/datum/element/forced_gravity, 0) if(deleting) return diff --git a/code/modules/mod/modules/modules_security.dm b/code/modules/mod/modules/modules_security.dm index a19cd09db2b..14f5ad80254 100644 --- a/code/modules/mod/modules/modules_security.dm +++ b/code/modules/mod/modules/modules_security.dm @@ -82,7 +82,7 @@ /obj/item/mod/module/pepper_shoulders/on_part_deactivation(deleting = FALSE) UnregisterSignal(mod.wearer, COMSIG_LIVING_CHECK_BLOCK) -/obj/item/mod/module/pepper_shoulders/on_use() +/obj/item/mod/module/pepper_shoulders/on_use(mob/activator) playsound(src, 'sound/effects/spray.ogg', 30, TRUE, -6) var/datum/reagents/capsaicin_holder = new(10) capsaicin_holder.add_reagent(/datum/reagent/consumable/condensedcapsaicin, 10) @@ -117,7 +117,7 @@ /// Gun we have holstered. var/obj/item/gun/holstered -/obj/item/mod/module/holster/on_use() +/obj/item/mod/module/holster/on_use(mob/activator) if(!holstered) var/obj/item/gun/holding = mod.wearer.get_active_held_item() if(!holding) @@ -163,10 +163,10 @@ /// List of spans we add to the speaker. var/list/voicespan = list(SPAN_COMMAND) -/obj/item/mod/module/megaphone/on_activation() +/obj/item/mod/module/megaphone/on_activation(mob/activator) RegisterSignal(mod.wearer, COMSIG_MOB_SAY, PROC_REF(handle_speech)) -/obj/item/mod/module/megaphone/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/megaphone/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) UnregisterSignal(mod.wearer, COMSIG_MOB_SAY) /obj/item/mod/module/megaphone/proc/handle_speech(datum/source, list/speech_args) @@ -203,7 +203,7 @@ idle_power_cost = linked_bodybag ? (DEFAULT_CHARGE_DRAIN * 3) : 0 return ..() -/obj/item/mod/module/criminalcapture/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/criminalcapture/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) if(!linked_bodybag) return packup() @@ -269,7 +269,7 @@ overlay_state_inactive = "module_mirage_grenade" dispense_type = /obj/item/grenade/mirage -/obj/item/mod/module/dispenser/mirage/on_use() +/obj/item/mod/module/dispenser/mirage/on_use(mob/activator) var/obj/item/grenade/mirage/grenade = ..() grenade.arm_grenade(mod.wearer) @@ -324,12 +324,12 @@ . = ..() projectile_effect = image('icons/effects/fields.dmi', "projectile_dampen_effect") -/obj/item/mod/module/projectile_dampener/on_activation() +/obj/item/mod/module/projectile_dampener/on_activation(mob/activator) if(istype(dampening_field)) QDEL_NULL(dampening_field) dampening_field = new(mod.wearer, field_radius, TRUE, src) -/obj/item/mod/module/projectile_dampener/on_deactivation(display_message, deleting = FALSE) +/obj/item/mod/module/projectile_dampener/on_deactivation(mob/activator, display_message, deleting = FALSE) QDEL_NULL(dampening_field) ///Active Sonar - Displays a hud circle on the turf of any living creatures in the given radius @@ -429,12 +429,12 @@ scanned_slice = 1 COOLDOWN_START(src, scan_cooldown, scan_cooldown_time) -/obj/item/mod/module/active_sonar/on_use() - balloon_alert(mod.wearer, "readying sonar...") +/obj/item/mod/module/active_sonar/on_use(mob/activator) + balloon_alert(activator, "readying sonar...") playsound(mod.wearer, 'sound/vehicles/mecha/skyfall_power_up.ogg', vol = 20, vary = TRUE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) if(!do_after(mod.wearer, 1.1 SECONDS, target = mod)) return - playsound(mod.wearer, 'sound/effects/ping_hit.ogg', vol = 75, vary = TRUE) // Should be audible for the radius of the sonar + playsound(src, 'sound/effects/ping_hit.ogg', vol = 75, vary = TRUE) // Should be audible for the radius of the sonar to_chat(mod.wearer, span_notice("You slam your fist into the ground, sending out a sonic wave that detects [detect_living_creatures()] living beings nearby!")) for(var/mob/living/creature as anything in keyed_creatures) new /obj/effect/temp_visual/sonar_ping(mod.wearer.loc, mod.wearer, creature) diff --git a/code/modules/mod/modules/modules_service.dm b/code/modules/mod/modules/modules_service.dm index 3a53705e24b..9ca53939fb2 100644 --- a/code/modules/mod/modules/modules_service.dm +++ b/code/modules/mod/modules/modules_service.dm @@ -12,7 +12,7 @@ incompatible_modules = list(/obj/item/mod/module/bikehorn) cooldown_time = 1 SECONDS -/obj/item/mod/module/bikehorn/on_use() +/obj/item/mod/module/bikehorn/on_use(mob/activator) playsound(src, 'sound/items/bikehorn.ogg', 100, FALSE) drain_power(use_energy_cost) diff --git a/code/modules/mod/modules/modules_supply.dm b/code/modules/mod/modules/modules_supply.dm index 75223f92162..4ba54760aca 100644 --- a/code/modules/mod/modules/modules_supply.dm +++ b/code/modules/mod/modules/modules_supply.dm @@ -18,8 +18,8 @@ . = ..() AddComponent(/datum/component/gps/item, "MOD0", state = GLOB.deep_inventory_state, overlay_state = FALSE) -/obj/item/mod/module/gps/on_use() - attack_self(mod.wearer) +/obj/item/mod/module/gps/on_use(mob/activator) + attack_self(mod.wearer) // todo: refactor to make compatable with pAIs. Maybe ui_interact(activator) ///Hydraulic Clamp - Lets you pick up and drop crates. /obj/item/mod/module/clamp @@ -40,16 +40,28 @@ var/load_time = 3 SECONDS /// The max amount of crates you can carry. var/max_crates = 3 + /// Disallow mobs larger than this size in containers + var/max_mob_size = MOB_SIZE_SMALL + /// Items that allowed to be picked up by this module + var/list/accepted_items /// The crates stored in the module. var/list/stored_crates = list() + +/obj/item/mod/module/clamp/Initialize(mapload) + . = ..() + accepted_items = typecacheof(list( + /obj/structure/closet/crate, + /obj/item/delivery/big + )) + /obj/item/mod/module/clamp/on_select_use(atom/target) . = ..() if(!.) return if(!mod.wearer.Adjacent(target)) return - if(istype(target, /obj/structure/closet/crate) || istype(target, /obj/item/delivery/big)) + if(is_type_in_typecache(target, accepted_items)) var/atom/movable/picked_crate = target if(!check_crate_pickup(picked_crate)) return @@ -92,7 +104,7 @@ balloon_alert(mod.wearer, "too many crates!") return FALSE for(var/mob/living/mob in target.get_all_contents()) - if(mob.mob_size < MOB_SIZE_HUMAN) + if(mob.mob_size <= max_mob_size) continue balloon_alert(mod.wearer, "crate too heavy!") return FALSE @@ -124,10 +136,10 @@ overlay_state_active = "module_drill" required_slots = list(ITEM_SLOT_GLOVES) -/obj/item/mod/module/drill/on_activation() +/obj/item/mod/module/drill/on_activation(mob/activator) RegisterSignal(mod.wearer, COMSIG_MOVABLE_BUMP, PROC_REF(bump_mine)) -/obj/item/mod/module/drill/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/drill/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) UnregisterSignal(mod.wearer, COMSIG_MOVABLE_BUMP) /obj/item/mod/module/drill/on_select_use(atom/target) @@ -202,7 +214,7 @@ ore.forceMove(src) ores += ore -/obj/item/mod/module/orebag/on_use() +/obj/item/mod/module/orebag/on_use(mob/activator) for(var/obj/item/ore as anything in ores) ore.forceMove(drop_location()) ores -= ore @@ -333,7 +345,7 @@ locker.throw_at(mod.wearer, range = 7, speed = 3, force = MOVE_FORCE_WEAK, \ callback = CALLBACK(src, PROC_REF(check_locker), locker)) -/obj/item/mod/module/magnet/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/magnet/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) if(istype(mod.wearer.pulling, /obj/structure/closet)) mod.wearer.stop_pulling() @@ -483,13 +495,13 @@ TRAIT_NO_SLIP_ALL, ) -/obj/item/mod/module/sphere_transform/activate() +/obj/item/mod/module/sphere_transform/activate(mob/activator) if(!mod.wearer.has_gravity()) - balloon_alert(mod.wearer, "no gravity!") + balloon_alert(activator, "no gravity!") return FALSE return ..() -/obj/item/mod/module/sphere_transform/on_activation() +/obj/item/mod/module/sphere_transform/on_activation(mob/activator) playsound(src, 'sound/items/modsuit/ballin.ogg', 100, TRUE) mod.wearer.add_filter("mod_ball", 1, alpha_mask_filter(icon = icon('icons/mob/clothing/modsuit/mod_modules.dmi', "ball_mask"), flags = MASK_INVERSE)) mod.wearer.add_filter("mod_blur", 2, angular_blur_filter(size = 15)) @@ -503,7 +515,7 @@ mod.wearer.add_movespeed_modifier(/datum/movespeed_modifier/sphere) RegisterSignal(mod.wearer, COMSIG_MOB_STATCHANGE, PROC_REF(on_statchange)) -/obj/item/mod/module/sphere_transform/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/sphere_transform/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) if(!deleting) playsound(src, 'sound/items/modsuit/ballin.ogg', 100, TRUE, frequency = -1) mod.wearer.remove_offsets(REF(src)) @@ -516,9 +528,9 @@ mod.wearer.remove_movespeed_modifier(/datum/movespeed_modifier/sphere) UnregisterSignal(mod.wearer, COMSIG_MOB_STATCHANGE) -/obj/item/mod/module/sphere_transform/used() +/obj/item/mod/module/sphere_transform/used(mob/activator) if(!lavaland_equipment_pressure_check(get_turf(src))) - balloon_alert(mod.wearer, "too much pressure!") + balloon_alert(activator, "too much pressure!") playsound(src, 'sound/items/weapons/gun/general/dry_fire.ogg', 25, TRUE) return FALSE return ..() diff --git a/code/modules/mod/modules/modules_timeline.dm b/code/modules/mod/modules/modules_timeline.dm index 701cbc30421..0a18a559830 100644 --- a/code/modules/mod/modules/modules_timeline.dm +++ b/code/modules/mod/modules/modules_timeline.dm @@ -29,9 +29,10 @@ UnregisterSignal(mod, COMSIG_MOD_ACTIVATE) UnregisterSignal(mod, COMSIG_MOD_MODULE_REMOVAL) -/obj/item/mod/module/eradication_lock/on_use() +/obj/item/mod/module/eradication_lock/on_use(mob/activator) true_owner_ckey = mod.wearer.ckey - balloon_alert(mod.wearer, "user remembered") + balloon_alert(activator, "user remembered") + playsound(src, 'sound/items/pshoom/pshoom.ogg', 25, TRUE) drain_power(use_energy_cost) ///Signal fired when the modsuit tries activating @@ -66,8 +67,8 @@ cooldown_time = 20 SECONDS required_slots = list(ITEM_SLOT_BACK) -/obj/item/mod/module/rewinder/on_use() - balloon_alert(mod.wearer, "anchor point set") +/obj/item/mod/module/rewinder/on_use(mob/activator) + balloon_alert(activator, "anchor point set") playsound(src, 'sound/items/modsuit/time_anchor_set.ogg', 50, TRUE) //stops all mods from triggering during rewinding for(var/obj/item/mod/module/module as anything in mod.modules) @@ -110,13 +111,13 @@ ///The current timestop in progress. var/obj/effect/timestop/channelled/timestop -/obj/item/mod/module/timestopper/used() +/obj/item/mod/module/timestopper/used(mob/activator) if(timestop) - mod.balloon_alert(mod.wearer, "already freezing time!") + mod.balloon_alert(activator, "already freezing time!") return FALSE return ..() -/obj/item/mod/module/timestopper/on_use() +/obj/item/mod/module/timestopper/on_use(mob/activator) //stops all mods from triggering during timestop- including timestop itself for(var/obj/item/mod/module/module as anything in mod.modules) RegisterSignal(module, COMSIG_MODULE_TRIGGERED, PROC_REF(on_module_triggered)) @@ -159,14 +160,14 @@ ///The dummy for phasing from this module, the wearer is phased out while this exists. var/obj/effect/dummy/phased_mob/chrono/phased_mob -/obj/item/mod/module/timeline_jumper/used() +/obj/item/mod/module/timeline_jumper/used(mob/activator) var/area/noteleport_check = get_area(mod.wearer) if(noteleport_check && !check_teleport_valid(mod.wearer, get_turf(mod.wearer))) - to_chat(mod.wearer, span_danger("Some dull, universal force is between you and the [phased_mob ? "current timeline" : "stream between timelines"].")) + to_chat(activator, span_danger("Some dull, universal force is between you and the [phased_mob ? "current timeline" : "stream between timelines"].")) return FALSE return ..() -/obj/item/mod/module/timeline_jumper/on_use() +/obj/item/mod/module/timeline_jumper/on_use(mob/activator) if(!phased_mob) //phasing out mod.visible_message(span_warning("[mod.wearer] leaps out of the timeline!")) diff --git a/code/modules/mod/modules/modules_visor.dm b/code/modules/mod/modules/modules_visor.dm index 7897ac404f2..c865cc3e670 100644 --- a/code/modules/mod/modules/modules_visor.dm +++ b/code/modules/mod/modules/modules_visor.dm @@ -12,12 +12,12 @@ /// The traits given by the visor. var/list/visor_traits = list() -/obj/item/mod/module/visor/on_activation() +/obj/item/mod/module/visor/on_activation(mob/activator) if(length(visor_traits)) mod.wearer.add_traits(visor_traits, REF(src)) mod.wearer.update_sight() -/obj/item/mod/module/visor/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/visor/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) if(length(visor_traits)) mod.wearer.remove_traits(visor_traits, REF(src)) mod.wearer.update_sight() @@ -91,10 +91,10 @@ incompatible_modules = list(/obj/item/mod/module/night, /obj/item/mod/module/visor/night) required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_EYES|ITEM_SLOT_MASK) -/obj/item/mod/module/night/on_activation() - ADD_TRAIT(mod.wearer, TRAIT_TRUE_NIGHT_VISION, REF(src)) +/obj/item/mod/module/night/on_activation(mob/activator) + mod.wearer.add_traits(mod.wearer, TRAIT_TRUE_NIGHT_VISION, REF(src)) mod.wearer.update_sight() -/obj/item/mod/module/night/on_deactivation(display_message = TRUE, deleting = FALSE) - REMOVE_TRAIT(mod.wearer, TRAIT_TRUE_NIGHT_VISION, REF(src)) +/obj/item/mod/module/night/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) + mod.wearer.remove_traits(mod.wearer, TRAIT_TRUE_NIGHT_VISION, REF(src)) mod.wearer.update_sight()