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
🆑 Stonetear
refactor: MODsuit module code now knows who clicked the activation
button.
/🆑

---------

Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
This commit is contained in:
Stonetear
2025-09-07 03:27:38 -07:00
committed by GitHub
parent 7a06cc69c2
commit 4756a44141
20 changed files with 256 additions and 209 deletions

View File

@@ -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

View File

@@ -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"

View File

@@ -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)

View File

@@ -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()

View File

@@ -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 ..()

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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 @@
<b>Name:</b> Nakamura Engineering Pathfinder Implant<BR> \
<b>Implant Details:</b> Allows for the recall of a Modular Outerwear Device by the implant owner at any time.<BR>"
/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)

View File

@@ -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))

View File

@@ -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)

View File

@@ -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))

View File

@@ -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))

View File

@@ -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."))

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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 ..()

View File

@@ -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!"))

View File

@@ -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()