diff --git a/code/__DEFINES/dcs/signals/signals_mod.dm b/code/__DEFINES/dcs/signals/signals_mod.dm index c4007d12969..d3439cf8572 100644 --- a/code/__DEFINES/dcs/signals/signals_mod.dm +++ b/code/__DEFINES/dcs/signals/signals_mod.dm @@ -1,10 +1,14 @@ //MODsuit signals /// Called when a module is selected to be the active one from on_select(obj/item/mod/module/module) #define COMSIG_MOD_MODULE_SELECTED "mod_module_selected" -/// Called when a MOD deploys one or more of its parts. +/// Called when a MOD user deploys one or more of its parts. #define COMSIG_MOD_DEPLOYED "mod_deployed" -/// Called when a MOD retracts one or more of its parts. +/// Called when a MOD user retracts one or more of its parts. #define COMSIG_MOD_RETRACTED "mod_retracted" +/// Called when a MOD deploys a part. +#define COMSIG_MOD_PART_DEPLOYED "mod_part_deployed" +/// Called when a MOD retracts a part. +#define COMSIG_MOD_PART_RETRACTED "mod_part_retracted" /// Called when a MOD is finished toggling itself. #define COMSIG_MOD_TOGGLED "mod_toggled" /// Called when a MOD activation is called from toggle_activate(mob/user) diff --git a/code/__DEFINES/mod.dm b/code/__DEFINES/mod.dm index be59793927f..8257e1969be 100644 --- a/code/__DEFINES/mod.dm +++ b/code/__DEFINES/mod.dm @@ -4,7 +4,7 @@ /// The default cell drain of a modsuit. The standard modsuit active power usage drains this much energy per modsuit second. #define DEFAULT_CHARGE_DRAIN (0.005 * STANDARD_CELL_CHARGE) // A standard cell lasts 200 seconds with this on active power usage, while a high power one lasts 2,000 seconds. -/// Default time for a part to seal +/// Default time for a part of the suit to seal. #define MOD_ACTIVATION_STEP_TIME (2 SECONDS) /// Passive module, just acts when put in naturally. @@ -23,14 +23,8 @@ /// This module can be used while the suit is off #define MODULE_ALLOW_INACTIVE (1<<2) -//Defines used by the theme for clothing flags and similar -#define CONTROL_LAYER "control_layer" -#define HELMET_FLAGS "helmet_flags" -#define CHESTPLATE_FLAGS "chestplate_flags" -#define GAUNTLETS_FLAGS "gauntlets_flags" -#define BOOTS_FLAGS "boots_flags" - #define UNSEALED_LAYER "unsealed_layer" +#define SEALED_LAYER "sealed_layer" #define UNSEALED_CLOTHING "unsealed_clothing" #define SEALED_CLOTHING "sealed_clothing" #define UNSEALED_INVISIBILITY "unsealed_invisibility" @@ -38,6 +32,8 @@ #define UNSEALED_COVER "unsealed_cover" #define SEALED_COVER "sealed_cover" #define CAN_OVERSLOT "can_overslot" +#define UNSEALED_MESSAGE "unsealed_message" +#define SEALED_MESSAGE "sealed_message" //Defines used to override MOD clothing's icon and worn icon files in the skin. #define MOD_ICON_OVERRIDE "mod_icon_override" @@ -49,6 +45,16 @@ #define MODLINK_FREQ_CHARLIE "CHRL" #define MODLINK_FREQ_CENTCOM "CC" +//Default text for different messages for the user. +#define HELMET_UNSEAL_MESSAGE "hisses open" +#define HELMET_SEAL_MESSAGE "hisses closed" +#define CHESTPLATE_UNSEAL_MESSAGE "releases your chest" +#define CHESTPLATE_SEAL_MESSAGE "cinches tightly around your chest" +#define GAUNTLET_UNSEAL_MESSAGE "become loose around your fingers" +#define GAUNTLET_SEAL_MESSAGE "tighten around your fingers and wrists" +#define BOOT_UNSEAL_MESSAGE "relax their grip on your legs" +#define BOOT_SEAL_MESSAGE "seal around your feet" + /// Global list of all /datum/mod_theme GLOBAL_LIST_INIT(mod_themes, setup_mod_themes()) /// Global list of all ids associated to a /datum/mod_link instance diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 6fdb2b5cdcc..1950667e315 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -685,6 +685,49 @@ GLOBAL_LIST_INIT(skin_tone_names, list( else return precise_zone +///Returns a list of strings for a given slot flag. +/proc/parse_slot_flags(slot_flags) + var/list/slot_strings = list() + if(slot_flags & ITEM_SLOT_BACK) + slot_strings += "back" + if(slot_flags & ITEM_SLOT_MASK) + slot_strings += "mask" + if(slot_flags & ITEM_SLOT_NECK) + slot_strings += "neck" + if(slot_flags & ITEM_SLOT_HANDCUFFED) + slot_strings += "handcuff" + if(slot_flags & ITEM_SLOT_LEGCUFFED) + slot_strings += "legcuff" + if(slot_flags & ITEM_SLOT_BELT) + slot_strings += "belt" + if(slot_flags & ITEM_SLOT_ID) + slot_strings += "id" + if(slot_flags & ITEM_SLOT_EARS) + slot_strings += "ear" + if(slot_flags & ITEM_SLOT_EYES) + slot_strings += "glasses" + if(slot_flags & ITEM_SLOT_GLOVES) + slot_strings += "glove" + if(slot_flags & ITEM_SLOT_HEAD) + slot_strings += "head" + if(slot_flags & ITEM_SLOT_FEET) + slot_strings += "shoe" + if(slot_flags & ITEM_SLOT_OCLOTHING) + slot_strings += "oversuit" + if(slot_flags & ITEM_SLOT_ICLOTHING) + slot_strings += "undersuit" + if(slot_flags & ITEM_SLOT_SUITSTORE) + slot_strings += "suit storage" + if(slot_flags & (ITEM_SLOT_LPOCKET|ITEM_SLOT_RPOCKET)) + slot_strings += "pocket" + if(slot_flags & ITEM_SLOT_HANDS) + slot_strings += "hand" + if(slot_flags & ITEM_SLOT_DEX_STORAGE) + slot_strings += "dextrous storage" + if(slot_flags & ITEM_SLOT_BACKPACK) + slot_strings += "backpack" + return slot_strings + ///Returns the direction that the initiator and the target are facing /proc/check_target_facings(mob/living/initiator, mob/living/target) /*This can be used to add additional effects on interactions between mobs depending on how the mobs are facing each other, such as adding a crit damage to blows to the back of a guy's head. diff --git a/code/modules/bitrunning/antagonists/cyber_tac.dm b/code/modules/bitrunning/antagonists/cyber_tac.dm index 26ad05081e8..a45fdb345d3 100644 --- a/code/modules/bitrunning/antagonists/cyber_tac.dm +++ b/code/modules/bitrunning/antagonists/cyber_tac.dm @@ -29,80 +29,3 @@ var/obj/item/implant/weapons_auth/auth = new(user) auth.implant(user) - -/obj/item/mod/control/pre_equipped/glitch - theme = /datum/mod_theme/glitch - applied_cell = /obj/item/stock_parts/cell/bluespace - applied_modules = list( - /obj/item/mod/module/storage, - /obj/item/mod/module/magnetic_harness, - /obj/item/mod/module/jetpack/advanced, - /obj/item/mod/module/jump_jet, - /obj/item/mod/module/flashlight, - ) - default_pins = list( - /obj/item/mod/module/armor_booster, - /obj/item/mod/module/jetpack/advanced, - /obj/item/mod/module/jump_jet, - ) - starting_frequency = null - -/datum/armor/mod_theme_glitch - melee = 15 - bullet = 20 - laser = 35 - bomb = 65 - bio = 100 - fire = 100 - acid = 100 - wound = 100 - -/datum/mod_theme/glitch - name = "glitch" - desc = "A modsuit outfitted for elite Cyber Authority units to track, capture, and eliminate organic intruders." - extended_desc = "The Cyber Authority function as a digital police force, patrolling the digital realm and enforcing the law. Cyber Tac units are the elite of the elite, outfitted with lethal weaponry and fast mobility specially designed to quell organic uprisings." - default_skin = "glitch" - armor_type = /datum/armor/mod_theme_glitch - resistance_flags = FIRE_PROOF|ACID_PROOF - atom_flags = PREVENT_CONTENTS_EXPLOSION_1 - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - complexity_max = DEFAULT_MAX_COMPLEXITY + 3 - siemens_coefficient = 0 - slowdown_inactive = 1 - slowdown_active = 0.5 - ui_theme = "terminal" - inbuilt_modules = list(/obj/item/mod/module/armor_booster) - allowed_suit_storage = list( - /obj/item/ammo_box, - /obj/item/ammo_casing, - /obj/item/restraints/handcuffs, - /obj/item/assembly/flash, - ) - skins = list( - "glitch" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, - UNSEALED_CLOTHING = SNUG_FIT, - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, - UNSEALED_INVISIBILITY = HIDEFACIALHAIR, - SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, - SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, - ), - CHESTPLATE_FLAGS = list( - UNSEALED_CLOTHING = THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, - SEALED_INVISIBILITY = HIDEJUMPSUIT, - ), - GAUNTLETS_FLAGS = list( - UNSEALED_CLOTHING = THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, - CAN_OVERSLOT = TRUE, - ), - BOOTS_FLAGS = list( - UNSEALED_CLOTHING = THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, - CAN_OVERSLOT = TRUE, - ), - ), - ) - diff --git a/code/modules/jobs/job_types/cargo_technician.dm b/code/modules/jobs/job_types/cargo_technician.dm index dd269bc7e37..008ddd6df0d 100644 --- a/code/modules/jobs/job_types/cargo_technician.dm +++ b/code/modules/jobs/job_types/cargo_technician.dm @@ -54,3 +54,4 @@ name = "Cargo Technician (MODsuit)" back = /obj/item/mod/control/pre_equipped/loader + suit = null diff --git a/code/modules/mod/adding_new_mod.md b/code/modules/mod/adding_new_mod.md index b0bf12486c1..8252822cf6c 100644 --- a/code/modules/mod/adding_new_mod.md +++ b/code/modules/mod/adding_new_mod.md @@ -82,16 +82,15 @@ So, now that we have our theme, we want to add a skin to it (or another theme of armor_type = /datum/armor/modtheme_psychological complexity_max = DEFAULT_MAX_COMPLEXITY - 7 charge_drain = DEFAULT_CHARGE_DRAIN * 0.5 - skins = list( + variants = list( "psychological" = list( - HELMET_LAYER = null, - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( ), ), ) @@ -101,8 +100,7 @@ We now have a psychological skin, this will apply the psychological icons to eve For example, if our helmet's icon covers the full head (like the research skin), we want to do something like this. ```dm - HELMET_LAYER = null, - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, @@ -113,8 +111,8 @@ For example, if our helmet's icon covers the full head (like the research skin), Otherwise, with an open helmet that becomes closed (like the engineering skin), we'd do this. ```dm - HELMET_LAYER = NECK_LAYER, - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( + UNSEALED_LAYER = NECK_LAYER UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, @@ -137,47 +135,46 @@ There are specific cases of helmets that semi-cover the head, like the cosmohonk armor_type = /datum/armor/modtheme_psychological complexity_max = DEFAULT_MAX_COMPLEXITY - 7 charge_drain = DEFAULT_CHARGE_DRAIN * 0.5 - skins = list( + variants = list( "psychological" = list( - HELMET_LAYER = NECK_LAYER, - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( + UNSEALED_LAYER = NECK_LAYER UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, ), "psychotherapeutic" = list( - HELMET_LAYER = null, - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, ), @@ -207,7 +204,7 @@ As we want this effect to be on demand, we probably want this to be an usable mo - Usable: You can use these for a one time effect. - Active: You can only have one selected at a time. It gives you a special click effect. -As we have an usable module, we want to set a cooldown time. All modules are also incompatible with themselves, have a specific power cost and complexity varying on how powerful they are, so let's update our definition, and also add a new variable for how much brain damage we'll heal. +As we have an usable module, we want to set a cooldown time. All modules are also incompatible with themselves, have a specific power cost and complexity varying on how powerful they are, and are equippable to certain slots, so let's update our definition, and also add a new variable for how much brain damage we'll heal. ```dm /obj/item/mod/module/neuron_healer @@ -220,25 +217,20 @@ As we have an usable module, we want to set a cooldown time. All modules are als use_energy_cost = DEFAULT_CHARGE_DRAIN incompatible_modules = list(/obj/item/mod/module/neuron_healer) cooldown_time = 15 SECONDS + required_slot = list(ITEM_SLOT_HEAD) var/brain_damage_healed = 25 ``` -Now, we want to override the on_use proc for our new effect. We want to make sure the use checks passed from parent. You can read about most procs and variables by reading [this](modules/_module.dm) +Now, we want to override the on_use proc for our new effect. You can read about most procs and variables by reading [this](modules/_module.dm) ```dm /obj/item/mod/module/neuron_healer/on_use() - . = ..() - if(!.) - return ``` After this, we want to put our special code, a basic effect of healing all mobs nearby for their brain damage and creating a beam to them. ```dm /obj/item/mod/module/neuron_healer/on_use() - . = ..() - if(!.) - return for(var/mob/living/carbon/carbon_mob in range(5, src)) if(carbon_mob == mod.wearer) continue @@ -272,47 +264,46 @@ Now we want to add it to the psychological theme, which is very simple, finishin complexity_max = DEFAULT_MAX_COMPLEXITY - 7 charge_drain = DEFAULT_CHARGE_DRAIN * 0.5 inbuilt_modules = list(/obj/item/mod/module/neuron_healer/advanced) - skins = list( + variants = list( "psychological" = list( - HELMET_LAYER = NECK_LAYER, - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( + UNSEALED_LAYER = NECK_LAYER UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, ), "psychotherapeutic" = list( - HELMET_LAYER = null, - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, ), diff --git a/code/modules/mod/mod_activation.dm b/code/modules/mod/mod_activation.dm index c76dfba1ed1..d36b7450022 100644 --- a/code/modules/mod/mod_activation.dm +++ b/code/modules/mod/mod_activation.dm @@ -6,7 +6,8 @@ return var/list/display_names = list() var/list/items = list() - for(var/obj/item/part as anything in mod_parts) + var/list/parts = get_parts() + for(var/obj/item/part as anything in parts) display_names[part.name] = REF(part) var/image/part_image = image(icon = part.icon, icon_state = part.icon_state) if(part.loc != src) @@ -16,17 +17,17 @@ if(!pick) return var/part_reference = display_names[pick] - var/obj/item/part = locate(part_reference) in mod_parts + var/obj/item/part = locate(part_reference) in parts if(!istype(part) || user.incapacitated()) return if(activating) // NOVA EDIT - RETRACTABLE EVERYTHING balloon_alert(user, "deactivate the suit first!") playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) return - var/parts_to_check = mod_parts - part + var/parts_to_check = parts - part if(part.loc == src) deploy(user, part) - on_mod_deployed(user) + SEND_SIGNAL(src, COMSIG_MOD_DEPLOYED, user) for(var/obj/item/checking_part as anything in parts_to_check) if(checking_part.loc != src) continue @@ -34,7 +35,7 @@ break else retract(user, part) - on_mod_retracted(user) + SEND_SIGNAL(src, COMSIG_MOD_RETRACTED, user) for(var/obj/item/checking_part as anything in parts_to_check) if(checking_part.loc == src) continue @@ -48,28 +49,29 @@ playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) return FALSE var/deploy = TRUE - for(var/obj/item/part as anything in mod_parts) + for(var/obj/item/part as anything in get_parts()) if(part.loc == src) continue deploy = FALSE break - for(var/obj/item/part as anything in mod_parts) + for(var/obj/item/part as anything in get_parts()) if(deploy && part.loc == src) deploy(null, part) else if(!deploy && part.loc != src) retract(null, part) - wearer.visible_message(span_notice("[wearer]'s [src] [deploy ? "deploys" : "retracts"] its' parts with a mechanical hiss."), - span_notice("[src] [deploy ? "deploys" : "retracts"] its' parts with a mechanical hiss."), + wearer.visible_message(span_notice("[wearer]'s [src] [deploy ? "deploys" : "retracts"] its parts with a mechanical hiss."), + span_notice("[src] [deploy ? "deploys" : "retracts"] its parts with a mechanical hiss."), span_hear("You hear a mechanical hiss.")) playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) if(deploy) - on_mod_deployed(user) + SEND_SIGNAL(src, COMSIG_MOD_DEPLOYED, user) else - on_mod_retracted(user) + SEND_SIGNAL(src, COMSIG_MOD_RETRACTED, user) return TRUE /// Deploys a part of the suit onto the user. /obj/item/mod/control/proc/deploy(mob/user, obj/item/part) + var/datum/mod_part/part_datum = get_part_datum(part) if(!wearer) playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) return FALSE // pAI is trying to deploy it from your hands @@ -78,10 +80,10 @@ return FALSE balloon_alert(user, "[part.name] already deployed!") playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) - if(part in overslotting_parts) + if(part_datum.can_overslot) var/obj/item/overslot = wearer.get_item_by_slot(part.slot_flags) if(overslot) - overslotting_parts[part] = overslot + part_datum.overslotting = overslot wearer.transferItemToLoc(overslot, part, force = TRUE) 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)) @@ -92,6 +94,7 @@ span_notice("[part] deploy[part.p_s()] with a mechanical hiss."), span_hear("You hear a mechanical hiss.")) playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + SEND_SIGNAL(src, COMSIG_MOD_PART_DEPLOYED, user, part) return TRUE else if(!user) @@ -102,6 +105,7 @@ /// Retract a part of the suit from the user. /obj/item/mod/control/proc/retract(mob/user, obj/item/part) + var/datum/mod_part/part_datum = get_part_datum(part) if(part.loc == src) if(!user) return FALSE @@ -109,17 +113,18 @@ playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) REMOVE_TRAIT(part, TRAIT_NODROP, MOD_TRAIT) wearer.transferItemToLoc(part, src, force = TRUE) - if(overslotting_parts[part]) + if(part_datum.overslotting) UnregisterSignal(part, COMSIG_ATOM_EXITED) - var/obj/item/overslot = overslotting_parts[part] - if(!wearer.equip_to_slot_if_possible(overslot, overslot.slot_flags, qdel_on_fail = FALSE, disable_warning = TRUE)) + 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) - overslotting_parts[part] = null + part_datum.overslotting = null // NOVA EDIT START - Avoiding exploits with the modules staying active when any of the parts are retracted. for(var/obj/item/mod/module/module as anything in modules) if(module.active) - module.on_deactivation(display_message = !!user) + module.deactivate(display_message = !!user) // NOVA EDIT END + SEND_SIGNAL(src, COMSIG_MOD_PART_RETRACTED, user, part) if(!user) return wearer.visible_message(span_notice("[wearer]'s [part.name] retract[part.p_s()] back into [src] with a mechanical hiss."), @@ -127,7 +132,7 @@ span_hear("You hear a mechanical hiss.")) playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) -/// Starts the activation sequence, where parts of the suit activate one by one until the whole suit is on +/// Starts the activation sequence, where parts of the suit activate one by one until the whole suit is on. /obj/item/mod/control/proc/toggle_activate(mob/user, force_deactivate = FALSE) if(!wearer) if(!force_deactivate) @@ -137,7 +142,7 @@ if(!force_deactivate && (SEND_SIGNAL(src, COMSIG_MOD_ACTIVATE, user) & MOD_CANCEL_ACTIVATE)) playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) return FALSE - for(var/obj/item/part as anything in mod_parts) + for(var/obj/item/part as anything in get_parts()) if(!force_deactivate && part.loc == src) balloon_alert(user, "deploy all parts first!") playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) @@ -162,34 +167,21 @@ for(var/obj/item/mod/module/module as anything in modules) if(!module.active || (module.allow_flags & MODULE_ALLOW_INACTIVE)) continue - module.on_deactivation(display_message = FALSE) - mod_link.end_call() + module.deactivate(display_message = FALSE) activating = TRUE + mod_link.end_call() to_chat(wearer, span_notice("MODsuit [active ? "shutting down" : "starting up"].")) - - if (ai_assistant) - to_chat(ai_assistant, span_notice("MODsuit [active ? "shutting down" : "starting up"].")) - if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)), hidden = TRUE)) - to_chat(wearer, span_notice("[boots] [active ? "relax their grip on your legs" : "seal around your feet"].")) - playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) - seal_part(boots, seal = !active) - if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)), hidden = TRUE)) - to_chat(wearer, span_notice("[gauntlets] [active ? "become loose around your fingers" : "tighten around your fingers and wrists"].")) - playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) - seal_part(gauntlets, seal = !active) - if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)), hidden = TRUE)) - to_chat(wearer, span_notice("[chestplate] [active ? "releases your chest" : "cinches tightly against your chest"].")) - playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) - seal_part(chestplate, seal = !active) - if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)), hidden = TRUE)) - to_chat(wearer, span_notice("[helmet] hisses [active ? "open" : "closed"].")) - playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) - seal_part(helmet, seal = !active) - if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)), hidden = TRUE)) + for(var/obj/item/part as anything in get_parts()) + var/datum/mod_part/part_datum = get_part_datum(part) + if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(get_wearer)), hidden = TRUE)) + to_chat(wearer, span_notice("[part] [active ? part_datum.unsealed_message : part_datum.sealed_message].")) + playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + seal_part(part, is_sealed = !active) + if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(get_wearer)), hidden = TRUE)) to_chat(wearer, span_notice("Systems [active ? "shut down. Parts unsealed. Goodbye" : "started up. Parts sealed. Welcome"], [wearer].")) if(ai_assistant) to_chat(ai_assistant, span_notice("SYSTEMS [active ? "DEACTIVATED. GOODBYE" : "ACTIVATED. WELCOME"]: \"[ai_assistant]\"")) - finish_activation(on = !active) + finish_activation(is_on = !active) if(active) playsound(src, 'sound/machines/synth_yes.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, frequency = 6000) if(!malfunctioning) @@ -200,16 +192,18 @@ SEND_SIGNAL(src, COMSIG_MOD_TOGGLED, user) return TRUE -///Seals or unseals the given part -/obj/item/mod/control/proc/seal_part(obj/item/clothing/part, seal) - if(seal) +///Seals or unseals the given part. +/obj/item/mod/control/proc/seal_part(obj/item/clothing/part, is_sealed) + var/datum/mod_part/part_datum = get_part_datum(part) + part_datum.sealed = is_sealed + if(part_datum.sealed) part.icon_state = "[skin]-[part.base_icon_state]-sealed" part.clothing_flags |= part.visor_flags part.flags_inv |= part.visor_flags_inv part.flags_cover |= part.visor_flags_cover part.heat_protection = initial(part.heat_protection) part.cold_protection = initial(part.cold_protection) - part.alternate_worn_layer = null + part.alternate_worn_layer = part_datum.sealed_layer else part.icon_state = "[skin]-[part.base_icon_state]" part.flags_cover &= ~part.visor_flags_cover @@ -217,15 +211,17 @@ part.clothing_flags &= ~part.visor_flags part.heat_protection = NONE part.cold_protection = NONE - part.alternate_worn_layer = mod_parts[part] + part.alternate_worn_layer = part_datum.unsealed_layer wearer.update_clothing(part.slot_flags) wearer.update_obscured_slots(part.visor_flags_inv) if((part.clothing_flags & (MASKINTERNALS|HEADINTERNALS)) && wearer.invalid_internals()) wearer.cutoff_internals() /// Finishes the suit's activation -/obj/item/mod/control/proc/finish_activation(on) - active = on +/obj/item/mod/control/proc/finish_activation(is_on) + var/datum/mod_part/part_datum = get_part_datum(src) + part_datum.sealed = is_on + active = is_on if(active) for(var/obj/item/mod/module/module as anything in modules) module.on_suit_activation() @@ -240,22 +236,13 @@ /// 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() var/seal = TRUE - for(var/obj/item/part as anything in mod_parts) + for(var/obj/item/part as anything in get_parts()) if(!deploy(null, part)) seal = FALSE if(!seal) return - for(var/obj/item/part as anything in mod_parts) - seal_part(part, seal = TRUE) - finish_activation(on = TRUE) - -/obj/item/mod/control/proc/has_wearer() - return wearer - -/obj/item/mod/control/proc/on_mod_deployed(mob/user) - SEND_SIGNAL(src, COMSIG_MOD_DEPLOYED, user) - -/obj/item/mod/control/proc/on_mod_retracted(mob/user) - SEND_SIGNAL(src, COMSIG_MOD_RETRACTED, user) + for(var/obj/item/part as anything in get_parts()) + seal_part(part, is_sealed = TRUE) + finish_activation(is_on = TRUE) #undef MOD_ACTIVATION_STEP_FLAGS diff --git a/code/modules/mod/mod_control.dm b/code/modules/mod/mod_control.dm index 91045a26fad..aca9bc0b086 100644 --- a/code/modules/mod/mod_control.dm +++ b/code/modules/mod/mod_control.dm @@ -65,20 +65,10 @@ var/activation_step_time = MOD_ACTIVATION_STEP_TIME /// Extended description of the theme. var/extended_desc - /// MOD helmet. - var/obj/item/clothing/head/mod/helmet - /// MOD chestplate. - var/obj/item/clothing/suit/mod/chestplate - /// MOD gauntlets. - var/obj/item/clothing/gloves/mod/gauntlets - /// MOD boots. - var/obj/item/clothing/shoes/mod/boots /// MOD core. var/obj/item/mod/core/core - /// Associated list of parts (helmet, chestplate, gauntlets, boots) to their unsealed worn layer. + /// List of MODsuit part datums. var/list/mod_parts = list() - /// Associated list of parts that can overslot to their overslot (overslot means the part can cover another layer of clothing). - var/list/overslotting_parts = list() /// Modules the MOD currently possesses. var/list/modules = list() /// Currently used module. @@ -103,43 +93,14 @@ if(new_theme) theme = new_theme theme = GLOB.mod_themes[theme] - slot_flags = theme.slot_flags - extended_desc = theme.extended_desc - slowdown_inactive = theme.slowdown_inactive - slowdown_active = theme.slowdown_active - activation_step_time = theme.activation_step_time - complexity_max = theme.complexity_max - ui_theme = theme.ui_theme - charge_drain = theme.charge_drain + theme.set_up_parts(src, new_skin) + for(var/obj/item/part as anything in get_parts()) + RegisterSignal(part, COMSIG_ATOM_DESTRUCTION, PROC_REF(on_part_destruction)) + RegisterSignal(part, COMSIG_QDELETING, PROC_REF(on_part_deletion)) set_wires(new /datum/wires/mod(src)) if(length(req_access)) locked = TRUE new_core?.install(src) - helmet = new /obj/item/clothing/head/mod(src) - mod_parts += helmet - chestplate = new /obj/item/clothing/suit/mod(src) - chestplate.allowed += theme.allowed_suit_storage - mod_parts += chestplate - gauntlets = new /obj/item/clothing/gloves/mod(src) - mod_parts += gauntlets - boots = new /obj/item/clothing/shoes/mod(src) - mod_parts += boots - var/list/all_parts = mod_parts + src - for(var/obj/item/part as anything in all_parts) - part.name = "[theme.name] [part.name]" - part.desc = "[part.desc] [theme.desc]" - part.set_armor(theme.armor_type) - part.resistance_flags = theme.resistance_flags - part.flags_1 |= theme.atom_flags //flags like initialization or admin spawning are here, so we cant set, have to add - part.heat_protection = NONE - part.cold_protection = NONE - part.max_heat_protection_temperature = theme.max_heat_protection_temperature - part.min_cold_protection_temperature = theme.min_cold_protection_temperature - part.siemens_coefficient = theme.siemens_coefficient - for(var/obj/item/part as anything in mod_parts) - RegisterSignal(part, COMSIG_ATOM_DESTRUCTION, PROC_REF(on_part_destruction)) - RegisterSignal(part, COMSIG_QDELETING, PROC_REF(on_part_deletion)) - set_mod_skin(new_skin || theme.default_skin) update_speed() RegisterSignal(src, COMSIG_ATOM_EXITED, PROC_REF(on_exit)) RegisterSignal(src, COMSIG_SPEED_POTION_APPLIED, PROC_REF(on_potion)) @@ -152,46 +113,23 @@ STOP_PROCESSING(SSobj, src) for(var/obj/item/mod/module/module as anything in modules) uninstall(module, deleting = TRUE) - for(var/obj/item/part as anything in mod_parts) - overslotting_parts -= part - var/atom/deleting_atom - if(!QDELETED(helmet)) - deleting_atom = helmet - helmet = null - mod_parts -= deleting_atom - qdel(deleting_atom) - if(!QDELETED(chestplate)) - deleting_atom = chestplate - chestplate = null - mod_parts -= deleting_atom - qdel(deleting_atom) - if(!QDELETED(gauntlets)) - deleting_atom = gauntlets - gauntlets = null - mod_parts -= deleting_atom - qdel(deleting_atom) - if(!QDELETED(boots)) - deleting_atom = boots - boots = null - mod_parts -= deleting_atom - qdel(deleting_atom) if(core) QDEL_NULL(core) QDEL_NULL(wires) QDEL_NULL(mod_link) + for(var/datum/mod_part/part_datum as anything in get_part_datums(all = TRUE)) + part_datum.part_item = null + part_datum.overslotting = null return ..() /obj/item/mod/control/atom_destruction(damage_flag) + if(wearer) + wearer.visible_message(span_danger("[src] fall[p_s()] apart, completely destroyed!"), vision_distance = COMBAT_MESSAGE_RANGE) + clean_up() for(var/obj/item/mod/module/module as anything in modules) for(var/obj/item/item in module) item.forceMove(drop_location()) uninstall(module) - for(var/obj/item/part as anything in mod_parts) - if(!overslotting_parts[part]) - continue - var/obj/item/overslot = overslotting_parts[part] - overslot.forceMove(drop_location()) - overslotting_parts[part] = null if(ai_assistant) if(ispAI(ai_assistant)) INVOKE_ASYNC(src, PROC_REF(remove_pai), /* user = */ null, /* forced = */ TRUE) // async to appease spaceman DMM because the branch we don't run has a do_after @@ -248,11 +186,10 @@ subtract_charge((charge_drain + malfunctioning_charge_drain) * seconds_per_tick) for(var/obj/item/mod/module/module as anything in modules) if(malfunctioning && module.active && SPT_PROB(5, seconds_per_tick)) - module.on_deactivation(display_message = TRUE) + module.deactivate(display_message = TRUE) module.on_process(seconds_per_tick) -/obj/item/mod/control/equipped(mob/user, slot) - ..() +/obj/item/mod/control/visual_equipped(mob/user, slot, initial = FALSE) //needs to be visual because we wanna show it in select equipment if(slot & slot_flags) set_wearer(user) else if(wearer) @@ -284,7 +221,7 @@ /obj/item/mod/control/allow_attack_hand_drop(mob/user) if(user != wearer) return ..() - for(var/obj/item/part as anything in mod_parts) + for(var/obj/item/part as anything in get_parts()) if(part.loc != src) balloon_alert(user, "retract parts first!") playsound(src, 'sound/machines/scanbuzz.ogg', 25, FALSE, SILENCED_SOUND_EXTRARANGE) @@ -293,7 +230,7 @@ /obj/item/mod/control/MouseDrop(atom/over_object) if(usr != wearer || !istype(over_object, /atom/movable/screen/inventory/hand)) return ..() - for(var/obj/item/part as anything in mod_parts) + for(var/obj/item/part as anything in get_parts()) if(part.loc != src) balloon_alert(wearer, "retract parts first!") playsound(src, 'sound/machines/scanbuzz.ogg', 25, FALSE, SILENCED_SOUND_EXTRARANGE) @@ -446,16 +383,12 @@ to_chat(wearer, span_notice("[severity > 1 ? "Light" : "Strong"] electromagnetic pulse detected!")) if(. & EMP_PROTECT_CONTENTS) return - selected_module?.on_deactivation(display_message = TRUE) + selected_module?.deactivate(display_message = TRUE) wearer.apply_damage(5 / severity, BURN, spread_damage=TRUE) to_chat(wearer, span_danger("You feel [src] heat up from the EMP, burning you slightly.")) if(wearer.stat < UNCONSCIOUS && prob(10)) wearer.emote("scream") -/obj/item/mod/control/visual_equipped(mob/user, slot, initial = FALSE) - if(slot & slot_flags) - set_wearer(user) - /obj/item/mod/control/on_outfit_equip(mob/living/carbon/human/outfit_wearer, visuals_only, item_slot) . = ..() quick_activation() @@ -463,7 +396,7 @@ /obj/item/mod/control/doStrip(mob/stripper, mob/owner) if(active && !toggle_activate(stripper, force_deactivate = TRUE)) return - for(var/obj/item/part as anything in mod_parts) + for(var/obj/item/part as anything in get_parts()) if(part.loc == src) continue retract(null, part) @@ -473,14 +406,44 @@ icon_state = "[skin]-[base_icon_state][active ? "-sealed" : ""]" return ..() +/obj/item/mod/control/proc/get_parts(all = FALSE) + . = list() + for(var/key in mod_parts) + var/datum/mod_part/part = mod_parts[key] + if(!all && part.part_item == src) + continue + . += part.part_item + +/obj/item/mod/control/proc/get_part_datums(all = FALSE) + . = list() + for(var/key in mod_parts) + var/datum/mod_part/part = mod_parts[key] + if(!all && part.part_item == src) + continue + . += part + +/obj/item/mod/control/proc/get_part_datum(obj/item/part) + RETURN_TYPE(/datum/mod_part) + var/datum/mod_part/potential_part = mod_parts["[part.slot_flags]"] + if(potential_part?.part_item == part) + return potential_part + for(var/datum/mod_part/mod_part in get_part_datums()) + if(mod_part.part_item == part) + return mod_part + CRASH("get_part_datum called with incorrect item [part] passed.") + +/obj/item/mod/control/proc/get_part_from_slot(slot) + slot = "[slot]" + for(var/part_slot in mod_parts) + if(slot != part_slot) + continue + var/datum/mod_part/part = mod_parts[part_slot] + return part.part_item + /obj/item/mod/control/proc/set_wearer(mob/living/carbon/human/user) - if (wearer == user) - // This should also not happen. - // This path is hit when equipping an outfit with visualsOnly, but only sometimes, and this eventually gets called twice. - // I'm not sure this proc should ever be being called by visualsOnly, but it is, - // and this was an emergency patch. - return - else if (!isnull(wearer)) + if(wearer == user) + CRASH("set_wearer() was called with the new wearer being the current wearer: [wearer]") + else if(!isnull(wearer)) stack_trace("set_wearer() was called with a new wearer without unset_wearer() being called") wearer = user @@ -500,17 +463,20 @@ wearer = null /obj/item/mod/control/proc/clean_up() + if(QDELING(src)) + unset_wearer() + return if(active || activating) for(var/obj/item/mod/module/module as anything in modules) if(!module.active) continue - module.on_deactivation(display_message = FALSE) - for(var/obj/item/part as anything in mod_parts) - seal_part(part, seal = FALSE) - for(var/obj/item/part as anything in mod_parts) + module.deactivate(display_message = FALSE) + for(var/obj/item/part as anything in get_parts()) + seal_part(part, is_sealed = FALSE) + for(var/obj/item/part as anything in get_parts()) retract(null, part) if(active) - finish_activation(on = FALSE) + finish_activation(is_on = FALSE) mod_link?.end_call() var/mob/old_wearer = wearer unset_wearer() @@ -519,8 +485,7 @@ /obj/item/mod/control/proc/on_species_gain(datum/source, datum/species/new_species, datum/species/old_species) SIGNAL_HANDLER - var/list/all_parts = mod_parts + src - for(var/obj/item/part in all_parts) + for(var/obj/item/part in get_parts(all = TRUE)) if(!(new_species.no_equip_flags & part.slot_flags) || is_type_in_list(new_species, part.species_exception)) continue forceMove(drop_location()) @@ -578,6 +543,11 @@ balloon_alert(user, "[new_module] would make [src] too complex!") playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) return + if(!new_module.has_required_parts(mod_parts)) + if(user) + balloon_alert(user, "[new_module] incompatible with [src]'s parts!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return new_module.forceMove(src) modules += new_module complexity += new_module.complexity @@ -600,7 +570,7 @@ if(active) old_module.on_suit_deactivation(deleting = deleting) if(old_module.active) - old_module.on_deactivation(display_message = !deleting, deleting = deleting) + 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) @@ -656,9 +626,8 @@ wearer.update_spacesuit_hud_icon(state_to_use || "0") /obj/item/mod/control/proc/update_speed() - var/list/all_parts = mod_parts + src - for(var/obj/item/part as anything in all_parts) - part.slowdown = (active ? slowdown_active : slowdown_inactive) / length(all_parts) + for(var/obj/item/part as anything in get_parts(all = TRUE)) + part.slowdown = (active ? slowdown_active : slowdown_inactive) / length(mod_parts) wearer?.update_equipment_speed_mods() /obj/item/mod/control/proc/power_off() @@ -666,54 +635,11 @@ toggle_activate(wearer, force_deactivate = TRUE) /obj/item/mod/control/proc/set_mod_color(new_color) - var/list/all_parts = mod_parts + src - for(var/obj/item/part as anything in all_parts) + for(var/obj/item/part as anything in get_parts(all = TRUE)) part.remove_atom_colour(WASHABLE_COLOUR_PRIORITY) part.add_atom_colour(new_color, FIXED_COLOUR_PRIORITY) wearer?.regenerate_icons() -/obj/item/mod/control/proc/set_mod_skin(new_skin) - if(active) - CRASH("[src] tried to set skin while active!") - skin = new_skin - var/list/used_skin = theme.skins[new_skin] - if(used_skin[CONTROL_LAYER]) - alternate_worn_layer = used_skin[CONTROL_LAYER] - var/list/skin_updating = mod_parts + src - for(var/obj/item/part as anything in skin_updating) - part.icon = used_skin[MOD_ICON_OVERRIDE] || 'icons/obj/clothing/modsuit/mod_clothing.dmi' - part.worn_icon = used_skin[MOD_WORN_ICON_OVERRIDE] || 'icons/mob/clothing/modsuit/mod_clothing.dmi' - part.icon_state = "[skin]-[part.base_icon_state]" - for(var/obj/item/clothing/part as anything in mod_parts) - var/used_category - if(part == helmet) - used_category = HELMET_FLAGS - if(part == chestplate) - used_category = CHESTPLATE_FLAGS - if(part == gauntlets) - used_category = GAUNTLETS_FLAGS - if(part == boots) - used_category = BOOTS_FLAGS - var/list/category = used_skin[used_category] - part.clothing_flags = category[UNSEALED_CLOTHING] || NONE - part.visor_flags = category[SEALED_CLOTHING] || NONE - part.flags_inv = category[UNSEALED_INVISIBILITY] || NONE - part.visor_flags_inv = category[SEALED_INVISIBILITY] || NONE - part.flags_cover = category[UNSEALED_COVER] || NONE - part.visor_flags_cover = category[SEALED_COVER] || NONE - part.alternate_worn_layer = category[UNSEALED_LAYER] - mod_parts[part] = part.alternate_worn_layer - /* NOVA EDIT START - All MODsuit parts can be worn as overslots. - if(!category[CAN_OVERSLOT]) - if(overslotting_parts[part]) - var/obj/item/overslot = overslotting_parts[part] - overslot.forceMove(drop_location()) - overslotting_parts -= part - continue - */ // NOVA EDIT END - overslotting_parts |= part - wearer?.regenerate_icons() - /obj/item/mod/control/proc/on_exit(datum/source, atom/movable/part, direction) SIGNAL_HANDLER @@ -727,7 +653,9 @@ if(part in modules) uninstall(part) return - if(part in mod_parts) + if(part in get_parts()) + if(isnull(part.loc)) + return if(!wearer) part.forceMove(src) return @@ -738,27 +666,25 @@ /obj/item/mod/control/proc/on_part_destruction(obj/item/part, damage_flag) SIGNAL_HANDLER - if(overslotting_parts[part]) - var/obj/item/overslot = overslotting_parts[part] - overslot.forceMove(drop_location()) - overslotting_parts[part] = null - if(QDELETED(src)) + if(QDELING(src)) return atom_destruction(damage_flag) -/obj/item/mod/control/proc/on_part_deletion(obj/item/part) //the part doesnt count as being qdeleted, so our destroying does an infinite loop, fix later +/obj/item/mod/control/proc/on_part_deletion(obj/item/part) SIGNAL_HANDLER - if(QDELETED(src)) + if(QDELING(src)) return + part.moveToNullspace() qdel(src) -/obj/item/mod/control/proc/on_overslot_exit(datum/source, atom/movable/overslot, direction) +/obj/item/mod/control/proc/on_overslot_exit(obj/item/part, atom/movable/overslot, direction) SIGNAL_HANDLER - if(overslot != overslotting_parts[source]) + var/datum/mod_part/part_datum = get_part_datum(part) + if(overslot != part_datum.overslotting) return - overslotting_parts[source] = null + part_datum.overslotting = null /obj/item/mod/control/proc/on_potion(atom/movable/source, obj/item/slimepotion/speed/speed_potion, mob/living/user) SIGNAL_HANDLER diff --git a/code/modules/mod/mod_paint.dm b/code/modules/mod/mod_paint.dm index 240c0897b33..1402a4aebc6 100644 --- a/code/modules/mod/mod_paint.dm +++ b/code/modules/mod/mod_paint.dm @@ -140,18 +140,18 @@ SStgui.close_uis(src) /obj/item/mod/paint/proc/paint_skin(obj/item/mod/control/mod, mob/user) - if(length(mod.theme.skins) <= 1) + if(length(mod.theme.variants) <= 1) balloon_alert(user, "no alternate skins!") return var/list/skins = list() - for(var/mod_skin_name in mod.theme.skins) - var/list/mod_skin = mod.theme.skins[mod_skin_name] + for(var/mod_skin_name in mod.theme.variants) + var/list/mod_skin = mod.theme.variants[mod_skin_name] skins[mod_skin_name] = image(icon = mod_skin[MOD_ICON_OVERRIDE] || mod.icon, icon_state = "[mod_skin_name]-control") var/pick = show_radial_menu(user, mod, skins, custom_check = CALLBACK(src, PROC_REF(check_menu), mod, user), require_near = TRUE) if(!pick) balloon_alert(user, "no skin picked!") return - mod.set_mod_skin(pick) + mod.theme.set_skin(pick) /obj/item/mod/paint/proc/check_menu(obj/item/mod/control/mod, mob/user) if(user.incapacitated() || !user.is_holding(src) || !mod || mod.active || mod.activating) @@ -171,7 +171,6 @@ icon = 'icons/obj/clothing/modsuit/mod_construction.dmi' icon_state = "skinapplier" var/skin = "civilian" - var/compatible_theme = /datum/mod_theme /obj/item/mod/skin_applier/Initialize(mapload) . = ..() @@ -184,14 +183,13 @@ if(mod.active || mod.activating) balloon_alert(user, "suit is active!") return TRUE - if(!istype(mod.theme, compatible_theme)) + if(!(skin in mod.theme.variants)) balloon_alert(user, "incompatible theme!") return TRUE - mod.set_mod_skin(skin) + mod.theme.set_skin(skin) balloon_alert(user, "skin applied") qdel(src) return TRUE /obj/item/mod/skin_applier/honkerative skin = "honkerative" - compatible_theme = /datum/mod_theme/syndicate diff --git a/code/modules/mod/mod_part.dm b/code/modules/mod/mod_part.dm new file mode 100644 index 00000000000..88f8024628d --- /dev/null +++ b/code/modules/mod/mod_part.dm @@ -0,0 +1,22 @@ +/// Datum to handle interactions between a MODsuit and its parts. +/datum/mod_part + /// The actual item we handle. + var/obj/item/part_item = null + /// Are we sealed? + var/sealed = FALSE + /// Message to user when unsealed. + var/unsealed_message + /// Message to user when sealed. + var/sealed_message + /// The layer the item will render on when unsealed. + var/unsealed_layer + /// The layer the item will render on when sealed. + var/sealed_layer + /// Can our part overslot over others? + var/can_overslot = FALSE + /// What are we overslotting over? + var/obj/item/overslotting = null + +/datum/mod_part/Destroy() + part_item = null + return ..() diff --git a/code/modules/mod/mod_theme.dm b/code/modules/mod/mod_theme.dm index 437eac384c4..2fdb8a2546e 100644 --- a/code/modules/mod/mod_theme.dm +++ b/code/modules/mod/mod_theme.dm @@ -49,58 +49,157 @@ var/list/inbuilt_modules = list() /// Allowed items in the chestplate's suit storage. var/list/allowed_suit_storage = list() - /// List of skins with their appropriate clothing flags. - var/list/skins = list( + /// List of variants and items created by them, with the flags we set. + var/list/variants = list( "standard" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|HEADINTERNALS, - SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), "civilian" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) +#ifdef UNIT_TESTS +/datum/mod_theme/New() + var/list/skin_parts = list() + for(var/variant in variants) + skin_parts += list(assoc_to_keys(variants[variant])) + for(var/skin in skin_parts) + for(var/compared_skin in skin_parts) + if(skin ~! compared_skin) + stack_trace("[type] variants [skin] and [compared_skin] aren't made of the same parts.") + skin_parts -= skin +#endif + +/// Create parts of the suit and modify them using the theme's variables. +/datum/mod_theme/proc/set_up_parts(obj/item/mod/control/mod, skin) + var/list/parts = list(mod) + mod.slot_flags = slot_flags + mod.extended_desc = extended_desc + mod.slowdown_inactive = slowdown_inactive + mod.slowdown_active = slowdown_active + mod.activation_step_time = activation_step_time + mod.complexity_max = complexity_max + mod.ui_theme = ui_theme + mod.charge_drain = charge_drain + var/datum/mod_part/control_part_datum = new() + control_part_datum.part_item = mod + mod.mod_parts["[mod.slot_flags]"] = control_part_datum + for(var/path in variants[default_skin]) + if(!ispath(path)) + continue + var/obj/item/mod_part = new path(mod) + if(mod_part.slot_flags == ITEM_SLOT_OCLOTHING && isclothing(mod_part)) + 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 + mod.mod_parts["[mod_part.slot_flags]"] = part_datum + parts += mod_part + for(var/obj/item/part as anything in parts) + part.name = "[name] [part.name]" + part.desc = "[part.desc] [desc]" + part.set_armor(armor_type) + part.resistance_flags = resistance_flags + part.flags_1 |= atom_flags //flags like initialization or admin spawning are here, so we cant set, have to add + part.heat_protection = NONE + part.cold_protection = NONE + part.max_heat_protection_temperature = max_heat_protection_temperature + part.min_cold_protection_temperature = min_cold_protection_temperature + part.siemens_coefficient = siemens_coefficient + set_skin(mod, skin || default_skin) + +/datum/mod_theme/proc/set_skin(obj/item/mod/control/mod, skin) + mod.skin = skin + var/list/used_skin = variants[skin] + var/list/parts = mod.get_parts() + for(var/obj/item/clothing/part as anything in parts) + var/list/category = used_skin[part.type] + var/datum/mod_part/part_datum = mod.get_part_datum(part) + part_datum.unsealed_layer = category[UNSEALED_LAYER] + part_datum.sealed_layer = category[SEALED_LAYER] + part_datum.unsealed_message = category[UNSEALED_MESSAGE] || "No unseal message set! Tell a coder!" + part_datum.sealed_message = category[SEALED_MESSAGE] || "No seal message set! Tell a coder!" + part_datum.can_overslot = TRUE //NOVA EDIT CHANGE, overslottable everything - Original: part_datum.can_overslot = category[CAN_OVERSLOT] || FALSE + part.clothing_flags = category[UNSEALED_CLOTHING] || NONE + part.visor_flags = category[SEALED_CLOTHING] || NONE + part.flags_inv = category[UNSEALED_INVISIBILITY] || NONE + part.visor_flags_inv = category[SEALED_INVISIBILITY] || NONE + part.flags_cover = category[UNSEALED_COVER] || NONE + part.visor_flags_cover = category[SEALED_COVER] || NONE + if(mod.get_part_datum(part).sealed) + part.clothing_flags |= part.visor_flags + part.flags_inv |= part.visor_flags_inv + part.flags_cover |= part.visor_flags_cover + part.alternate_worn_layer = part_datum.sealed_layer + else + part.alternate_worn_layer = part_datum.unsealed_layer + if(!part_datum.can_overslot && part_datum.overslotting) + var/obj/item/overslot = part_datum.overslotting + overslot.forceMove(mod.drop_location()) + for(var/obj/item/part as anything in parts + mod) + part.icon = used_skin[MOD_ICON_OVERRIDE] || 'icons/obj/clothing/modsuit/mod_clothing.dmi' + part.worn_icon = used_skin[MOD_WORN_ICON_OVERRIDE] || 'icons/mob/clothing/modsuit/mod_clothing.dmi' + part.icon_state = "[skin]-[part.base_icon_state][mod.get_part_datum(part).sealed ? "-sealed" : ""]" + mod.wearer?.update_clothing(part.slot_flags) + /datum/armor/mod_theme melee = 10 bullet = 5 @@ -108,7 +207,7 @@ energy = 5 bio = 100 fire = 25 - acid =25 + acid = 25 wound = 5 /datum/mod_theme/engineering @@ -131,30 +230,38 @@ /obj/item/fireaxe/metal_h2_axe, /obj/item/storage/bag/construction, ) - skins = list( + variants = list( "engineering" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -190,9 +297,9 @@ /obj/item/pipe_dispenser, /obj/item/t_scanner, ) - skins = list( + variants = list( "atmospheric" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, @@ -200,21 +307,29 @@ SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR, UNSEALED_COVER = HEADCOVERSMOUTH, SEALED_COVER = HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -255,30 +370,38 @@ /obj/item/storage/bag/construction, /obj/item/t_scanner, ) - skins = list( + variants = list( "advanced" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -322,55 +445,69 @@ complexity_max = DEFAULT_MAX_COMPLEXITY - 2 charge_drain = DEFAULT_CHARGE_DRAIN * 2 inbuilt_modules = list(/obj/item/mod/module/ash_accretion, /obj/item/mod/module/sphere_transform) - skins = list( + variants = list( "mining" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEYES|HIDEFACE|HIDEFACIALHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), "asteroid" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, SEALED_INVISIBILITY = HIDEMASK|HIDEEYES|HIDEFACE, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -417,23 +554,26 @@ /obj/item/storage/bag/mail, ) inbuilt_modules = list(/obj/item/mod/module/hydraulic, /obj/item/mod/module/clamp/loader, /obj/item/mod/module/magnet) - skins = list( + variants = list( "loader" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( SEALED_CLOTHING = THICKMATERIAL, CAN_OVERSLOT = TRUE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( SEALED_CLOTHING = THICKMATERIAL, CAN_OVERSLOT = TRUE, ), @@ -480,55 +620,71 @@ /obj/item/storage/bag/chemistry, /obj/item/storage/bag/bio, ) - skins = list( + variants = list( "medical" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), "corpsman" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -577,30 +733,38 @@ /obj/item/storage/bag/bio, /obj/item/melee/baton/telescopic, ) - skins = list( + variants = list( "rescue" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -643,29 +807,36 @@ /obj/item/storage/bag/bio, /obj/item/melee/baton/telescopic, ) - skins = list( + variants = list( "research" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -701,31 +872,38 @@ /obj/item/assembly/flash, /obj/item/melee/baton, ) - skins = list( + variants = list( "security" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, SEALED_INVISIBILITY = HIDEMASK|HIDEEYES|HIDEFACE, UNSEALED_COVER = HEADCOVERSMOUTH, SEALED_COVER = HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -763,29 +941,36 @@ /obj/item/assembly/flash, /obj/item/melee/baton, ) - skins = list( + variants = list( "safeguard" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -827,30 +1012,38 @@ /obj/item/assembly/flash, /obj/item/melee/baton, ) - skins = list( + variants = list( "magnate" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -887,30 +1080,38 @@ /obj/item/instrument, /obj/item/toy/balloon_animal, ) - skins = list( + variants = list( "cosmohonk" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -954,55 +1155,71 @@ /obj/item/melee/energy/sword, /obj/item/shield/energy, ) - skins = list( + variants = list( "syndicate" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), "honkerative" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1045,30 +1262,37 @@ /obj/item/melee/energy/sword, /obj/item/shield/energy, ) - skins = list( + variants = list( "elite" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1112,26 +1336,29 @@ /obj/item/melee/energy/sword, /obj/item/shield/energy, ) - skins = list( + variants = list( "infiltrator" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_INVISIBILITY = HIDEJUMPSUIT, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( SEALED_CLOTHING = THICKMATERIAL, CAN_OVERSLOT = TRUE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( SEALED_CLOTHING = THICKMATERIAL, CAN_OVERSLOT = TRUE, ), @@ -1167,7 +1394,7 @@ charge_drain = DEFAULT_CHARGE_DRAIN * 2 slowdown_inactive = 0.0 slowdown_active = -0.5 - inbuilt_modules = list(/obj/item/mod/module/quick_carry/advanced, /obj/item/mod/module/organ_thrower) + inbuilt_modules = list(/obj/item/mod/module/quick_carry/advanced) allowed_suit_storage = list( /obj/item/assembly/flash, /obj/item/healthanalyzer, @@ -1189,30 +1416,38 @@ /obj/item/storage/bag/chemistry, /obj/item/storage/pill_bottle, ) - skins = list( + variants = list( "interdyne" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1253,29 +1488,34 @@ /obj/item/highfrequencyblade/wizard, /obj/item/gun/magic, ) - skins = list( + variants = list( "enchanted" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL|CASTING_CLOTHES, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL|CASTING_CLOTHES, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1314,30 +1554,37 @@ /obj/item/melee/baton, /obj/item/restraints/handcuffs, ) - skins = list( + variants = list( "ninja" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1379,29 +1626,36 @@ /obj/item/pipe_dispenser, /obj/item/construction/rcd, ) - skins = list( + variants = list( "prototype" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1417,6 +1671,73 @@ acid = 75 wound = 5 +/datum/mod_theme/glitch + name = "glitch" + desc = "A modsuit outfitted for elite Cyber Authority units to track, capture, and eliminate organic intruders." + extended_desc = "The Cyber Authority function as a digital police force, patrolling the digital realm and enforcing the law. Cyber Tac units are \ + the elite of the elite, outfitted with lethal weaponry and fast mobility specially designed to quell organic uprisings." + default_skin = "glitch" + armor_type = /datum/armor/mod_theme_glitch + resistance_flags = FIRE_PROOF|ACID_PROOF + atom_flags = PREVENT_CONTENTS_EXPLOSION_1 + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT + complexity_max = DEFAULT_MAX_COMPLEXITY + 3 + siemens_coefficient = 0 + slowdown_inactive = 1 + slowdown_active = 0.5 + ui_theme = "terminal" + inbuilt_modules = list(/obj/item/mod/module/armor_booster) + allowed_suit_storage = list( + /obj/item/ammo_box, + /obj/item/ammo_casing, + /obj/item/restraints/handcuffs, + /obj/item/assembly/flash, + ) + variants = list( + "glitch" = list( + /obj/item/clothing/head/mod = list( + UNSEALED_CLOTHING = SNUG_FIT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR, + SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, + ), + /obj/item/clothing/suit/mod = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, + ), + /obj/item/clothing/gloves/mod = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, + ), + /obj/item/clothing/shoes/mod = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, + ), + ), + ) + +/datum/armor/mod_theme_glitch + melee = 15 + bullet = 20 + laser = 35 + bomb = 65 + bio = 100 + fire = 100 + acid = 100 + wound = 100 + /datum/mod_theme/responsory name = "responsory" desc = "A high-speed rescue suit by Nanotrasen, intended for its emergency response teams." @@ -1438,54 +1759,69 @@ /obj/item/assembly/flash, /obj/item/melee/baton, ) - skins = list( + variants = list( "responsory" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), "inquisitory" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1537,30 +1873,37 @@ /obj/item/melee/energy/sword, /obj/item/shield/energy, ) - skins = list( + variants = list( "apocryphal" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1599,30 +1942,37 @@ /obj/item/assembly/flash, /obj/item/melee/baton, ) - skins = list( + variants = list( "corporate" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, SEALED_INVISIBILITY = HIDEMASK|HIDEEYES|HIDEFACE, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1655,30 +2005,38 @@ allowed_suit_storage = list( /obj/item/restraints/handcuffs, ) - skins = list( + variants = list( "chrono" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1713,31 +2071,38 @@ allowed_suit_storage = list( /obj/item/gun, ) - skins = list( + variants = list( "debug" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE, UNSEALED_COVER = HEADCOVERSMOUTH, SEALED_COVER = HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1773,24 +2138,25 @@ allowed_suit_storage = list( /obj/item/gun, ) - skins = list( + variants = list( "debug" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, ), @@ -1807,54 +2173,3 @@ fire = 100 acid = 100 wound = 100 - -/datum/mod_theme/timeline - name = "chrono" - desc = "A suit beyond our time, beyond time itself. Used to traverse timelines and \"correct their course\"." - extended_desc = "A suit whose tech goes beyond this era's understanding. The internal mechanisms are all but \ - completely alien, but the purpose is quite simple. The suit protects the user from the many incredibly lethal \ - and sometimes hilariously painful side effects of jumping timelines, while providing inbuilt equipment for \ - making timeline adjustments to correct a bad course." - default_skin = "timeline" - armor_type = /datum/armor/mod_theme_timeline - resistance_flags = FIRE_PROOF|ACID_PROOF - max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT - complexity_max = 15 - slowdown_inactive = 0 - slowdown_active = 0 - skins = list( - "timeline" = list( - HELMET_LAYER = null, - HELMET_FLAGS = list( - UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT, - UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, - SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE, - UNSEALED_COVER = HEADCOVERSMOUTH, - SEALED_COVER = HEADCOVERSEYES|PEPPERPROOF, - ), - CHESTPLATE_FLAGS = list( - UNSEALED_CLOTHING = THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, - SEALED_INVISIBILITY = HIDEJUMPSUIT, - ), - GAUNTLETS_FLAGS = list( - UNSEALED_CLOTHING = THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, - ), - BOOTS_FLAGS = list( - UNSEALED_CLOTHING = THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, - ), - ), - ) - -/datum/armor/mod_theme_timeline - melee = 60 - bullet = 60 - laser = 60 - energy = 60 - bomb = 30 - bio = 90 - fire = 100 - acid = 100 diff --git a/code/modules/mod/mod_types.dm b/code/modules/mod/mod_types.dm index 2789763e12c..8843a811756 100644 --- a/code/modules/mod/mod_types.dm +++ b/code/modules/mod/mod_types.dm @@ -212,7 +212,7 @@ /obj/item/mod/module/storage, /obj/item/mod/module/waddle, /obj/item/mod/module/bikehorn, - /obj/item/mod/module/balloon_advanced, + /obj/item/mod/module/balloon/advanced, ) /obj/item/mod/control/pre_equipped/traitor @@ -352,6 +352,7 @@ starting_frequency = MODLINK_FREQ_SYNDICATE applied_cell = /obj/item/stock_parts/cell/super applied_modules = list( + /obj/item/mod/module/organ_thrower, /obj/item/mod/module/defibrillator/combat, /obj/item/mod/module/flashlight, /obj/item/mod/module/health_analyzer, @@ -413,6 +414,23 @@ /obj/item/mod/module/anomaly_locked/kinesis/prototype, ) +/obj/item/mod/control/pre_equipped/glitch + theme = /datum/mod_theme/glitch + starting_frequency = null + applied_cell = /obj/item/stock_parts/cell/bluespace + applied_modules = list( + /obj/item/mod/module/storage, + /obj/item/mod/module/magnetic_harness, + /obj/item/mod/module/jetpack/advanced, + /obj/item/mod/module/jump_jet, + /obj/item/mod/module/flashlight, + ) + default_pins = list( + /obj/item/mod/module/armor_booster, + /obj/item/mod/module/jetpack/advanced, + /obj/item/mod/module/jump_jet, + ) + /obj/item/mod/control/pre_equipped/responsory theme = /datum/mod_theme/responsory starting_frequency = MODLINK_FREQ_CENTCOM diff --git a/code/modules/mod/mod_ui.dm b/code/modules/mod/mod_ui.dm index 2f1e6faa0f4..f994b91060f 100644 --- a/code/modules/mod/mod_ui.dm +++ b/code/modules/mod/mod_ui.dm @@ -53,7 +53,7 @@ "cooldown" = round(COOLDOWN_TIMELEFT(module, cooldown_timer), 1 SECONDS), "id" = module.tgui_id, "ref" = REF(module), - "configuration_data" = module.get_configuration(user) + "configuration_data" = module.get_configuration(user), )) data["module_custom_status"] = module_custom_status data["module_info"] = module_info @@ -64,10 +64,13 @@ data["ui_theme"] = ui_theme data["control"] = name data["complexity_max"] = complexity_max - data["helmet"] = helmet?.name - data["chestplate"] = chestplate?.name - data["gauntlets"] = gauntlets?.name - data["boots"] = boots?.name + var/part_info = list() + for(var/obj/item/part as anything in get_parts()) + part_info += list(list( + "slot" = english_list(parse_slot_flags(part.slot_flags)), + "name" = part.name, + )) + data["parts"] = part_info return data /obj/item/mod/control/ui_state(mob/user) diff --git a/code/modules/mod/modules/_module.dm b/code/modules/mod/modules/_module.dm index 8cecea0cc54..609287bc837 100644 --- a/code/modules/mod/modules/_module.dm +++ b/code/modules/mod/modules/_module.dm @@ -43,6 +43,8 @@ var/list/pinned_to = list() /// flags that let the module ability be used in odd circumstances var/allow_flags = NONE + /// A list of slots required in the suit to work. Formatted like list(x|y, z, ...) where either x or y are required and z is required. + var/list/required_slots = list() /// Timer for the cooldown COOLDOWN_DECLARE(cooldown_timer) @@ -65,28 +67,61 @@ /obj/item/mod/module/examine(mob/user) . = ..() + if(length(required_slots)) + 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 ") + . += span_notice("Requires the MOD unit to have the following slots: [english_list(slot_strings)]") if(HAS_TRAIT(user, TRAIT_DIAGNOSTIC_HUD)) . += span_notice("Complexity level: [complexity]") +/// Looks through the MODsuit's parts to see if it has the parts required to support this module +/obj/item/mod/module/proc/has_required_parts(list/parts, need_extended = FALSE) + if(!length(required_slots)) + return TRUE + var/total_slot_flags = NONE + for(var/part_slot in parts) + if(need_extended) + var/datum/mod_part/part_datum = parts[part_slot] + if(part_datum.part_item.loc == mod) + continue + total_slot_flags |= text2num(part_slot) + var/list/needed_slots = required_slots.Copy() + for(var/needed_slot in needed_slots) + if(!(needed_slot & total_slot_flags)) + break + needed_slots -= needed_slot + return !length(needed_slots) /// 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!") + return if(((!mod.active || mod.activating) && !(allow_flags & MODULE_ALLOW_INACTIVE)) || module_type == MODULE_PASSIVE) if(mod.wearer) balloon_alert(mod.wearer, "not active!") return // NOVA EDIT START - DEPLOYABLE EVERYTHING OVER EVERYTHING - if((mod.wearer.wear_suit != mod.chestplate) && !(allow_flags & MODULE_ALLOW_INACTIVE)) - balloon_alert(mod.wearer, "chestplate retracted!") + var/can_activate = TRUE + if(!(allow_flags & MODULE_ALLOW_INACTIVE)) + for(var/obj/item/part in mod.get_parts()) + if(part.loc == mod) + can_activate = FALSE + break + if(!can_activate) + balloon_alert(mod.wearer, "not fully deployed!") return // NOVA EDIT END if(module_type != MODULE_USABLE) if(active) - on_deactivation() + deactivate() else - on_activation() + activate() else - on_use() + used() SEND_SIGNAL(mod, COMSIG_MOD_MODULE_SELECTED, src) /// Apply a cooldown until this item can be used again @@ -97,7 +132,7 @@ SEND_SIGNAL(src, COMSIG_MODULE_COOLDOWN_STARTED, applied_cooldown) /// Called when the module is activated -/obj/item/mod/module/proc/on_activation() +/obj/item/mod/module/proc/activate() if(!COOLDOWN_FINISHED(src, cooldown_timer)) balloon_alert(mod.wearer, "on cooldown!") return FALSE @@ -107,7 +142,7 @@ // NOVA EDIT START - No using modules when not all parts are deployed. if(!(allow_flags & MODULE_ALLOW_INACTIVE)) - for(var/obj/item/part as anything in mod.mod_parts) + for(var/obj/item/part as anything in mod.get_parts()) if(part.loc == mod) balloon_alert(mod.wearer, "deploy all parts first!") return FALSE @@ -119,7 +154,7 @@ if(SEND_SIGNAL(src, COMSIG_MODULE_TRIGGERED, mod.wearer) & MOD_ABORT_USE) return FALSE if(module_type == MODULE_ACTIVE) - if(mod.selected_module && !mod.selected_module.on_deactivation(display_message = FALSE)) + if(mod.selected_module && !mod.selected_module.deactivate(display_message = FALSE)) return FALSE mod.selected_module = src if(device) @@ -139,10 +174,11 @@ mod.wearer.update_clothing(mod.slot_flags) start_cooldown() SEND_SIGNAL(src, COMSIG_MODULE_ACTIVATED) + on_activation() return TRUE /// Called when the module is deactivated -/obj/item/mod/module/proc/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/proc/deactivate(display_message = TRUE, deleting = FALSE) active = FALSE if(module_type == MODULE_ACTIVE) mod.selected_module = null @@ -157,10 +193,11 @@ 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) return TRUE /// Called when the module is used -/obj/item/mod/module/proc/on_use() +/obj/item/mod/module/proc/used() if(!COOLDOWN_FINISHED(src, cooldown_timer)) balloon_alert(mod.wearer, "on cooldown!") return FALSE @@ -177,6 +214,7 @@ 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) SEND_SIGNAL(src, COMSIG_MODULE_USED) + on_use() return TRUE /// Called when an activated module without a device is used @@ -184,7 +222,7 @@ if(!(allow_flags & MODULE_ALLOW_INCAPACITATED) && mod.wearer.incapacitated(IGNORE_GRAB)) return FALSE mod.wearer.face_atom(target) - if(!on_use()) + if(!used()) return FALSE return TRUE @@ -198,22 +236,34 @@ /obj/item/mod/module/proc/on_process(seconds_per_tick) if(active) if(!drain_power(active_power_cost * seconds_per_tick)) - on_deactivation() + deactivate() return FALSE on_active_process(seconds_per_tick) else drain_power(idle_power_cost * seconds_per_tick) return TRUE +/// Called from the module's activate() +/obj/item/mod/module/proc/on_activation() + return + +/// Called from the module's deactivate() +/obj/item/mod/module/proc/on_deactivation(display_message = TRUE, deleting = FALSE) + return + +/// Called from the module's used() +/obj/item/mod/module/proc/on_use() + return + /// Called on the MODsuit's process if it is an active module /obj/item/mod/module/proc/on_active_process(seconds_per_tick) return -/// Called from MODsuit's install() proc, so when the module is installed. +/// Called from MODsuit's install() proc, so when the module is installed /obj/item/mod/module/proc/on_install() return -/// Called from MODsuit's uninstall() proc, so when the module is uninstalled. +/// Called from MODsuit's uninstall() proc, so when the module is uninstalled /obj/item/mod/module/proc/on_uninstall(deleting = FALSE) return @@ -271,7 +321,7 @@ if(part.loc == mod.wearer) return if(part == device) - on_deactivation(display_message = FALSE) + deactivate(display_message = FALSE) /// Called when the device gets deleted on active modules /obj/item/mod/module/proc/on_device_deletion(datum/source) @@ -338,7 +388,7 @@ if(user.get_active_held_item() != device) return - on_deactivation() + deactivate() return COMSIG_KB_ACTIVATED ///Anomaly Locked - Causes the module to not function without an anomaly. diff --git a/code/modules/mod/modules/module_kinesis.dm b/code/modules/mod/modules/module_kinesis.dm index 4f4fa44ff96..81a266f8ff4 100644 --- a/code/modules/mod/modules/module_kinesis.dm +++ b/code/modules/mod/modules/module_kinesis.dm @@ -15,6 +15,7 @@ overlay_state_inactive = "module_kinesis" overlay_state_active = "module_kinesis_on" accepted_anomalies = list(/obj/item/assembly/signaler/anomaly/grav) + required_slots = list(ITEM_SLOT_GLOVES) /// Range of the knesis grab. var/grab_range = 5 /// Time between us hitting objects with kinesis. @@ -63,9 +64,6 @@ grab_atom(target) /obj/item/mod/module/anomaly_locked/kinesis/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return 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 16814960368..64790eacb3b 100644 --- a/code/modules/mod/modules/module_pathfinder.dm +++ b/code/modules/mod/modules/module_pathfinder.dm @@ -13,6 +13,7 @@ complexity = 1 use_energy_cost = DEFAULT_CHARGE_DRAIN * 10 incompatible_modules = list(/obj/item/mod/module/pathfinder) + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) /// The pathfinding implant. var/obj/item/implant/mod/implant diff --git a/code/modules/mod/modules/modules_antag.dm b/code/modules/mod/modules/modules_antag.dm index bd96c5aec5f..8d8d7775924 100644 --- a/code/modules/mod/modules/modules_antag.dm +++ b/code/modules/mod/modules/modules_antag.dm @@ -23,11 +23,9 @@ /// Speed that we actually added. var/actual_speed_added = 0 /// Armor values added to the suit parts. - var/list/armor_mod = /datum/armor/mod_module_armor_boost + var/datum/armor/armor_mod = /datum/armor/mod_module_armor_boost /// List of parts of the suit that are spaceproofed, for giving them back the pressure protection. var/list/spaceproofed = list() - /// List of traits added when the mod is activated - var/list/traits_to_add = list(TRAIT_HEAD_INJURY_BLOCKED) /obj/item/mod/module/armor_booster/no_speedbost speed_added = 0 @@ -39,25 +37,27 @@ energy = 15 /obj/item/mod/module/armor_booster/on_suit_activation() - mod.helmet.flash_protect = FLASH_PROTECTION_WELDER + var/obj/item/clothing/head_cover = mod.get_part_from_slot(ITEM_SLOT_HEAD) || mod.get_part_from_slot(ITEM_SLOT_MASK) || mod.get_part_from_slot(ITEM_SLOT_EYES) + if(istype(head_cover)) + head_cover.flash_protect = FLASH_PROTECTION_WELDER /obj/item/mod/module/armor_booster/on_suit_deactivation(deleting = FALSE) if(deleting) return - mod.helmet.flash_protect = initial(mod.helmet.flash_protect) + var/obj/item/clothing/head_cover = mod.get_part_from_slot(ITEM_SLOT_HEAD) || mod.get_part_from_slot(ITEM_SLOT_MASK) || mod.get_part_from_slot(ITEM_SLOT_EYES) + if(istype(head_cover)) + head_cover.flash_protect = initial(head_cover.flash_protect) /obj/item/mod/module/armor_booster/on_activation() - . = ..() - if(!.) - return playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) balloon_alert(mod.wearer, "armor boosted, EVA lost") actual_speed_added = max(0, min(mod.slowdown_active, speed_added)) mod.slowdown -= actual_speed_added mod.wearer.update_equipment_speed_mods() - mod.wearer.add_traits(traits_to_add, MOD_TRAIT) - var/list/parts = mod.mod_parts + mod - for(var/obj/item/part as anything in parts) + var/obj/item/clothing/head_cover = mod.get_part_from_slot(ITEM_SLOT_HEAD) || mod.get_part_from_slot(ITEM_SLOT_MASK) || mod.get_part_from_slot(ITEM_SLOT_EYES) + if(istype(head_cover)) + ADD_TRAIT(mod.wearer, TRAIT_HEAD_INJURY_BLOCKED, MOD_TRAIT) + for(var/obj/item/part as anything in mod.get_parts(all = TRUE)) part.set_armor(part.get_armor().add_other_armor(armor_mod)) if(!remove_pressure_protection || !isclothing(part)) continue @@ -67,17 +67,15 @@ spaceproofed[clothing_part] = TRUE /obj/item/mod/module/armor_booster/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return if(!deleting) playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) balloon_alert(mod.wearer, "armor retracts, EVA ready") mod.slowdown += actual_speed_added mod.wearer.update_equipment_speed_mods() - mod.wearer.remove_traits(traits_to_add, MOD_TRAIT) - var/list/parts = mod.mod_parts + mod - for(var/obj/item/part as anything in parts) + var/obj/item/clothing/head_cover = mod.get_part_from_slot(ITEM_SLOT_HEAD) || mod.get_part_from_slot(ITEM_SLOT_MASK) || mod.get_part_from_slot(ITEM_SLOT_EYES) + if(istype(head_cover)) + REMOVE_TRAIT(mod.wearer, TRAIT_HEAD_INJURY_BLOCKED, MOD_TRAIT) + for(var/obj/item/part as anything in mod.get_parts(all = TRUE)) part.set_armor(part.get_armor().subtract_other_armor(armor_mod)) if(!remove_pressure_protection || !isclothing(part)) continue @@ -103,6 +101,7 @@ idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.5 use_energy_cost = DEFAULT_CHARGE_DRAIN * 2 incompatible_modules = list(/obj/item/mod/module/energy_shield) + required_slots = list(ITEM_SLOT_BACK) /// Max charges of the shield. var/max_charges = 1 /// The time it takes for the first charge to recover. @@ -167,6 +166,7 @@ shield_icon_file = 'icons/effects/magic.dmi' shield_icon = "mageshield" recharge_path = /obj/item/wizard_armour_charge + required_slots = list() ///Magic Nullifier - Protects you from magic. /obj/item/mod/module/anti_magic @@ -179,6 +179,7 @@ icon_state = "magic_nullifier" removable = FALSE incompatible_modules = list(/obj/item/mod/module/anti_magic) + required_slots = list(ITEM_SLOT_BACK) /obj/item/mod/module/anti_magic/on_suit_activation() mod.wearer.add_traits(list(TRAIT_ANTIMAGIC, TRAIT_HOLY), MOD_TRAIT) @@ -193,6 +194,7 @@ The field will neutralize all magic that comes into contact with the user. \ It will not protect the caster from social ridicule." icon_state = "magic_neutralizer" + required_slots = list() /obj/item/mod/module/anti_magic/wizard/on_suit_activation() mod.wearer.add_traits(list(TRAIT_ANTIMAGIC, TRAIT_ANTIMAGIC_NO_SELFBLOCK), MOD_TRAIT) @@ -254,6 +256,7 @@ complexity = 1 idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.1 incompatible_modules = list(/obj/item/mod/module/noslip) + required_slots = list(ITEM_SLOT_FEET) /obj/item/mod/module/noslip/on_suit_activation() ADD_TRAIT(mod.wearer, TRAIT_NO_SLIP_WATER, MOD_TRAIT) @@ -298,6 +301,7 @@ cooldown_time = 2.5 SECONDS overlay_state_inactive = "module_flamethrower" overlay_state_active = "module_flamethrower_on" + required_slots = list(ITEM_SLOT_OCLOTHING|ITEM_SLOT_ICLOTHING) /obj/item/mod/module/flamethrower/on_select_use(atom/target) . = ..() @@ -320,6 +324,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 5 incompatible_modules = list(/obj/item/mod/module/power_kick) cooldown_time = 5 SECONDS + required_slots = list(ITEM_SLOT_FEET) /// Damage on kick. var/damage = 20 /// The wound bonus of the kick. @@ -399,13 +404,13 @@ return_look() possible_disguises = null -/obj/item/mod/module/chameleon/on_use() +/obj/item/mod/module/chameleon/used() if(mod.active || mod.activating) balloon_alert(mod.wearer, "suit active!") - return - . = ..() - if(!.) - return + return FALSE + return ..() + +/obj/item/mod/module/chameleon/on_use() if(current_disguise) return_look() return @@ -433,10 +438,9 @@ mod.name = "[mod.theme.name] [initial(mod.name)]" mod.desc = "[initial(mod.desc)] [mod.theme.desc]" mod.icon_state = "[mod.skin]-[initial(mod.icon_state)]" - var/list/mod_skin = mod.theme.skins[mod.skin] + var/list/mod_skin = mod.theme.variants[mod.skin] mod.icon = mod_skin[MOD_ICON_OVERRIDE] || 'icons/obj/clothing/modsuit/mod_clothing.dmi' mod.worn_icon = mod_skin[MOD_WORN_ICON_OVERRIDE] || 'icons/mob/clothing/modsuit/mod_clothing.dmi' - mod.alternate_worn_layer = mod_skin[CONTROL_LAYER] mod.lefthand_file = initial(mod.lefthand_file) mod.righthand_file = initial(mod.righthand_file) mod.worn_icon_state = null @@ -481,6 +485,7 @@ complexity = 0 idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.1 removable = FALSE + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) var/datum/proximity_monitor/advanced/demoraliser/demoralizer /obj/item/mod/module/demoralizer/on_suit_activation() @@ -500,6 +505,7 @@ removable = FALSE idle_power_cost = DEFAULT_CHARGE_DRAIN * 0 incompatible_modules = list(/obj/item/mod/module/infiltrator, /obj/item/mod/module/armor_booster, /obj/item/mod/module/welding, /obj/item/mod/module/headprotector) + required_slots = list(ITEM_SLOT_FEET, ITEM_SLOT_HEAD, ITEM_SLOT_OCLOTHING) /// List of traits added when the suit is activated var/list/traits_to_add = list(TRAIT_SILENT_FOOTSTEPS, TRAIT_UNKNOWN, TRAIT_HEAD_INJURY_BLOCKED) @@ -510,18 +516,22 @@ mod.item_flags &= ~EXAMINE_SKIP /obj/item/mod/module/infiltrator/on_suit_activation() - mod.wearer.add_traits(traits_to_add, MOD_TRAIT) - mod.helmet.flash_protect = FLASH_PROTECTION_WELDER + mod.wearer.add_traits(list(TRAIT_SILENT_FOOTSTEPS, TRAIT_UNKNOWN), MOD_TRAIT) + var/obj/item/clothing/head_cover = mod.get_part_from_slot(ITEM_SLOT_HEAD) + if(istype(head_cover)) + head_cover.flash_protect = FLASH_PROTECTION_WELDER /obj/item/mod/module/infiltrator/on_suit_deactivation(deleting = FALSE) mod.wearer.remove_traits(traits_to_add, MOD_TRAIT) if(deleting) return - mod.helmet.flash_protect = initial(mod.helmet.flash_protect) + var/obj/item/clothing/head_cover = mod.get_part_from_slot(ITEM_SLOT_HEAD) + if(istype(head_cover)) + head_cover.flash_protect = initial(head_cover.flash_protect) ///Medbeam - Medbeam but built into a modsuit /obj/item/mod/module/medbeam - name = "MOD Medbeam Module" + name = "MOD medical beamgun module" desc = "A wrist mounted variant of the medbeam gun, allowing the user to heal their allies without the risk of dropping it." icon_state = "chronogun" module_type = MODULE_ACTIVE @@ -531,6 +541,7 @@ incompatible_modules = list(/obj/item/mod/module/medbeam) removable = TRUE cooldown_time = 0.5 + required_slots = list(ITEM_SLOT_BACK) /obj/item/gun/medbeam/mod name = "MOD medbeam" diff --git a/code/modules/mod/modules/modules_engineering.dm b/code/modules/mod/modules/modules_engineering.dm index 1ddcab08180..cb830b2128e 100644 --- a/code/modules/mod/modules/modules_engineering.dm +++ b/code/modules/mod/modules/modules_engineering.dm @@ -10,14 +10,19 @@ complexity = 1 incompatible_modules = list(/obj/item/mod/module/welding, /obj/item/mod/module/armor_booster) overlay_state_inactive = "module_welding" + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_EYES|ITEM_SLOT_MASK) /obj/item/mod/module/welding/on_suit_activation() - mod.helmet.flash_protect = FLASH_PROTECTION_WELDER + var/obj/item/clothing/head_cover = mod.get_part_from_slot(ITEM_SLOT_HEAD) || mod.get_part_from_slot(ITEM_SLOT_MASK) || mod.get_part_from_slot(ITEM_SLOT_EYES) + if(istype(head_cover)) + head_cover.flash_protect = FLASH_PROTECTION_WELDER /obj/item/mod/module/welding/on_suit_deactivation(deleting = FALSE) if(deleting) return - mod.helmet.flash_protect = initial(mod.helmet.flash_protect) + var/obj/item/clothing/head_cover = mod.get_part_from_slot(ITEM_SLOT_HEAD) || mod.get_part_from_slot(ITEM_SLOT_MASK) || mod.get_part_from_slot(ITEM_SLOT_EYES) + if(istype(head_cover)) + head_cover.flash_protect = initial(head_cover.flash_protect) ///T-Ray Scan - Scans the terrain for undertile objects. /obj/item/mod/module/t_ray @@ -31,6 +36,7 @@ active_power_cost = DEFAULT_CHARGE_DRAIN * 0.5 incompatible_modules = list(/obj/item/mod/module/t_ray) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_EYES|ITEM_SLOT_MASK) /// T-ray scan range. var/range = 4 @@ -50,23 +56,18 @@ active_power_cost = DEFAULT_CHARGE_DRAIN * 0.5 incompatible_modules = list(/obj/item/mod/module/magboot, /obj/item/mod/module/atrocinator) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_FEET) /// Slowdown added onto the suit. var/slowdown_active = 0.5 /// A list of traits to add to the wearer when we're active (see: Magboots) 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_activation() - . = ..() - if(!.) - return mod.wearer.add_traits(active_traits, MOD_TRAIT) mod.slowdown += slowdown_active mod.wearer.update_equipment_speed_mods() /obj/item/mod/module/magboot/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return mod.wearer.remove_traits(active_traits, MOD_TRAIT) mod.slowdown -= slowdown_active mod.wearer.update_equipment_speed_mods() @@ -89,8 +90,9 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN incompatible_modules = list(/obj/item/mod/module/tether) cooldown_time = 1.5 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) -/obj/item/mod/module/tether/on_use() +/obj/item/mod/module/tether/used() if(mod.wearer.has_gravity(get_turf(src))) balloon_alert(mod.wearer, "too much gravity!") playsound(src, 'sound/weapons/gun/general/dry_fire.ogg', 25, TRUE) @@ -153,14 +155,14 @@ AddComponent(/datum/component/geiger_sound) ADD_TRAIT(mod.wearer, TRAIT_BYPASS_EARLY_IRRADIATED_CHECK, MOD_TRAIT) RegisterSignal(mod.wearer, COMSIG_IN_RANGE_OF_IRRADIATION, PROC_REF(on_pre_potential_irradiation)) - for(var/obj/item/part in mod.mod_parts) + for(var/obj/item/part in mod.get_parts(all = TRUE)) ADD_TRAIT(part, TRAIT_RADIATION_PROTECTED_CLOTHING, MOD_TRAIT) /obj/item/mod/module/rad_protection/on_suit_deactivation(deleting = FALSE) qdel(GetComponent(/datum/component/geiger_sound)) REMOVE_TRAIT(mod.wearer, TRAIT_BYPASS_EARLY_IRRADIATED_CHECK, MOD_TRAIT) UnregisterSignal(mod.wearer, COMSIG_IN_RANGE_OF_IRRADIATION) - for(var/obj/item/part in mod.mod_parts) + for(var/obj/item/part in mod.get_parts(all = TRUE)) REMOVE_TRAIT(part, TRAIT_RADIATION_PROTECTED_CLOTHING, MOD_TRAIT) /obj/item/mod/module/rad_protection/add_ui_data() @@ -190,6 +192,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 2 incompatible_modules = list(/obj/item/mod/module/constructor, /obj/item/mod/module/quick_carry) cooldown_time = 11 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) /obj/item/mod/module/constructor/on_suit_activation() ADD_TRAIT(mod.wearer, TRAIT_QUICK_BUILD, MOD_TRAIT) @@ -198,15 +201,12 @@ REMOVE_TRAIT(mod.wearer, TRAIT_QUICK_BUILD, MOD_TRAIT) /obj/item/mod/module/constructor/on_use() - . = ..() - if(!.) - return rcd_scan(src, fade_time = 10 SECONDS) drain_power(use_energy_cost) ///Safety-First Head Protection - Protects your brain matter from sudden impacts. /obj/item/mod/module/headprotector - name = "MOD Safety-First Head Protection module" + name = "MOD safety-first head protection module" desc = "A series of dampening plates are installed along the back and upper areas of \ the helmet. These plates absorb abrupt kinetic shocks delivered to the skull. \ The bulk of this module prevents it from being installed in any suit that is capable \ @@ -215,6 +215,7 @@ icon_state = "welding" complexity = 1 incompatible_modules = list(/obj/item/mod/module/armor_booster, /obj/item/mod/module/infiltrator) + required_slots = list(ITEM_SLOT_HEAD) /obj/item/mod/module/constructor/on_suit_activation() ADD_TRAIT(mod.wearer, TRAIT_HEAD_INJURY_BLOCKED, MOD_TRAIT) @@ -233,6 +234,7 @@ device = /obj/item/reagent_containers/spray/mister incompatible_modules = list(/obj/item/mod/module/mister) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_BACK) /// Volume of our reagent holder. var/volume = 500 diff --git a/code/modules/mod/modules/modules_general.dm b/code/modules/mod/modules/modules_general.dm index 2aec3e361c4..87cab74b24f 100644 --- a/code/modules/mod/modules/modules_general.dm +++ b/code/modules/mod/modules/modules_general.dm @@ -8,6 +8,7 @@ icon_state = "storage" complexity = 3 incompatible_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/plate_compression) + required_slots = list(ITEM_SLOT_BACK) /// Max weight class of items in the storage. var/max_w_class = WEIGHT_CLASS_NORMAL /// Max combined weight of all items in the storage. @@ -28,16 +29,20 @@ modstorage.set_real_location(src) modstorage.allow_big_nesting = big_nesting atom_storage.locked = STORAGE_NOT_LOCKED - RegisterSignal(mod.chestplate, COMSIG_ITEM_PRE_UNEQUIP, PROC_REF(on_chestplate_unequip)) + var/obj/item/clothing/suit = mod.get_part_from_slot(ITEM_SLOT_OCLOTHING) + if(istype(suit)) + RegisterSignal(suit, COMSIG_ITEM_PRE_UNEQUIP, PROC_REF(on_suit_unequip)) /obj/item/mod/module/storage/on_uninstall(deleting = FALSE) atom_storage.locked = STORAGE_FULLY_LOCKED QDEL_NULL(mod.atom_storage) if(!deleting) atom_storage.remove_all(mod.drop_location()) - UnregisterSignal(mod.chestplate, COMSIG_ITEM_PRE_UNEQUIP) + var/obj/item/clothing/suit = mod.get_part_from_slot(ITEM_SLOT_OCLOTHING) + if(istype(suit)) + UnregisterSignal(suit, COMSIG_ITEM_PRE_UNEQUIP) -/obj/item/mod/module/storage/proc/on_chestplate_unequip(obj/item/source, force, atom/newloc, no_move, invdrop, silent) +/obj/item/mod/module/storage/proc/on_suit_unequip(obj/item/source, force, atom/newloc, no_move, invdrop, silent) if(QDELETED(source) || !mod.wearer || newloc == mod.wearer || !mod.wearer.s_store) return if(!atom_storage?.attempt_insert(mod.wearer.s_store, mod.wearer, override = TRUE)) @@ -68,14 +73,14 @@ /obj/item/mod/module/storage/belt name = "MOD case storage module" desc = "Some concessions had to be made when creating a compressed modular suit core. \ - As a result, Roseus Galactic equipped their suit with a slimline storage case. \ - If you find this equipped to a standard modular suit, then someone has almost certainly shortchanged you on a proper storage module." + As a result, Roseus Galactic equipped their suit with a slimline storage case. \ + If you find this equipped to a standard modular suit, then someone has almost certainly shortchanged you on a proper storage module." icon_state = "storage_case" complexity = 0 max_w_class = WEIGHT_CLASS_SMALL - removable = FALSE max_combined_w_class = 21 max_items = 7 + required_slots = list(ITEM_SLOT_BELT) /obj/item/mod/module/storage/bluespace name = "MOD bluespace storage module" @@ -102,6 +107,7 @@ cooldown_time = 0.5 SECONDS overlay_state_inactive = "module_jetpack" overlay_state_active = "module_jetpack_on" + required_slots = list(ITEM_SLOT_BACK) /// Do we give the wearer a speed buff. var/full_speed = FALSE /// Do we have stabilizers? If yes the user won't move from inertia. @@ -138,14 +144,10 @@ ) /obj/item/mod/module/jetpack/on_activation() - . = ..() - if(!.) - return if(full_speed) mod.wearer.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/fullspeed) /obj/item/mod/module/jetpack/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() if(full_speed) mod.wearer.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/fullspeed) @@ -188,6 +190,7 @@ cooldown_time = 30 SECONDS use_energy_cost = DEFAULT_CHARGE_DRAIN * 5 incompatible_modules = list(/obj/item/mod/module/jump_jet) + required_slots = list(ITEM_SLOT_BACK) /obj/item/mod/module/jump_jet/on_use() . = ..() @@ -228,6 +231,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 0.1 incompatible_modules = list(/obj/item/mod/module/status_readout) tgui_id = "status_readout" + required_slots = list(ITEM_SLOT_BACK) /// Does this show damage types, body temp, satiety var/display_detailed_vitals = TRUE /// Does this show DNA data @@ -305,22 +309,41 @@ complexity = 1 incompatible_modules = list(/obj/item/mod/module/mouthhole) overlay_state_inactive = "module_apparatus" + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_MASK) /// Former flags of the helmet. - var/former_flags = NONE + var/former_helmet_flags = NONE /// Former visor flags of the helmet. - var/former_visor_flags = NONE + var/former_visor_helmet_flags = NONE + /// Former flags of the mask. + var/former_mask_flags = NONE + /// Former visor flags of the mask. + var/former_visor_mask_flags = NONE /obj/item/mod/module/mouthhole/on_install() - former_flags = mod.helmet.flags_cover - former_visor_flags = mod.helmet.visor_flags_cover - mod.helmet.flags_cover &= ~(HEADCOVERSMOUTH|PEPPERPROOF) - mod.helmet.visor_flags_cover &= ~(HEADCOVERSMOUTH|PEPPERPROOF) + var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) + if(istype(helmet)) + former_helmet_flags = helmet.flags_cover + former_visor_helmet_flags = helmet.visor_flags_cover + helmet.flags_cover &= ~(HEADCOVERSMOUTH|PEPPERPROOF) + helmet.visor_flags_cover &= ~(HEADCOVERSMOUTH|PEPPERPROOF) + var/obj/item/clothing/mask = mod.get_part_from_slot(ITEM_SLOT_MASK) + if(istype(mask)) + former_mask_flags = mask.flags_cover + former_visor_mask_flags = mask.visor_flags_cover + mask.flags_cover &= ~(MASKCOVERSMOUTH |PEPPERPROOF) + mask.visor_flags_cover &= ~(MASKCOVERSMOUTH |PEPPERPROOF) /obj/item/mod/module/mouthhole/on_uninstall(deleting = FALSE) if(deleting) return - mod.helmet.flags_cover |= former_flags - mod.helmet.visor_flags_cover |= former_visor_flags + var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) + if(istype(helmet)) + helmet.flags_cover |= former_helmet_flags + helmet.visor_flags_cover |= former_visor_helmet_flags + var/obj/item/clothing/mask = mod.get_part_from_slot(ITEM_SLOT_MASK) + if(istype(mask)) + mask.flags_cover |= former_mask_flags + mask.visor_flags_cover |= former_visor_mask_flags ///EMP Shield - Protects the suit from EMPs. /obj/item/mod/module/emp_shield @@ -332,6 +355,7 @@ complexity = 1 idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.3 incompatible_modules = list(/obj/item/mod/module/emp_shield) + 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) @@ -349,7 +373,7 @@ /obj/item/mod/module/emp_shield/advanced/on_suit_activation() mod.wearer.AddElement(/datum/element/empprotection, EMP_PROTECT_SELF|EMP_PROTECT_CONTENTS) -/obj/item/mod/module/emp_shield/advanced/on_suit_deactivation(deleting) +/obj/item/mod/module/emp_shield/advanced/on_suit_deactivation(deleting = FALSE) mod.wearer.RemoveElement(/datum/element/empprotection, EMP_PROTECT_SELF|EMP_PROTECT_CONTENTS) ///Flashlight - Gives the suit a customizable flashlight. @@ -370,6 +394,7 @@ light_range = 4 light_power = 1 light_on = FALSE + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_MASK) /// Charge drain per range amount. var/base_power = DEFAULT_CHARGE_DRAIN * 0.1 /// Minimum range we can set. @@ -384,17 +409,11 @@ UnregisterSignal(mod.wearer, COMSIG_HIT_BY_SABOTEUR) /obj/item/mod/module/flashlight/on_activation() - . = ..() - if(!.) - return 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) - . = ..() - if(!.) - return set_light_flags(light_flags & ~LIGHT_ATTACHED) set_light_on(active) @@ -464,15 +483,13 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 2 incompatible_modules = list(/obj/item/mod/module/dispenser) cooldown_time = 5 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) /// Path we dispense. var/dispense_type = /obj/item/food/burger/plain /// Time it takes for us to dispense. var/dispense_time = 0 SECONDS /obj/item/mod/module/dispenser/on_use() - . = ..() - if(!.) - return if(dispense_time && !do_after(mod.wearer, dispense_time, target = mod)) balloon_alert(mod.wearer, "interrupted!") return FALSE @@ -494,6 +511,7 @@ complexity = 1 use_energy_cost = DEFAULT_CHARGE_DRAIN * 5 incompatible_modules = list(/obj/item/mod/module/longfall) + required_slots = list(ITEM_SLOT_FEET) /obj/item/mod/module/longfall/on_suit_activation() RegisterSignal(mod.wearer, COMSIG_LIVING_Z_IMPACT, PROC_REF(z_impact_react)) @@ -532,6 +550,7 @@ active_power_cost = DEFAULT_CHARGE_DRAIN * 0.3 incompatible_modules = list(/obj/item/mod/module/thermal_regulator) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) /// The temperature we are regulating to. var/temperature_setting = BODYTEMP_NORMAL /// Minimum temperature we can set. @@ -579,9 +598,6 @@ UnregisterSignal(mod, COMSIG_ATOM_EMAG_ACT) /obj/item/mod/module/dna_lock/on_use() - . = ..() - if(!.) - return dna = mod.wearer.dna.unique_enzymes balloon_alert(mod.wearer, "dna updated") drain_power(use_energy_cost) @@ -640,6 +656,7 @@ idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.3 incompatible_modules = list(/obj/item/mod/module/plasma_stabilizer) overlay_state_inactive = "module_plasma" + required_slots = list(ITEM_SLOT_HEAD) /obj/item/mod/module/plasma_stabilizer/generate_worn_overlay() if(locate(/obj/item/mod/module/infiltrator) in mod.modules) @@ -663,6 +680,7 @@ This is a must-have for Nanotrasen Captains, enabling them to show off their authoritative hat even while in their MODsuit." icon_state = "hat_holder" incompatible_modules = list(/obj/item/mod/module/hat_stabilizer) + required_slots = list(ITEM_SLOT_HEAD) /*Intentionally left inheriting 0 complexity and removable = TRUE; even though it comes inbuilt into the Magnate/Corporate MODS and spawns in maints, I like the idea of stealing them*/ /// Currently "stored" hat. No armor or function will be inherited, only the icon and cover flags. @@ -672,18 +690,24 @@ var/former_visor_flags /obj/item/mod/module/hat_stabilizer/on_suit_activation() - RegisterSignal(mod.helmet, COMSIG_ATOM_EXAMINE, PROC_REF(add_examine)) - RegisterSignal(mod.helmet, COMSIG_ATOM_ATTACKBY, PROC_REF(place_hat)) - RegisterSignal(mod.helmet, COMSIG_ATOM_ATTACK_HAND_SECONDARY, PROC_REF(remove_hat)) + var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) + if(!istype(helmet)) + return + RegisterSignal(helmet, COMSIG_ATOM_EXAMINE, PROC_REF(add_examine)) + RegisterSignal(helmet, COMSIG_ATOM_ATTACKBY, PROC_REF(place_hat)) + RegisterSignal(helmet, COMSIG_ATOM_ATTACK_HAND_SECONDARY, PROC_REF(remove_hat)) /obj/item/mod/module/hat_stabilizer/on_suit_deactivation(deleting = FALSE) if(deleting) return if(attached_hat) //knock off the helmet if its on their head. Or, technically, auto-rightclick it for them; that way it saves us code, AND gives them the bubble remove_hat(src, mod.wearer) - UnregisterSignal(mod.helmet, COMSIG_ATOM_EXAMINE) - UnregisterSignal(mod.helmet, COMSIG_ATOM_ATTACKBY) - UnregisterSignal(mod.helmet, COMSIG_ATOM_ATTACK_HAND_SECONDARY) + var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) + if(!istype(helmet)) + return + UnregisterSignal(helmet, COMSIG_ATOM_EXAMINE) + UnregisterSignal(helmet, COMSIG_ATOM_ATTACKBY) + UnregisterSignal(helmet, COMSIG_ATOM_ATTACK_HAND_SECONDARY) /obj/item/mod/module/hat_stabilizer/proc/add_examine(datum/source, mob/user, list/base_examine) SIGNAL_HANDLER @@ -708,10 +732,12 @@ return if(mod.wearer.transferItemToLoc(hitting_item, src, force = FALSE, silent = TRUE)) attached_hat = hat - former_flags = mod.helmet.flags_cover - former_visor_flags = mod.helmet.visor_flags_cover - mod.helmet.flags_cover |= attached_hat.flags_cover - mod.helmet.visor_flags_cover |= attached_hat.visor_flags_cover + var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) + if(istype(helmet)) + former_flags = helmet.flags_cover + former_visor_flags = helmet.visor_flags_cover + helmet.flags_cover |= attached_hat.flags_cover + helmet.visor_flags_cover |= attached_hat.visor_flags_cover balloon_alert(user, "hat attached, right-click to remove") mod.wearer.update_clothing(mod.slot_flags) @@ -731,10 +757,21 @@ else balloon_alert_to_viewers("the hat falls to the floor!") attached_hat = null - mod.helmet.flags_cover = former_flags - mod.helmet.visor_flags_cover = former_visor_flags + var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) + if(istype(helmet)) + helmet.flags_cover = former_flags + helmet.visor_flags_cover = former_visor_flags mod.wearer.update_clothing(mod.slot_flags) +/obj/item/mod/module/hat_stabilizer/syndicate + name = "MOD elite hat stabilizer module" + desc = "A simple set of deployable stands, directly atop one's head; \ + these will deploy under a hat to keep it from falling off, allowing them to be worn atop the sealed helmet. \ + You still need to take the hat off your head while the helmet deploys, though. This is a must-have for \ + Syndicate Operatives and Agents alike, enabling them to continue to style on the opposition even while in their MODsuit." + complexity = 0 + removable = FALSE + ///Sign Language Translator - allows people to sign over comms using the modsuit's gloves. /obj/item/mod/module/signlang_radio name = "MOD glove translator module" @@ -745,6 +782,7 @@ complexity = 1 idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.3 incompatible_modules = list(/obj/item/mod/module/signlang_radio) + required_slots = list(ITEM_SLOT_GLOVES) /obj/item/mod/module/signlang_radio/on_suit_activation() ADD_TRAIT(mod.wearer, TRAIT_CAN_SIGN_ON_COMMS, MOD_TRAIT) @@ -759,6 +797,7 @@ icon_state = "joint_torsion" complexity = 1 incompatible_modules = list(/obj/item/mod/module/joint_torsion) + required_slots = list(ITEM_SLOT_FEET) var/power_per_step = DEFAULT_CHARGE_DRAIN * 0.3 /obj/item/mod/module/joint_torsion/on_suit_activation() @@ -788,15 +827,6 @@ return mod.core.add_charge(power_per_step) -/obj/item/mod/module/hat_stabilizer/syndicate - name = "MOD elite hat stabilizer module" - desc = "A simple set of deployable stands, directly atop one's head; \ - these will deploy under a hat to keep it from falling off, allowing them to be worn atop the sealed helmet. \ - You still need to take the hat off your head while the helmet deploys, though. This is a must-have for \ - Syndicate Operatives and Agents alike, enabling them to continue to style on the opposition even while in their MODsuit." - complexity = 0 - removable = FALSE - /// Module that shoves garbage inside its material container when the user crosses it, and eject the recycled material with MMB. /obj/item/mod/module/recycler name = "MOD recycler module" @@ -810,6 +840,7 @@ incompatible_modules = list(/obj/item/mod/module/recycler) overlay_state_inactive = "module_recycler" overlay_state_active = "module_recycler" + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) /// A multiplier of the amount of material extracted from the item var/efficiency = 1 /// Items that will be collected diff --git a/code/modules/mod/modules/modules_maint.dm b/code/modules/mod/modules/modules_maint.dm index 1f7c322e031..0d45bc4a44d 100644 --- a/code/modules/mod/modules/modules_maint.dm +++ b/code/modules/mod/modules/modules_maint.dm @@ -10,6 +10,7 @@ icon_state = "springlock" complexity = 3 // it is inside every part of your suit, so incompatible_modules = list(/obj/item/mod/module/springlock) + var/set_off = FALSE /obj/item/mod/module/springlock/on_install() mod.activation_step_time *= 0.5 @@ -27,12 +28,13 @@ /obj/item/mod/module/springlock/proc/on_wearer_exposed(atom/source, list/reagents, datum/reagents/source_reagents, methods, volume_modifier, show_message) SIGNAL_HANDLER - if(!(methods & (VAPOR|PATCH|TOUCH))) + if(!(methods & (VAPOR|PATCH|TOUCH)) || set_off || mod.wearer.stat == DEAD) return //remove non-touch reagent exposure to_chat(mod.wearer, span_danger("[src] makes an ominous click sound...")) playsound(src, 'sound/items/modsuit/springlock.ogg', 75, TRUE) addtimer(CALLBACK(src, PROC_REF(snap_shut)), rand(3 SECONDS, 5 SECONDS)) RegisterSignal(mod, COMSIG_MOD_ACTIVATE, PROC_REF(on_activate_spring_block)) + set_off = TRUE ///Signal fired when wearer attempts to activate/deactivate suits /obj/item/mod/module/springlock/proc/on_activate_spring_block(datum/source, user) @@ -55,6 +57,7 @@ mod.wearer.investigate_log("has been killed by [src].", INVESTIGATE_DEATHS) mod.wearer.death() //just in case, for some reason, they're still alive flash_color(mod.wearer, flash_color = "#FF0000", flash_time = 10 SECONDS) + set_off = FALSE ///Rave Visor - Gives you a rainbow visor and plays jukebox music to you. /obj/item/mod/module/visor/rave @@ -63,6 +66,7 @@ icon_state = "rave_visor" complexity = 1 overlay_state_inactive = "module_rave" + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_MASK) /// The client colors applied to the wearer. var/datum/client_colour/rave_screen /// The current element in the rainbow_order list we are on. @@ -90,17 +94,11 @@ return ..() /obj/item/mod/module/visor/rave/on_activation() - . = ..() - if(!.) - return rave_screen = mod.wearer.add_client_colour(/datum/client_colour/rave) rave_screen.update_colour(rainbow_order[rave_number]) music_player.start_music(mod.wearer) /obj/item/mod/module/visor/rave/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return QDEL_NULL(rave_screen) if(isnull(music_player.active_song_sound)) return @@ -151,11 +149,9 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 5 incompatible_modules = list(/obj/item/mod/module/tanner) cooldown_time = 30 SECONDS + required_slots = list(ITEM_SLOT_OCLOTHING|ITEM_SLOT_ICLOTHING) /obj/item/mod/module/tanner/on_use() - . = ..() - if(!.) - return playsound(src, 'sound/machines/microwave/microwave-end.ogg', 50, TRUE) var/datum/reagents/holder = new() holder.add_reagent(/datum/reagent/spraytan, 10) @@ -174,16 +170,17 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 0.5 incompatible_modules = list(/obj/item/mod/module/balloon) cooldown_time = 15 SECONDS + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_MASK) + var/balloon_path = /obj/item/toy/balloon + var/blowing_time = 10 SECONDS + var/oxygen_damage = 20 /obj/item/mod/module/balloon/on_use() - . = ..() - if(!.) - return - if(!do_after(mod.wearer, 10 SECONDS, target = mod)) + if(!do_after(mod.wearer, blowing_time, target = mod)) return FALSE - mod.wearer.adjustOxyLoss(20) + mod.wearer.adjustOxyLoss(oxygen_damage) playsound(src, 'sound/items/modsuit/inflate_bloon.ogg', 50, TRUE) - var/obj/item/toy/balloon/balloon = new(get_turf(src)) + var/obj/item/balloon = new balloon_path(get_turf(src)) mod.wearer.put_in_hands(balloon) drain_power(use_energy_cost) @@ -198,13 +195,11 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 0.5 incompatible_modules = list(/obj/item/mod/module/paper_dispenser) cooldown_time = 5 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) /// 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() - . = ..() - if(!.) - return if(!do_after(mod.wearer, 1 SECONDS, target = mod)) return FALSE @@ -243,6 +238,7 @@ device = /obj/item/stamp/mod incompatible_modules = list(/obj/item/mod/module/stamp) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) /obj/item/stamp/mod name = "MOD electronic stamp" @@ -267,15 +263,13 @@ incompatible_modules = list(/obj/item/mod/module/atrocinator, /obj/item/mod/module/magboot, /obj/item/mod/module/anomaly_locked/antigrav) cooldown_time = 0.5 SECONDS overlay_state_inactive = "module_atrocinator" + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) /// How many steps the user has taken since turning the suit on, used for footsteps. var/step_count = 0 /// 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() - . = ..() - if(!.) - return playsound(src, 'sound/effects/curseattack.ogg', 50) mod.wearer.AddElement(/datum/element/forced_gravity, NEGATIVE_GRAVITY) RegisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED, PROC_REF(check_upstairs)) @@ -284,14 +278,14 @@ passtable_on(mod.wearer, MOD_TRAIT) check_upstairs() //todo at some point flip your screen around -/obj/item/mod/module/atrocinator/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/atrocinator/deactivate(display_message = TRUE, deleting = FALSE) if(you_fucked_up && !deleting) to_chat(mod.wearer, span_danger("It's too late.")) return FALSE - . = ..() - if(!.) - return - if(deleting) + return ..() + +/obj/item/mod/module/atrocinator/on_deactivation(display_message = TRUE, deleting = FALSE) + if(!deleting) playsound(src, 'sound/effects/curseattack.ogg', 50) qdel(mod.wearer.RemoveElement(/datum/element/forced_gravity, NEGATIVE_GRAVITY)) UnregisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED) diff --git a/code/modules/mod/modules/modules_medical.dm b/code/modules/mod/modules/modules_medical.dm index 0e04de51c86..3cf1d34a63a 100644 --- a/code/modules/mod/modules/modules_medical.dm +++ b/code/modules/mod/modules/modules_medical.dm @@ -9,8 +9,7 @@ name = "MOD health analyzer module" desc = "A module installed into the glove of the suit. This is a high-tech biological scanning suite, \ allowing the user indepth information on the vitals and injuries of others even at a distance, \ - all with the flick of the wrist. Data is displayed in a convenient package on HUD in the helmet, \ - but it's up to you to do something with it." + all with the flick of the wrist. Data is displayed in a convenient package, but it's up to you to do something with it." icon_state = "health" module_type = MODULE_ACTIVE complexity = 1 @@ -18,6 +17,7 @@ incompatible_modules = list(/obj/item/mod/module/health_analyzer) cooldown_time = 0.5 SECONDS tgui_id = "health_analyzer" + required_slots = list(ITEM_SLOT_GLOVES) /// Scanning mode, changes how we scan something. var/mode = HEALTH_SCAN @@ -74,6 +74,7 @@ complexity = 1 idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.3 incompatible_modules = list(/obj/item/mod/module/quick_carry, /obj/item/mod/module/constructor) + required_slots = list(ITEM_SLOT_GLOVES) var/quick_carry_trait = TRAIT_QUICK_CARRY /obj/item/mod/module/quick_carry/on_suit_activation() @@ -105,6 +106,7 @@ device = /obj/item/reagent_containers/syringe/mod incompatible_modules = list(/obj/item/mod/module/injector) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) /obj/item/reagent_containers/syringe/mod name = "MOD injector syringe" @@ -131,6 +133,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN incompatible_modules = list(/obj/item/mod/module/organ_thrower, /obj/item/mod/module/microwave_beam) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) /// How many organs the module can hold. var/max_organs = 5 /// A list of all our organs. @@ -247,6 +250,7 @@ overlay_state_active = "module_defibrillator_active" incompatible_modules = list(/obj/item/mod/module/defibrillator) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) var/defib_cooldown = 5 SECONDS /obj/item/mod/module/defibrillator/Initialize(mapload) @@ -308,6 +312,7 @@ incompatible_modules = list(/obj/item/mod/module/thread_ripper) cooldown_time = 1.5 SECONDS overlay_state_inactive = "module_threadripper" + required_slots = list(ITEM_SLOT_GLOVES) /// An associated list of ripped clothing and the body part covering slots they covered before var/list/ripped_clothing = list() @@ -357,7 +362,7 @@ playsound(src, 'sound/items/zip.ogg', 25, TRUE) balloon_alert(mod.wearer, "clothing mended") -/obj/item/mod/module/thread_ripper/on_suit_deactivation(deleting) +/obj/item/mod/module/thread_ripper/on_suit_deactivation(deleting = FALSE) if(!length(ripped_clothing)) return for(var/obj/item/clothing as anything in ripped_clothing) diff --git a/code/modules/mod/modules/modules_ninja.dm b/code/modules/mod/modules/modules_ninja.dm index d52a5e1fb4c..a868eb62056 100644 --- a/code/modules/mod/modules/modules_ninja.dm +++ b/code/modules/mod/modules/modules_ninja.dm @@ -13,15 +13,13 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 10 incompatible_modules = list(/obj/item/mod/module/stealth) cooldown_time = 5 SECONDS + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) /// Whether or not the cloak turns off on bumping. var/bumpoff = TRUE /// The alpha applied when the cloak is on. var/stealth_alpha = 50 /obj/item/mod/module/stealth/on_activation() - . = ..() - if(!.) - return if(bumpoff) RegisterSignal(mod.wearer, COMSIG_LIVING_MOB_BUMP, PROC_REF(unstealth)) RegisterSignal(mod.wearer, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_unarmed_attack)) @@ -31,9 +29,6 @@ drain_power(use_energy_cost) /obj/item/mod/module/stealth/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return 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)) @@ -45,7 +40,7 @@ to_chat(mod.wearer, span_warning("[src] gets discharged from contact!")) do_sparks(2, TRUE, src) drain_power(use_energy_cost) - on_deactivation(display_message = TRUE, deleting = FALSE) + deactivate() /obj/item/mod/module/stealth/proc/on_unarmed_attack(datum/source, atom/target) SIGNAL_HANDLER @@ -99,6 +94,7 @@ removable = FALSE complexity = 0 overlay_state_inactive = null + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_EYES|ITEM_SLOT_MASK) /obj/item/mod/module/welding/camera_vision/on_suit_activation() . = ..() @@ -133,6 +129,7 @@ icon_state = "hacker" removable = FALSE incompatible_modules = list(/obj/item/mod/module/hacker) + required_slots = list(ITEM_SLOT_GLOVES) /// Whether or not the communication console hack was used to summon another antagonist. var/communication_console_hack_success = FALSE /// How many times the module has been used to force open doors. @@ -173,6 +170,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 2 incompatible_modules = list(/obj/item/mod/module/weapon_recall) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_GLOVES, ITEM_SLOT_BACK|ITEM_SLOT_BELT) /// The item linked to the module that will get recalled. var/obj/item/linked_weapon /// The accepted typepath we can link to. @@ -185,9 +183,6 @@ REMOVE_TRAIT(mod.wearer, TRAIT_NOGUNS, MOD_TRAIT) /obj/item/mod/module/weapon_recall/on_use() - . = ..() - if(!.) - return if(!linked_weapon) var/obj/item/weapon_to_link = mod.wearer.is_holding_item_of_type(accepted_type) if(!weapon_to_link) @@ -288,9 +283,6 @@ cooldown_time = 8 SECONDS /obj/item/mod/module/emp_shield/pulse/on_use() - . = ..() - if(!.) - return playsound(src, 'sound/effects/empulse.ogg', 60, TRUE) empulse(src, heavy_range = 4, light_range = 6) drain_power(use_energy_cost) @@ -320,6 +312,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 6 incompatible_modules = list(/obj/item/mod/module/energy_net) cooldown_time = 5 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) /// List of all energy nets this module made. var/list/energy_nets = list() @@ -404,6 +397,7 @@ allow_flags = MODULE_ALLOW_INCAPACITATED incompatible_modules = list(/obj/item/mod/module/adrenaline_boost) cooldown_time = 12 SECONDS + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) /// What reagent we need to refill? var/reagent_required = /datum/reagent/uranium/radium /// How much of a reagent we need to refill the boost. @@ -414,13 +408,13 @@ create_reagents(reagent_required_amount) reagents.add_reagent(reagent_required, reagent_required_amount) -/obj/item/mod/module/adrenaline_boost/on_use() +/obj/item/mod/module/adrenaline_boost/used() if(!reagents.has_reagent(reagent_required, reagent_required_amount)) balloon_alert(mod.wearer, "no charge!") - return - . = ..() - if(!.) - return + return FALSE + return ..() + +/obj/item/mod/module/adrenaline_boost/on_use() 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.")) @@ -438,7 +432,7 @@ /obj/item/mod/module/adrenaline_boost/on_install() RegisterSignal(mod, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby)) -/obj/item/mod/module/adrenaline_boost/on_uninstall(deleting) +/obj/item/mod/module/adrenaline_boost/on_uninstall(deleting = FALSE) UnregisterSignal(mod, COMSIG_ATOM_ATTACKBY) /obj/item/mod/module/adrenaline_boost/attackby(obj/item/attacking_item, mob/user, params) diff --git a/code/modules/mod/modules/modules_science.dm b/code/modules/mod/modules/modules_science.dm index a5a56975f6c..9f2c54b8eff 100644 --- a/code/modules/mod/modules/modules_science.dm +++ b/code/modules/mod/modules/modules_science.dm @@ -12,17 +12,12 @@ active_power_cost = DEFAULT_CHARGE_DRAIN * 0.2 incompatible_modules = list(/obj/item/mod/module/reagent_scanner) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_EYES|ITEM_SLOT_MASK) /obj/item/mod/module/reagent_scanner/on_activation() - . = ..() - if(!.) - return ADD_TRAIT(mod.wearer, TRAIT_REAGENT_SCANNER, MOD_TRAIT) /obj/item/mod/module/reagent_scanner/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return REMOVE_TRAIT(mod.wearer, TRAIT_REAGENT_SCANNER, MOD_TRAIT) /obj/item/mod/module/reagent_scanner/advanced @@ -32,16 +27,10 @@ var/explosion_detection_dist = 21 /obj/item/mod/module/reagent_scanner/advanced/on_activation() - . = ..() - if(!.) - return ADD_TRAIT(mod.wearer, TRAIT_RESEARCH_SCANNER, MOD_TRAIT) RegisterSignal(SSdcs, COMSIG_GLOB_EXPLOSION, PROC_REF(sense_explosion)) /obj/item/mod/module/reagent_scanner/advanced/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return REMOVE_TRAIT(mod.wearer, TRAIT_RESEARCH_SCANNER, MOD_TRAIT) UnregisterSignal(SSdcs, COMSIG_GLOB_EXPLOSION) @@ -66,20 +55,15 @@ incompatible_modules = list(/obj/item/mod/module/anomaly_locked, /obj/item/mod/module/atrocinator) cooldown_time = 0.5 SECONDS 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() - . = ..() - if(!.) - return 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) - . = ..() - if(!.) - return mod.wearer.RemoveElement(/datum/element/forced_gravity, 0) if(deleting) return @@ -103,6 +87,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 5 cooldown_time = 5 SECONDS accepted_anomalies = list(/obj/item/assembly/signaler/anomaly/bluespace) + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) /// Time it takes to teleport var/teleport_time = 3 SECONDS diff --git a/code/modules/mod/modules/modules_security.dm b/code/modules/mod/modules/modules_security.dm index 6d91b24469b..2a317becf18 100644 --- a/code/modules/mod/modules/modules_security.dm +++ b/code/modules/mod/modules/modules_security.dm @@ -8,6 +8,7 @@ complexity = 2 use_energy_cost = DEFAULT_CHARGE_DRAIN incompatible_modules = list(/obj/item/mod/module/magnetic_harness) + required_slots = list(ITEM_SLOT_OCLOTHING) /// Time before we activate the magnet. var/magnet_delay = 0.8 SECONDS /// The typecache of all guns we allow. @@ -21,13 +22,19 @@ 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/mod/module/magnetic_harness/on_install() - already_allowed_guns = guns_typecache & mod.chestplate.allowed - mod.chestplate.allowed |= guns_typecache + var/obj/item/clothing/suit = mod.get_part_from_slot(ITEM_SLOT_OCLOTHING) + if(!istype(suit)) + return + already_allowed_guns = guns_typecache & suit.allowed + suit.allowed |= guns_typecache /obj/item/mod/module/magnetic_harness/on_uninstall(deleting = FALSE) if(deleting) return - mod.chestplate.allowed -= (guns_typecache - already_allowed_guns) + var/obj/item/clothing/suit = mod.get_part_from_slot(ITEM_SLOT_OCLOTHING) + if(!istype(suit)) + return + suit.allowed -= (guns_typecache - already_allowed_guns) /obj/item/mod/module/magnetic_harness/on_suit_activation() RegisterSignal(mod.wearer, COMSIG_MOB_UNEQUIPPED_ITEM, PROC_REF(check_dropped_item)) @@ -65,6 +72,7 @@ cooldown_time = 5 SECONDS overlay_state_inactive = "module_pepper" overlay_state_use = "module_pepper_used" + required_slots = list(ITEM_SLOT_OCLOTHING) /obj/item/mod/module/pepper_shoulders/on_suit_activation() RegisterSignal(mod.wearer, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(on_check_block)) @@ -73,9 +81,6 @@ UnregisterSignal(mod.wearer, COMSIG_LIVING_CHECK_BLOCK) /obj/item/mod/module/pepper_shoulders/on_use() - . = ..() - if(!.) - return 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) @@ -92,7 +97,7 @@ if(!check_power(use_energy_cost)) return mod.wearer.visible_message(span_warning("[src] reacts to the attack with a smoke of pepper spray!"), span_notice("Your [src] releases a cloud of pepper spray!")) - on_use() + used() ///Holster - Instantly holsters any not huge gun. /obj/item/mod/module/holster @@ -107,13 +112,11 @@ incompatible_modules = list(/obj/item/mod/module/holster) cooldown_time = 0.5 SECONDS allow_flags = MODULE_ALLOW_INACTIVE + required_slots = list(ITEM_SLOT_OCLOTHING|ITEM_SLOT_GLOVES|ITEM_SLOT_FEET) /// Gun we have holstered. var/obj/item/gun/holstered /obj/item/mod/module/holster/on_use() - . = ..() - if(!.) - return if(!holstered) var/obj/item/gun/holding = mod.wearer.get_active_held_item() if(!holding) @@ -155,19 +158,14 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 0.5 incompatible_modules = list(/obj/item/mod/module/megaphone) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_EYES|ITEM_SLOT_MASK) /// List of spans we add to the speaker. var/list/voicespan = list(SPAN_COMMAND) /obj/item/mod/module/megaphone/on_activation() - . = ..() - if(!.) - return RegisterSignal(mod.wearer, COMSIG_MOB_SAY, PROC_REF(handle_speech)) /obj/item/mod/module/megaphone/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return UnregisterSignal(mod.wearer, COMSIG_MOB_SAY) /obj/item/mod/module/megaphone/proc/handle_speech(datum/source, list/speech_args) @@ -190,6 +188,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 0.5 incompatible_modules = list(/obj/item/mod/module/criminalcapture) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) /// Time to capture a prisoner. var/capture_time = 2.5 SECONDS /// Time to dematerialize a bodybag. @@ -203,10 +202,7 @@ idle_power_cost = linked_bodybag ? (DEFAULT_CHARGE_DRAIN * 3) : 0 return ..() -/obj/item/mod/module/criminalcapture/on_deactivation(display_message, deleting) - . = ..() - if(!.) - return +/obj/item/mod/module/criminalcapture/on_deactivation(display_message = TRUE, deleting = FALSE) if(!linked_bodybag) return packup() @@ -273,9 +269,6 @@ dispense_type = /obj/item/grenade/mirage /obj/item/mod/module/dispenser/mirage/on_use() - . = ..() - if(!.) - return var/obj/item/grenade/mirage/grenade = . grenade.arm_grenade(mod.wearer) @@ -310,6 +303,7 @@ active_power_cost = DEFAULT_CHARGE_DRAIN incompatible_modules = list(/obj/item/mod/module/projectile_dampener) cooldown_time = 1.5 SECONDS + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) /// Radius of the dampening field. var/field_radius = 2 /// Damage multiplier on projectiles. @@ -328,9 +322,6 @@ projectile_effect = image('icons/effects/fields.dmi', "projectile_dampen_effect") /obj/item/mod/module/projectile_dampener/on_activation() - . = ..() - if(!.) - return if(istype(dampening_field)) QDEL_NULL(dampening_field) dampening_field = new(mod.wearer, field_radius, TRUE, src) @@ -370,6 +361,7 @@ complexity = 2 incompatible_modules = list(/obj/item/mod/module/active_sonar) cooldown_time = 15 SECONDS + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_EYES|ITEM_SLOT_MASK) /// Time between us displaying radial scans var/scan_cooldown_time = 0.5 SECONDS /// The current slice we're going to scan @@ -454,9 +446,6 @@ COOLDOWN_START(src, scan_cooldown, scan_cooldown_time) /obj/item/mod/module/active_sonar/on_use() - . = ..() - if(!.) - return balloon_alert(mod.wearer, "readying sonar...") playsound(mod.wearer, 'sound/mecha/skyfall_power_up.ogg', vol = 20, vary = TRUE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) if(!do_after(mod.wearer, 1.1 SECONDS, target = mod)) @@ -486,6 +475,7 @@ module_type = MODULE_PASSIVE complexity = 3 incompatible_modules = list(/obj/item/mod/module/shooting_assistant) + required_slots = list(ITEM_SLOT_GLOVES) var/selected_mode = SHOOTING_ASSISTANT_OFF ///Association list, the assoc values are the balloon alerts shown to the user when the mode is set. var/static/list/available_modes = list( @@ -585,6 +575,7 @@ icon_state = "bulwark" complexity = 3 incompatible_modules = list(/obj/item/mod/module/shove_blocker) + required_slots = list(ITEM_SLOT_OCLOTHING) /obj/item/mod/module/shove_blocker/on_suit_activation() mod.wearer.add_traits(list(TRAIT_BRAWLING_KNOCKDOWN_BLOCKED, TRAIT_NO_STAGGER, TRAIT_NO_THROW_HITPUSH), MOD_TRAIT) @@ -603,6 +594,7 @@ desc = "Enhanced gauntlent grip pads that help with placing individuals in restraints more quickly. Doesn't look like they'll come off." removable = FALSE complexity = 0 + required_slots = list(ITEM_SLOT_GLOVES) /obj/item/mod/module/quick_cuff/on_suit_activation() . = ..() diff --git a/code/modules/mod/modules/modules_service.dm b/code/modules/mod/modules/modules_service.dm index be71c621802..044137f0f2d 100644 --- a/code/modules/mod/modules/modules_service.dm +++ b/code/modules/mod/modules/modules_service.dm @@ -13,36 +13,17 @@ cooldown_time = 1 SECONDS /obj/item/mod/module/bikehorn/on_use() - . = ..() - if(!.) - return playsound(src, 'sound/items/bikehorn.ogg', 100, FALSE) drain_power(use_energy_cost) ///Advanced Balloon Blower - Blows a long balloon. -/obj/item/mod/module/balloon_advanced +/obj/item/mod/module/balloon/advanced name = "MOD advanced balloon blower module" desc = "A relatively new piece of technology developed by finest clown engineers to make long balloons and balloon animals \ - at party-appropriate rate." - icon_state = "bloon" - module_type = MODULE_USABLE - complexity = 1 - use_energy_cost = DEFAULT_CHARGE_DRAIN * 0.5 - incompatible_modules = list(/obj/item/mod/module/balloon_advanced) - cooldown_time = 15 SECONDS - -/obj/item/mod/module/balloon_advanced/on_use() - . = ..() - if(!.) - return - if(!do_after(mod.wearer, 15 SECONDS, target = mod)) - return FALSE - mod.wearer.adjustOxyLoss(20) - playsound(src, 'sound/items/modsuit/inflate_bloon.ogg', 50, TRUE) - var/obj/item/toy/balloon/long/l_balloon = new(get_turf(src)) - mod.wearer.put_in_hands(l_balloon) - drain_power(use_energy_cost) - + at party-appropriate rate." + cooldown_time = 20 SECONDS + balloon_path = /obj/item/toy/balloon/long + blowing_time = 15 SECONDS ///Microwave Beam - Microwaves items instantly. /obj/item/mod/module/microwave_beam @@ -56,6 +37,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 5 incompatible_modules = list(/obj/item/mod/module/microwave_beam, /obj/item/mod/module/organ_thrower) cooldown_time = 10 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) /obj/item/mod/module/microwave_beam/on_select_use(atom/target) . = ..() @@ -84,7 +66,7 @@ /obj/item/mod/module/waddle name = "MOD waddle module" desc = "Some of the most primitive technology in use by Honk Co. This module works off an automatic intention system, \ - utilizing its' sensitivity to the pilot's often-limited brainwaves to directly read their next step, \ + utilizing its sensitivity to the pilot's often-limited brainwaves to directly read their next step, \ affecting the boots they're installed in. Employing a twin-linked gravitonic drive to create \ miniaturized etheric blasts of space-time beneath the user's feet, this enables them to... \ to waddle around, bouncing to and fro with a pep in their step." @@ -92,16 +74,20 @@ complexity = 1 idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.2 incompatible_modules = list(/obj/item/mod/module/waddle) + required_slots = list(ITEM_SLOT_FEET) /obj/item/mod/module/waddle/on_suit_activation() - mod.boots.AddComponent(/datum/component/squeak, list('sound/effects/footstep/clownstep1.ogg'=1,'sound/effects/footstep/clownstep2.ogg'=1), 50, falloff_exponent = 20) //die off quick please + var/obj/item/shoes = mod.get_part_from_slot(ITEM_SLOT_FEET) + if(shoes) + shoes.AddComponent(/datum/component/squeak, list('sound/effects/footstep/clownstep1.ogg'=1,'sound/effects/footstep/clownstep2.ogg'=1), 50, falloff_exponent = 20) //die off quick please mod.wearer.AddElementTrait(TRAIT_WADDLING, MOD_TRAIT, /datum/element/waddling) if(is_clown_job(mod.wearer.mind?.assigned_role)) mod.wearer.add_mood_event("clownshoes", /datum/mood_event/clownshoes) /obj/item/mod/module/waddle/on_suit_deactivation(deleting = FALSE) - if(!deleting) - qdel(mod.boots.GetComponent(/datum/component/squeak)) + var/obj/item/shoes = mod.get_part_from_slot(ITEM_SLOT_FEET) + if(shoes && !deleting) + qdel(shoes.GetComponent(/datum/component/squeak)) REMOVE_TRAIT(mod.wearer, TRAIT_WADDLING, MOD_TRAIT) if(is_clown_job(mod.wearer.mind?.assigned_role)) mod.wearer.clear_mood_event("clownshoes") diff --git a/code/modules/mod/modules/modules_supply.dm b/code/modules/mod/modules/modules_supply.dm index e2e002de6e2..d71bde1ff0f 100644 --- a/code/modules/mod/modules/modules_supply.dm +++ b/code/modules/mod/modules/modules_supply.dm @@ -19,9 +19,6 @@ AddComponent(/datum/component/gps/item, "MOD0", state = GLOB.deep_inventory_state, overlay_state = FALSE) /obj/item/mod/module/gps/on_use() - . = ..() - if(!.) - return attack_self(mod.wearer) ///Hydraulic Clamp - Lets you pick up and drop crates. @@ -38,6 +35,7 @@ cooldown_time = 0.5 SECONDS overlay_state_inactive = "module_clamp" overlay_state_active = "module_clamp_on" + required_slots = list(ITEM_SLOT_GLOVES, ITEM_SLOT_BACK) /// Time it takes to load a crate. var/load_time = 3 SECONDS /// The max amount of crates you can carry. @@ -110,6 +108,7 @@ load_time = 1 SECONDS max_crates = 5 use_mod_colors = TRUE + required_slots = list(ITEM_SLOT_BACK) ///Drill - Lets you dig through rock and basalt. /obj/item/mod/module/drill @@ -123,17 +122,12 @@ incompatible_modules = list(/obj/item/mod/module/drill) cooldown_time = 0.5 SECONDS overlay_state_active = "module_drill" + required_slots = list(ITEM_SLOT_GLOVES) /obj/item/mod/module/drill/on_activation() - . = ..() - if(!.) - return RegisterSignal(mod.wearer, COMSIG_MOVABLE_BUMP, PROC_REF(bump_mine)) /obj/item/mod/module/drill/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return UnregisterSignal(mod.wearer, COMSIG_MOVABLE_BUMP) /obj/item/mod/module/drill/on_select_use(atom/target) @@ -180,6 +174,7 @@ incompatible_modules = list(/obj/item/mod/module/orebag) cooldown_time = 0.5 SECONDS allow_flags = MODULE_ALLOW_INACTIVE + required_slots = list(ITEM_SLOT_BACK) /// The ores stored in the bag. var/list/ores = list() @@ -208,9 +203,6 @@ ores += ore /obj/item/mod/module/orebag/on_use() - . = ..() - if(!.) - return for(var/obj/item/ore as anything in ores) ore.forceMove(drop_location()) ores -= ore @@ -228,6 +220,7 @@ overlay_state_inactive = "module_hydraulic" overlay_state_active = "module_hydraulic_active" use_mod_colors = TRUE + required_slots = list(ITEM_SLOT_BACK) /// Time it takes to launch var/launch_time = 2 SECONDS /// User overlay @@ -316,6 +309,7 @@ cooldown_time = 1.5 SECONDS overlay_state_active = "module_magnet" use_mod_colors = TRUE + required_slots = list(ITEM_SLOT_BACK) /obj/item/mod/module/magnet/on_select_use(atom/target) . = ..() @@ -340,9 +334,6 @@ callback = CALLBACK(src, PROC_REF(check_locker), locker)) /obj/item/mod/module/magnet/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return if(istype(mod.wearer.pulling, /obj/structure/closet)) mod.wearer.stop_pulling() @@ -370,6 +361,7 @@ incompatible_modules = list(/obj/item/mod/module/ash_accretion) overlay_state_inactive = "module_ash" use_mod_colors = TRUE + required_slots = list(ITEM_SLOT_OCLOTHING|ITEM_SLOT_ICLOTHING) /// How many tiles we can travel to max out the armor. var/max_traveled_tiles = 10 /// How many tiles we traveled through. @@ -423,9 +415,8 @@ UnregisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED) if(!traveled_tiles) return - var/list/parts = mod.mod_parts + mod var/datum/armor/to_remove = get_armor_by_type(armor_mod) - for(var/obj/item/part as anything in parts) + for(var/obj/item/part as anything in mod.get_parts(all = TRUE)) part.set_armor(part.get_armor().subtract_other_armor(to_remove.generate_new_with_multipliers(list(ARMOR_ALL = traveled_tiles)))) if(traveled_tiles == max_traveled_tiles) mod.slowdown += speed_added @@ -445,8 +436,7 @@ if(traveled_tiles >= max_traveled_tiles) return traveled_tiles++ - var/list/parts = mod.mod_parts + mod - for(var/obj/item/part as anything in parts) + for(var/obj/item/part as anything in mod.get_parts(all = TRUE)) part.set_armor(part.get_armor().add_other_armor(armor_mod)) if(traveled_tiles >= max_traveled_tiles) balloon_alert(mod.wearer, "fully ash covered") @@ -465,8 +455,7 @@ mod.slowdown += actual_speed_added mod.wearer.update_equipment_speed_mods() traveled_tiles-- - var/list/parts = mod.mod_parts + mod - for(var/obj/item/part as anything in parts) + for(var/obj/item/part as anything in mod.get_parts(all = TRUE)) part.set_armor(part.get_armor().subtract_other_armor(armor_mod)) if(traveled_tiles <= 0) balloon_alert(mod.wearer, "ran out of ash!") @@ -482,6 +471,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 3 incompatible_modules = list(/obj/item/mod/module/sphere_transform) cooldown_time = 1.25 SECONDS + required_slots = list(ITEM_SLOT_OCLOTHING|ITEM_SLOT_ICLOTHING, ITEM_SLOT_HEAD|ITEM_SLOT_MASK) /// Time it takes us to complete the animation. var/animate_time = 0.25 SECONDS /// List of traits to add/remove from our subject as needed. @@ -492,13 +482,13 @@ TRAIT_NO_SLIP_ALL, ) -/obj/item/mod/module/sphere_transform/on_activation() +/obj/item/mod/module/sphere_transform/activate() if(!mod.wearer.has_gravity()) balloon_alert(mod.wearer, "no gravity!") return FALSE - . = ..() - if(!.) - return + return ..() + +/obj/item/mod/module/sphere_transform/on_activation() 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)) @@ -513,9 +503,6 @@ RegisterSignal(mod.wearer, COMSIG_MOB_STATCHANGE, PROC_REF(on_statchange)) /obj/item/mod/module/sphere_transform/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return if(!deleting) playsound(src, 'sound/items/modsuit/ballin.ogg', 100, TRUE, frequency = -1) mod.wearer.base_pixel_y += 4 @@ -528,7 +515,7 @@ mod.wearer.remove_movespeed_modifier(/datum/movespeed_modifier/sphere) UnregisterSignal(mod.wearer, COMSIG_MOB_STATCHANGE) -/obj/item/mod/module/sphere_transform/on_use() +/obj/item/mod/module/sphere_transform/used() if(!lavaland_equipment_pressure_check(get_turf(src))) balloon_alert(mod.wearer, "too much pressure!") playsound(src, 'sound/weapons/gun/general/dry_fire.ogg', 25, TRUE) @@ -550,14 +537,14 @@ animate(mod.wearer) //stop the animation mod.wearer.SpinAnimation(1.5) //start it back again if(!mod.wearer.has_gravity()) - on_deactivation() //deactivate in no grav + deactivate() //deactivate in no grav /obj/item/mod/module/sphere_transform/proc/on_statchange(datum/source) SIGNAL_HANDLER if(!mod.wearer.stat) return - on_deactivation() + deactivate() /obj/projectile/bullet/mining_bomb name = "mining bomb" diff --git a/code/modules/mod/modules/modules_timeline.dm b/code/modules/mod/modules/modules_timeline.dm index 4e4d751065c..522ddf57501 100644 --- a/code/modules/mod/modules/modules_timeline.dm +++ b/code/modules/mod/modules/modules_timeline.dm @@ -28,9 +28,6 @@ UnregisterSignal(mod, COMSIG_MOD_MODULE_REMOVAL) /obj/item/mod/module/eradication_lock/on_use() - . = ..() - if(!.) - return true_owner_ckey = mod.wearer.ckey balloon_alert(mod.wearer, "user remembered") drain_power(use_energy_cost) @@ -65,11 +62,9 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 5 incompatible_modules = list(/obj/item/mod/module/rewinder) cooldown_time = 20 SECONDS + required_slots = list(ITEM_SLOT_BACK) /obj/item/mod/module/rewinder/on_use() - . = ..() - if(!.) - return balloon_alert(mod.wearer, "anchor point set") playsound(src, 'sound/items/modsuit/time_anchor_set.ogg', 50, TRUE) //stops all mods from triggering during rewinding @@ -109,16 +104,17 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 5 incompatible_modules = list(/obj/item/mod/module/timestopper) cooldown_time = 60 SECONDS + required_slots = list(ITEM_SLOT_BACK) ///The current timestop in progress. var/obj/effect/timestop/channelled/timestop -/obj/item/mod/module/timestopper/on_use() - . = ..() - if(!.) - return +/obj/item/mod/module/timestopper/used() if(timestop) mod.balloon_alert(mod.wearer, "already freezing time!") - return + return FALSE + return ..() + +/obj/item/mod/module/timestopper/on_use() //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)) @@ -157,18 +153,18 @@ incompatible_modules = list(/obj/item/mod/module/timeline_jumper) cooldown_time = 5 SECONDS allow_flags = MODULE_ALLOW_PHASEOUT + required_slots = list(ITEM_SLOT_BACK) ///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/on_use() - . = ..() - if(!.) - return +/obj/item/mod/module/timeline_jumper/used() var/area/noteleport_check = get_area(mod.wearer) if(noteleport_check && noteleport_check.area_flags & NOTELEPORT) to_chat(mod.wearer, 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() if(!phased_mob) //phasing out mod.visible_message(span_warning("[mod.wearer] leaps out of the timeline!")) @@ -210,6 +206,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 5 incompatible_modules = list(/obj/item/mod/module/tem) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_BACK) ///Reference to the chrono field being controlled by this module var/obj/structure/chrono_field/field = null ///Where the chronofield maker was when the field went up diff --git a/code/modules/mod/modules/modules_visor.dm b/code/modules/mod/modules/modules_visor.dm index e8656fe9233..4527fa631a6 100644 --- a/code/modules/mod/modules/modules_visor.dm +++ b/code/modules/mod/modules/modules_visor.dm @@ -9,15 +9,13 @@ active_power_cost = DEFAULT_CHARGE_DRAIN * 0.3 incompatible_modules = list(/obj/item/mod/module/visor) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_EYES|ITEM_SLOT_MASK) /// The HUD type given by the visor. var/hud_type /// The traits given by the visor. var/list/visor_traits = list() /obj/item/mod/module/visor/on_activation() - . = ..() - if(!.) - return if(hud_type) var/datum/atom_hud/hud = GLOB.huds[hud_type] hud.show_to(mod.wearer) @@ -26,9 +24,6 @@ mod.wearer.update_sight() /obj/item/mod/module/visor/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return if(hud_type) var/datum/atom_hud/hud = GLOB.huds[hud_type] hud.hide_from(mod.wearer) diff --git a/code/modules/unit_tests/modsuit.dm b/code/modules/unit_tests/modsuit.dm index 0dfc9815117..33aedb9ce49 100644 --- a/code/modules/unit_tests/modsuit.dm +++ b/code/modules/unit_tests/modsuit.dm @@ -7,10 +7,6 @@ for(var/modpath in paths) var/obj/item/mod/control/pre_equipped/mod = new modpath() TEST_ASSERT(mod.theme, "[modpath] spawned without a theme.") - TEST_ASSERT(mod.helmet, "[modpath] spawned without a helmet.") - TEST_ASSERT(mod.chestplate, "[modpath] spawned without a chestplate.") - TEST_ASSERT(mod.gauntlets, "[modpath] spawned without gauntlets.") - TEST_ASSERT(mod.boots, "[modpath] spawned without boots.") var/list/modules = list() var/complexity_max = mod.complexity_max var/complexity = 0 @@ -18,6 +14,7 @@ module = new module() complexity += module.complexity TEST_ASSERT(complexity <= complexity_max, "[modpath] starting modules reach above max complexity.") + TEST_ASSERT(module.has_required_parts(mod.mod_parts), "[modpath] initial module [module.type] is not supported by its parts.") for(var/obj/item/mod/module/module_to_check as anything in modules) TEST_ASSERT(!is_type_in_list(module, module_to_check.incompatible_modules), "[modpath] initial module [module.type] is incompatible with initial module [module_to_check.type]") TEST_ASSERT(!is_type_in_list(module_to_check, module.incompatible_modules), "[modpath] initial module [module.type] is incompatible with initial module [module_to_check.type]") diff --git a/code/modules/unit_tests/suit_storage_icons.dm b/code/modules/unit_tests/suit_storage_icons.dm index 12305e7abfc..7cc987bb468 100644 --- a/code/modules/unit_tests/suit_storage_icons.dm +++ b/code/modules/unit_tests/suit_storage_icons.dm @@ -14,9 +14,9 @@ for(var/path in clothing_path::allowed) //find all usable suit storage stuff. wearable_item_paths |= path - for(var/obj/item/mod/control/mod_path in subtypesof(/obj/item/mod/control)) - for(var/path in mod_path::chestplate::allowed) - wearable_item_paths |= path + for(var/datum/mod_theme/mod_theme as anything in GLOB.mod_themes) + mod_theme = GLOB.mod_themes[mod_theme] + wearable_item_paths |= mod_theme.allowed_suit_storage var/list/already_warned_icons = list() var/count = 1 //to be removed once the test goes live / into CI failure mode. diff --git a/modular_nova/master_files/code/modules/entombed_quirk/code/entombed.dm b/modular_nova/master_files/code/modules/entombed_quirk/code/entombed.dm index 297e8169bcd..28afbecaf2a 100644 --- a/modular_nova/master_files/code/modules/entombed_quirk/code/entombed.dm +++ b/modular_nova/master_files/code/modules/entombed_quirk/code/entombed.dm @@ -100,7 +100,7 @@ modsuit.theme.name = LOWER_TEXT(modsuit_skin_prefix) // ensure we're applying our config theme changes, just in case - for(var/obj/item/part as anything in modsuit.mod_parts) + for(var/obj/item/part as anything in modsuit.get_parts()) part.name = "[modsuit.theme.name] [initial(part.name)]" part.desc = "[initial(part.desc)] [modsuit.theme.desc]" diff --git a/modular_nova/master_files/code/modules/entombed_quirk/code/entombed_alt_actions.dm b/modular_nova/master_files/code/modules/entombed_quirk/code/entombed_alt_actions.dm index 24dffc324c1..77a80c62b6c 100644 --- a/modular_nova/master_files/code/modules/entombed_quirk/code/entombed_alt_actions.dm +++ b/modular_nova/master_files/code/modules/entombed_quirk/code/entombed_alt_actions.dm @@ -21,7 +21,7 @@ user.visible_message(span_info("[user] begins initiating emergency reactivation procedures on [entombed_suit]...")) if (do_after(user, 3 SECONDS, entombed_suit.wearer)) // deploy all our parts so activation actually works - for (var/obj/item/part as anything in entombed_suit.mod_parts) + for (var/obj/item/part as anything in entombed_suit.get_parts()) entombed_suit.deploy(user, part) entombed_suit.toggle_activate(user, TRUE) else diff --git a/modular_nova/master_files/code/modules/entombed_quirk/code/entombed_mod.dm b/modular_nova/master_files/code/modules/entombed_quirk/code/entombed_mod.dm index 745d4c5c790..6b48f40fa17 100644 --- a/modular_nova/master_files/code/modules/entombed_quirk/code/entombed_mod.dm +++ b/modular_nova/master_files/code/modules/entombed_quirk/code/entombed_mod.dm @@ -137,7 +137,7 @@ /obj/item/mod/control/pre_equipped/entombed/Initialize(mapload, new_theme, new_skin, new_core) . = ..() // Apply the entombed mod piece component to our applicable clothing pieces, so that they *always* return to the unit or self-delete if they can't. - for (var/obj/item/part as anything in mod_parts) + for (var/obj/item/part as anything in get_parts()) part.AddComponent(/datum/component/entombed_mod_piece, host_suit = src) ADD_TRAIT(src, TRAIT_NODROP, QUIRK_TRAIT) diff --git a/modular_nova/master_files/code/modules/mod/modules/_module.dm b/modular_nova/master_files/code/modules/mod/modules/_module.dm index 1e79a7f884a..f17d50558a5 100644 --- a/modular_nova/master_files/code/modules/mod/modules/_module.dm +++ b/modular_nova/master_files/code/modules/mod/modules/_module.dm @@ -29,8 +29,11 @@ // Set the retracts_into WEAKREF to mod.helmet, mod.chestplate, mod.boots, or mod.gauntlets as desired in the on_install proc just like shown below /obj/item/mod/module/visor/on_install() . = ..() - retracts_into = WEAKREF(mod.helmet) // hide visor module when the helmet is retracted + retracts_into = WEAKREF(mod.get_part_from_slot(ITEM_SLOT_HEAD) || mod.get_part_from_slot(ITEM_SLOT_MASK) || mod.get_part_from_slot(ITEM_SLOT_EYES)) // hide visor module when the helmet is retracted +/obj/item/mod/module/flashlight/on_install() + . = ..() + retracts_into = WEAKREF(mod.get_part_from_slot(ITEM_SLOT_HEAD) || mod.get_part_from_slot(ITEM_SLOT_MASK)) // hide visor module when the helmet is retracted /** * Proc that handles the mutable_appearances of the module on the MODsuits @@ -46,11 +49,12 @@ if(mod.wearer) if(is_module_hidden()) // retracted modules can hide parts that aren't usable when inactive return - - if(mod.chestplate && (mod.chestplate.supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION) && (mod.wearer.bodyshape & BODYSHAPE_DIGITIGRADE)) + var/obj/item/clothing/suit/mod/chestplate = mod.get_part_from_slot(ITEM_SLOT_OCLOTHING) + var/obj/item/clothing/head/mod/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) + if(chestplate && (chestplate.supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION) && (mod.wearer.bodyshape & BODYSHAPE_DIGITIGRADE)) suit_supports_variations_flags |= CLOTHING_DIGITIGRADE_VARIATION - if(mod.helmet && (mod.helmet.supports_variations_flags & CLOTHING_SNOUTED_VARIATION) && mod.wearer.bodyshape & BODYSHAPE_SNOUTED) + if(helmet && (helmet.supports_variations_flags & CLOTHING_SNOUTED_VARIATION) && mod.wearer.bodyshape & BODYSHAPE_SNOUTED) suit_supports_variations_flags |= CLOTHING_SNOUTED_VARIATION is_new_vox = isvoxprimalis(mod.wearer) is_old_vox = isvox(mod.wearer) diff --git a/modular_nova/master_files/code/modules/mod/modules/modules_supply.dm b/modular_nova/master_files/code/modules/mod/modules/modules_supply.dm index ed459386ee5..7614328e4d1 100644 --- a/modular_nova/master_files/code/modules/mod/modules/modules_supply.dm +++ b/modular_nova/master_files/code/modules/mod/modules/modules_supply.dm @@ -40,7 +40,13 @@ /// Checks if the suit's current state is valid for buff-granting purposes. Should only be called when the MOD is deployed or retracted. /obj/item/mod/module/ash_accretion/proc/on_mod_toggle() - if((mod.wearer.head == mod.helmet) && (mod.wearer.wear_suit == mod.chestplate) && (mod.wearer.gloves == mod.gauntlets) && (mod.wearer.shoes == mod.boots) && mod.active) + var/fully_deployed = TRUE + for(var/obj/item/part as anything in mod.get_parts()) + if(part.loc == mod) + fully_deployed = FALSE + break + + if(fully_deployed && mod.active) // suit is on and fully deployed, give them their proofing mod.wearer.add_traits(list(TRAIT_ASHSTORM_IMMUNE, TRAIT_SNOWSTORM_IMMUNE), MOD_TRAIT) RegisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED, PROC_REF(on_move)) @@ -59,9 +65,8 @@ if(!traveled_tiles) return - var/list/parts = mod.mod_parts + mod var/datum/armor/to_remove = get_armor_by_type(armor_mod) - for(var/obj/item/part as anything in parts) + for(var/obj/item/part as anything in mod.get_parts(all = TRUE)) part.set_armor(part.get_armor().subtract_other_armor(to_remove.generate_new_with_multipliers(list(ARMOR_ALL = traveled_tiles)))) if(traveled_tiles == max_traveled_tiles) diff --git a/modular_nova/modules/blueshield/code/modsuit/mod_theme.dm b/modular_nova/modules/blueshield/code/modsuit/mod_theme.dm index f7155396c92..e5882a38c48 100644 --- a/modular_nova/modules/blueshield/code/modsuit/mod_theme.dm +++ b/modular_nova/modules/blueshield/code/modsuit/mod_theme.dm @@ -25,32 +25,40 @@ /obj/item/assembly/flash, /obj/item/melee/baton, ) - skins = list( + variants = list( "praetorian" = list( MOD_ICON_OVERRIDE = 'modular_nova/modules/blueshield/icons/praetorian.dmi', MOD_WORN_ICON_OVERRIDE = 'modular_nova/modules/blueshield/icons/worn_praetorian.dmi', - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = null, UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) diff --git a/modular_nova/modules/contractor/code/items/modsuit/modules.dm b/modular_nova/modules/contractor/code/items/modsuit/modules.dm index 2f1420a1cf8..9c4c827bf2f 100644 --- a/modular_nova/modules/contractor/code/items/modsuit/modules.dm +++ b/modular_nova/modules/contractor/code/items/modsuit/modules.dm @@ -13,6 +13,7 @@ incompatible_modules = list(/obj/item/mod/module/baton_holster) cooldown_time = 0.5 SECONDS allow_flags = MODULE_ALLOW_INACTIVE + required_slots = list(ITEM_SLOT_GLOVES) /// Have they sacrificed a baton to actually be able to use this? var/eaten_baton = FALSE @@ -82,3 +83,4 @@ active_power_cost = DEFAULT_CHARGE_DRAIN * 0.3 device = /obj/item/gun/magic/hook/contractor cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) diff --git a/modular_nova/modules/contractor/code/items/modsuit/theme.dm b/modular_nova/modules/contractor/code/items/modsuit/theme.dm index c4c58014af7..b9254d92d77 100644 --- a/modular_nova/modules/contractor/code/items/modsuit/theme.dm +++ b/modular_nova/modules/contractor/code/items/modsuit/theme.dm @@ -30,32 +30,40 @@ /obj/item/melee/energy/sword, /obj/item/shield/energy, ) - skins = list( + variants = list( "contractor" = list( MOD_ICON_OVERRIDE = 'modular_nova/modules/contractor/icons/modsuit.dmi', MOD_WORN_ICON_OVERRIDE = 'modular_nova/modules/contractor/icons/worn_modsuit.dmi', - HELMET_LAYER = NECK_LAYER, - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( + UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) diff --git a/modular_nova/modules/customization/modules/mob/living/carbon/human/MOD_sprite_accessories/mod_accessory_handler.dm b/modular_nova/modules/customization/modules/mob/living/carbon/human/MOD_sprite_accessories/mod_accessory_handler.dm index fd01e77c4f0..f003f7fab86 100644 --- a/modular_nova/modules/customization/modules/mob/living/carbon/human/MOD_sprite_accessories/mod_accessory_handler.dm +++ b/modular_nova/modules/customization/modules/mob/living/carbon/human/MOD_sprite_accessories/mod_accessory_handler.dm @@ -1,25 +1,25 @@ // This DMI holds all of the overlayable textures for MODs #define HARDLIGHT_DMI 'modular_nova/modules/customization/modules/mob/living/carbon/human/MOD_sprite_accessories/icons/MOD_mask.dmi' -/obj/item/mod/control/seal_part(obj/item/clothing/part, seal) +/obj/item/mod/control/seal_part(obj/item/clothing/part, is_sealed) . = ..() if(activating) return - update_external_organs_modsuit_status(seal && active) + update_external_organs_modsuit_status(is_sealed && active) wearer.update_body_parts(TRUE) -/obj/item/mod/control/finish_activation(on) +/obj/item/mod/control/finish_activation(is_on) . = ..() - update_external_organs_modsuit_status(on) + update_external_organs_modsuit_status(is_on) wearer.update_body_parts(TRUE) -/obj/item/mod/control/on_mod_deployed(mob/user) +/obj/item/mod/control/deploy(mob/user, obj/item/part) . = ..() update_external_organs_modsuit_status(active) wearer.update_body_parts(TRUE) -/obj/item/mod/control/on_mod_retracted(mob/user) +/obj/item/mod/control/retract(mob/user, obj/item/part) . = ..() update_external_organs_modsuit_status(FALSE) wearer.update_body_parts(TRUE) diff --git a/modular_nova/modules/kahraman_equipment/code/clothing/mod.dm b/modular_nova/modules/kahraman_equipment/code/clothing/mod.dm index f3ef68e8f66..924cc3e6b75 100644 --- a/modular_nova/modules/kahraman_equipment/code/clothing/mod.dm +++ b/modular_nova/modules/kahraman_equipment/code/clothing/mod.dm @@ -42,31 +42,39 @@ /obj/item/analyzer, /obj/item/storage/medkit, ) - skins = list( + variants = list( "colonist" = list( MOD_ICON_OVERRIDE = 'modular_nova/modules/kahraman_equipment/icons/modsuits/mod.dmi', MOD_WORN_ICON_OVERRIDE = 'modular_nova/modules/kahraman_equipment/icons/modsuits/mod_worn.dmi', - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = null, UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) diff --git a/modular_nova/modules/marines/code/mod.dm b/modular_nova/modules/marines/code/mod.dm index b10a66cd8e9..bb87bb3bca4 100644 --- a/modular_nova/modules/marines/code/mod.dm +++ b/modular_nova/modules/marines/code/mod.dm @@ -28,32 +28,40 @@ /obj/item/gun/ballistic, /obj/item/melee/breaching_hammer, ) - skins = list( + variants = list( "marine" = list( MOD_ICON_OVERRIDE = 'modular_nova/modules/marines/icons/mod.dmi', MOD_WORN_ICON_OVERRIDE = 'modular_nova/modules/marines/icons/wornmod.dmi', - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|FLASH_PROTECTION_WELDER, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT|HIDETAIL, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) diff --git a/modular_nova/modules/marines/code/modsuit_modules.dm b/modular_nova/modules/marines/code/modsuit_modules.dm index 1ad2612370c..5ef96d451e9 100644 --- a/modular_nova/modules/marines/code/modsuit_modules.dm +++ b/modular_nova/modules/marines/code/modsuit_modules.dm @@ -16,6 +16,7 @@ cooldown_time = 0.5 SECONDS overlay_state_inactive = "module_smartgun_off" //appears on back when it's off overlay_state_active = "module_smartgun_on" + required_slots = list(ITEM_SLOT_GLOVES) /// Power consumed per bullet fired var/power_per_bullet = 25 diff --git a/modular_nova/modules/novaya_ert/code/mod_suit.dm b/modular_nova/modules/novaya_ert/code/mod_suit.dm index fa54739f0c7..fb7755d227b 100644 --- a/modular_nova/modules/novaya_ert/code/mod_suit.dm +++ b/modular_nova/modules/novaya_ert/code/mod_suit.dm @@ -24,31 +24,39 @@ /obj/item/shield/riot, /obj/item/gun, ) - skins = list( + variants = list( "frontline" = list( MOD_ICON_OVERRIDE = 'modular_nova/modules/novaya_ert/icons/mod.dmi', MOD_WORN_ICON_OVERRIDE = 'modular_nova/modules/novaya_ert/icons/wornmod.dmi', - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = HEAD_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT|HIDETAIL, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -113,31 +121,39 @@ /obj/item/shield/riot, /obj/item/gun, ) - skins = list( + variants = list( "policing" = list( MOD_ICON_OVERRIDE = 'modular_nova/modules/novaya_ert/icons/mod.dmi', MOD_WORN_ICON_OVERRIDE = 'modular_nova/modules/novaya_ert/icons/wornmod.dmi', - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = HEAD_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT|HIDETAIL, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) diff --git a/modular_nova/modules/tarkon/code/clothing/mod.dm b/modular_nova/modules/tarkon/code/clothing/mod.dm index d9e0e1f6f92..e109b85d7a3 100644 --- a/modular_nova/modules/tarkon/code/clothing/mod.dm +++ b/modular_nova/modules/tarkon/code/clothing/mod.dm @@ -19,11 +19,11 @@ /obj/item/shield/riot, /obj/item/gun, ) - skins = list( + variants = list( "tarkon" = list( MOD_ICON_OVERRIDE = 'modular_nova/modules/tarkon/icons/obj/clothing/mod.dmi', MOD_WORN_ICON_OVERRIDE = 'modular_nova/modules/tarkon/icons/mob/clothing/mod.dmi', - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = HEAD_LAYER, UNSEALED_CLOTHING = SNUG_FIT, UNSEALED_COVER = HEADCOVERSEYES|PEPPERPROOF, @@ -31,21 +31,29 @@ SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT|HIDETAIL, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) diff --git a/tgstation.dme b/tgstation.dme index 4284535ad3c..63ed39b4b11 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5250,6 +5250,7 @@ #include "code\modules\mod\mod_core.dm" #include "code\modules\mod\mod_link.dm" #include "code\modules\mod\mod_paint.dm" +#include "code\modules\mod\mod_part.dm" #include "code\modules\mod\mod_theme.dm" #include "code\modules\mod\mod_types.dm" #include "code\modules\mod\mod_ui.dm" diff --git a/tgui/packages/tgui/interfaces/MODsuit.tsx b/tgui/packages/tgui/interfaces/MODsuit.tsx index f78bd4dd1d8..c39724aedc8 100644 --- a/tgui/packages/tgui/interfaces/MODsuit.tsx +++ b/tgui/packages/tgui/interfaces/MODsuit.tsx @@ -27,10 +27,7 @@ type MODsuitData = { ui_theme: string; control: string; complexity_max: number; - helmet: string; - chestplate: string; - gauntlets: string; - boots: string; + parts: PartData[]; // Dynamic suit_status: SuitStatus; user_status: UserStatus; @@ -38,6 +35,11 @@ type MODsuitData = { module_info: Module[]; }; +type PartData = { + slot: string; + name: string; +}; + type SuitStatus = { core_name: string; cell_charge_current: number; @@ -476,7 +478,7 @@ const SuitStatusSection = (props) => { const HardwareSection = (props) => { const { act, data } = useBackend(); - const { control, helmet, chestplate, gauntlets, boots } = data; + const { control } = data; const { ai_name, core_name } = data.suit_status; return (
@@ -488,19 +490,28 @@ const HardwareSection = (props) => { {core_name || 'No Core Detected'} {control} - {helmet || 'None'} - - {chestplate || 'None'} - - - {gauntlets || 'None'} - - {boots || 'None'} +
); }; +const ModParts = (props) => { + const { act, data } = useBackend(); + const { parts } = data; + return ( + <> + {parts.map((part) => { + return ( + + {part.name} + + ); + })} + + ); +}; + const UserStatusSection = (props) => { const { act, data } = useBackend(); const { active } = data.suit_status;