diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index fc6113046ca..3f3d01a6db2 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -765,87 +765,109 @@ GLOBAL_LIST_INIT(human_heights_to_offsets, list( "[HUMAN_HEIGHT_TALLEST]" = list(3, 2), )) -// Mob Overlays Indexes -/// Total number of layers for mob overlays -/// KEEP THIS UP-TO-DATE OR SHIT WILL BREAK -/// Also consider updating layers_to_offset -#define TOTAL_LAYERS 39 -/// Mutations layer - Tk headglows, cold resistance glow, etc -#define MUTATIONS_LAYER 38 -/// Mutantrace features (tail when looking south) that must appear behind the body parts -#define BODY_BEHIND_LAYER 37 -/// Layer for bodyparts that should appear behind every other bodypart - Mostly, legs when facing WEST or EAST -#define BODYPARTS_LOW_LAYER 36 -/// Layer for most bodyparts, appears above BODYPARTS_LOW_LAYER and below BODYPARTS_HIGH_LAYER -#define BODYPARTS_LAYER 35 -/// Mutantrace features (snout, body markings) that must appear above the body parts -#define BODY_ADJ_LAYER 34 -/// Underwear, undershirts, socks -#define BODY_LAYER 33 -/// Eyes and eyelids -#define EYES_LAYER 32 -/// Mutations that should appear above body, body_adj and bodyparts layer (e.g. laser eyes) -#define FRONT_MUTATIONS_LAYER 31 -/// Damage indicators (cuts and burns) -#define DAMAGE_LAYER 30 -/// Jumpsuit clothing layer -#define UNIFORM_LAYER 29 -/// ID card layer -#define ID_LAYER 28 -/// ID card layer (might be deprecated) -#define ID_CARD_LAYER 27 -/// Layer for bodyparts that should appear above every other bodypart - Currently only used for hands -#define BODYPARTS_HIGH_LAYER 26 -/// Gloves layer -#define GLOVES_LAYER 25 -/// Shoes layer -#define SHOES_LAYER 24 -/// Layer for masks that are worn below ears and eyes (like Balaclavas) (layers below hair, use flagsinv=HIDEHAIR as needed) -#define LOW_FACEMASK_LAYER 23 -/// Ears layer (Spessmen have ears? Wow) -#define EARS_LAYER 22 -/// Layer for neck apperal that should appear below the suit slot (like neckties) -#define LOW_NECK_LAYER 21 -/// Suit layer (armor, coats, etc.) -#define SUIT_LAYER 20 -/// Glasses layer -#define GLASSES_LAYER 19 -/// Belt layer -#define BELT_LAYER 18 //Possible make this an overlay of something required to wear a belt? -/// Suit storage layer (tucking a gun or baton underneath your armor) -#define SUIT_STORE_LAYER 17 -/// Neck layer (for wearing capes and bedsheets) -#define NECK_LAYER 16 -/// Back layer (for backpacks and equipment on your back) -#define BACK_LAYER 15 -/// Special layer for rendering beneath hair, for special facemasks -#define BENEATH_HAIR_LAYER 14 -/// Hair layer (mess with the fro and you got to go!) -#define HAIR_LAYER 13 //TODO: make part of head layer? -/// Facemask layer (gas masks, breath masks, etc.) -#define FACEMASK_LAYER 12 -/// Head layer (hats, helmets, etc.) -#define HEAD_LAYER 11 -/// Hair that layers out above clothing, including hats (high ponytails and such) -#define OUTER_HAIR_LAYER 10 -/// Handcuff layer (when your hands are cuffed) -#define HANDCUFF_LAYER 9 -/// Legcuff layer (when your feet are cuffed) -#define LEGCUFF_LAYER 8 -/// Hands layer (for the actual hand, not the arm... I think?) -#define HANDS_LAYER 7 -/// Body front layer. Usually used for mutant bodyparts that need to be in front of stuff (e.g. cat ears) -#define BODY_FRONT_LAYER 6 -/// Special body layer that actually require to be above the hair (e.g. lifted welding goggles) -#define ABOVE_BODY_FRONT_GLASSES_LAYER 5 -/// Special body layer for the rare cases where something on the head needs to be above everything else (e.g. flowers) -#define ABOVE_BODY_FRONT_HEAD_LAYER 4 -/// Bleeding wound icons -#define WOUND_LAYER 3 -/// Blood cult ascended halo layer, because there's currently no better solution for adding/removing -#define HALO_LAYER 2 +/* + * Mob overlays + * + * Integers are standing overlays which are managed by the mob overlay system + * They're drawn in order from least to greatest, with the lowest layer drawn highest on the screen + * + * Decimals are sub-layers or alternate layers + * These are not managed by the mob overlay system, but still layer according to their value + * + * Please keep this organized and in order, to make it easier to see at a glance how mobs layer + * Don't be afraid to change the values of existing layers either, it won't break anything so long as order is the same + * + * If you want to add a new layer, make sure to update TOTAL_LAYERS and layers_to_offset as needed + * NOTE: You ONLY need to add standing layers if you're using the standing overlay system, ie. apply_overlay(YOUR_LAYER)! + * If you're NOT using this sytem just add it as a sub-layer where appropriate + */ + /// The highest most layer for mob overlays. Unused #define HIGHEST_LAYER 1 + /// Blood cult ascended halo layer + #define HALO_LAYER 1.1 +/// Bleeding wound icons +#define WOUND_LAYER 2 + /// Special body layer for the rare cases where something on the head needs to be above everything else (e.g. flowers) + #define ABOVE_BODY_FRONT_HEAD_LAYER 2.3 + /// The layer above mutant body parts + #define ABOVE_BODY_FRONT_LAYER 2.4 + /// Body front layer. Usually used for mutant bodyparts that need to be in front of stuff (e.g. cat ears) + #define BODY_FRONT_LAYER 2.5 +/// Hands layer (for the actual hand, not the arm... I think?) +#define HANDS_LAYER 3 +/// Legcuff layer (when your feet are cuffed) +#define LEGCUFF_LAYER 4 +/// Handcuff layer (when your hands are cuffed) +#define HANDCUFF_LAYER 5 + /// Hair that layers out above clothing, including hats (high ponytails and such) + #define OUTER_HAIR_LAYER 5.9 +/// Head layer (hats, helmets, etc.) +#define HEAD_LAYER 6 + /// The layer underneath the head (for hats) + #define UNDER_HEAD_LAYER 6.1 +/// Facemask layer (gas masks, breath masks, etc.) +#define FACEMASK_LAYER 7 +/// Hair layer (mess with the fro and you got to go!) +#define HAIR_LAYER 8 + /// Special layer for rendering beneath hair, for special facemasks + #define BENEATH_HAIR_LAYER 8.1 +/// Back layer (for backpacks and equipment on your back) +#define BACK_LAYER 9 +/// Neck layer (for wearing capes and bedsheets) +#define NECK_LAYER 10 +/// Suit storage layer (tucking a gun or baton underneath your armor) +#define SUIT_STORE_LAYER 11 +/// Belt layer +#define BELT_LAYER 12 //Possible make this an overlay of something required to wear a belt? +/// Glasses layer +#define GLASSES_LAYER 13 +/// Suit layer (armor, coats, etc.) +#define SUIT_LAYER 14 + /// The layer underneath the suit + #define UNDER_SUIT_LAYER 14.1 + /// Layer for neck apperal that should appear below the suit slot (like neckties) + #define LOW_NECK_LAYER 14.2 +/// Ears layer (Spessmen have ears? Wow) +#define EARS_LAYER 15 + /// Layer for masks that are worn below ears and eyes (like Balaclavas) (layers below hair, use flagsinv=HIDEHAIR as needed) + #define LOW_FACEMASK_LAYER 15.1 + /// The layer above shoes + #define ABOVE_SHOES_LAYER 15.9 +/// Shoes layer +#define SHOES_LAYER 16 +/// Gloves layer +#define GLOVES_LAYER 17 + /// Layer for bodyparts that should appear above every other bodypart - Currently only used for hands + #define BODYPARTS_HIGH_LAYER 17.5 +/// ID card layer +#define ID_LAYER 18 +/// Jumpsuit clothing layer +#define UNIFORM_LAYER 19 + /// The layer underneath the uniform + #define UNDER_UNIFORM_LAYER 19.1 +/// Damage indicators (cuts and burns) +#define DAMAGE_LAYER 20 + /// Mutations that should appear above everything else (e.g. laser eyes) + #define FRONT_MUTATIONS_LAYER 20.9 +/// Eyes and eyelids +#define EYES_LAYER 21 +/// Underwear, undershirts, socks +#define BODY_LAYER 22 + /// Mutantrace features (snout, body markings) that must appear above the body parts + #define BODY_ADJ_LAYER 22.9 +/// Layer for most bodyparts, appears above BODYPARTS_LOW_LAYER and below BODYPARTS_HIGH_LAYER +#define BODYPARTS_LAYER 23 + /// Layer for bodyparts that should appear behind every other bodypart - Mostly, legs when facing WEST or EAST + #define BODYPARTS_LOW_LAYER 23.1 + /// Mutantrace features (tail when looking south) that must appear behind the body parts + #define BODY_BEHIND_LAYER 23.2 + /// Mutations layer - Tk headglows, cold resistance glow, etc. Very bottom of the mob + #define MUTATIONS_LAYER 23.9 +/// Total number of standing overlays. +/// KEEP THIS UP-TO-DATE OR SHIT WILL BREAK. +/// (You ONLY need to update this if you add a standing overlay, adding an integer.) +#define TOTAL_LAYERS 23 #define UPPER_BODY "upper body" #define LOWER_BODY "lower body" @@ -869,32 +891,10 @@ GLOBAL_LIST_INIT(layers_to_offset, list( // (In practice they'd be fine if they got a filter but we can optimize a bit by not.) "[NECK_LAYER]" = UPPER_BODY, "[GLASSES_LAYER]" = UPPER_BODY, - "[LOW_NECK_LAYER]" = UPPER_BODY, - "[ABOVE_BODY_FRONT_GLASSES_LAYER]" = UPPER_BODY, // currently unused - "[ABOVE_BODY_FRONT_HEAD_LAYER]" = UPPER_BODY, // only used for head stuff "[GLOVES_LAYER]" = LOWER_BODY, - "[HALO_LAYER]" = UPPER_BODY, // above the head "[HANDCUFF_LAYER]" = LOWER_BODY, - "[ID_CARD_LAYER]" = UPPER_BODY, // unused "[ID_LAYER]" = UPPER_BODY, "[FACEMASK_LAYER]" = UPPER_BODY, - "[LOW_FACEMASK_LAYER]" = UPPER_BODY, - "[BENEATH_HAIR_LAYER]" = UPPER_BODY, // alt mask layer - // These two are cached, and have their appearance shared(?), so it's safer to just not touch it - "[MUTATIONS_LAYER]" = NO_MODIFY, - "[FRONT_MUTATIONS_LAYER]" = NO_MODIFY, - // These DO get a filter, I'm leaving them here as reference, - // to show how many filters are added at a glance - // BACK_LAYER (backpacks are big) - // BODYPARTS_HIGH_LAYER (arms) - // BODY_LAYER (body markings (full body), underwear (full body)) - // BODY_ADJ_LAYER (external organs like wings) - // BODY_BEHIND_LAYER (external organs like wings) - // BODY_FRONT_LAYER (external organs like wings) - // DAMAGE_LAYER (full body) - // HIGHEST_LAYER (full body) - // UNIFORM_LAYER (full body) - // WOUND_LAYER (full body) )) //Bitflags for the layers a bodypart overlay can draw on (can be drawn on multiple layers) @@ -916,22 +916,6 @@ GLOBAL_LIST_INIT(layers_to_offset, list( /// This organ allows restyling with enamel restyling (like a fucking file or something?). It's for horns and shit #define EXTERNAL_RESTYLE_ENAMEL (1 << 2) -//Mob Overlay Index Shortcuts for alternate_worn_layer, layers -//Because I *KNOW* somebody will think layer+1 means "above" -//IT DOESN'T OK, IT MEANS "UNDER" -/// The layer underneath the uniform -#define UNDER_UNIFORM_LAYER (UNIFORM_LAYER+1) -/// The layer underneath the suit -#define UNDER_SUIT_LAYER (SUIT_LAYER+1) -/// The layer underneath the head (for hats) -#define UNDER_HEAD_LAYER (HEAD_LAYER+1) - -//AND -1 MEANS "ABOVE", OK?, OK!?! -/// The layer above shoes -#define ABOVE_SHOES_LAYER (SHOES_LAYER-1) -/// The layer above mutant body parts -#define ABOVE_BODY_FRONT_LAYER (BODY_FRONT_LAYER-1) - /// If gravity must be present to perform action (can't use pens without gravity) #define NEED_GRAVITY (1<<0) /// If reading is required to perform action (can't read a book if you are illiterate) diff --git a/code/_globalvars/layers.dm b/code/_globalvars/layers.dm index 4652d00a389..8f1d01c4ab8 100644 --- a/code/_globalvars/layers.dm +++ b/code/_globalvars/layers.dm @@ -150,42 +150,45 @@ GLOBAL_LIST_INIT(admin_readable_layers, list( "LIGHTING_ABOVE_ALL" = LIGHTING_ABOVE_ALL, "EMISSIVE_LAYER_UNBLOCKABLE" = EMISSIVE_LAYER_UNBLOCKABLE, // Mob layers - "MUTATIONS_LAYER" = -MUTATIONS_LAYER, "BODY_BEHIND_LAYER" = -BODY_BEHIND_LAYER, - "BODYPARTS_LOW_LAYER" = -BODYPARTS_LOW_LAYER, "BODYPARTS_LAYER" = -BODYPARTS_LAYER, "BODY_ADJ_LAYER" = -BODY_ADJ_LAYER, "BODY_LAYER" = -BODY_LAYER, "EYES_LAYER" = -EYES_LAYER, - "FRONT_MUTATIONS_LAYER" = -FRONT_MUTATIONS_LAYER, "DAMAGE_LAYER" = -DAMAGE_LAYER, "UNIFORM_LAYER" = -UNIFORM_LAYER, "ID_LAYER" = -ID_LAYER, - "ID_CARD_LAYER" = -ID_CARD_LAYER, - "BODYPARTS_HIGH_LAYER" = -BODYPARTS_HIGH_LAYER, "GLOVES_LAYER" = -GLOVES_LAYER, - "UNDER_UNIFORM_LAYER" = -UNDER_UNIFORM_LAYER, "SHOES_LAYER" = -SHOES_LAYER, - "LOW_FACEMASK_LAYER" = -LOW_FACEMASK_LAYER, "EARS_LAYER" = -EARS_LAYER, - "LOW_NECK_LAYER" = -LOW_NECK_LAYER, "SUIT_LAYER" = -SUIT_LAYER, "GLASSES_LAYER" = -GLASSES_LAYER, "BELT_LAYER" = -BELT_LAYER, "SUIT_STORE_LAYER" = -SUIT_STORE_LAYER, "NECK_LAYER" = -NECK_LAYER, "BACK_LAYER" = -BACK_LAYER, - "BENEATH_HAIR_LAYER" = -BENEATH_HAIR_LAYER, "HAIR_LAYER" = -HAIR_LAYER, "FACEMASK_LAYER" = -FACEMASK_LAYER, "HEAD_LAYER" = -HEAD_LAYER, - "OUTER_HAIR_LAYER" = -OUTER_HAIR_LAYER, "HANDCUFF_LAYER" = -HANDCUFF_LAYER, "LEGCUFF_LAYER" = -LEGCUFF_LAYER, "HANDS_LAYER" = -HANDS_LAYER, "BODY_FRONT_LAYER" = -BODY_FRONT_LAYER, - "ABOVE_BODY_FRONT_GLASSES_LAYER" = -ABOVE_BODY_FRONT_GLASSES_LAYER, - "ABOVE_BODY_FRONT_HEAD_LAYER" = -ABOVE_BODY_FRONT_HEAD_LAYER, "WOUND_LAYER" = -WOUND_LAYER, + // Alt. mob layers + "ABOVE_BODY_FRONT_HEAD_LAYER" = -ABOVE_BODY_FRONT_HEAD_LAYER, + "ABOVE_BODY_FRONT_LAYER" = -ABOVE_BODY_FRONT_LAYER, + "ABOVE_SHOES_LAYER" = -ABOVE_SHOES_LAYER, + "BENEATH_HAIR_LAYER" = -BENEATH_HAIR_LAYER, + "BODYPARTS_HIGH_LAYER" = -BODYPARTS_HIGH_LAYER, + "BODYPARTS_LOW_LAYER" = -BODYPARTS_LOW_LAYER, + "FRONT_MUTATIONS_LAYER" = -FRONT_MUTATIONS_LAYER, "HALO_LAYER" = -HALO_LAYER, + "LOW_FACEMASK_LAYER" = -LOW_FACEMASK_LAYER, + "LOW_NECK_LAYER" = -LOW_NECK_LAYER, + "MUTATIONS_LAYER" = -MUTATIONS_LAYER, + "OUTER_HAIR_LAYER" = -OUTER_HAIR_LAYER, + "UNDER_HEAD_LAYER" = -UNDER_HEAD_LAYER, + "UNDER_SUIT_LAYER" = -UNDER_SUIT_LAYER, + "UNDER_UNIFORM_LAYER" = -UNDER_UNIFORM_LAYER, )) diff --git a/code/datums/dna/dna.dm b/code/datums/dna/dna.dm index effe0bd1ce5..5847b83a61e 100644 --- a/code/datums/dna/dna.dm +++ b/code/datums/dna/dna.dm @@ -410,10 +410,9 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) log_mob_tag("TAG: [tag] SPECIES: [key_name(src)] \[[mrace]\]") /mob/living/carbon/human/set_species(datum/species/mrace, icon_update = TRUE, pref_load = FALSE, replace_missing = TRUE) - ..() + . = ..() if(icon_update) update_body(is_creating = TRUE) - update_mutations_overlay()// no lizard with human hulk overlay please. /mob/proc/has_dna() return @@ -464,7 +463,6 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(mrace || newfeatures || unique_identity) update_body(is_creating = TRUE) - update_mutations_overlay() if(LAZYLEN(mutations) && force_transfer_mutations && can_mutate()) for(var/datum/mutation/mutation as anything in mutations) @@ -502,7 +500,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(icon_update) update_body(is_creating = mutcolor_update) if(mutations_overlay_update) - update_mutations_overlay() + update_appearance(UPDATE_OVERLAYS) /mob/proc/domutcheck() return @@ -514,7 +512,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) for(var/mutation in dna.mutation_index) dna.check_block(mutation) - update_mutations_overlay() + update_appearance(UPDATE_OVERLAYS) /datum/dna/proc/check_block(mutation_path) var/datum/mutation/mutation = get_mutation(mutation_path) diff --git a/code/datums/elements/cult_halo.dm b/code/datums/elements/cult_halo.dm deleted file mode 100644 index 684144ca0ab..00000000000 --- a/code/datums/elements/cult_halo.dm +++ /dev/null @@ -1,53 +0,0 @@ -/** - * # Cult halo element - * - * Applies and removes the cult halo - */ -/datum/element/cult_halo - -/datum/element/cult_halo/Attach(datum/target, initial_delay = 20 SECONDS) - . = ..() - if (!isliving(target)) - return ELEMENT_INCOMPATIBLE - - // Register signals for mob transformation to prevent premature halo removal - RegisterSignals(target, list(COMSIG_CHANGELING_TRANSFORM, COMSIG_MONKEY_HUMANIZE, COMSIG_HUMAN_MONKEYIZE), PROC_REF(set_halo)) - addtimer(CALLBACK(src, PROC_REF(set_halo), target), initial_delay) - -/** - * Halo setter proc - * - * Adds the cult halo overlays, and adds the halo trait to the mob. - */ -/datum/element/cult_halo/proc/set_halo(mob/living/target) - SIGNAL_HANDLER - - if(!IS_CULTIST(target)) - target.RemoveElement(/datum/element/cult_halo) - return - - ADD_TRAIT(target, TRAIT_CULT_HALO, CULT_TRAIT) - var/mutable_appearance/new_halo_overlay = mutable_appearance('icons/mob/effects/halo.dmi', "halo[rand(1, 6)]", -HALO_LAYER) - if (ishuman(target)) - var/mob/living/carbon/human/human_parent = target - new /obj/effect/temp_visual/cult/sparks(get_turf(human_parent), human_parent.dir) - human_parent.overlays_standing[HALO_LAYER] = new_halo_overlay - human_parent.apply_overlay(HALO_LAYER) - else - target.add_overlay(new_halo_overlay) - -/** - * Detach proc - * - * Removes the halo overlays, and trait from the mob - */ -/datum/element/cult_halo/Detach(mob/living/target, ...) - REMOVE_TRAIT(target, TRAIT_CULT_HALO, CULT_TRAIT) - if (ishuman(target)) - var/mob/living/carbon/human/human_parent = target - human_parent.remove_overlay(HALO_LAYER) - human_parent.update_body() - else - target.cut_overlay(HALO_LAYER) - UnregisterSignal(target, list(COMSIG_CHANGELING_TRANSFORM, COMSIG_HUMAN_MONKEYIZE, COMSIG_MONKEY_HUMANIZE)) - return ..() diff --git a/code/datums/mutations/_mutations.dm b/code/datums/mutations/_mutations.dm index 7f88a696b5b..9616adfa742 100644 --- a/code/datums/mutations/_mutations.dm +++ b/code/datums/mutations/_mutations.dm @@ -30,12 +30,16 @@ var/text_gain_indication = "" /// Message given to the user upon losing this mutation var/text_lose_indication = "" - /// Visual indicators upon the character of the owner of this mutation - var/static/list/visual_indicators = list() /// The path of action we grant to our user on mutation gain var/datum/action/cooldown/power_path + /// Optional: Icon for overlay the mutation gives the mod + var/mutation_icon = 'icons/mob/effects/genetics.dmi' + /// Optional: Icon state for the overlay the mutation gives the mob + var/mutation_icon_state = "" /// Which mutation layer to use var/layer_used = MUTATIONS_LAYER + /// Where the mutation overlay is located + var/offset_location = UPPER_BODY /// To restrict mutation to only certain species var/list/species_allowed /// Minimum health required to acquire the mutation @@ -115,7 +119,7 @@ /datum/mutation/proc/on_acquiring(mob/living/carbon/human/acquirer) if(!acquirer || !istype(acquirer) || acquirer.stat == DEAD || (src in acquirer.dna.mutations)) return FALSE - if(species_allowed && !species_allowed.Find(acquirer.dna.species.id)) + if(LAZYLEN(species_allowed) && !LAZYFIND(species_allowed, acquirer.dna.species.id)) return FALSE if(health_req && acquirer.health < health_req) return FALSE @@ -132,14 +136,11 @@ SEND_SIGNAL(src, COMSIG_MUTATION_GAINED, acquirer) if(text_gain_indication) to_chat(owner, text_gain_indication) - if(visual_indicators.len) - var/list/mut_overlay = list(get_visual_indicator()) - if(owner.overlays_standing[layer_used]) - mut_overlay = owner.overlays_standing[layer_used] - mut_overlay |= get_visual_indicator() - owner.remove_overlay(layer_used) - owner.overlays_standing[layer_used] = mut_overlay - owner.apply_overlay(layer_used) + if(LAZYLEN(species_allowed)) + RegisterSignal(owner, COMSIG_SPECIES_GAIN, PROC_REF(on_species_change)) + if(mutation_icon && mutation_icon_state) + RegisterSignal(owner, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_update_overlay)) + owner.update_appearance(UPDATE_OVERLAYS) grant_power() //we do checks here so nothing about hulk getting magic if(mutation_traits) owner.add_traits(mutation_traits, GENETIC_MUTATION) @@ -156,41 +157,27 @@ return TRUE . = FALSE SEND_SIGNAL(src, COMSIG_MUTATION_LOST, owner) + UnregisterSignal(owner, list(COMSIG_SPECIES_GAIN, COMSIG_ATOM_UPDATE_OVERLAYS)) + if(mutation_icon && mutation_icon_state) + owner.update_appearance(UPDATE_OVERLAYS) if(text_lose_indication && owner.stat != DEAD) to_chat(owner, text_lose_indication) - if(visual_indicators.len) - var/list/mut_overlay = list() - if(owner.overlays_standing[layer_used]) - mut_overlay = owner.overlays_standing[layer_used] - owner.remove_overlay(layer_used) - mut_overlay.Remove(get_visual_indicator()) - owner.overlays_standing[layer_used] = mut_overlay - owner.apply_overlay(layer_used) - if(mutation_traits) owner.remove_traits(mutation_traits, GENETIC_MUTATION) -/mob/living/carbon/proc/update_mutations_overlay() - return +/datum/mutation/proc/on_species_change(datum/source, datum/species/new_species) + SIGNAL_HANDLER -/mob/living/carbon/human/update_mutations_overlay() - for(var/datum/mutation/mutation as anything in dna.mutations) - if(mutation.species_allowed && !mutation.species_allowed.Find(dna.species.id)) - dna.remove_mutation(mutation, mutation.sources) //shouldn't have that mutation at all - continue - if(mutation.visual_indicators.len == 0) - continue - var/list/mut_overlay = list() - if(overlays_standing[mutation.layer_used]) - mut_overlay = overlays_standing[mutation.layer_used] - var/mutable_appearance/indicator_to_add = mutation.get_visual_indicator() - if(!mut_overlay.Find(indicator_to_add)) //either we lack the visual indicator or we have the wrong one - remove_overlay(mutation.layer_used) - for(var/mutable_appearance/indicator_to_remove in mutation.visual_indicators[mutation.type]) - mut_overlay.Remove(indicator_to_remove) - mut_overlay |= indicator_to_add - overlays_standing[mutation.layer_used] = mut_overlay - apply_overlay(mutation.layer_used) + if(!LAZYFIND(species_allowed, new_species.id)) + dna.remove_mutation(src, src.sources) // shouldn't have this mutation at all + +/datum/mutation/proc/on_update_overlay(datum/source, list/overlay_list) + SIGNAL_HANDLER + + var/mutable_appearance/mutation_appearance = mutable_appearance(mutation_icon, mutation_icon_state, -layer_used) + owner.apply_height_offsets(mutation_appearance, offset_location) + + overlay_list += mutation_appearance /** * Called after on_aquiring, or when a chromosome is applied. diff --git a/code/datums/mutations/adaptation.dm b/code/datums/mutations/adaptation.dm index 4228a59376c..7bf6cb12b63 100644 --- a/code/datums/mutations/adaptation.dm +++ b/code/datums/mutations/adaptation.dm @@ -8,17 +8,11 @@ locked = TRUE // fake parent conflicts = list(/datum/mutation/adaptation) mutation_traits = list(TRAIT_WADDLING) - /// Icon used for the adaptation overlay - var/adapt_icon = "meow" + mutation_icon = 'icons/mob/effects/genetics.dmi' /datum/mutation/adaptation/New(datum/mutation/copymut) - ..() + . = ..() conflicts = typesof(/datum/mutation/adaptation) - if(!(type in visual_indicators)) - visual_indicators[type] = list(mutable_appearance('icons/mob/effects/genetics.dmi', adapt_icon, -MUTATIONS_LAYER)) - -/datum/mutation/adaptation/get_visual_indicator() - return visual_indicators[type][1] /datum/mutation/adaptation/cold name = "Cold Adaptation" @@ -26,7 +20,7 @@ text_gain_indication = span_notice("Your body feels refreshingly cold.") instability = POSITIVE_INSTABILITY_MODERATE mutation_traits = list(TRAIT_RESISTCOLD, TRAIT_NO_SLIP_ICE) - adapt_icon = "cold" + mutation_icon_state = "cold" locked = FALSE /datum/mutation/adaptation/heat @@ -35,7 +29,7 @@ text_gain_indication = span_notice("Your body feels invigoratingly warm.") instability = POSITIVE_INSTABILITY_MODERATE mutation_traits = list(TRAIT_RESISTHEAT, TRAIT_ASHSTORM_IMMUNE) - adapt_icon = "fire" + mutation_icon_state = "fire" locked = FALSE /datum/mutation/adaptation/thermal @@ -45,7 +39,7 @@ text_gain_indication = span_notice("Your body feels pleasantly room temperature.") instability = POSITIVE_INSTABILITY_MAJOR mutation_traits = list(TRAIT_RESISTHEAT, TRAIT_RESISTCOLD) - adapt_icon = "thermal" + mutation_icon_state = "thermal" locked = TRUE // recipe /datum/mutation/adaptation/pressure @@ -53,6 +47,6 @@ desc = "A strange mutation that renders the host immune to damage from both low and high pressure environments. Does not protect from temperature, including the cold of space." text_gain_indication = span_notice("Your body feels impressively pressurized.") instability = POSITIVE_INSTABILITY_MODERATE - adapt_icon = "pressure" + mutation_icon_state = "pressure" mutation_traits = list(TRAIT_RESISTLOWPRESSURE, TRAIT_RESISTHIGHPRESSURE) locked = FALSE diff --git a/code/datums/mutations/antenna.dm b/code/datums/mutations/antenna.dm index f38a03f933a..ce494bb3753 100644 --- a/code/datums/mutations/antenna.dm +++ b/code/datums/mutations/antenna.dm @@ -6,6 +6,8 @@ text_lose_indication = span_notice("Your antenna shrinks back down.") instability = POSITIVE_INSTABILITY_MINOR difficulty = 8 + mutation_icon_state = "antenna" + layer_used = FRONT_MUTATIONS_LAYER var/datum/weakref/radio_weakref /obj/item/implant/radio/antenna @@ -33,14 +35,6 @@ if(linked_radio) QDEL_NULL(linked_radio) -/datum/mutation/antenna/New(datum/mutation/copymut) - ..() - if(!(type in visual_indicators)) - visual_indicators[type] = list(mutable_appearance('icons/mob/effects/genetics.dmi', "antenna", -FRONT_MUTATIONS_LAYER+1))//-MUTATIONS_LAYER+1 - -/datum/mutation/antenna/get_visual_indicator() - return visual_indicators[type][1] - /datum/mutation/mindreader name = "Mind Reader" desc = "The affected person can look into the recent memories of others." @@ -51,6 +45,8 @@ instability = POSITIVE_INSTABILITY_MINOR difficulty = 8 locked = TRUE + mutation_icon_state = "antenna" + layer_used = FRONT_MUTATIONS_LAYER /datum/action/cooldown/spell/pointed/mindread name = "Mindread" @@ -174,11 +170,3 @@ log_info += "Current thought: \"[read_text]\"" log_combat(examiner, examined, "mind read (triggered on examine)", null, "info: [english_list(log_info, and_text = ", ")]") - -/datum/mutation/mindreader/New(datum/mutation/copymut) - ..() - if(!(type in visual_indicators)) - visual_indicators[type] = list(mutable_appearance('icons/mob/effects/genetics.dmi', "antenna", -FRONT_MUTATIONS_LAYER+1)) - -/datum/mutation/mindreader/get_visual_indicator() - return visual_indicators[type][1] diff --git a/code/datums/mutations/radioactive.dm b/code/datums/mutations/radioactive.dm index d31b3393fce..9ec68dddfb2 100644 --- a/code/datums/mutations/radioactive.dm +++ b/code/datums/mutations/radioactive.dm @@ -6,17 +6,10 @@ instability = NEGATIVE_STABILITY_MAJOR difficulty = 8 power_coeff = 1 + mutation_icon_state = "radiation" /// Weakref to our radiation emitter component var/datum/weakref/radioactivity_source_ref -/datum/mutation/radioactive/New(datum/mutation/copymut) - . = ..() - if(!(type in visual_indicators)) - visual_indicators[type] = list(mutable_appearance('icons/mob/effects/genetics.dmi', "radiation", -MUTATIONS_LAYER)) - -/datum/mutation/radioactive/get_visual_indicator() - return visual_indicators[type][1] - /datum/mutation/radioactive/on_acquiring(mob/living/carbon/human/acquirer) . = ..() if(!.) diff --git a/code/datums/mutations/reach.dm b/code/datums/mutations/reach.dm index 24f2d5d37e8..2c93ec8e92c 100644 --- a/code/datums/mutations/reach.dm +++ b/code/datums/mutations/reach.dm @@ -7,14 +7,10 @@ text_gain_indication = span_notice("You feel smarter!") limb_req = BODY_ZONE_HEAD instability = POSITIVE_INSTABILITY_MAJOR + mutation_icon_state = "telekinesishead" ///Typecache of atoms that TK shouldn't interact with var/static/list/blacklisted_atoms = typecacheof(list(/atom/movable/screen)) -/datum/mutation/telekinesis/New(datum/mutation/copymut) - ..() - if(!(type in visual_indicators)) - visual_indicators[type] = list(mutable_appearance('icons/mob/effects/genetics.dmi', "telekinesishead", -MUTATIONS_LAYER)) - /datum/mutation/telekinesis/on_acquiring(mob/living/carbon/human/homan) . = ..() if(!.) @@ -27,9 +23,6 @@ return UnregisterSignal(homan, COMSIG_MOB_ATTACK_RANGED) -/datum/mutation/telekinesis/get_visual_indicator() - return visual_indicators[type][1] - ///Triggers on COMSIG_MOB_ATTACK_RANGED. Usually handles stuff like picking up items at range. /datum/mutation/telekinesis/proc/on_ranged_attack(mob/source, atom/target) SIGNAL_HANDLER diff --git a/code/datums/mutations/sight.dm b/code/datums/mutations/sight.dm index 24449177a51..26f85ed0d2c 100644 --- a/code/datums/mutations/sight.dm +++ b/code/datums/mutations/sight.dm @@ -141,11 +141,7 @@ text_gain_indication = span_notice("You feel pressure building up behind your eyes.") layer_used = FRONT_MUTATIONS_LAYER limb_req = BODY_ZONE_HEAD - -/datum/mutation/laser_eyes/New(datum/mutation/copymut) - ..() - if(!(type in visual_indicators)) - visual_indicators[type] = list(mutable_appearance('icons/mob/effects/genetics.dmi', "lasereyes", -FRONT_MUTATIONS_LAYER)) + mutation_icon_state = "lasereyes" /datum/mutation/laser_eyes/on_acquiring(mob/living/carbon/human/H) . = ..() @@ -159,9 +155,6 @@ return UnregisterSignal(H, COMSIG_MOB_ATTACK_RANGED) -/datum/mutation/laser_eyes/get_visual_indicator() - return visual_indicators[type][1] - ///Triggers on COMSIG_MOB_ATTACK_RANGED. Does the projectile shooting. /datum/mutation/laser_eyes/proc/on_ranged_attack(mob/living/carbon/human/source, atom/target, modifiers) SIGNAL_HANDLER diff --git a/code/datums/proximity_monitor/fields/heretic_arena.dm b/code/datums/proximity_monitor/fields/heretic_arena.dm index 432a9dfbd7b..07383a38748 100644 --- a/code/datums/proximity_monitor/fields/heretic_arena.dm +++ b/code/datums/proximity_monitor/fields/heretic_arena.dm @@ -156,6 +156,11 @@ GLOBAL_LIST_EMPTY(heretic_arenas) owner.cut_overlay(crown_overlay) crown_overlay = mutable_appearance('icons/mob/effects/crown.dmi', "arena_victor", -HALO_LAYER) crown_overlay.pixel_z = 24 + if(ishuman(owner)) + var/mob/living/carbon/human/human_parent = owner + human_parent.apply_height_offsets(crown_overlay, UPPER_BODY) + var/obj/item/bodypart/head/human_head = human_parent.get_bodypart(BODY_ZONE_HEAD) + human_head?.worn_head_offset?.apply_offset(crown_overlay) owner.add_overlay(crown_overlay) owner.remove_traits(list(TRAIT_ELDRITCH_ARENA_PARTICIPANT, TRAIT_NO_TELEPORT), TRAIT_STATUS_EFFECT(id)) @@ -203,6 +208,11 @@ GLOBAL_LIST_EMPTY(heretic_arenas) owner.add_traits(list(TRAIT_ELDRITCH_ARENA_PARTICIPANT, TRAIT_NO_TELEPORT), TRAIT_STATUS_EFFECT(id)) crown_overlay = mutable_appearance('icons/mob/effects/crown.dmi', "arena_fighter", -HALO_LAYER) crown_overlay.pixel_z = 24 + if(ishuman(owner)) + var/mob/living/carbon/human/human_parent = owner + human_parent.apply_height_offsets(crown_overlay, UPPER_BODY) + var/obj/item/bodypart/head/human_head = human_parent.get_bodypart(BODY_ZONE_HEAD) + human_head?.worn_head_offset?.apply_offset(crown_overlay) owner.add_overlay(crown_overlay) return TRUE diff --git a/code/datums/status_effects/buffs/cult_halo.dm b/code/datums/status_effects/buffs/cult_halo.dm new file mode 100644 index 00000000000..bf7c1a92f8a --- /dev/null +++ b/code/datums/status_effects/buffs/cult_halo.dm @@ -0,0 +1,52 @@ +/// Adds the cult halo effect vfx to the mob (instantly/after a delay) +/datum/status_effect/cult_halo + id = "cult_halo" + alert_type = null + tick_interval = STATUS_EFFECT_NO_TICK + /// Cooldown for when the halo is actually visible + COOLDOWN_DECLARE(halo_start) + /// The actual halo applied to the mob + VAR_PRIVATE/mutable_appearance/halo_overlay + +/datum/status_effect/cult_halo/on_creation(mob/living/new_owner, initial_delay = 20 SECONDS) + COOLDOWN_START(src, halo_start, initial_delay) + return ..() + +/datum/status_effect/cult_halo/on_apply() + RegisterSignal(owner, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(add_halo)) + if(COOLDOWN_FINISHED(src, halo_start)) + refresh_halo() + else + addtimer(CALLBACK(src, PROC_REF(refresh_halo)), COOLDOWN_TIMELEFT(src, halo_start), TIMER_DELETE_ME) + return TRUE + +/datum/status_effect/cult_halo/on_remove() + UnregisterSignal(owner, COMSIG_ATOM_UPDATE_OVERLAYS) + owner.update_appearance(UPDATE_OVERLAYS) + REMOVE_TRAIT(owner, TRAIT_CULT_HALO, TRAIT_STATUS_EFFECT(id)) + halo_overlay = null + return TRUE + +/datum/status_effect/cult_halo/proc/refresh_halo() + COOLDOWN_RESET(src, halo_start) + ADD_TRAIT(owner, TRAIT_CULT_HALO, TRAIT_STATUS_EFFECT(id)) + owner.update_appearance(UPDATE_OVERLAYS) + new /obj/effect/temp_visual/cult/sparks(get_turf(owner), owner.dir) + +/datum/status_effect/cult_halo/proc/add_halo(datum/source, list/overlay_list) + SIGNAL_HANDLER + + if(!COOLDOWN_FINISHED(src, halo_start)) + return + + halo_overlay ||= mutable_appearance('icons/mob/effects/halo.dmi', "halo[rand(1, 6)]", -HALO_LAYER) + halo_overlay.pixel_z = 0 + halo_overlay.pixel_w = 0 + if (ishuman(owner)) + var/mob/living/carbon/human/human_parent = owner + human_parent.apply_height_offsets(halo_overlay, UPPER_BODY) + + var/obj/item/bodypart/head/human_head = human_parent.get_bodypart(BODY_ZONE_HEAD) + human_head?.worn_head_offset?.apply_offset(halo_overlay) + + overlay_list += halo_overlay diff --git a/code/game/objects/effects/decals/crayon.dm b/code/game/objects/effects/decals/crayon.dm index bbd451584d2..ada037b02be 100644 --- a/code/game/objects/effects/decals/crayon.dm +++ b/code/game/objects/effects/decals/crayon.dm @@ -68,7 +68,7 @@ if(ishuman(outlined_atom)) //humans are special, we want to exclude things like wounds so the outline isn't animated. var/mob/living/carbon/human/human_outline = outlined_atom - add_overlay(human_outline.get_overlays_copy(list(WOUND_LAYER, HALO_LAYER))) + add_overlay(human_outline.get_overlays_copy(list(WOUND_LAYER))) else icon = outlined_atom.icon icon_state = outlined_atom.icon_state diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index ee4b16dc10d..03315f2ad4d 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -225,7 +225,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) to_chat(race_changer, span_notice("Invalid color. Your color is not bright enough.")) race_changer.update_body(is_creating = TRUE) - race_changer.update_mutations_overlay() // no hulk lizard /// Hook for mirrors to do stuff on species change /obj/structure/mirror/proc/on_species_change(mob/living/carbon/human/race_changer, datum/species/newrace) @@ -261,7 +260,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) sexy.dna.update_ui_block(/datum/dna_block/identity/gender) sexy.update_body(is_creating = TRUE) // or else physique won't change properly - sexy.update_mutations_overlay() //(hulk male/female) sexy.update_clothing(ITEM_SLOT_ICLOTHING) // update gender shaped clothing /obj/structure/mirror/proc/change_eyes(mob/living/carbon/human/user) diff --git a/code/modules/antagonists/cult/datums/cult_team.dm b/code/modules/antagonists/cult/datums/cult_team.dm index 939938f621c..05d4e5bc3f4 100644 --- a/code/modules/antagonists/cult/datums/cult_team.dm +++ b/code/modules/antagonists/cult/datums/cult_team.dm @@ -66,7 +66,7 @@ if(mind.current) SEND_SOUND(mind.current, 'sound/music/antag/bloodcult/bloodcult_halos.ogg') to_chat(mind.current, span_cult_large(span_warning("Your cult is ascendant and the red harvest approaches - you cannot hide your true nature for much longer!!"))) - mind.current.AddElement(/datum/element/cult_halo) + mind.current.apply_status_effect(/datum/status_effect/cult_halo) cult_ascendent = TRUE log_game("The blood cult has ascended with [cultplayers] players.") #endif diff --git a/code/modules/antagonists/cult/datums/cultist.dm b/code/modules/antagonists/cult/datums/cultist.dm index de1d5ad2978..cb853d1b358 100644 --- a/code/modules/antagonists/cult/datums/cultist.dm +++ b/code/modules/antagonists/cult/datums/cultist.dm @@ -67,7 +67,7 @@ if(cult_team.cult_risen) current.AddElement(/datum/element/cult_eyes, initial_delay = 0 SECONDS) if(cult_team.cult_ascendent) - current.AddElement(/datum/element/cult_halo, initial_delay = 0 SECONDS) + current.apply_status_effect(/datum/status_effect/cult_halo, 0 SECONDS) ADD_TRAIT(current, TRAIT_HEALS_FROM_CULT_PYLONS, CULT_TRAIT) add_team_hud(current) @@ -85,8 +85,7 @@ if (HAS_TRAIT(current, TRAIT_UNNATURAL_RED_GLOWY_EYES)) current.RemoveElement(/datum/element/cult_eyes) - if (HAS_TRAIT(current, TRAIT_CULT_HALO)) - current.RemoveElement(/datum/element/cult_halo) + current.remove_status_effect(/datum/status_effect/cult_halo) REMOVE_TRAIT(current, TRAIT_HEALS_FROM_CULT_PYLONS, CULT_TRAIT) diff --git a/code/modules/deathmatch/deathmatch_loadouts.dm b/code/modules/deathmatch/deathmatch_loadouts.dm index 92ac46acfa6..cec6a4b16e1 100644 --- a/code/modules/deathmatch/deathmatch_loadouts.dm +++ b/code/modules/deathmatch/deathmatch_loadouts.dm @@ -925,7 +925,7 @@ /datum/outfit/deathmatch_loadout/cultish/pre_equip(mob/living/carbon/human/user, visuals_only) . = ..() ADD_TRAIT(user, TRAIT_ACT_AS_CULTIST, REF(src)) - user.AddElement(/datum/element/cult_halo, initial_delay = 0 SECONDS) + user.apply_status_effect(/datum/status_effect/cult_halo, 0 SECONDS) user.AddElement(/datum/element/cult_eyes, initial_delay = 0 SECONDS) // Cultist Invoker, has all the balanced cult gear diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm index e15594a8eec..0b1830af621 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -64,7 +64,6 @@ There are several things that need to be remembered: update_pockets() update_worn_neck() update_transform() - update_mutations_overlay() update_damage_overlays() // These are done via parent call update_body(), keeping them here for clarity // update_hair() diff --git a/tgstation.dme b/tgstation.dme index fb417168f4b..584b5c9bde6 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1588,7 +1588,6 @@ #include "code\datums\elements\cuffable_item.dm" #include "code\datums\elements\cuffsnapping.dm" #include "code\datums\elements\cult_eyes.dm" -#include "code\datums\elements\cult_halo.dm" #include "code\datums\elements\curse_announcement.dm" #include "code\datums\elements\cursed.dm" #include "code\datums\elements\damage_threshold.dm" @@ -2088,6 +2087,7 @@ #include "code\datums\status_effects\song_effects.dm" #include "code\datums\status_effects\stacking_effect.dm" #include "code\datums\status_effects\wound_effects.dm" +#include "code\datums\status_effects\buffs\cult_halo.dm" #include "code\datums\status_effects\buffs\stop_drop_roll.dm" #include "code\datums\status_effects\buffs\stun_absorption.dm" #include "code\datums\status_effects\buffs\xray.dm"