Refactors MODsuit module rendering and allows overslotted parts to show items they overslot when unsealed (#90414)

MODsuit modules now render on the part they're attached to, that being
first part if required_slots is set, otherwise defaulting to the control
module. Instead of using icon ops and a cache, module masking (used by
armor boosters and insignias) will instead render the module on all
parts, each overlay alpha filtered using the worn piece as the mask. To
do this we also migrate modules to separate_worn_overlays, which fixes
the issue where they'd always get painted the same color as the back
piece, ignoring use_mod_colors's value (which is FALSE by default). So
now modules that inherit MOD's color like armor booster will be painted
accordingly to their piece.
This also means that modules actually layer properly, and don't go ontop
of items that they should be under.

Additionally, whenever gloves or boots overslot an item, the overslotted
item will still render underneath them if they're unsealed. Because it
looks weird when your gloves disappear when you extend your MODsuit
ones.

![dreamseeker_BaWjJBcMVO](https://github.com/user-attachments/assets/2b374913-7761-4b54-9bbd-cbd57d343fd6)

Look at that hip look, she'd have bare hands and ankles without this PR.

Closes #90370

Fixes a bunch of visual jank that looks weird, and overslotting
displaying overslotted item is just behavior you'd expect normally.

🆑
add: When a MODsuit piece overslots an item, it will now render beneath
that piece as long as its unsealed.
refactor: Refactored how MODsuit modules are rendered, report any bugs
on GitHub!
/🆑
This commit is contained in:
SmArtKar
2025-04-15 10:21:10 +02:00
committed by Shadow-Quill
parent 711b8c215e
commit 8e0750a6c3
19 changed files with 234 additions and 147 deletions

View File

@@ -57,9 +57,5 @@
/// Global list of all /datum/mod_theme
GLOBAL_LIST_INIT(mod_themes, setup_mod_themes())
/// Global cache of mod skins to masks per different configuration of pulled out parts.
GLOBAL_LIST_EMPTY(mod_masks)
/// Global cache of mod skins to deployed parts to module icon states
GLOBAL_LIST_EMPTY(mod_module_overlays)
/// Global list of all ids associated to a /datum/mod_link instance
GLOBAL_LIST_EMPTY(mod_link_ids)

View File

@@ -119,49 +119,12 @@
var/obj/item/worn_item = worn_items[slot_flag]
if(!worn_item)
continue
var/default_layer = 0
var/default_icon = null
var/default_icon = get_default_icon_by_slot(text2num(slot_flag))
var/default_layer = get_default_layer_by_slot(text2num(slot_flag))
var/female_icon = NO_FEMALE_UNIFORM
switch(text2num(slot_flag)) //this kinda sucks because build worn icon kinda sucks
if(ITEM_SLOT_HEAD)
default_layer = HEAD_LAYER
default_icon = 'icons/mob/clothing/head/default.dmi'
if(ITEM_SLOT_EYES)
default_layer = GLASSES_LAYER
default_icon = 'icons/mob/clothing/eyes.dmi'
if(ITEM_SLOT_EARS)
default_layer = EARS_LAYER
default_icon = 'icons/mob/clothing/ears.dmi'
if(ITEM_SLOT_MASK)
default_layer = FACEMASK_LAYER
default_icon = 'icons/mob/clothing/mask.dmi'
if(ITEM_SLOT_NECK)
default_layer = NECK_LAYER
default_icon = 'icons/mob/clothing/neck.dmi'
if(ITEM_SLOT_BACK)
default_layer = BACK_LAYER
default_icon = 'icons/mob/clothing/back.dmi'
if(ITEM_SLOT_BELT)
default_layer = BELT_LAYER
default_icon = 'icons/mob/clothing/belt.dmi'
if(ITEM_SLOT_ID)
default_layer = ID_LAYER
default_icon = 'icons/mob/clothing/id.dmi'
if(ITEM_SLOT_ICLOTHING)
default_layer = UNIFORM_LAYER
default_icon = DEFAULT_UNIFORM_FILE
if(body_type == FEMALE && istype(worn_item, /obj/item/clothing/under))
var/obj/item/clothing/under/worn_jumpsuit = worn_item
female_icon = worn_jumpsuit.female_sprite_flags
if(ITEM_SLOT_OCLOTHING)
default_layer = SUIT_LAYER
default_icon = DEFAULT_SUIT_FILE
if(ITEM_SLOT_GLOVES)
default_layer = GLOVES_LAYER
default_icon = 'icons/mob/clothing/hands.dmi'
if(ITEM_SLOT_FEET)
default_layer = SHOES_LAYER
default_icon = DEFAULT_SHOES_FILE
. += worn_item.build_worn_icon(default_layer, default_icon, female_uniform = female_icon)
/obj/structure/mannequin/attack_hand_secondary(mob/user, list/modifiers)

View File

@@ -78,8 +78,7 @@
/datum/outfit/clown_operative/post_equip(mob/living/carbon/human/H, visuals_only)
var/obj/item/mod/module/armor_booster/booster = locate() in H.back
booster.active = TRUE
H.update_worn_back()
booster.activate()
/datum/outfit/clown_operative_elite
name = "Clown Operative (Elite, Preview only)"
@@ -89,5 +88,4 @@
/datum/outfit/clown_operative_elite/post_equip(mob/living/carbon/human/H, visuals_only)
var/obj/item/mod/module/armor_booster/booster = locate() in H.back
booster.active = TRUE
H.update_worn_back()
booster.activate()

View File

@@ -188,8 +188,7 @@
/datum/outfit/nuclear_operative/post_equip(mob/living/carbon/human/H, visuals_only)
var/obj/item/mod/module/armor_booster/booster = locate() in H.back
booster.active = TRUE
H.update_worn_back()
booster.activate()
/datum/outfit/nuclear_operative_elite
name = "Nuclear Operative (Elite, Preview only)"
@@ -201,8 +200,7 @@
/datum/outfit/nuclear_operative_elite/post_equip(mob/living/carbon/human/H, visuals_only)
var/obj/item/mod/module/armor_booster/booster = locate() in H.back
booster.active = TRUE
H.update_worn_back()
booster.activate()
var/obj/item/shield/energy/shield = locate() in H.held_items
shield.icon_state = "[shield.base_icon_state]1"
H.update_held_items()

View File

@@ -658,3 +658,57 @@ GLOBAL_LIST_EMPTY(masked_leg_icons_cache)
new_leg_appearance_lower.layer = -BODYPARTS_LOW_LAYER
. += new_leg_appearance_lower
return .
/proc/get_default_icon_by_slot(slot_flag)
switch(slot_flag)
if(ITEM_SLOT_HEAD)
return 'icons/mob/clothing/head/default.dmi'
if(ITEM_SLOT_EYES)
return 'icons/mob/clothing/eyes.dmi'
if(ITEM_SLOT_EARS)
return 'icons/mob/clothing/ears.dmi'
if(ITEM_SLOT_MASK)
return 'icons/mob/clothing/mask.dmi'
if(ITEM_SLOT_NECK)
return 'icons/mob/clothing/neck.dmi'
if(ITEM_SLOT_BACK)
return 'icons/mob/clothing/back.dmi'
if(ITEM_SLOT_BELT)
return 'icons/mob/clothing/belt.dmi'
if(ITEM_SLOT_ID)
return 'icons/mob/clothing/id.dmi'
if(ITEM_SLOT_ICLOTHING)
return DEFAULT_UNIFORM_FILE
if(ITEM_SLOT_OCLOTHING)
return DEFAULT_SUIT_FILE
if(ITEM_SLOT_GLOVES)
return 'icons/mob/clothing/hands.dmi'
if(ITEM_SLOT_FEET)
return DEFAULT_SHOES_FILE
/proc/get_default_layer_by_slot(slot_flag)
switch(text2num(slot_flag))
if(ITEM_SLOT_HEAD)
return HEAD_LAYER
if(ITEM_SLOT_EYES)
return GLASSES_LAYER
if(ITEM_SLOT_EARS)
return EARS_LAYER
if(ITEM_SLOT_MASK)
return FACEMASK_LAYER
if(ITEM_SLOT_NECK)
return NECK_LAYER
if(ITEM_SLOT_BACK)
return BACK_LAYER
if(ITEM_SLOT_BELT)
return BELT_LAYER
if(ITEM_SLOT_ID)
return ID_LAYER
if(ITEM_SLOT_ICLOTHING)
return UNIFORM_LAYER
if(ITEM_SLOT_OCLOTHING)
return SUIT_LAYER
if(ITEM_SLOT_GLOVES)
return GLOVES_LAYER
if(ITEM_SLOT_FEET)
return SHOES_LAYER

View File

@@ -93,7 +93,7 @@
RegisterSignal(part, COMSIG_ATOM_EXITED, PROC_REF(on_overslot_exit))
if(wearer.equip_to_slot_if_possible(part, part.slot_flags, qdel_on_fail = FALSE, disable_warning = TRUE))
ADD_TRAIT(part, TRAIT_NODROP, MOD_TRAIT)
wearer.update_clothing(slot_flags)
wearer.update_clothing(slot_flags|part.slot_flags)
SEND_SIGNAL(src, COMSIG_MOD_PART_DEPLOYED, user, part_datum)
if(user)
wearer.visible_message(span_notice("[wearer]'s [part.name] deploy[part.p_s()] with a mechanical hiss."),
@@ -131,7 +131,9 @@
return FALSE
if(SEND_SIGNAL(src, COMSIG_MOD_PART_RETRACTING, user, part_datum) & MOD_CANCEL_RETRACTION)
return FALSE
var/unsealing = FALSE
if(active && part_datum.sealed)
unsealing = TRUE
if(instant)
seal_part(part, is_sealed = FALSE)
else if(!delayed_seal_part(part))
@@ -144,12 +146,13 @@
var/obj/item/overslot = part_datum.overslotting
if(!QDELING(wearer) && !wearer.equip_to_slot_if_possible(overslot, overslot.slot_flags, qdel_on_fail = FALSE, disable_warning = TRUE))
wearer.dropItemToGround(overslot, force = TRUE, silent = TRUE)
wearer.update_clothing(slot_flags)
wearer.update_clothing(slot_flags|part.slot_flags)
if(!user)
return TRUE
wearer.visible_message(span_notice("[wearer]'s [part.name] retract[part.p_s()] back into [src] with a mechanical hiss."),
span_notice("[part] retract[part.p_s()] back into [src] with a mechanical hiss."),
span_hear("You hear a mechanical hiss."))
if (!unsealing)
playsound(src, 'sound/vehicles/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
return TRUE
@@ -268,7 +271,6 @@
part.heat_protection = NONE
part.cold_protection = NONE
part.alternate_worn_layer = part_datum.unsealed_layer
generate_suit_mask()
update_speed()
wearer.update_clothing(part.slot_flags | slot_flags)
wearer.update_obscured_slots(part.visor_flags_inv)
@@ -300,23 +302,16 @@
active = is_on
if(active)
for(var/obj/item/mod/module/module as anything in modules)
if(module.part_activated || !module.has_required_parts(mod_parts, need_active = TRUE))
continue
if(!module.part_activated && module.has_required_parts(mod_parts, need_active = TRUE))
module.on_part_activation()
module.part_activated = TRUE
else
for(var/obj/item/mod/module/module as anything in modules)
if(!module.part_activated)
continue
module.on_part_deactivation()
module.part_activated = FALSE
if(!module.active || (module.allow_flags & MODULE_ALLOW_INACTIVE))
continue
module.deactivate(display_message = FALSE)
update_charge_alert()
update_appearance(UPDATE_ICON_STATE)
generate_suit_mask()
wearer.update_clothing(slot_flags)
wearer.update_clothing()
/// Quickly deploys all the suit parts and if successful, seals them and turns on the suit. Intended mostly for outfits.
/obj/item/mod/control/proc/quick_activation()

View File

@@ -115,13 +115,10 @@
if(core)
QDEL_NULL(core)
QDEL_NULL(mod_link)
for(var/datum/mod_part/part_datum as anything in get_part_datums(all = TRUE))
var/obj/item/part_item = part_datum.part_item
part_datum.part_item = null
part_datum.overslotting = null
mod_parts -= part_datum
if(!QDELING(part_item))
qdel(part_item)
for(var/part_key in mod_parts)
var/datum/mod_part/part_datum = mod_parts[part_key]
mod_parts -= part_key
qdel(part_datum)
return ..()
/obj/item/mod/control/atom_destruction(damage_flag)
@@ -454,11 +451,14 @@
CRASH("get_part_datum called with incorrect item [part] passed.")
/obj/item/mod/control/proc/get_part_from_slot(slot)
var/datum/mod_part/part = mod_parts["[slot]"]
return part?.part_item
RETURN_TYPE(/obj/item)
return get_part_datum_from_slot(slot)?.part_item
/obj/item/mod/control/proc/get_part_datum_from_slot(slot)
return mod_parts["[slot]"]
RETURN_TYPE(/datum/mod_part)
for (var/part_key in mod_parts)
if (text2num(part_key) & slot)
return mod_parts[part_key]
/obj/item/mod/control/proc/set_wearer(mob/living/carbon/human/user)
if(wearer == user)
@@ -492,21 +492,6 @@
covered_slots |= part.slot_flags
return covered_slots
/obj/item/mod/control/proc/generate_suit_mask()
var/list/parts = get_parts(all = TRUE)
var/covered_slots = get_sealed_slots(parts)
if(GLOB.mod_masks[skin])
if(GLOB.mod_masks[skin]["[covered_slots]"])
return GLOB.mod_masks[skin]["[covered_slots]"]
else
GLOB.mod_masks[skin] = list()
var/icon/slot_mask = icon('icons/blanks/32x32.dmi', "nothing")
for(var/obj/item/part as anything in parts)
slot_mask.Blend(icon(part.worn_icon, part.icon_state), ICON_OVERLAY)
slot_mask.Blend("#fff", ICON_ADD)
GLOB.mod_masks[skin]["[covered_slots]"] = slot_mask
return GLOB.mod_masks[skin]["[covered_slots]"]
/obj/item/mod/control/proc/clean_up()
if(QDELING(src))
unset_wearer()
@@ -613,7 +598,6 @@
modules += new_module
complexity += new_module.complexity
new_module.mod = src
new_module.RegisterSignal(src, COMSIG_ITEM_GET_WORN_OVERLAYS, TYPE_PROC_REF(/obj/item/mod/module, add_module_overlay))
new_module.on_install()
if(wearer)
new_module.on_equip()
@@ -633,7 +617,6 @@
old_module.on_part_deactivation(deleting = deleting)
if(old_module.active)
old_module.deactivate(display_message = !deleting, deleting = deleting)
old_module.UnregisterSignal(src, COMSIG_ITEM_GET_WORN_OVERLAYS)
old_module.on_uninstall(deleting = deleting)
QDEL_LIST_ASSOC_VAL(old_module.pinned_to)
old_module.mod = null

View File

@@ -18,5 +18,29 @@
var/obj/item/overslotting = null
/datum/mod_part/Destroy()
// To avoid qdel loops in MOD control units, since they're also a part
if (!QDELING(part_item))
qdel(part_item)
part_item = null
overslotting = null
return ..()
/datum/mod_part/proc/set_item(obj/item/new_part)
part_item = new_part
RegisterSignal(part_item, COMSIG_ITEM_GET_SEPARATE_WORN_OVERLAYS, PROC_REF(get_separate_worn_overlays))
// If we're overslotting an item, add its visual as an underlay
/datum/mod_part/proc/get_separate_worn_overlays(obj/item/source, list/overlays, mutable_appearance/standing, mutable_appearance/draw_target, isinhands, icon_file)
SIGNAL_HANDLER
if (!overslotting || sealed)
return
var/checked_slot = source.slot_flags
if (ismob(source.loc))
var/mob/as_mob = source.loc
checked_slot = as_mob.get_slot_by_item(source)
var/mutable_appearance/worn_overlay = overslotting.build_worn_icon(default_layer = -draw_target.layer + 0.1, default_icon_file = get_default_icon_by_slot(checked_slot))
for (var/mutable_appearance/overlay in worn_overlay.overlays)
overlay.layer = draw_target.layer + 0.1
overlays += worn_overlay

View File

@@ -108,7 +108,7 @@
mod.ui_theme = ui_theme
mod.charge_drain = charge_drain
var/datum/mod_part/control_part_datum = new()
control_part_datum.part_item = mod
control_part_datum.set_item(mod)
mod.mod_parts["[mod.slot_flags]"] = control_part_datum
for(var/path in variants[default_skin])
if(!ispath(path))
@@ -118,7 +118,7 @@
var/obj/item/clothing/chestplate = mod_part
chestplate.allowed |= allowed_suit_storage
var/datum/mod_part/part_datum = new()
part_datum.part_item = mod_part
part_datum.set_item(mod_part)
mod.mod_parts["[mod_part.slot_flags]"] = part_datum
parts += mod_part

View File

@@ -180,9 +180,9 @@
update_signal(used_button)
balloon_alert(mod.wearer, "[src] activated, [used_button]-click to use")
active = TRUE
mod.wearer.update_clothing(mod.slot_flags)
SEND_SIGNAL(src, COMSIG_MODULE_ACTIVATED)
on_activation()
update_clothing_slots()
return TRUE
/// Called when the module is deactivated
@@ -199,11 +199,22 @@
else
UnregisterSignal(mod.wearer, used_signal)
used_signal = null
mod.wearer.update_clothing(mod.slot_flags)
SEND_SIGNAL(src, COMSIG_MODULE_DEACTIVATED, mod.wearer)
on_deactivation(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()
var/updated_slots = mod.slot_flags
if (mask_worn_overlay)
for (var/obj/item/part as anything in mod.get_parts())
updated_slots |= part.slot_flags
else if (length(required_slots))
for (var/slot in required_slots)
updated_slots |= slot
mod.wearer.update_clothing(updated_slots)
/// Called when the module is used
/obj/item/mod/module/proc/used()
if(!COOLDOWN_FINISHED(src, cooldown_timer))
@@ -220,7 +231,7 @@
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
mod.wearer.update_clothing(mod.slot_flags)
update_clothing_slots()
SEND_SIGNAL(src, COMSIG_MODULE_USED)
on_use()
return TRUE
@@ -271,12 +282,39 @@
/// Called from MODsuit's install() proc, so when the module is installed
/obj/item/mod/module/proc/on_install()
SHOULD_CALL_PARENT(TRUE)
if (mask_worn_overlay)
for (var/obj/item/part as anything in mod.get_parts(all = TRUE))
RegisterSignal(part, COMSIG_ITEM_GET_SEPARATE_WORN_OVERLAYS, PROC_REF(add_module_overlay))
return
if (!length(required_slots))
RegisterSignal(mod, COMSIG_ITEM_GET_SEPARATE_WORN_OVERLAYS, PROC_REF(add_module_overlay))
return
var/obj/item/part = mod.get_part_from_slot(required_slots[1])
RegisterSignal(part, COMSIG_ITEM_GET_SEPARATE_WORN_OVERLAYS, PROC_REF(add_module_overlay))
/// Called from MODsuit's uninstall() proc, so when the module is uninstalled
/obj/item/mod/module/proc/on_uninstall(deleting = FALSE)
SHOULD_CALL_PARENT(TRUE)
if (deleting)
return
if (mask_worn_overlay)
for (var/obj/item/part as anything in mod.get_parts(all = TRUE))
UnregisterSignal(part, COMSIG_ITEM_GET_SEPARATE_WORN_OVERLAYS)
return
if (!length(required_slots))
UnregisterSignal(mod, COMSIG_ITEM_GET_SEPARATE_WORN_OVERLAYS)
return
var/obj/item/part = mod.get_part_from_slot(required_slots[1])
UnregisterSignal(part, COMSIG_ITEM_GET_SEPARATE_WORN_OVERLAYS)
/// Called when the MODsuit is activated
/obj/item/mod/module/proc/on_part_activation()
return
@@ -343,27 +381,45 @@
qdel(src)
/// Adds the worn overlays to the suit.
/obj/item/mod/module/proc/add_module_overlay(obj/item/source, list/overlays, mutable_appearance/standing, isinhands, icon_file)
/obj/item/mod/module/proc/add_module_overlay(obj/item/source, list/overlays, mutable_appearance/standing, mutable_appearance/draw_target, isinhands, icon_file)
SIGNAL_HANDLER
overlays += generate_worn_overlay(standing)
if (isinhands)
return
var/list/added_overlays = generate_worn_overlay(source, standing)
if (!added_overlays)
return
if (!mask_worn_overlay)
overlays += added_overlays
return
for (var/mutable_appearance/overlay as anything in added_overlays)
overlay.add_filter("mod_mask_overlay", 1, alpha_mask_filter(icon = icon(draw_target.icon, draw_target.icon_state)))
overlays += overlay
/// Generates an icon to be used for the suit's worn overlays
/obj/item/mod/module/proc/generate_worn_overlay(mutable_appearance/standing)
. = list()
if(!mod.active || !has_required_parts(mod.mod_parts, need_active = TRUE))
/obj/item/mod/module/proc/generate_worn_overlay(obj/item/source, mutable_appearance/standing)
if(!mask_worn_overlay)
if(!has_required_parts(mod.mod_parts, need_active = TRUE))
return
else
var/datum/mod_part/part_datum = mod.get_part_datum(source)
if (!part_datum?.sealed)
return
. = list()
var/used_overlay = get_current_overlay_state()
if (!used_overlay)
return
/* BUBBER EDIT START - Making MODsuits mutant-compatible - ORIGINAL:
var/mutable_appearance/module_icon
if(mask_worn_overlay)
module_icon = mutable_appearance(get_module_icon_cache(used_overlay), layer = standing.layer + 0.1)
else
module_icon = mutable_appearance(overlay_icon_file, used_overlay, layer = standing.layer + 0.1)
if(!use_mod_colors)
module_icon.appearance_flags |= RESET_COLOR
var/mutable_appearance/module_icon = mutable_appearance(overlay_icon_file, used_overlay, layer = standing.layer + 0.1)
if(use_mod_colors)
module_icon.color = mod.color
if (mod.cached_color_filter)
module_icon = filter_appearance_recursive(module_icon, mod.cached_color_filter)
. += module_icon
*/
@@ -380,22 +436,6 @@
return overlay_state_inactive
return null
/obj/item/mod/module/proc/get_module_icon_cache(used_overlay)
var/covered_slots = mod.get_sealed_slots(mod.get_parts(all = TRUE))
if (GLOB.mod_module_overlays[mod.skin])
if (GLOB.mod_module_overlays[mod.skin]["[covered_slots]"])
if (GLOB.mod_module_overlays[mod.skin]["[covered_slots]"][used_overlay])
return GLOB.mod_module_overlays[mod.skin]["[covered_slots]"][used_overlay]
else
GLOB.mod_module_overlays[mod.skin]["[covered_slots]"] = list()
else
GLOB.mod_module_overlays[mod.skin] = list()
GLOB.mod_module_overlays[mod.skin]["[covered_slots]"] = list()
var/icon/mod_mask = icon(mod.generate_suit_mask())
mod_mask.Blend(icon(overlay_icon_file, used_overlay), ICON_MULTIPLY)
GLOB.mod_module_overlays[mod.skin]["[covered_slots]"][used_overlay] = mod_mask
return GLOB.mod_module_overlays[mod.skin]["[covered_slots]"][used_overlay]
/// Updates the signal used by active modules to be activated
/obj/item/mod/module/proc/update_signal(value)
switch(value)

View File

@@ -90,7 +90,7 @@
if (!active)
module_slowdowns += space_slowdown
/obj/item/mod/module/armor_booster/generate_worn_overlay(mutable_appearance/standing)
/obj/item/mod/module/armor_booster/generate_worn_overlay(obj/item/source, mutable_appearance/standing)
overlay_state_inactive = "[initial(overlay_state_inactive)]-[mod.skin]"
overlay_state_active = "[initial(overlay_state_active)]-[mod.skin]"
return ..()
@@ -105,9 +105,11 @@
REMOVE_TRAIT(mod.wearer, TRAIT_HEAD_INJURY_BLOCKED, REF(src))
/obj/item/mod/module/armor_booster/on_install()
. = ..()
RegisterSignal(mod, COMSIG_MOD_GET_VISOR_OVERLAY, PROC_REF(on_visor_overlay))
/obj/item/mod/module/armor_booster/on_uninstall(deleting)
/obj/item/mod/module/armor_booster/on_uninstall(deleting = FALSE)
. = ..()
UnregisterSignal(mod, COMSIG_MOD_GET_VISOR_OVERLAY)
/obj/item/mod/module/armor_booster/proc/on_visor_overlay(datum/source, mutable_appearance/standing, list/overrides)
@@ -241,7 +243,7 @@
overlay_state_inactive = "module_insignia"
mask_worn_overlay = TRUE
/obj/item/mod/module/insignia/generate_worn_overlay(mutable_appearance/standing)
/obj/item/mod/module/insignia/generate_worn_overlay(obj/item/source, mutable_appearance/standing)
overlay_state_inactive = "[initial(overlay_state_inactive)]-[mod.skin]"
. = ..()
for(var/mutable_appearance/appearance as anything in .)
@@ -409,6 +411,7 @@
var/obj/item/current_disguise
/obj/item/mod/module/chameleon/on_install()
. = ..()
var/list/all_disguises = sort_list(subtypesof(get_path_by_slot(mod.slot_flags)), GLOBAL_PROC_REF(cmp_typepaths_asc))
for(var/clothing_path in all_disguises)
var/obj/item/clothing = clothing_path
@@ -418,6 +421,7 @@
possible_disguises[chameleon_item_name] = clothing_path
/obj/item/mod/module/chameleon/on_uninstall(deleting = FALSE)
. = ..()
if(current_disguise)
return_look()
possible_disguises = null
@@ -449,7 +453,7 @@
mod.righthand_file = initial(current_disguise.righthand_file)
mod.worn_icon_state = initial(current_disguise.worn_icon_state)
mod.inhand_icon_state = initial(current_disguise.inhand_icon_state)
mod.wearer.update_clothing(mod.slot_flags)
update_clothing_slots()
RegisterSignal(mod, COMSIG_MOD_ACTIVATE, PROC_REF(return_look))
/obj/item/mod/module/chameleon/proc/return_look()
@@ -463,7 +467,7 @@
mod.righthand_file = initial(mod.righthand_file)
mod.worn_icon_state = null
mod.inhand_icon_state = null
mod.wearer.update_clothing(mod.slot_flags)
update_clothing_slots()
current_disguise = null
UnregisterSignal(mod, COMSIG_MOD_ACTIVATE)
@@ -481,10 +485,12 @@
var/old_size
/obj/item/mod/module/plate_compression/on_install()
. = ..()
old_size = mod.w_class
mod.update_weight_class(new_size)
/obj/item/mod/module/plate_compression/on_uninstall(deleting = FALSE)
. = ..()
mod.update_weight_class(old_size)
old_size = null
if(!mod.loc)
@@ -528,9 +534,11 @@
var/list/traits_to_add = list(TRAIT_SILENT_FOOTSTEPS, TRAIT_UNKNOWN, TRAIT_HEAD_INJURY_BLOCKED)
/obj/item/mod/module/infiltrator/on_install()
. = ..()
ADD_TRAIT(mod, TRAIT_EXAMINE_SKIP, REF(src))
/obj/item/mod/module/infiltrator/on_uninstall(deleting = FALSE)
. = ..()
REMOVE_TRAIT(mod, TRAIT_EXAMINE_SKIP, REF(src))
/obj/item/mod/module/infiltrator/on_part_activation()

View File

@@ -62,9 +62,11 @@
var/list/active_traits = list(TRAIT_NO_SLIP_WATER, TRAIT_NO_SLIP_ICE, TRAIT_NO_SLIP_SLIDE, TRAIT_NEGATES_GRAVITY)
/obj/item/mod/module/magboot/on_install()
. = ..()
RegisterSignal(mod, COMSIG_MOD_UPDATE_SPEED, PROC_REF(on_update_speed))
/obj/item/mod/module/magboot/on_uninstall(deleting)
/obj/item/mod/module/magboot/on_uninstall(deleting = FALSE)
. = ..()
UnregisterSignal(mod, COMSIG_MOD_UPDATE_SPEED)
/obj/item/mod/module/magboot/on_activation()

View File

@@ -25,6 +25,7 @@
atom_storage.set_locked(STORAGE_FULLY_LOCKED)
/obj/item/mod/module/storage/on_install()
. = ..()
var/datum/storage/modstorage = mod.create_storage(max_specific_storage = max_w_class, max_total_storage = max_combined_w_class, max_slots = max_items)
modstorage.set_real_location(src)
modstorage.allow_big_nesting = big_nesting
@@ -34,6 +35,7 @@
RegisterSignal(suit, COMSIG_ITEM_PRE_UNEQUIP, PROC_REF(on_suit_unequip))
/obj/item/mod/module/storage/on_uninstall(deleting = FALSE)
. = ..()
atom_storage.set_locked(STORAGE_FULLY_LOCKED)
QDEL_NULL(mod.atom_storage)
if(!deleting)
@@ -328,6 +330,7 @@
var/former_visor_mask_flags = NONE
/obj/item/mod/module/mouthhole/on_install()
. = ..()
var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD)
if(istype(helmet))
former_helmet_flags = helmet.flags_cover
@@ -351,6 +354,7 @@
return FALSE
/obj/item/mod/module/mouthhole/on_uninstall(deleting = FALSE)
. = ..()
if(deleting)
return
var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD)
@@ -375,9 +379,11 @@
required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT)
/obj/item/mod/module/emp_shield/on_install()
. = ..()
mod.AddElement(/datum/element/empprotection, EMP_PROTECT_ALL)
/obj/item/mod/module/emp_shield/on_uninstall(deleting = FALSE)
. = ..()
mod.RemoveElement(/datum/element/empprotection, EMP_PROTECT_ALL)
/obj/item/mod/module/emp_shield/advanced
@@ -437,7 +443,7 @@
active_power_cost = base_power * light_range
return ..()
/obj/item/mod/module/flashlight/generate_worn_overlay(mutable_appearance/standing)
/obj/item/mod/module/flashlight/generate_worn_overlay(obj/item/source, mutable_appearance/standing)
. = ..()
if(!active)
return
@@ -460,7 +466,7 @@
balloon_alert(mod.wearer, "too dark!")
return
set_light_color(value)
mod.wearer.update_clothing(mod.slot_flags)
update_clothing_slots()
if("light_range")
set_light_range(clamp(value, min_range, max_range))
@@ -594,12 +600,14 @@
var/dna = null
/obj/item/mod/module/dna_lock/on_install()
. = ..()
RegisterSignal(mod, COMSIG_MOD_ACTIVATE, PROC_REF(on_mod_activation))
RegisterSignal(mod, COMSIG_MOD_MODULE_REMOVAL, PROC_REF(on_mod_removal))
RegisterSignal(mod, COMSIG_ATOM_EMP_ACT, PROC_REF(on_emp))
RegisterSignal(mod, COMSIG_ATOM_EMAG_ACT, PROC_REF(on_emag))
/obj/item/mod/module/dna_lock/on_uninstall(deleting = FALSE)
. = ..()
UnregisterSignal(mod, COMSIG_MOD_ACTIVATE)
UnregisterSignal(mod, COMSIG_MOD_MODULE_REMOVAL)
UnregisterSignal(mod, COMSIG_ATOM_EMP_ACT)
@@ -665,11 +673,15 @@
incompatible_modules = list(/obj/item/mod/module/plasma_stabilizer)
required_slots = list(ITEM_SLOT_HEAD)
/obj/item/mod/module/plasma_stabilizer/generate_worn_overlay(mutable_appearance/standing)
/obj/item/mod/module/plasma_stabilizer/generate_worn_overlay(obj/item/source, mutable_appearance/standing)
. = ..()
if (!.)
return
var/mutable_appearance/visor_overlay = mod.get_visor_overlay(standing)
visor_overlay.appearance_flags |= RESET_COLOR
visor_overlay.color = COLOR_VIOLET
return list(visor_overlay)
. += visor_overlay
/obj/item/mod/module/plasma_stabilizer/on_equip()
ADD_TRAIT(mod.wearer, TRAIT_HEAD_ATMOS_SEALED, REF(src))

View File

@@ -17,9 +17,11 @@
var/step_change = 0.5
/obj/item/mod/module/springlock/on_install()
. = ..()
mod.activation_step_time *= step_change
/obj/item/mod/module/springlock/on_uninstall(deleting = FALSE)
. = ..()
mod.activation_step_time /= step_change
/obj/item/mod/module/springlock/on_part_activation()
@@ -149,18 +151,22 @@
return
SEND_SOUND(mod.wearer, sound('sound/machines/terminal/terminal_off.ogg', volume = 50, channel = CHANNEL_JUKEBOX))
/obj/item/mod/module/visor/rave/generate_worn_overlay(mutable_appearance/standing)
/obj/item/mod/module/visor/rave/generate_worn_overlay(obj/item/source, mutable_appearance/standing)
. = ..()
if (!.)
return
var/mutable_appearance/visor_overlay = mod.get_visor_overlay(standing)
visor_overlay.appearance_flags |= RESET_COLOR
if (!isnull(music_player.active_song_sound))
visor_overlay.color = rainbow_order[rave_number]
return list(visor_overlay)
. += visor_overlay
/obj/item/mod/module/visor/rave/on_active_process(seconds_per_tick)
rave_number++
if(rave_number > length(rainbow_order))
rave_number = 1
mod.wearer.update_clothing(mod.slot_flags)
update_clothing_slots()
rave_screen.update_color(rainbow_order[rave_number])
/obj/item/mod/module/visor/rave/get_configuration()

View File

@@ -93,11 +93,9 @@
required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_EYES|ITEM_SLOT_MASK)
/obj/item/mod/module/welding/camera_vision/on_part_activation()
. = ..()
RegisterSignal(mod.wearer, COMSIG_LIVING_CAN_TRACK, PROC_REF(can_track))
/obj/item/mod/module/welding/camera_vision/on_part_deactivation(deleting = FALSE)
. = ..()
UnregisterSignal(mod.wearer, COMSIG_LIVING_CAN_TRACK)
/obj/item/mod/module/welding/camera_vision/proc/can_track(datum/source, mob/user)
@@ -422,9 +420,11 @@
addtimer(CALLBACK(src, PROC_REF(boost_aftereffects), mod.wearer), 7 SECONDS)
/obj/item/mod/module/adrenaline_boost/on_install()
. = ..()
RegisterSignal(mod, COMSIG_ATOM_ITEM_INTERACTION, PROC_REF(try_boost))
/obj/item/mod/module/adrenaline_boost/on_uninstall(deleting = FALSE)
. = ..()
UnregisterSignal(mod, COMSIG_ATOM_ITEM_INTERACTION)
/obj/item/mod/module/adrenaline_boost/proc/try_boost(source, mob/user, obj/item/attacking_item)

View File

@@ -22,6 +22,7 @@
guns_typecache = typecacheof(list(/obj/item/gun/ballistic, /obj/item/gun/energy, /obj/item/gun/grenadelauncher, /obj/item/gun/chem, /obj/item/gun/syringe, /obj/item/gun/microfusion)) //SKYRAT EDIT - MICROFUSION
/obj/item/mod/module/magnetic_harness/on_install()
. = ..()
var/obj/item/clothing/suit = mod.get_part_from_slot(ITEM_SLOT_OCLOTHING)
if(!istype(suit))
return
@@ -29,6 +30,7 @@
suit.allowed |= guns_typecache
/obj/item/mod/module/magnetic_harness/on_uninstall(deleting = FALSE)
. = ..()
if(deleting)
return
var/obj/item/clothing/suit = mod.get_part_from_slot(ITEM_SLOT_OCLOTHING)
@@ -135,6 +137,7 @@
balloon_alert(mod.wearer, "holster full!")
/obj/item/mod/module/holster/on_uninstall(deleting = FALSE)
. = ..()
if(holstered)
holstered.forceMove(drop_location())

View File

@@ -422,7 +422,7 @@
mod.update_speed()
traveled_tiles = 0
/obj/item/mod/module/ash_accretion/generate_worn_overlay(mutable_appearance/standing)
/obj/item/mod/module/ash_accretion/generate_worn_overlay(obj/item/source, mutable_appearance/standing)
overlay_state_inactive = "[initial(overlay_state_inactive)]-[mod.skin]"
return ..()

View File

@@ -20,10 +20,12 @@
var/true_owner_ckey
/obj/item/mod/module/eradication_lock/on_install()
. = ..()
RegisterSignal(mod, COMSIG_MOD_ACTIVATE, PROC_REF(on_mod_activation))
RegisterSignal(mod, COMSIG_MOD_MODULE_REMOVAL, PROC_REF(on_mod_removal))
/obj/item/mod/module/eradication_lock/on_uninstall(deleting = FALSE)
. = ..()
UnregisterSignal(mod, COMSIG_MOD_ACTIVATE)
UnregisterSignal(mod, COMSIG_MOD_MODULE_REMOVAL)
@@ -228,6 +230,7 @@
INVOKE_ASYNC(chrono_beam, TYPE_PROC_REF(/obj/projectile, fire))
/obj/item/mod/module/tem/on_uninstall(deleting = FALSE)
. = ..()
if(!field)
return
field_disconnect(field)

View File

@@ -41,11 +41,13 @@
QDEL_LIST_ASSOC_VAL(action_comp.granted_to)
/obj/item/mod/module/circuit/on_install()
. = ..()
if(!shell?.attached_circuit)
return
RegisterSignal(shell?.attached_circuit, COMSIG_CIRCUIT_PRE_POWER_USAGE, PROC_REF(override_power_usage))
/obj/item/mod/module/circuit/on_uninstall(deleting = FALSE)
. = ..()
if(!shell?.attached_circuit)
return
for(var/obj/item/circuit_component/equipment_action/action_comp in action_comps)