Radiation additions & Component (#18642)

* It begins

* Better coding practices

* No mapwide radiation glow!

* Update radiation_effects.dm

* A bit more efficient

* Theeese too

* moar

* caps

* lint

* Stops self contamiantion

* Mregen

Fixes this bug with mRegen. Also gives bruteloss the 1% heal chance.

* MAR!

* TGUI panel

* Nuclear png

Attribution not required, but being listed for posterity:
From uxwing. Icon name is "Radiation Icon SVG Vector"

* colorful

* Update nuclear.scss

* Update damage_procs.dm

* Radiation Negative Trait

* Update radiation_effects.dm

* get rid of this bad documentation

Should only EVER be registerwithparent.
This commit is contained in:
Cameron Lennox
2025-10-26 22:21:17 -04:00
committed by GitHub
parent e87fb82f0e
commit 477cc076d8
26 changed files with 469 additions and 79 deletions
+11
View File
@@ -450,6 +450,11 @@
#define COMSIG_LIVING_CAN_TRACK "mob_cantrack"
#define COMPONENT_CANT_TRACK (1<<0)
///from base of /mob/living/proc/apply_effect(var/effect = 0,var/effecttype = STUN, var/blocked = 0, var/check_protection = 1, rad_protection)
#define COMSIG_LIVING_IRRADIATE_EFFECT "living_irradiate_effect"
///Return this if you want to block the effect.
#define COMPONENT_BLOCK_IRRADIATION (1<<0)
// /mob/living/carbon signals
///from base of mob/living/carbon/soundbang_act(): (list(intensity))
@@ -694,6 +699,12 @@
#define COMSIG_HUMAN_DNA_FINALIZED "human_dna_finished"
///from /proc/domutcheck(): ()
#define COMSIG_MOB_DNA_MUTATION "mob_dna_mutation"
///from /mob/living/proc/handle_radiation()
#define COMSIG_HANDLE_RADIATION "handle_radiation"
#define COMPONENT_BLOCK_LIVING_RADIATION (1<<0)
///from /mob/living/proc/handle_mutations()
#define COMSIG_HANDLE_MUTATIONS "handle_mutations"
#define COMPONENT_BLOCK_LIVING_MUTATIONS (1<<0)
// Organ specific signals
+3
View File
@@ -20,3 +20,6 @@
#define TECHNOMANCER_INSTABILITY_MIN_GLOW 10 // When above this number, the entity starts glowing, affecting others.
#define RADIATION_SPEED_COEFFICIENT 0.1
///Maximum amount of radiation an entity can have.
#define RADIATION_CAP 5000
+2
View File
@@ -4,11 +4,13 @@
// Please do note that there is absolutely no bearing on what traits are added to what subtype of `/datum`, this is just an easily referenceable list sorted by type.
// The only thing that truly matters about traits is the code that is built to handle the traits, and where that code is located. Nothing else.
#define WEAKENED_RADIATION_RESISTANCE "Weakened"
#define NORMAL_RADIATION_RESISTANCE "Normal"
#define RESISTANT_RADIATION_RESISTANCE "Resistant"
#define MAJOR_RESISTANT_RADIATION_RESISTANCE "Major Resistance"
#define IMMUNITY_RADIATION_RESISTANCE "Immunity"
GLOBAL_LIST_INIT(radiation_levels, list(
WEAKENED_RADIATION_RESISTANCE = list("safe" = 15, "danger_1" = 50, "danger_2" = 150, "danger_3" = 200, "danger_4" = 750),
NORMAL_RADIATION_RESISTANCE = list("safe" = 50, "danger_1" = 100, "danger_2" = 300, "danger_3" = 400, "danger_4" = 1500),
RESISTANT_RADIATION_RESISTANCE = list("safe" = 70, "danger_1" = 150, "danger_2" = 450, "danger_3" = 600, "danger_4" = 2250),
MAJOR_RESISTANT_RADIATION_RESISTANCE = list("safe" = 150, "danger_1" = 300, "danger_2" = 600, "danger_3" = 1000, "danger_4" = 3000),
@@ -17,6 +17,8 @@
//Reference to our owner (the person that possesses us)
//This can be anything that is our owner that we want to reference. Swap out with mob/living/carbon/human/owner as needed.
var/mob/living/owner //easy reference
//NOTE: Alternatively, you can do something like "var/mob/living/owner = parent" in procs where needed to avoid having a hard ref to our owner...
//It's just a matter of preference at that point.
//dupe_mode = COMPONENT_DUPE_HIGHLANDER //Default mode. See flags.dm
@@ -29,10 +31,17 @@
owner = parent
add_verb(owner,/mob/living/proc/example_proc) //We can add verbs to our owner.
RegisterSignal(owner, COMSIG_EXAMPLE_SIGNAL, PROC_REF(example_proc)) //To put this easily: Owner is the person we're attached to, COMSIG_EXAMPLE_SIGNAL is the signal we expect them to send out when they want us to use our 'example_proc'
/datum/component/template/RegisterWithParent()
//To put this easily: Owner is the person we're attached to, COMSIG_EXAMPLE_SIGNAL is the signal we expect them to send out when they want us to use our 'example_proc'
RegisterSignal(parent, COMSIG_EXAMPLE_SIGNAL, PROC_REF(example_proc))
//Register this to a signal that is sent out whenever you want this to be called. For example: We want this trait to happen every life() tick, so we register it to the COMSIG_LIVING_LIFE signal that is sent every time life() is called on a /mob.
RegisterSignal(owner, COMSIG_LIVING_LIFE, PROC_REF(process))
RegisterSignal(parent, COMSIG_LIVING_LIFE, PROC_REF(process))
/datum/component/template/UnregisterFromParent()
//IF we registered a signal, we need to unregister it. This can be a list or done separtely. It's suggested to do it as a list.
UnregisterSignal(parent, list(COMSIG_EXAMPLE_SIGNAL, COMSIG_LIVING_LIFE))
/datum/component/template/process()
if (QDELETED(parent))
@@ -40,8 +49,6 @@
energy = min(100, energy+1) //Add one energy per tick, up to 100
/datum/component/template/Destroy(force = FALSE)
UnregisterSignal(owner, COMSIG_LIVING_LIFE) //IF we registered a signal, we need to unregister it.
UnregisterSignal(owner, COMSIG_EXAMPLE_SIGNAL) //MAKE SURE TO UNREGISTER YOUR SIGNALS. SERIOUSLY. OR THE SERVER WILL DIE.
owner = null //MAKE SURE TO CLEAR YOUR REFS!
. = ..()
@@ -54,11 +61,26 @@
/datum/component/template/proc/example_proc()
if (stat == DEAD)
if(stat == DEAD)
return
if (energy <= 0) //Check a variable on the component.
if(energy <= 0) //Check a variable on the component.
to_chat(owner, span_danger("You currently have no energy!"))
else if (cooldown > world.time) //Check the cooldown variable on the component and compare it.
else if(cooldown > world.time) //Check the cooldown variable on the component and compare it.
var/time_to_wait = (cooldown - world.time) / (1 SECONDS) //Simple cooldown
to_chat(owner, span_warning("You're currently on cooldown! Wait for another [round(time_to_wait,0.1)] seconds!"))
return
else
cooldown = world.time + 5 SECONDS //Set the component on a 5 second cooldown.
to_chat(owner, span_warning("You successfully used the example proc!"))
//Variant of the example proc but under the presumption we don't have a ref to owner.
/datum/component/template/proc/example_proc2()
var/mob/living/owner = parent
if(owner.stat == DEAD)
return
if(energy <= 0) //Check a variable on the component.
to_chat(owner, span_danger("You currently have no energy!"))
else if(cooldown > world.time) //Check the cooldown variable on the component and compare it.
var/time_to_wait = (cooldown - world.time) / (1 SECONDS) //Simple cooldown
to_chat(owner, span_warning("You're currently on cooldown! Wait for another [round(time_to_wait,0.1)] seconds!"))
return
@@ -0,0 +1,221 @@
/* Component that handles species effects for mobs/species when they are afflicted with radiation.
* Allows for glowing, healing, contamination, and immunity.
*/
/datum/component/radiation_effects
///Below this value, no glow occurs.
var/radiation_glow_threshold = 50
///If we spread radiation or not.
var/contamination = FALSE
///Strength of our contamination, if we contaminate. Each 1 strength is 100% of the rads we're dissipating.
var/contamination_strength = 0.1
///What level our radiation has to be above to begin to contaminate our surroundings.
var/contamination_threshold = 600
///If we glow or not.
var/glows = TRUE
///What color we glow.
var/radiation_color = "#c3f314"
///Intensity modifier of our glow
var/intensity_mod = 1
///Range modifier of our glow
var/range_mod = 1
///How much we divide our radiation by to determine how far our glow is.
var/range_coefficient = 100
///How much we divide our radiation by to determine how intense our glow is.
var/intensity_coefficient = 150
///If we are immune to radiation damage or not.
var/radiation_immunity = FALSE
///If we heal from radiation or not
var/radiation_healing = FALSE
///If we dissipate radiation or keep it.
var/radiation_dissipation = TRUE
/datum/component/radiation_effects/Initialize(glows, radiation_glow_minor_threshold, contamination, contamination_strength, radiation_color, intensity_mod, range_mod, radiation_immunity, radiation_healing, radiation_dissipation)
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE
if(glows)
src.glows = glows
if(radiation_glow_threshold)
src.radiation_glow_threshold = radiation_glow_threshold
if(contamination)
src.contamination = contamination
if(contamination_strength)
src.contamination_strength = contamination_strength
if(radiation_color)
src.radiation_color = radiation_color
if(intensity_mod)
src.intensity_mod = intensity_mod
if(range_mod)
src.range_mod = range_mod
if(radiation_immunity)
src.radiation_immunity = radiation_immunity
if(radiation_healing)
src.radiation_healing = radiation_healing
if(radiation_dissipation)
src.radiation_dissipation = radiation_dissipation
add_verb(parent, /mob/living/proc/radiation_control_panel)
/datum/component/radiation_effects/RegisterWithParent()
RegisterSignal(parent, COMSIG_HANDLE_RADIATION, PROC_REF(process_component))
RegisterSignal(parent, COMSIG_LIVING_LIFE, PROC_REF(process_glow))
RegisterSignal(parent, COMSIG_LIVING_IRRADIATE_EFFECT, PROC_REF(handle_irradiate_effect))
/datum/component/radiation_effects/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_HANDLE_RADIATION, COMSIG_LIVING_LIFE, COMSIG_LIVING_IRRADIATE_EFFECT))
/datum/component/radiation_effects/proc/process_glow()
SIGNAL_HANDLER
var/mob/living/living_guy = parent
if(!glows)
if(living_guy.glow_override) //Toggled glow off while we were still actively glowing.
living_guy.glow_override = FALSE
living_guy.set_light(0)
return
if(living_guy.radiation < radiation_glow_threshold)
living_guy.glow_override = FALSE
living_guy.set_light(0)
return
if(glows)
var/light_range = CLAMP((living_guy.radiation/range_coefficient) * range_mod, 1, 7) //Min 1, max 7
var/light_power = CLAMP(living_guy.radiation/intensity_coefficient * intensity_mod, 1, 10)
living_guy.set_light(l_range = light_range, l_power = light_power, l_color = radiation_color, l_on = TRUE)
living_guy.glow_override = TRUE
///Handles the radiation removal, immunity, and healing effects.
/datum/component/radiation_effects/proc/process_component()
SIGNAL_HANDLER
var/mob/living/living_guy = parent
if(living_guy.radiation > RADIATION_CAP)
living_guy.radiation = CLAMP(living_guy.radiation,0,RADIATION_CAP)
living_guy.accumulated_rads = CLAMP(living_guy.accumulated_rads,0,RADIATION_CAP)
if(QDELETED(parent))
return
//Radiation calculation, done here since contamination uses it
var/rad_removal_mod = 1
var/rads = living_guy.radiation * 0.04
if(ishuman(living_guy))
var/mob/living/carbon/human/human_guy = parent
rad_removal_mod = human_guy.species.rad_removal_mod
//End of the calculation.
if(contamination && living_guy.radiation > contamination_threshold)
SSradiation.radiate(living_guy, rads * contamination_strength * rad_removal_mod)
if(radiation_immunity || radiation_healing)
//We have to remove radiation here since we're blocking radiation altogether.
var/rads_to_utilize = rads * rad_removal_mod
//If we heal from radiation, we will dissipate (use up) the amount we heal.
if(radiation_healing)
living_guy.radiation -= rads_to_utilize
living_guy.accumulated_rads -= rads_to_utilize
rads_to_utilize = CLAMP(rads_to_utilize, 1, 10) //Only heal up to 10 rads.
living_guy.adjust_nutrition(rads_to_utilize)
living_guy.adjustBruteLoss(-rads_to_utilize)
living_guy.adjustFireLoss(-rads_to_utilize)
living_guy.adjustOxyLoss(-rads_to_utilize)
living_guy.adjustToxLoss(-rads_to_utilize)
living_guy.updatehealth()
else if(radiation_dissipation)
living_guy.radiation -= rads_to_utilize
living_guy.accumulated_rads -= rads_to_utilize
return COMPONENT_BLOCK_LIVING_RADIATION
/datum/component/radiation_effects/proc/handle_irradiate_effect(var/mob/living/living_guy, var/effect, var/effecttype, var/blocked, var/check_protection, var/rad_protection)
SIGNAL_HANDLER
///If we're not contaminating, don't worry about this. Proceed like normal.
if(!contamination || (contamination && living_guy.radiation < contamination_threshold))
//to_chat(world, "Radiation like normal. Current rads = [living_guy.radiation]. Amount of rads being added = [effect].")
return
var/rad_removal_mod = 1
if(ishuman(living_guy))
var/mob/living/carbon/human/human_guy = parent
rad_removal_mod = human_guy.species.rad_removal_mod
var/radiation_offput = ((living_guy.radiation * 0.04) * contamination_strength * rad_removal_mod)
var/radiation_to_apply = (effect - radiation_offput)
if(radiation_to_apply > 0)
// to_chat(world, "Radiation blocker. Current rads = [living_guy.radiation]. Original = [effect] RTA = [radiation_to_apply] After protection = [radiation_to_apply * rad_protection]. Amount of rads we're offputting = [radiation_offput]")
//This stops MOST of the radiation we're offputting from hitting us.
//If we linger in one place for a prolonged period, the area around us will become irradiated and give us a small bit of radiation back. (only got ~1 rad per tick when we were offputting 60 rads for example)
//However, we'll lose our rads faster than we accumulate.
living_guy.radiation += max((radiation_to_apply * rad_protection), 0)
return COMPONENT_BLOCK_IRRADIATION
/datum/component/radiation_effects/promethean
radiation_immunity = TRUE
/datum/component/radiation_effects/shadekin
radiation_immunity = TRUE
glows = FALSE
///Heals from radiation. Does not glow.
/datum/component/radiation_effects/diona
glows = FALSE
radiation_healing = TRUE
///TGUI below here
//TGUI Weaver Panel
/datum/component/radiation_effects/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "RadiationConfig", "Radiation Config")
ui.open()
/mob/living/proc/radiation_control_panel()
set name = "Radiation Control Panel"
set desc = "Allows you to adjust the settings of various radioactive settings!"
set category = "Abilities.Radiation"
var/datum/component/radiation_effects/rad = get_radiation_component()
if(!rad)
to_chat(src, span_warning("You don't have the radiation component! This is a bug! Please report this to a maintainer."))
return FALSE
rad.tgui_interact(src)
/datum/component/radiation_effects/tgui_data(mob/user)
var/data = list(
"glowing" = glows,
"radiation_color" = radiation_color,
)
return data
/datum/component/radiation_effects/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return TRUE
switch(action)
if("toggle_color")
var/set_new_color = tgui_color_picker(ui.user, "Select a color you wish your radioactive glow to be!", "Color Selector", radiation_color)
if(!set_new_color)
return FALSE
radiation_color = set_new_color
return TRUE
if("toggle_glow")
glows = !glows
to_chat(parent, span_info("You are [glows ? "now" : "no longer"] glowing."))
return FALSE
/mob/living/proc/get_radiation_component()
var/datum/component/radiation_effects/rad = GetComponent(/datum/component/radiation_effects)
if(rad)
return rad
+4 -1
View File
@@ -17,7 +17,10 @@
//Status updates, death etc.
update_icons()
/mob/living/carbon/alien/handle_mutations_and_radiation()
/mob/living/carbon/alien/handle_radiation()
. = ..()
if(.)
return
// Currently both Dionaea and larvae like to eat radiation, so I'm defining the
// rad absorbtion here. This will need to be changed if other baby aliens are added.
+4 -1
View File
@@ -1,7 +1,10 @@
/mob/living/carbon/brain/handle_breathing()
return
/mob/living/carbon/brain/handle_mutations_and_radiation()
/mob/living/carbon/brain/handle_radiation()
. = ..()
if(.)
return
if (radiation)
if (radiation > 100)
radiation = 100
+37 -51
View File
@@ -206,6 +206,37 @@
to_chat(src, span_danger("Your legs won't respond properly, you fall down!"))
Weaken(10)
/mob/living/carbon/human/handle_mutations()
. = ..()
if(.)
return
if(inStasisNow())
return
if(getFireLoss())
if((COLD_RESISTANCE in mutations) || (prob(1)))
heal_organ_damage(0,1)
if(getBruteLoss()) //Fireloss gets this RNG change so may as well give bruteloss it as well.
if(prob(1))
heal_organ_damage(1,0)
if((mRegen in mutations))
var/heal = rand(0.2,1.3)
if(prob(50))
for(var/obj/item/organ/external/O in organs) //HAS to be organs and NOT bad_external_organs as a fully healed limb w/ internal damage will NOT be in bad_external_organs
for(var/datum/wound/W in O.wounds)
if(W.bleeding())
W.damage = max(W.damage - heal, 0)
if(W.damage <= 0)
O.wounds -= W
if(W.internal)
W.damage = max(W.damage - heal, 0)
if(W.damage <= 0)
O.wounds -= W
else
heal_organ_damage(heal,heal)
// RADIATION! Everyone's favorite thing in the world! So let's get some numbers down off the bat.
// 50 rads = 1Bq. This means 1 rad = 0.02Bq.
// However, unless I am a smoothbrained dumbo, absorbed rads are in Gy. Not Bq.
@@ -227,65 +258,20 @@
// Additionally, RADIATION_SPEED_COEFFICIENT = 0.1
/mob/living/carbon/human/handle_mutations_and_radiation() //Radiation rework! Now with 'accumulated_rads'
/mob/living/carbon/human/handle_radiation() //Radiation rework! Now with 'accumulated_rads'
. = ..()
if(.)
return
if(inStasisNow())
return
if(getFireLoss())
if((COLD_RESISTANCE in mutations) || (prob(1)))
heal_organ_damage(0,1)
if(stat != DEAD)
if((mRegen in mutations))
var/heal = rand(0.2,1.3)
if(prob(50))
for(var/obj/item/organ/external/O in bad_external_organs)
for(var/datum/wound/W in O.wounds)
if(W.bleeding())
W.damage = max(W.damage - heal, 0)
if(W.damage <= 0)
O.wounds -= W
if(W.internal)
W.damage = max(W.damage - heal, 0)
if(W.damage <= 0)
O.wounds -= W
else
heal_organ_damage(heal,heal)
radiation = CLAMP(radiation,0,5000) //Max of 100Gy. If you reach that...You're going to wish you were dead. You probably will be dead.
accumulated_rads = CLAMP(accumulated_rads,0,5000) //Max of 100Gy as well. You should never get higher than this. You will be dead before you can reach this.
radiation = CLAMP(radiation,0,RADIATION_CAP) //Max of 100Gy. If you reach that...You're going to wish you were dead. You probably will be dead.
accumulated_rads = CLAMP(accumulated_rads,0,RADIATION_CAP) //Max of 100Gy as well. You should never get higher than this. You will be dead before you can reach this.
var/obj/item/organ/internal/I = null //Used for further down below when an organ is picked.
if(!radiation)
if(species.appearance_flags & RADIATION_GLOWS)
glow_override = FALSE
set_light(0)
if(accumulated_rads)
accumulated_rads -= RADIATION_SPEED_COEFFICIENT //Accumulated rads slowly dissipate very slowly. Get to medical to get it treated!
else if(((life_tick % 5 == 0) && radiation) || (radiation > 600)) //Radiation is a slow, insidious killer. Unless you get a massive dose, then the onset is sudden!
if(species.appearance_flags & RADIATION_GLOWS)
glow_override = TRUE
set_light(max(1,min(5,radiation/15)), max(1,min(10,radiation/25)), species.get_flesh_colour(src))
// END DOGSHIT SNOWFLAKE
var/obj/item/organ/internal/diona/nutrients/rad_organ = locate() in internal_organs
if(rad_organ && !rad_organ.is_broken())
var/rads = radiation/25
radiation -= (rads * species.rad_removal_mod)
adjust_nutrition(rads * species.rad_removal_mod)
adjustBruteLoss(-(rads * species.rad_removal_mod))
adjustFireLoss(-(rads * species.rad_removal_mod))
adjustOxyLoss(-(rads * species.rad_removal_mod))
adjustToxLoss(-(rads * species.rad_removal_mod))
updatehealth()
return
var/obj/item/organ/internal/brain/slime/core = locate() in internal_organs
if(core)
return
var/obj/item/organ/internal/brain/shadekin/s_brain = locate() in internal_organs
if(s_brain)
return
if(reagents.has_reagent(REAGENT_ID_PRUSSIANBLUE)) //Prussian Blue temporarily stops radiation effects.
return
@@ -26,7 +26,7 @@
assisted_langs = list()
species_component = /datum/component/burninlight/shadow // Until a parent component like xenochimera have is needed, only handles burning in light.
species_component = list(/datum/component/burninlight/shadow) // Until a parent component like xenochimera have is needed, only handles burning in light.
/datum/species/shadow/handle_death(var/mob/living/carbon/human/H)
spawn(1)
@@ -100,7 +100,7 @@
BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right)
)
species_component = /datum/component/shadekin
species_component = list(/datum/component/shadekin, /datum/component/radiation_effects/shadekin)
component_requires_late_recalc = TRUE
/datum/species/shadekin/handle_death(var/mob/living/carbon/human/H)
@@ -246,7 +246,7 @@
var/list/env_traits = list()
var/pixel_offset_x = 0 // Used for offsetting 64x64 and up icons.
var/pixel_offset_y = 0 // Used for offsetting 64x64 and up icons.
var/rad_levels = NORMAL_RADIATION_RESISTANCE //For handle_mutations_and_radiation
var/rad_levels = NORMAL_RADIATION_RESISTANCE //For handle_radiation
var/rad_removal_mod = 1
var/ambulant_blood = FALSE // Force changeling blood effects
@@ -359,7 +359,7 @@
var/list/food_preference = list() //RS edit
var/food_preference_bonus = 0
var/datum/component/species_component = null // The component that this species uses. Example: Xenochimera use /datum/component/xenochimera
var/list/species_component = list() // The component that this species uses. Example: Xenochimera use /datum/component/xenochimera
var/component_requires_late_recalc = FALSE // If TRUE, the component will do special recalculation stuff at the end of update_icons_body()
// For Lleill and Hanner
@@ -804,8 +804,9 @@
..()
/datum/species/proc/apply_components(var/mob/living/carbon/human/H)
if(species_component)
H.LoadComponent(species_component)
if(LAZYLEN(species_component))
for(var/component in species_component)
H.LoadComponent(component)
/datum/species/proc/produceCopy(var/list/traits, var/mob/living/carbon/human/H, var/custom_base, var/reset_dna = TRUE) // Traitgenes reset_dna flag required, or genes get reset on resleeve
ASSERT(src)
@@ -35,6 +35,8 @@ var/datum/species/shapeshifter/promethean/prometheans
secondary_langs = list(LANGUAGE_PROMETHEAN, LANGUAGE_SOL_COMMON) // For some reason, having this as their species language does not allow it to be chosen.
assisted_langs = list(LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX) // Prometheans are weird, let's just assume they can use basically any language.
species_component = list(/datum/component/radiation_effects/promethean)
blood_name = "gelatinous ooze"
blood_reagents = REAGENT_ID_SLIMEJELLY
@@ -657,13 +657,14 @@
return 1
return 0
/mob/living/simple_mob/protean_blob/handle_mutations_and_radiation()
/mob/living/simple_mob/protean_blob/handle_radiation()
..()
if(!humanform)
to_chat(src, span_giant(span_boldwarning("You are currently a blob without a humanform and should be deleted shortly Please report what you were doing when this error occurred to the admins.")))
stack_trace("URGENT, SERVER-CRASHING ISSUE: A protean blob does not have a humanform! src = [src] ckey = [ckey]! The blob has been deleted.")
qdel(src)
return
humanform.handle_mutations_and_radiation()
humanform.handle_radiation()
/mob/living/simple_mob/protean_blob/update_icon()
..()
@@ -490,7 +490,7 @@
reagent_tag = IS_ZADDAT
species_component = /datum/component/burninlight // Until a parent component like xenochimera have is needed, only handles burning in light.
species_component = list(/datum/component/burninlight) // Until a parent component like xenochimera have is needed, only handles burning in light.
heat_discomfort_strings = list(
"Your joints itch.",
@@ -564,6 +564,8 @@
min_age = 18
max_age = 300
species_component = list(/datum/component/radiation_effects/diona)
economic_modifier = 10
blurb = "Commonly referred to (erroneously) as 'plant people', the Dionaea are a strange space-dwelling collective \
@@ -1548,7 +1550,7 @@
tail = "tail" //Spider tail.
icobase_tail = 1
species_component = /datum/component/weaver
species_component = list(/datum/component/weaver)
inherent_verbs = list(
/mob/living/carbon/human/proc/tie_hair)
@@ -1741,7 +1743,7 @@
reagent_tag = IS_CHIMERA
species_component = /datum/component/xenochimera
species_component = list(/datum/component/xenochimera)
/datum/species/xenochimera/handle_environment_special(var/mob/living/carbon/human/H)
//Cold/pressure effects when not regenerating
@@ -677,3 +677,9 @@
else if(istype(ex_organ, /obj/item/organ/external/chest))
ex_organ.encased = FALSE
/datum/trait/negative/rad_weakness
name = "Radiation Weakness"
desc = "You are approximately 50% more susceptible to radiation, and it dissipates slower from your body."
cost = -2
var_changes = list("radiation_mod" = 1.5, "rad_removal_mod" = 0.5, "rad_levels" = WEAKENED_RADIATION_RESISTANCE)
@@ -1795,3 +1795,17 @@
/datum/trait/neutral/strongimmunesystem/apply(datum/species/S, mob/living/carbon/human/H, trait_prefs)
..()
ADD_TRAIT(H, STRONG_IMMUNITY_TRAIT, ROUNDSTART_TRAIT)
/datum/trait/neutral/glowing_radiation
name = "Radioactive Glow"
desc = "You emit a glow when exposed to radiation! This does not prevent you from being harmed by radiation."
cost = 0
has_preferences = list("glow_color" = list(TRAIT_PREF_TYPE_COLOR, "Glow color", TRAIT_VAREDIT_TARGET_MOB, "#c3f314"))
added_component_path = /datum/component/radiation_effects
excludes = list(/datum/trait/positive/radioactive_heal)
/datum/trait/neutral/glowing_radiation/apply(var/datum/species/S,var/mob/living/carbon/human/H, var/list/trait_prefs)
..()
var/datum/component/radiation_effects/G = H.GetComponent(added_component_path)
if(trait_prefs)
G.radiation_color = trait_prefs["glow_color"]
@@ -542,3 +542,23 @@
can_take = ORGANICS
var_changes = list("virus_immune" = TRUE)
/datum/trait/positive/radioactive_heal
name = "Radioactive Heal"
desc = "You heal when exposed to radiation instead of becoming ill. You can also choose to emit a glow when irradiated."
cost = 6
is_genetrait = TRUE
hidden = FALSE
has_preferences = list("glow_color" = list(TRAIT_PREF_TYPE_COLOR, "Glow color", TRAIT_VAREDIT_TARGET_MOB, "#c3f314",),
"glow_enabled" = list(TRAIT_PREF_TYPE_BOOLEAN, "Glow enabled on spawn", TRAIT_VAREDIT_TARGET_MOB, FALSE))
added_component_path = /datum/component/radiation_effects
excludes = list(/datum/trait/neutral/glowing_radiation, /datum/trait/positive/rad_resistance, /datum/trait/positive/rad_resistance_extreme, /datum/trait/positive/rad_immune, /datum/trait/negative/rad_weakness)
/datum/trait/positive/radioactive_heal/apply(var/datum/species/S,var/mob/living/carbon/human/H, var/list/trait_prefs)
..()
var/datum/component/radiation_effects/G = H.GetComponent(added_component_path)
if(trait_prefs)
G.radiation_color = trait_prefs["glow_color"]
G.glows = trait_prefs["glow_enabled"]
G.radiation_healing = TRUE
+2 -5
View File
@@ -159,13 +159,10 @@
if(AGONY)
halloss += max((effect * blocked), 0) // Useful for objects that cause "subdual" damage. PAIN!
if(IRRADIATE)
/*
var/rad_protection = check_protection ? getarmor(null, "rad")/100 : 0
radiation += max((1-rad_protection)*effect/(blocked+1),0)//Rads auto check armor
*/
var/rad_protection = getarmor(null, "rad")
rad_protection = (100-rad_protection)/100
radiation += max((effect * rad_protection), 0)
if(!(SEND_SIGNAL(src, COMSIG_LIVING_IRRADIATE_EFFECT, effect, effecttype, blocked, check_protection, rad_protection) & COMPONENT_BLOCK_IRRADIATION))
radiation += max((effect * rad_protection), 0)
if(STUTTER)
if(status_flags & CANSTUN) // stun is usually associated with stutter
stuttering = max(stuttering,(effect * blocked))
+11 -3
View File
@@ -25,7 +25,8 @@
handle_breathing()
//Mutations and radiation
handle_mutations_and_radiation()
handle_mutations()
handle_radiation()
@@ -89,8 +90,15 @@
/mob/living/proc/handle_breathing()
return
/mob/living/proc/handle_mutations_and_radiation()
return
/mob/living/proc/handle_mutations()
SHOULD_CALL_PARENT(TRUE)
if(SEND_SIGNAL(src, COMSIG_HANDLE_MUTATIONS) & COMPONENT_BLOCK_LIVING_MUTATIONS)
return COMPONENT_BLOCK_LIVING_MUTATIONS
/mob/living/proc/handle_radiation()
SHOULD_CALL_PARENT(TRUE)
if(SEND_SIGNAL(src, COMSIG_HANDLE_RADIATION) & COMPONENT_BLOCK_LIVING_RADIATION)
return COMPONENT_BLOCK_LIVING_RADIATION
/mob/living/proc/handle_chemicals_in_body()
return
+2
View File
@@ -22,6 +22,8 @@
qdel(src) // Decayed to nothing
else
rad_power = new_power
if(rad_power > 1e15) // Arbitrary cap to prevent going to infinity
rad_power = 1e15
if(!flat)
range = min(round(sqrt(rad_power / CONFIG_GET(number/radiation_lower_limit))), 31) // R = rad_power / dist**2 - Solve for dist
return
@@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 122.88 122.88" style="enable-background:new 0 0 122.88 122.88" xml:space="preserve"><style type="text/css">.st0{fill-rule:evenodd;clip-rule:evenodd;}</style><g><path class="st0" d="M86.71,104.87c-16.58,8.49-33.27,8.72-50.08-0.02L54.62,74.2c4.09,2.43,8.89,2.45,14.39,0.01L86.71,104.87 L86.71,104.87z M61.44,0c16.97,0,32.33,6.88,43.44,18c11.12,11.12,18,26.48,18,43.44c0,16.97-6.88,32.33-18,43.44 c-11.12,11.12-26.48,18-43.44,18S29.11,116,18,104.88C6.88,93.77,0,78.41,0,61.44C0,44.47,6.88,29.11,18,18 C29.11,6.88,44.47,0,61.44,0L61.44,0z M101.53,21.35C91.27,11.09,77.1,4.74,61.44,4.74c-15.66,0-29.83,6.35-40.09,16.61 C11.09,31.61,4.74,45.78,4.74,61.44c0,15.66,6.35,29.83,16.61,40.09c10.26,10.26,24.43,16.61,40.09,16.61 c15.66,0,29.83-6.35,40.09-16.61c10.26-10.26,16.61-24.43,16.61-40.09C118.14,45.78,111.79,31.61,101.53,21.35L101.53,21.35z M86.45,17.73c15.64,10.11,24.19,24.45,25.02,43.38l-35.55-0.25c0.06-4.76-2.32-8.92-7.18-12.46L86.45,17.73L86.45,17.73z M61.5,52.41c5.33,0,9.65,4.32,9.65,9.65c0,5.33-4.32,9.65-9.65,9.65c-5.33,0-9.65-4.32-9.65-9.65 C51.85,56.73,56.17,52.41,61.5,52.41L61.5,52.41z M11.53,61.33c0.93-18.6,9.08-33.17,25.06-43.36l17.56,30.91 c-4.15,2.33-6.56,6.47-7.2,12.45H11.53L11.53,61.33z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+1
View File
@@ -9,6 +9,7 @@ import './styles/main.scss';
import './styles/themes/abductor.scss';
import './styles/themes/cardtable.scss';
import './styles/themes/spookyconsole.scss';
import './styles/themes/nuclear.scss';
import './styles/themes/hackerman.scss';
import './styles/themes/crtsoul.scss';
import './styles/themes/malfunction.scss';
@@ -0,0 +1,59 @@
import { useBackend } from 'tgui/backend';
import { Window } from 'tgui/layouts';
import {
Button,
ColorBox,
LabeledList,
Section,
Stack,
} from 'tgui-core/components';
type Data = {
radiation_color: string | null;
glowing: number;
};
export const RadiationConfig = (props) => {
const { act, data } = useBackend<Data>();
const {
radiation_color,
glowing,
} = data;
return (
<Window width={220} height={125} theme="nuclear">
<Window.Content>
<Stack vertical fill>
<Stack.Item>
<Section fill title="Cosmetic Settings">
<LabeledList>
<LabeledList.Item label="Radiation Color">
<Stack align="center">
<Stack.Item>
<Button
onClick={() => act('toggle_color')}
tooltip="Select a color you wish to glow when irradiated."
>
Set Color
</Button>
</Stack.Item>
<Stack.Item>
<ColorBox color={radiation_color || '#FFFFFF'} />
</Stack.Item>
</Stack>
</LabeledList.Item>
<LabeledList.Item label="Glow">
<Button.Checkbox
tooltip="Toggle if you glow when irradiated."
checked={glowing}
onClick={() => act('toggle_glow')}
/>
</LabeledList.Item>
</LabeledList>
</Section>
</Stack.Item>
</Stack>
</Window.Content>
</Window>
);
};
@@ -0,0 +1,23 @@
.theme-nuclear:root {
// Base
--color-base: hsl(71, 100%, 13%);
--color-primary: hsl(73, 95%, 30%);
--color-good: hsl(73, 95%, 46%);
--color-average: hsl(64, 99%, 34%);
--color-bad: hsl(74, 100%, 25%);
--base-gradient-spread: 12;
--secondary-lightness-adjustment: 9;
// Components
--button-background-selected: var(--color-good);
--button-background-caution: hsl(240, 80%, 35%);
--button-background-danger: hsl(282, 61%, 30%);
--dimmer-background-opacity: 0.45;
--notice-box-background: hsl(64, 90%, 23%);
--notice-box-color: var(--color-fixed-white);
--progress-bar-background: hsla(0, 97%, 7%, 0.5);
.Layout__content {
background-image: url('../../assets/bg-radiation.svg');
}
}
@@ -3,6 +3,7 @@
--color-base: hsl(0, 100%, 12.5%);
--color-primary: hsl(345, 95%, 30%);
--color-good: hsl(0, 82%, 52%);
--color-average: hsl(0, 77%, 44%);
--color-bad: hsl(340, 91%, 32%);
--base-gradient-spread: 12;
--secondary-lightness-adjustment: 9;
+1
View File
@@ -666,6 +666,7 @@
#include "code\datums\components\traits\gargoyle.dm"
#include "code\datums\components\traits\nutrition_size_change.dm"
#include "code\datums\components\traits\photosynth.dm"
#include "code\datums\components\traits\radiation_effects.dm"
#include "code\datums\components\traits\unlucky.dm"
#include "code\datums\components\traits\waddle.dm"
#include "code\datums\components\traits\weaver.dm"