Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ports displacement filters for height/dwarfism #1916

Closed
wants to merge 19 commits into from
Closed
Next Next commit
Ports tg pr #72344
Height filters
  • Loading branch information
thgvr committed Apr 20, 2023
commit 11a5549cd7a49a9d646c330659b24b3388326dca
34 changes: 0 additions & 34 deletions code/__DEFINES/misc.dm
Original file line number Diff line number Diff line change
Expand Up @@ -12,40 +12,6 @@
/// Inverse direction, taking into account UP|DOWN if necessary.
#define REVERSE_DIR(dir) (((dir & 85) << 1) | ((dir & 170) >> 1))

//Human Overlays Indexes/////////
#define MUTATIONS_LAYER 31 //mutations. Tk headglows, cold resistance glow, etc
#define HANDS_UNDER_BODY_LAYER 30 //Held items that render underneath the user due to perspective
#define BODY_BEHIND_LAYER 29 //certain mutantrace features (tail when looking south) that must appear behind the body parts
#define BODYPARTS_LOW_LAYER 28 //Layer for bodyparts that should appear behind every other bodypart - Mostly, legs when facing WEST or EAST
#define BODYPARTS_LAYER 27 //Initially "AUGMENTS", this was repurposed to be a catch-all bodyparts flag
#define BODY_ADJ_LAYER 26 //certain mutantrace features (snout, body markings) that must appear above the body parts
#define BODY_LAYER 25 //underwear, undershirts, socks, eyes, lips(makeup)
#define FRONT_MUTATIONS_LAYER 24 //mutations that should appear above body, body_adj and bodyparts layer (e.g. laser eyes)
#define DAMAGE_LAYER 23 //damage indicators (cuts and burns)
#define UNIFORM_LAYER 22
#define ID_LAYER 21 //lmao at the idiot who put both ids and hands on the same layer
#define BODYPARTS_HIGH_LAYER 20
#define GLOVES_LAYER 19
#define SHOES_LAYER 18
#define EARS_LAYER 17
#define SPLINT_LAYER 16 //WS Edit - breakable bones
#define SUIT_LAYER 15
#define GLASSES_LAYER 14
#define BELT_LAYER 13 //Possible make this an overlay of somethign required to wear a belt?
#define SUIT_STORE_LAYER 12
#define NECK_LAYER 11
#define BACK_LAYER 10
#define HAIR_LAYER 9 //TODO: make part of head layer?
#define FACEMASK_LAYER 8
#define HEAD_LAYER 7
#define HANDCUFF_LAYER 6
#define LEGCUFF_LAYER 5
#define HANDS_LAYER 4
#define BODY_FRONT_LAYER 3
#define HALO_LAYER 2 //blood cult ascended halo, because there's currently no better solution for adding/removing
#define FIRE_LAYER 1 //If you're on fire
#define TOTAL_LAYERS 31 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_;

//Human 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"
Expand Down
103 changes: 103 additions & 0 deletions code/__DEFINES/mobs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -434,3 +434,106 @@
#define THROW_MODE_DISABLED 0
#define THROW_MODE_TOGGLE 1
#define THROW_MODE_HOLD 2

// Height defines
// - They are numbers so you can compare height values (x height < y height)
// - They do not start at 0 for futureproofing
// - They skip numbers for futureproofing as well
// Otherwise they are completely arbitrary
#define HUMAN_HEIGHT_DWARF 2
#define HUMAN_HEIGHT_SHORTEST 4
#define HUMAN_HEIGHT_SHORT 6
#define HUMAN_HEIGHT_MEDIUM 8
#define HUMAN_HEIGHT_TALL 10
#define HUMAN_HEIGHT_TALLEST 12

/// Assoc list of all heights, cast to strings, to """"tuples"""""
/// The first """tuple""" index is the upper body offset
/// The second """tuple""" index is the lower body offset
GLOBAL_LIST_INIT(human_heights_to_offsets, list(
"[HUMAN_HEIGHT_DWARF]" = list(-5, -4),
"[HUMAN_HEIGHT_SHORTEST]" = list(-2, -1),
"[HUMAN_HEIGHT_SHORT]" = list(-1, -1),
"[HUMAN_HEIGHT_MEDIUM]" = list(0, 0),
"[HUMAN_HEIGHT_TALL]" = list(1, 1),
"[HUMAN_HEIGHT_TALLEST]" = list(2, 2),
))

//Human Overlays Indexes/////////
#define TOTAL_LAYERS 34 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_;
#define MUTATIONS_LAYER 33 //mutations. Tk headglows, cold resistance glow, etc
#define HANDS_UNDER_BODY_LAYER 32 //Held items that render underneath the user due to perspective
#define BODY_BEHIND_LAYER 31 //certain mutantrace features (tail when looking south) that must appear behind the body parts
#define BODYPARTS_LOW_LAYER 30 //Layer for bodyparts that should appear behind every other bodypart - Mostly, legs when facing WEST or EAST
#define BODYPARTS_LAYER 29 //Initially "AUGMENTS", this was repurposed to be a catch-all bodyparts flag
#define BODY_ADJ_LAYER 28 //certain mutantrace features (snout, body markings) that must appear above the body parts
#define BODY_LAYER 27 //underwear, undershirts, socks, eyes, lips(makeup)
#define FRONT_MUTATIONS_LAYER 26 //mutations that should appear above body, body_adj and bodyparts layer (e.g. laser eyes)
#define DAMAGE_LAYER 25 //damage indicators (cuts and burns)
#define UNIFORM_LAYER 24
#define ID_LAYER 23 //lmao at the idiot who put both ids and hands on the same layer
#define BODYPARTS_HIGH_LAYER 22
#define GLOVES_LAYER 21
#define SHOES_LAYER 20
#define EARS_LAYER 19
#define SPLINT_LAYER 18 //WS Edit - breakable bones
#define SUIT_LAYER 17
#define GLASSES_LAYER 16
#define BELT_LAYER 15 //Possible make this an overlay of somethign required to wear a belt?
#define SUIT_STORE_LAYER 14
#define NECK_LAYER 13
#define BACK_LAYER 12
#define HAIR_LAYER 11 //TODO: make part of head layer?
#define FACEMASK_LAYER 10
#define HEAD_LAYER 9
#define HANDCUFF_LAYER 8
#define LEGCUFF_LAYER 7
#define HANDS_LAYER 6
#define BODY_FRONT_LAYER 5
#define ABOVE_BODY_FRONT_HEAD_LAYER 4
#define ABOVE_BODY_FRONT_GLASSES_LAYER 3
#define HALO_LAYER 2 //blood cult ascended halo, because there's currently no better solution for adding/removing
#define FIRE_LAYER 1 //If you're on fire

#define UPPER_BODY "upper body"
#define LOWER_BODY "lower body"
#define NO_MODIFY "do not modify"

/// Used for human height overlay adjustments
/// Certain standing overlay layers shouldn't have a filter applied and should instead just offset by a pixel y
/// This list contains all the layers that must offset, with its value being whether it's a part of the upper half of the body (TRUE) or not (FALSE)
GLOBAL_LIST_INIT(layers_to_offset, list(
// Weapons commonly cross the middle of the sprite so they get cut in half by the filter
"[HANDS_LAYER]" = LOWER_BODY,
// Very tall hats will get cut off by filter
"[HEAD_LAYER]" = UPPER_BODY,
// Hair will get cut off by filter
"[HAIR_LAYER]" = UPPER_BODY,
// Long belts (sabre sheathe) will get cut off by filter
"[BELT_LAYER]" = LOWER_BODY,
// Everything below looks fine with or without a filter, so we can skip it and just offset
// (In practice they'd be fine if they got a filter but we can optimize a bit by not.)
"[GLASSES_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,
// 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_ADJ_LAYER (external organs like wings)
// BODY_BEHIND_LAYER (external organs like wings)
// BODY_FRONT_LAYER (external organs like wings)
// DAMAGE_LAYER (full body)
// FIRE_LAYER (full body)
// UNIFORM_LAYER (full body)
// WOUND_LAYER (full body)
))
2 changes: 2 additions & 0 deletions code/__DEFINES/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -413,3 +413,5 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define BRAIN_UNAIDED "brain-unaided"
/// Trait granted by [/obj/item/clothing/head/helmet/space/hardsuit/berserker]
#define BERSERK_TRAIT "berserk_trait"
/// The person with this trait always appears as 'unknown'.
#define TRAIT_UNKNOWN "unknown"
105 changes: 105 additions & 0 deletions code/datums/datum.dm
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
/// A weak reference to another datum
var/datum/weakref/weak_reference

/// List for handling persistent filters.
var/list/filter_data

#ifdef TESTING
var/running_find_references
var/last_find_references = 0
Expand Down Expand Up @@ -217,3 +220,105 @@
qdel(D)
else
return returned

/** Add a filter to the datum.
* This is on datum level, despite being most commonly / primarily used on atoms, so that filters can be applied to images / mutable appearances.
* Can also be used to assert a filter's existence. I.E. update a filter regardless if it exists or not.
*
* Arguments:
* * name - Filter name
* * priority - Priority used when sorting the filter.
* * params - Parameters of the filter.
*/
/datum/proc/add_filter(name, priority, list/params)
LAZYINITLIST(filter_data)
var/list/copied_parameters = params.Copy()
copied_parameters["priority"] = priority
filter_data[name] = copied_parameters
update_filters()

/// Reapplies all the filters.
/datum/proc/update_filters()
ASSERT(isatom(src) || istype(src, /image))
var/atom/atom_cast = src // filters only work with images or atoms.
atom_cast.filters = null
filter_data = sortTim(filter_data, GLOBAL_PROC_REF(cmp_filter_data_priority), TRUE)
for(var/filter_raw in filter_data)
MarkSuckerberg marked this conversation as resolved.
Show resolved Hide resolved
var/list/data = filter_data[filter_raw]
var/list/arguments = data.Copy()
arguments -= "priority"
atom_cast.filters += filter(arglist(arguments))
UNSETEMPTY(filter_data)

/** Update a filter's parameter to the new one. If the filter doesnt exist we won't do anything.
*
* Arguments:
* * name - Filter name
* * new_params - New parameters of the filter
* * overwrite - TRUE means we replace the parameter list completely. FALSE means we only replace the things on new_params.
*/
/datum/proc/modify_filter(name, list/new_params, overwrite = FALSE)
var/filter = get_filter(name)
if(!filter)
return
if(overwrite)
filter_data[name] = new_params
else
for(var/thing in new_params)
filter_data[name][thing] = new_params[thing]
update_filters()

/** Update a filter's parameter and animate this change. If the filter doesnt exist we won't do anything.
* Basically a [datum/proc/modify_filter] call but with animations. Unmodified filter parameters are kept.
*
* Arguments:
* * name - Filter name
* * new_params - New parameters of the filter
* * time - time arg of the BYOND animate() proc.
* * easing - easing arg of the BYOND animate() proc.
* * loop - loop arg of the BYOND animate() proc.
*/
/datum/proc/transition_filter(name, list/new_params, time, easing, loop)
var/filter = get_filter(name)
if(!filter)
return
animate(filter, new_params, time = time, easing = easing, loop = loop)
modify_filter(name, new_params)

/// Updates the priority of the passed filter key
/datum/proc/change_filter_priority(name, new_priority)
if(!filter_data || !filter_data[name])
return

filter_data[name]["priority"] = new_priority
update_filters()

/// Returns the filter associated with the passed key
/datum/proc/get_filter(name)
ASSERT(isatom(src) || istype(src, /image))
if(filter_data && filter_data[name])
var/atom/atom_cast = src // filters only work with images or atoms.
return atom_cast.filters[filter_data.Find(name)]

/// Returns the indice in filters of the given filter name.
/// If it is not found, returns null.
/datum/proc/get_filter_index(name)
return filter_data?.Find(name)

/// Removes the passed filter, or multiple filters, if supplied with a list.
/datum/proc/remove_filter(name_or_names)
if(!filter_data)
return

var/list/names = islist(name_or_names) ? name_or_names : list(name_or_names)

for(var/name in names)
if(filter_data[name])
filter_data -= name
update_filters()

/datum/proc/clear_filters()
ASSERT(isatom(src) || istype(src, /image))
var/atom/atom_cast = src // filters only work with images or atoms.
filter_data = null
atom_cast.filters = null
2 changes: 0 additions & 2 deletions code/datums/mutations/body.dm
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@
return
ADD_TRAIT(owner, TRAIT_DWARF, GENETIC_MUTATION)
ADD_TRAIT(owner, TRAIT_SCOOPABLE, GENETIC_MUTATION)
owner.transform = owner.transform.Scale(1, 0.8)
passtable_on(owner, GENETIC_MUTATION)
owner.visible_message("<span class='danger'>[owner] suddenly shrinks!</span>", "<span class='notice'>Everything around you seems to grow..</span>")

Expand All @@ -103,7 +102,6 @@
return
REMOVE_TRAIT(owner, TRAIT_DWARF, GENETIC_MUTATION)
REMOVE_TRAIT(owner, TRAIT_SCOOPABLE, GENETIC_MUTATION)
owner.transform = owner.transform.Scale(1, 1.25)
passtable_off(owner, GENETIC_MUTATION)
owner.visible_message("<span class='danger'>[owner] suddenly grows!</span>", "<span class='notice'>Everything around you seems to shrink..</span>")

Expand Down
2 changes: 0 additions & 2 deletions code/datums/mutations/dorfism.dm
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@
if(..())
return
ADD_TRAIT(owner, TRAIT_DWARF, GENETIC_MUTATION)
owner.transform = owner.transform.Scale(1, 0.8)
owner.visible_message("<span class='danger'>[owner] suddenly shrinks!</span>", "<span class='notice'>Everything around you seems to grow..</span>")

/datum/mutation/human/dorfism/on_losing(mob/living/carbon/human/owner)
if(..())
return
REMOVE_TRAIT(owner, TRAIT_DWARF, GENETIC_MUTATION)
owner.transform = owner.transform.Scale(1, 1.25)
owner.visible_message("<span class='danger'>[owner] suddenly grows!</span>", "<span class='notice'>Everything around you seems to shrink..</span>")
66 changes: 0 additions & 66 deletions code/game/atoms.dm
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@
///Last fingerprints to touch this atom
var/fingerprintslast

var/list/filter_data //For handling persistent filters

///Economy cost of item
var/custom_price
///Economy cost of item in premium vendor
Expand Down Expand Up @@ -1362,70 +1360,6 @@
var/reverse_message = "has been [what_done] by [ssource][postfix]"
target.log_message(reverse_message, LOG_ATTACK, color="orange", log_globally=FALSE)

/atom/proc/add_filter(name,priority,list/params)
LAZYINITLIST(filter_data)
var/list/p = params.Copy()
p["priority"] = priority
filter_data[name] = p
update_filters()

/atom/proc/update_filters()
filters = null
filter_data = sortTim(filter_data, /proc/cmp_filter_data_priority, TRUE)
for(var/f in filter_data)
var/list/data = filter_data[f]
var/list/arguments = data.Copy()
arguments -= "priority"
filters += filter(arglist(arguments))
UNSETEMPTY(filter_data)

/atom/proc/transition_filter(name, time, list/new_params, easing, loop)
var/filter = get_filter(name)
if(!filter)
return

var/list/old_filter_data = filter_data[name]

var/list/params = old_filter_data.Copy()
for(var/thing in new_params)
params[thing] = new_params[thing]

animate(filter, new_params, time = time, easing = easing, loop = loop)
for(var/param in params)
filter_data[name][param] = params[param]

/atom/proc/change_filter_priority(name, new_priority)
if(!filter_data || !filter_data[name])
return

filter_data[name]["priority"] = new_priority
update_filters()

/obj/item/update_filters()
. = ..()
for(var/X in actions)
var/datum/action/A = X
A.UpdateButtonIcon()

/atom/proc/get_filter(name)
if(filter_data && filter_data[name])
return filters[filter_data.Find(name)]

/atom/proc/remove_filter(name_or_names)
if(!filter_data)
return

var/list/names = islist(name_or_names) ? name_or_names : list(name_or_names)

for(var/name in names)
if(filter_data[name])
filter_data -= name
update_filters()

/atom/proc/clear_filters()
filter_data = null
filters = null

/atom/proc/intercept_zImpact(atom/movable/AM, levels = 1)
. |= SEND_SIGNAL(src, COMSIG_ATOM_INTERCEPT_Z_FALL, AM, levels)

Expand Down
1 change: 1 addition & 0 deletions code/game/objects/items.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1095,3 +1095,4 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
/obj/item/proc/on_offer_taken(mob/living/carbon/offerer, mob/living/carbon/taker)
if(SEND_SIGNAL(src, COMSIG_ITEM_OFFER_TAKEN, offerer, taker) & COMPONENT_OFFER_INTERRUPT)
return TRUE

Loading