Files
Letter NandGitHub d38246bb69 Init-&-co (#6833)
<!-- Write **BELOW** The Headers and **ABOVE** The comments else it may
not be viewable. -->
<!-- You can view Contributing.MD for a detailed description of the pull
request process. -->

## About The Pull Request
update init code, LateInitialize now complains if it doesnt have
anything in it
<!-- Describe The Pull Request. Please be sure every change is
documented or this can delay review and even discourage maintainers from
merging your PR! -->

## Why It's Good For The Game

<!-- Argue for the merits of your changes and how they benefit the game,
especially if they are controversial and/or far reaching. If you can't
actually explain WHY what you are doing will improve the game, then it
probably isn't good for the game in the first place. -->

## Changelog

<!-- If your PR modifies aspects of the game that can be concretely
observed by players or admins you should add a changelog. If your change
does NOT meet this description, remove this section. Be sure to properly
mark your PRs to prevent unnecessary GBP loss. You can read up on GBP
and it's effects on PRs in the tgstation guides for contributors. Please
note that maintainers freely reserve the right to remove and add tags
should they deem it appropriate. You can attempt to finagle the system
all you want, but it's best to shoot for clear communication right off
the bat. -->

🆑
code: update how init does things
code: update matrix helpers
/🆑

<!-- Both 🆑's are required for the changelog to work! You can put
your name to the right of the first 🆑 if you want to overwrite your
GitHub username as author ingame. -->
<!-- You can use multiple of the same prefix (they're only used for the
icon ingame) and delete the unneeded ones. Despite some of the tags,
changelogs should generally represent how a player might be affected by
the changes rather than a summary of the PR's contents. -->
2024-11-03 10:06:10 -08:00

286 lines
12 KiB
Plaintext

GLOBAL_LIST_EMPTY(limb_icon_cache)
/obj/item/organ/external/proc/compile_icon()
cut_overlays()
// This is a kludge, only one icon has more than one generation of children though.
for(var/obj/item/organ/external/organ in contents)
if(organ.children && organ.children.len)
for(var/obj/item/organ/external/child in organ.children)
add_overlay(child.mob_icon)
add_overlay(organ.mob_icon)
/obj/item/organ/external/proc/sync_colour_to_human(var/mob/living/carbon/human/human)
s_tone = null
s_col = null
h_col = null
if(robotic >= ORGAN_ROBOT)
var/datum/robolimb/franchise = GLOB.all_robolimbs[model]
if(!(franchise && franchise.skin_tone) && !(franchise && franchise.skin_color))
if(human.synth_color)
s_col = list(human.r_synth, human.g_synth, human.b_synth)
return
if(robotic && !(human.species.species_appearance_flags & HAS_BASE_SKIN_COLOR))
var/datum/robolimb/franchise = GLOB.all_robolimbs[model]
if(!(franchise && franchise.skin_tone))
return
if(species && human.species && species.name != human.species.name)
return
if(!isnull(human.s_tone) && (human.species.species_appearance_flags & HAS_SKIN_TONE))
s_tone = human.s_tone
if(human.species.species_appearance_flags & HAS_SKIN_COLOR)
s_col = list(human.r_skin, human.g_skin, human.b_skin)
h_col = list(human.r_hair, human.g_hair, human.b_hair)
/obj/item/organ/external/proc/sync_colour_to_dna()
s_tone = null
s_col = null
h_col = null
if(robotic >= ORGAN_ROBOT)
var/datum/robolimb/franchise = GLOB.all_robolimbs[model]
if(!(franchise && franchise.skin_tone) && !(franchise && franchise.skin_color))
return
if(!isnull(dna.GetUIValue(DNA_UI_SKIN_TONE)) && (species.species_appearance_flags & HAS_SKIN_TONE))
s_tone = dna.GetUIValue(DNA_UI_SKIN_TONE)
if(species.species_appearance_flags & HAS_SKIN_COLOR)
s_col = list(dna.GetUIValue(DNA_UI_SKIN_R), dna.GetUIValue(DNA_UI_SKIN_G), dna.GetUIValue(DNA_UI_SKIN_B))
h_col = list(dna.GetUIValue(DNA_UI_HAIR_R),dna.GetUIValue(DNA_UI_HAIR_G),dna.GetUIValue(DNA_UI_HAIR_B))
/obj/item/organ/external/head/sync_colour_to_human(var/mob/living/carbon/human/human)
..()
var/obj/item/organ/internal/eyes/eyes = owner.internal_organs_by_name[O_EYES]
if(eyes) eyes.update_colour()
/obj/item/organ/external/head/get_icon()
..()
//The overlays are not drawn on the mob, they are used for if the head is removed and becomes an item
cut_overlays()
//Every 'addon' below requires information from species
if(!iscarbon(owner) || !owner.species)
return
///? Holds eye icon to render over markings later.
var/icon/eyecon
//Eye color/icon
var/should_have_eyes = owner.should_have_organ(O_EYES)
var/has_eye_color = owner.species.species_appearance_flags & HAS_EYE_COLOR
if((should_have_eyes || has_eye_color) && eye_icon)
var/obj/item/organ/internal/eyes/eyes = owner.internal_organs_by_name[O_EYES]
var/icon/eyes_icon = new/icon(eye_icon_location, eye_icon)
//Should have eyes
if(should_have_eyes)
//And we have them
if(eyes)
if(has_eye_color)
eyes_icon.Blend(rgb(eyes.eye_colour[1], eyes.eye_colour[2], eyes.eye_colour[3]), ICON_ADD)
//They're gone!
else
eyes_icon.Blend(rgb(128,0,0), ICON_ADD)
//We have weird other-sorts of eyes (as we're not supposed to have eye organ, but we have HAS_EYE_COLOR species)
else
eyes_icon.Blend(rgb(owner.r_eyes, owner.g_eyes, owner.b_eyes), ICON_ADD)
//Allow rendering of eyes over markings.
if(eyes_over_markings)
eyecon = eyes_icon
else
add_overlay(eyes_icon)
mob_icon.Blend(eyes_icon, ICON_OVERLAY)
icon_cache_key += "[eye_icon]"
//Lip color/icon
if(owner.lip_style && (species && (species.species_appearance_flags & HAS_LIPS)))
var/icon/lip_icon = new/icon('icons/mob/human_face.dmi', "lips_[owner.lip_style]_s")
add_overlay(lip_icon)
mob_icon.Blend(lip_icon, ICON_OVERLAY)
//Head markings
for(var/M in markings)
var/datum/sprite_accessory/marking/mark_style = markings[M]["datum"]
var/icon/mark_s = new/icon("icon" = mark_style.icon, "icon_state" = "[mark_style.icon_state]-[organ_tag]")
mark_s.Blend(markings[M]["color"], mark_style.legacy_use_additive_color_matrix? ICON_ADD : ICON_MULTIPLY)
add_overlay(mark_s) //So when it's not on your body, it has icons
mob_icon.Blend(mark_s, ICON_OVERLAY) //So when it's on your body, it has icons
icon_cache_key += "[M][markings[M]["color"]]"
//Toggle to render eyes above markings.
if(eyes_over_markings && eyecon)
add_overlay(eyecon)
mob_icon.Blend(eyecon, ICON_OVERLAY)
icon_cache_key += "[eye_icon]"
add_overlay(owner.render_spriteacc_facehair())
add_overlay(owner.render_spriteacc_hair())
return mob_icon
/obj/item/organ/external/proc/get_icon(var/skeletal)
if(owner && ishuman(owner))
var/mob/living/carbon/human/H = owner
s_base = LAZYACCESS(species.base_skin_colours, H.s_base)
var/gender = "f"
if(owner && owner.gender == MALE)
gender = "m"
if(!force_icon_key)
icon_cache_key = "[icon_name]_[species ? species.get_bodytype_legacy() : SPECIES_HUMAN]"
else
icon_cache_key = "[icon_name]_[force_icon_key]"
if(force_icon)
mob_icon = new /icon(force_icon, "[icon_name][gendered_icon ? "_[gender]" : ""]")
else
if(!dna)
mob_icon = new /icon('icons/mob/species/human/body.dmi', "[icon_name][gendered_icon ? "_[gender]" : ""]")
else
if(!gendered_icon)
gender = null
if(skeletal)
mob_icon = new /icon('icons/mob/species/human/skeleton.dmi', "[icon_name][gender ? "_[gender]" : ""]")
else if (robotic >= ORGAN_ROBOT && species == !SPECIES_ADHERENT)
mob_icon = new /icon('icons/mob/cyberlimbs/robotic.dmi', "[icon_name][s_base ? "_[s_base]" : ""][gender ? "_[gender]" : ""]")
else
mob_icon = new /icon(species.get_icobase(owner, (status & ORGAN_MUTATED)), "[icon_name][s_base ? "_[s_base]" : ""][gender ? "_[gender]" : ""]")
apply_colouration(mob_icon)
//Body markings, actually does not include head this time. Done separately above.
if(!istype(src,/obj/item/organ/external/head))
for(var/M in markings)
var/datum/sprite_accessory/marking/mark_style = markings[M]["datum"]
var/icon/mark_s = new/icon("icon" = mark_style.icon, "icon_state" = "[mark_style.icon_state]-[organ_tag]")
mark_s.Blend(markings[M]["color"], mark_style.legacy_use_additive_color_matrix? ICON_ADD : ICON_MULTIPLY)
add_overlay(mark_s) //So when it's not on your body, it has icons
mob_icon.Blend(mark_s, ICON_OVERLAY) //So when it's on your body, it has icons
icon_cache_key += "[M][markings[M]["color"]]"
if(body_hair && islist(h_col) && h_col.len >= 3)
var/cache_key = "[body_hair]-[icon_name]-[h_col[1]][h_col[2]][h_col[3]]-[s_base]"
if(!GLOB.limb_icon_cache[cache_key])
var/icon/I = icon(species.get_icobase(owner), "[icon_name]_[body_hair]")
I.Blend(rgb(h_col[1],h_col[2],h_col[3]), ICON_MULTIPLY)
GLOB.limb_icon_cache[cache_key] = I
mob_icon.Blend(GLOB.limb_icon_cache[cache_key], ICON_OVERLAY)
if(model)
icon_cache_key += "_model_[model]"
apply_colouration(mob_icon)
if(owner && owner.synth_markings)
for(var/M in markings)
var/datum/sprite_accessory/marking/mark_style = markings[M]["datum"]
var/icon/mark_s = new/icon("icon" = mark_style.icon, "icon_state" = "[mark_style.icon_state]-[organ_tag]")
mark_s.Blend(markings[M]["color"], mark_style.legacy_use_additive_color_matrix? ICON_ADD : ICON_MULTIPLY)
add_overlay(mark_s) //So when it's not on your body, it has icons
mob_icon.Blend(mark_s, ICON_OVERLAY) //So when it's on your body, it has icons
icon_cache_key += "[M][markings[M]["color"]]"
if(body_hair && islist(h_col) && h_col.len >= 3)
var/cache_key = "[body_hair]-[icon_name]-[h_col[1]][h_col[2]][h_col[3]]"
if(!GLOB.limb_icon_cache[cache_key])
var/icon/I = icon(species.get_icobase(owner), "[icon_name]_[body_hair]")
I.Blend(rgb(h_col[1],h_col[2],h_col[3]), ICON_MULTIPLY)
GLOB.limb_icon_cache[cache_key] = I
mob_icon.Blend(GLOB.limb_icon_cache[cache_key], ICON_OVERLAY)
dir = EAST
icon = mob_icon
return mob_icon
/obj/item/organ/external/proc/apply_colouration(var/icon/applying)
if(transparent)
applying.MapColors("#4D4D4D","#969696","#1C1C1C", "#000000")
if(species && species.get_bodytype_legacy(owner) != SPECIES_HUMAN)
applying.SetIntensity(1) // Unathi, Taj and Skrell have -very- dark base icons.
else
applying.SetIntensity(1) // Makes Prometheans not look like shit with mob coloring.
else if(status & ORGAN_DEAD)
icon_cache_key += "_dead"
applying.ColorTone(rgb(10,50,0))
applying.SetIntensity(0.7)
if(!isnull(s_tone))
if(s_tone >= 0)
applying.Blend(rgb(s_tone, s_tone, s_tone), ICON_ADD)
else
applying.Blend(rgb(-s_tone, -s_tone, -s_tone), ICON_SUBTRACT)
icon_cache_key += "_tone_[s_tone]"
else if(s_col && s_col.len >= 3)
// Support for species.color_mult
if(species.color_force_greyscale)
applying.MapColors(arglist(COLOR_MATRIX_GRAYSCALE))
icon_cache_key += "_ags"
if(species && species.color_mult)
applying.Blend(rgb(s_col[1], s_col[2], s_col[3]), ICON_MULTIPLY)
icon_cache_key += "_color_[s_col[1]]_[s_col[2]]_[s_col[3]]_[ICON_MULTIPLY]"
else
applying.Blend(rgb(s_col[1], s_col[2], s_col[3]), ICON_ADD)
icon_cache_key += "_color_[s_col[1]]_[s_col[2]]_[s_col[3]]_[ICON_ADD]"
// Translucency.
if(transparent) applying += rgb(,,,180) // SO INTUITIVE TY BYOND
return applying
/obj/item/organ/external/var/icon_cache_key
// new damage icon system
// adjusted to set damage_state to brute/burn code only (without r_name0 as before)
/obj/item/organ/external/update_icon()
var/n_is = damage_state_text()
if (n_is != damage_state)
damage_state = n_is
return TRUE
return FALSE
// Returns an image for use by the human health dolly HUD element.
// If the user has traumatic shock, it will be passed in as a minimum
// damage amount to represent the pain of the injuries involved.
// Global scope, used in code below.
var/list/flesh_hud_colours = list("#02BA08","#9ECF19","#DEDE10","#FFAA00","#FF0000","#AA0000","#660000")
var/list/robot_hud_colours = list("#CFCFCF","#AFAFAF","#8F8F8F","#6F6F6F","#4F4F4F","#2F2F2F","#000000")
/obj/item/organ/external/proc/get_damage_hud_image(var/min_dam_state)
// Generate the greyscale base icon and cache it for later.
// icon_cache_key is set by any get_icon() calls that are made.
// This looks convoluted, but it's this way to avoid icon proc calls.
if(!hud_damage_image)
var/cache_key = "dambase-[icon_cache_key]"
if(!icon_cache_key || !GLOB.limb_icon_cache[cache_key])
GLOB.limb_icon_cache[cache_key] = icon(get_icon(), null, SOUTH)
var/image/temp = image(GLOB.limb_icon_cache[cache_key])
if((robotic < ORGAN_ROBOT) && species)
// Calculate the required colour matrix.
var/r = 0.30 * species.health_hud_intensity
var/g = 0.59 * species.health_hud_intensity
var/b = 0.11 * species.health_hud_intensity
temp.color = list(r, r, r, g, g, g, b, b, b)
else if(model)
var/datum/robolimb/R = GLOB.all_robolimbs[model]
if(istype(R))
var/r = 0.30 * R.health_hud_intensity
var/g = 0.59 * R.health_hud_intensity
var/b = 0.11 * R.health_hud_intensity
temp.color = list(r, r, r, g, g, g, b, b, b)
hud_damage_image = image(null)
hud_damage_image.add_overlay(temp)
// Calculate the required color index.
var/dam_state = min(1,((brute_dam+burn_dam)/max_damage))
// Apply traumatic shock min damage state.
if(!isnull(min_dam_state) && dam_state < min_dam_state)
dam_state = min_dam_state
// Apply colour and return product.
var/list/hud_colours = (robotic < ORGAN_ROBOT) ? flesh_hud_colours : robot_hud_colours
hud_damage_image.color = hud_colours[max(1,min(CEILING(dam_state*hud_colours.len, 1),hud_colours.len))]
return hud_damage_image