[PORT] help, i just wanted to give visuals to being wet, now i've ported an entire fire_stacks refactor (#20735)

* oh god

* Update atoms_movable.dm

* Update atoms_movable.dm

* oh god oh fuck what have i done

* Update life.dm

* Update Hallucination.dm
This commit is contained in:
Molti
2023-10-29 22:49:18 -05:00
committed by GitHub
parent e068b0adcf
commit 274c21e88b
34 changed files with 769 additions and 340 deletions

View File

@@ -1,11 +1,13 @@
/datum/component/igniter
var/fire_stacks
var/fire_type
/datum/component/igniter/Initialize(fire_stacks=1)
/datum/component/igniter/Initialize(fire_stacks=1, fire_type = /datum/status_effect/fire_handler/fire_stacks)
if(!isitem(parent) && !ishostile(parent) && !isgun(parent) && !ismachinery(parent) && !isstructure(parent))
return COMPONENT_INCOMPATIBLE
src.fire_stacks = fire_stacks
src.fire_type = fire_type
/datum/component/igniter/RegisterWithParent()
if(ismachinery(parent) || isstructure(parent) || isgun(parent)) // turrets, etc
@@ -32,5 +34,5 @@
/datum/component/igniter/proc/do_igniter(atom/target)
if(isliving(target))
var/mob/living/L = target
L.adjust_fire_stacks(fire_stacks)
L.adjust_fire_stacks(fire_stacks, fire_type)
L.ignite_mob()

View File

@@ -0,0 +1,288 @@
#define ALERT_FIRE "fire"
// If a mob has a higher threshold than this, the icon shown will be increased to the big fire icon.
#define MOB_BIG_FIRE_STACK_THRESHOLD 3
/datum/status_effect/fire_handler
duration = -1
alert_type = null
status_type = STATUS_EFFECT_REFRESH //Custom code
on_remove_on_mob_delete = TRUE
tick_interval = 2 SECONDS
/// Current amount of stacks we have
var/stacks
/// Maximum of stacks that we could possibly get
var/stack_limit = 20
/// What status effect types do we remove uppon being applied. These are just deleted without any deduction from our or their stacks when forced.
var/list/enemy_types
/// What status effect types do we merge into if they exist. Ignored when forced.
var/list/merge_types
/// What status effect types do we override if they exist. These are simply deleted when forced.
var/list/override_types
/// For how much firestacks does one our stack count
var/stack_modifier = 1
/datum/status_effect/fire_handler/refresh(mob/living/new_owner, new_stacks, forced = FALSE)
if(forced)
set_stacks(new_stacks)
else
adjust_stacks(new_stacks)
/datum/status_effect/fire_handler/on_creation(mob/living/new_owner, new_stacks, forced = FALSE)
. = ..()
if(isanimal(owner))
qdel(src)
return
owner = new_owner
set_stacks(new_stacks)
for(var/enemy_type in enemy_types)
var/datum/status_effect/fire_handler/enemy_effect = owner.has_status_effect(enemy_type)
if(enemy_effect)
if(forced)
qdel(enemy_effect)
continue
var/cur_stacks = stacks
adjust_stacks(-abs(enemy_effect.stacks * enemy_effect.stack_modifier / stack_modifier))
enemy_effect.adjust_stacks(-abs(cur_stacks * stack_modifier / enemy_effect.stack_modifier))
if(enemy_effect.stacks <= 0)
qdel(enemy_effect)
if(stacks <= 0)
qdel(src)
return
if(!forced)
var/list/merge_effects = list()
for(var/merge_type in merge_types)
var/datum/status_effect/fire_handler/merge_effect = owner.has_status_effect(merge_type)
if(merge_effect)
merge_effects += merge_effects
if(LAZYLEN(merge_effects))
for(var/datum/status_effect/fire_handler/merge_effect in merge_effects)
merge_effect.adjust_stacks(stacks * stack_modifier / merge_effect.stack_modifier / LAZYLEN(merge_effects))
qdel(src)
return
for(var/override_type in override_types)
var/datum/status_effect/fire_handler/override_effect = owner.has_status_effect(override_type)
if(override_effect)
if(forced)
qdel(override_effect)
continue
adjust_stacks(override_effect.stacks)
qdel(override_effect)
/**
* Setter and adjuster procs for firestacks
*
* Arguments:
* - new_stacks
*
*/
/datum/status_effect/fire_handler/proc/set_stacks(new_stacks)
stacks = max(0, min(stack_limit, new_stacks))
cache_stacks()
/datum/status_effect/fire_handler/proc/adjust_stacks(new_stacks)
stacks = max(0, min(stack_limit, stacks + new_stacks))
cache_stacks()
/**
* Refresher for mob's fire_stacks
*/
/datum/status_effect/fire_handler/proc/cache_stacks()
owner.fire_stacks = 0
var/was_on_fire = owner.on_fire
owner.on_fire = FALSE
for(var/datum/status_effect/fire_handler/possible_fire in owner.status_effects)
owner.fire_stacks += possible_fire.stacks * possible_fire.stack_modifier
if(!istype(possible_fire, /datum/status_effect/fire_handler/fire_stacks))
continue
var/datum/status_effect/fire_handler/fire_stacks/our_fire = possible_fire
if(our_fire.on_fire)
owner.on_fire = TRUE
if(was_on_fire && !owner.on_fire)
owner.clear_alert(ALERT_FIRE)
else if(!was_on_fire && owner.on_fire)
owner.throw_alert(ALERT_FIRE, /atom/movable/screen/alert/fire)
/**
* Used to update owner's effect overlay
*/
/datum/status_effect/fire_handler/proc/update_overlay()
/datum/status_effect/fire_handler/fire_stacks
id = "fire_stacks" //fire_stacks and wet_stacks should have different IDs or else has_status_effect won't work
remove_on_fullheal = TRUE
enemy_types = list(/datum/status_effect/fire_handler/wet_stacks)
stack_modifier = 1
/// If we're on fire
var/on_fire = FALSE
/// Stores current fire overlay icon state, for optimisation purposes
var/last_icon_state
/// Reference to the mob light emitter itself
var/obj/effect/dummy/lighting_obj/moblight
/// Type of mob light emitter we use when on fire
var/moblight_type = /obj/effect/dummy/lighting_obj/moblight/fire
/datum/status_effect/fire_handler/fire_stacks/tick(seconds_between_ticks)
if(stacks <= 0)
qdel(src)
return TRUE
if(!on_fire)
return TRUE
adjust_stacks(-0.05 * seconds_between_ticks)
if(stacks <= 0)
qdel(src)
return TRUE
var/datum/gas_mixture/air = owner.loc.return_air()
if(!air || (air.get_moles(/datum/gas/oxygen) < 1))
qdel(src)
return TRUE
deal_damage(seconds_between_ticks)
update_overlay()
update_particles()
/datum/status_effect/fire_handler/fire_stacks/update_particles()
if(on_fire)
if(!particle_effect)
particle_effect = new(owner, /particles/embers)
if(stacks > MOB_BIG_FIRE_STACK_THRESHOLD)
particle_effect.particles.spawning = 5
else
particle_effect.particles.spawning = 1
else if(particle_effect)
QDEL_NULL(particle_effect)
/**
* Proc that handles damage dealing and all special effects
*
* Arguments:
* - seconds_between_ticks
*
*/
/datum/status_effect/fire_handler/fire_stacks/proc/deal_damage(seconds_per_tick)
owner.on_fire_stack(seconds_per_tick, src)
var/turf/location = get_turf(owner)
location.hotspot_expose(700, 25 * seconds_per_tick, TRUE)
/**
* Used to deal damage to humans and count their protection.
*
* Arguments:
* - seconds_between_ticks
* - no_protection: When set to TRUE, fire will ignore any possible fire protection
*
*/
/datum/status_effect/fire_handler/fire_stacks/proc/harm_human(seconds_per_tick, no_protection = FALSE)
var/mob/living/carbon/human/victim = owner
var/thermal_protection = victim.get_thermal_protection()
if(thermal_protection >= FIRE_IMMUNITY_MAX_TEMP_PROTECT && !no_protection)
return
if(thermal_protection >= FIRE_SUIT_MAX_TEMP_PROTECT && !no_protection)
victim.adjust_bodytemperature(5.5 * seconds_per_tick)
return
victim.adjust_bodytemperature((BODYTEMP_HEATING_MAX + (stacks * 12)) * 0.5 * seconds_per_tick)
SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "on_fire", /datum/mood_event/on_fire)
/**
* Handles mob ignition, should be the only way to set on_fire to TRUE
*
* Arguments:
* - silent: When set to TRUE, no message is displayed
*
*/
/datum/status_effect/fire_handler/fire_stacks/proc/ignite(silent = FALSE)
if(HAS_TRAIT(owner, TRAIT_NOFIRE))
return FALSE
on_fire = TRUE
if(!silent)
owner.visible_message(span_warning("[owner] catches fire!"), span_userdanger("You're set on fire!"))
if(moblight_type)
if(moblight)
qdel(moblight)
moblight = new moblight_type(owner)
SEND_SIGNAL(owner, COMSIG_LIVING_IGNITED, owner)
cache_stacks()
update_overlay()
update_particles()
return TRUE
/**
* Handles mob extinguishing, should be the only way to set on_fire to FALSE
*/
/datum/status_effect/fire_handler/fire_stacks/proc/extinguish()
QDEL_NULL(moblight)
on_fire = FALSE
SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, "on_fire")
SEND_SIGNAL(owner, COMSIG_LIVING_EXTINGUISHED, owner)
cache_stacks()
update_overlay()
update_particles()
for(var/obj/item/equipped in owner.get_equipped_items())
equipped.extinguish()
/datum/status_effect/fire_handler/fire_stacks/on_remove()
if(on_fire)
extinguish()
set_stacks(0)
update_overlay()
update_particles()
return ..()
/datum/status_effect/fire_handler/fire_stacks/update_overlay()
last_icon_state = owner.update_fire_overlay(stacks, on_fire, last_icon_state)
/datum/status_effect/fire_handler/fire_stacks/on_apply()
. = ..()
update_overlay()
/obj/effect/dummy/lighting_obj/moblight/fire
name = "fire"
light_color = LIGHT_COLOR_FIRE
light_range = LIGHT_RANGE_FIRE
/datum/status_effect/fire_handler/wet_stacks
id = "wet_stacks"
enemy_types = list(/datum/status_effect/fire_handler/fire_stacks)
stack_modifier = -1
/datum/status_effect/fire_handler/wet_stacks/tick(seconds_between_ticks)
adjust_stacks(-0.5 * seconds_between_ticks)
if(stacks <= 0)
qdel(src)
/datum/status_effect/fire_handler/wet_stacks/update_particles()
if(particle_effect)
return
particle_effect = new(owner, /particles/droplets)

View File

@@ -30,6 +30,8 @@
//var/heal_flag_necessary = HEAL_STATUS
///If defined, this text will appear when the mob is examined - to use he, she etc. use "SUBJECTPRONOUN" and replace it in the examines themselves
var/examine_text
/// A particle effect, for things like embers - Should be set on update_particles()
var/obj/effect/abstract/particle_holder/particle_effect
/datum/status_effect/New(list/arguments)
on_creation(arglist(arguments))
@@ -62,6 +64,7 @@
START_PROCESSING(SSfastprocess, src)
if(STATUS_EFFECT_NORMAL_PROCESS)
START_PROCESSING(SSprocessing, src)
update_particles()
return TRUE
@@ -78,6 +81,8 @@
on_remove()
UnregisterSignal(owner, COMSIG_LIVING_POST_FULLY_HEAL)
owner = null
if(particle_effect)
QDEL_NULL(particle_effect)
return ..()
// Status effect process. Handles adjusting its duration and ticks.
@@ -169,6 +174,14 @@
return FALSE
/**
* Updates the particles for the status effects
* Should be handled by subtypes!
*/
/datum/status_effect/proc/update_particles()
SHOULD_CALL_PARENT(FALSE)
////////////////
// ALERT HOOK //
////////////////

View File

@@ -283,7 +283,7 @@
/obj/effect/particle_effect/fluid/foam/firefighting/foam_mob(mob/living/foaming, delta_time)
if(!istype(foaming))
return
foaming.adjust_fire_stacks(-2)
foaming.adjust_wet_stacks(2)
foaming.extinguish_mob()
/// A factory which produces firefighting foam

View File

@@ -29,7 +29,7 @@
for(var/obj/O in T)
O.extinguish()
for(var/mob/living/L in T)
L.adjust_fire_stacks(-2.5)
L.adjust_wet_stacks(2.5)
L.extinguish_mob()
/datum/reagent/blob/pressurized_slime
@@ -42,7 +42,7 @@
var/turf/open/T = get_turf(M)
if(istype(T) && prob(reac_volume))
T.MakeSlippery(TURF_WET_LUBE, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS)
M.adjust_fire_stacks(-(reac_volume / 10))
M.adjust_wet_stacks(reac_volume / 10)
M.extinguish_mob()
M.apply_damage(0.4*reac_volume, BRUTE, wound_bonus=CANT_WOUND)
if(M)

View File

@@ -21,4 +21,4 @@
. = ..()
if(isliving(AM) && opacity)
var/mob/living/L = AM
L.adjust_fire_stacks(-1) //It's wet!
L.adjust_wet_stacks(1) //It's wet!

View File

@@ -247,11 +247,6 @@
/obj/effect/hotspot/singularity_pull()
return
/obj/effect/dummy/lighting_obj/moblight/fire
name = "fire"
light_color = LIGHT_COLOR_FIRE
light_range = LIGHT_RANGE_FIRE
#undef INSUFFICIENT
#undef IGNITE_TURF_LOW_POWER
#undef IGNITE_TURF_HIGH_POWER

View File

@@ -1188,37 +1188,105 @@ GLOBAL_LIST_INIT(hallucination_list, list(
target.silent = FALSE
qdel(src)
#define RAISE_FIRE_COUNT 3
#define RAISE_FIRE_TIME 3
/datum/hallucination/fire
random_hallucination_weight = 3
/// Are we currently burning our mob?
var/active = TRUE
/// What stare of fire are we in?
var/stage = 0
/// What icon file to use for our hallucinator
var/fire_icon = 'icons/mob/effects/onfire.dmi'
/// What icon state to use for our hallucinator
var/fire_icon_state = "human_big_fire"
/// Our fire overlay we generate
var/image/fire_overlay
/datum/hallucination/fire/New(mob/living/carbon/C, forced = TRUE)
set waitfor = FALSE
..()
target.fire_stacks = max(target.fire_stacks, 0.1) //Placebo flammability
fire_overlay = image('icons/mob/OnFire.dmi', target, "Standing", ABOVE_MOB_LAYER)
if(target.client)
target.client.images += fire_overlay
/// When should we do our next action of the hallucination?
var/next_action = 0
/// How may times do we apply stamina damage to our mob?
var/times_to_lower_stamina
/// Are we currently fake-clearing our hallucinated fire?
var/fire_clearing = FALSE
/// Are the stages going up or down?
var/increasing_stages = TRUE
/// How long have we spent on fire?
var/time_spent = 0
/datum/hallucination/fire/New(mob/living/hallucinator)
if(ismonkey(hallucinator))
fire_icon_state = "monkey_big_fire"
else if(!ishuman(hallucinator))
fire_icon_state = "generic_fire"
return ..()
/datum/hallucination/fire/start()
target.set_fire_stacks(max(target.fire_stacks, 0.1)) //Placebo flammability
fire_overlay = image(fire_icon, target, fire_icon_state, ABOVE_MOB_LAYER)
target.client?.images |= fire_overlay
to_chat(target, span_userdanger("You're set on fire!"))
target.throw_alert("fire", /atom/movable/screen/alert/fire, override = TRUE)
sleep(2 SECONDS)
for(var/i in 1 to 3)
if(target.fire_stacks <= 0)
clear_fire()
return
stage++
update_temp()
sleep(3 SECONDS)
for(var/i in 1 to rand(5, 10))
if(target.fire_stacks <= 0)
clear_fire()
return
target.adjustStaminaLoss(15)
sleep(2 SECONDS)
clear_fire()
target.throw_alert(ALERT_FIRE, /atom/movable/screen/alert/fire, override = TRUE)
times_to_lower_stamina = rand(5, 10)
addtimer(CALLBACK(src, PROC_REF(start_expanding)), 2 SECONDS)
return TRUE
/datum/hallucination/fire/Destroy()
target.adjust_fire_stacks(-0.1)
target.clear_alert(ALERT_FIRE, clear_override = TRUE)
target.clear_alert("temp", clear_override = TRUE)
if(fire_overlay)
target.client?.images -= fire_overlay
fire_overlay = null
STOP_PROCESSING(SSfastprocess, src)
return ..()
/datum/hallucination/fire/proc/start_expanding()
if(QDELETED(src))
return
START_PROCESSING(SSfastprocess, src)
/datum/hallucination/fire/process(seconds_per_tick)
if(QDELETED(src))
return
if(target.fire_stacks <= 0)
clear_fire()
time_spent += seconds_per_tick
if(fire_clearing)
next_action -= seconds_per_tick
if(next_action < 0)
stage -= 1
update_temp()
next_action += 3
else if(increasing_stages)
var/new_stage = min(round(time_spent / RAISE_FIRE_TIME), RAISE_FIRE_COUNT)
if(stage != new_stage)
stage = new_stage
update_temp()
if(stage == RAISE_FIRE_COUNT)
increasing_stages = FALSE
else if(times_to_lower_stamina)
next_action -= seconds_per_tick
if(next_action < 0)
target.adjustStaminaLoss(15)
next_action += 2
times_to_lower_stamina -= 1
else
clear_fire()
/datum/hallucination/fire/proc/update_temp()
if(stage <= 0)
@@ -1230,16 +1298,17 @@ GLOBAL_LIST_INIT(hallucination_list, list(
/datum/hallucination/fire/proc/clear_fire()
if(!active)
return
active = FALSE
target.clear_alert("fire", clear_override = TRUE)
if(target.client)
target.client.images -= fire_overlay
QDEL_NULL(fire_overlay)
while(stage > 0)
stage--
update_temp()
sleep(3 SECONDS)
qdel(src)
target.clear_alert(ALERT_FIRE, clear_override = TRUE)
target.client?.images -= fire_overlay
fire_overlay = null
fire_clearing = TRUE
next_action = 0
#undef RAISE_FIRE_COUNT
#undef RAISE_FIRE_TIME
/datum/hallucination/shock
random_hallucination_weight = 1

View File

@@ -128,3 +128,6 @@ In all, this is a lot like the monkey code. /N
/mob/living/carbon/alien/acid_act(acidpwr, acid_volume)
return 0//aliens are immune to acid.
/mob/living/carbon/alien/on_fire_stack(seconds_per_tick, datum/status_effect/fire_handler/fire_stacks/fire_handler)
adjust_bodytemperature((BODYTEMP_HEATING_MAX + (fire_handler.stacks * 12)) * 0.5 * seconds_per_tick)

View File

@@ -38,9 +38,3 @@
//natural reduction of movement delay due to stun.
if(move_delay_add > 0)
move_delay_add = max(0, move_delay_add - rand(1, 2))
/mob/living/carbon/alien/handle_fire()//Aliens on fire code
. = ..()
if(.) //if the mob isn't on fire anymore
return
adjust_bodytemperature(BODYTEMP_HEATING_MAX) //If you're on fire, you heat up!

View File

@@ -93,15 +93,10 @@
if(HAS_TRAIT(src, TRAIT_DUMB))
msg += "[t_He] seem[p_s()] to be clumsy and unable to think.\n"
switch(fire_stacks)
if(1 to INFINITY)
msg += "[t_He] [t_is] covered in something flammable.\n"
if(-5 to -1)
msg += "[t_He] look[p_s()] a little damp.\n"
if(-10 to -5)
msg += "[t_He] look[p_s()] a little soaked.\n"
if(-INFINITY to -10)
msg += "[t_He] look[p_s()] drenched.\n"
if(has_status_effect(/datum/status_effect/fire_handler/fire_stacks))
msg += "[t_He] [t_is] covered in something flammable.\n"
if(has_status_effect(/datum/status_effect/fire_handler/wet_stacks))
msg += "[t_He] look[p_s()] a little soaked.\n"
if(visible_tumors)
msg += "[t_He] [t_has] has growths all over [t_his] body...\n"

View File

@@ -252,15 +252,10 @@
surgery_text += ", [S.operated_bodypart]"
msg += "[surgery_text].\n"
switch(fire_stacks)
if(1 to INFINITY)
msg += "[t_He] [t_is] covered in something flammable.\n"
if(-5 to -1)
msg += "[t_He] look[p_s()] a little damp.\n"
if(-10 to -5)
msg += "[t_He] look[p_s()] a little soaked.\n"
if(-INFINITY to -10)
msg += "[t_He] look[p_s()] drenched.\n"
if(has_status_effect(/datum/status_effect/fire_handler/fire_stacks))
msg += "[t_He] [t_is] covered in something flammable.\n"
if(has_status_effect(/datum/status_effect/fire_handler/wet_stacks))
msg += "[t_He] look[p_s()] a little soaked.\n"
if(visible_tumors)
msg += "[t_He] [t_has] has growths all over [t_his] body...\n"

View File

@@ -1032,3 +1032,68 @@
for(var/obj/item/I in torn_items)
I.take_damage(damage_amount, damage_type, damage_flag, 0)
/**
* Used by fire code to damage worn items.
*
* Arguments:
* - seconds_per_tick
* - times_fired
* - stacks: Current amount of firestacks
*
*/
/mob/living/carbon/human/proc/burn_clothing(seconds_per_tick, stacks)
var/list/burning_items = list()
var/obscured = check_obscured_slots(TRUE)
//HEAD//
if(glasses && !(obscured & ITEM_SLOT_EYES))
burning_items += glasses
if(wear_mask && !(obscured & ITEM_SLOT_MASK))
burning_items += wear_mask
if(wear_neck && !(obscured & ITEM_SLOT_NECK))
burning_items += wear_neck
if(ears && !(obscured & ITEM_SLOT_EARS))
burning_items += ears
if(head)
burning_items += head
//CHEST//
if(w_uniform && !(obscured & ITEM_SLOT_ICLOTHING))
burning_items += w_uniform
if(wear_suit)
burning_items += wear_suit
//ARMS & HANDS//
var/obj/item/clothing/arm_clothes = null
if(gloves && !(obscured & ITEM_SLOT_GLOVES))
arm_clothes = gloves
else if(wear_suit && ((wear_suit.body_parts_covered & HANDS) || (wear_suit.body_parts_covered & ARMS)))
arm_clothes = wear_suit
else if(w_uniform && ((w_uniform.body_parts_covered & HANDS) || (w_uniform.body_parts_covered & ARMS)))
arm_clothes = w_uniform
if(arm_clothes)
burning_items |= arm_clothes
//LEGS & FEET//
var/obj/item/clothing/leg_clothes = null
if(shoes && !(obscured & ITEM_SLOT_FEET))
leg_clothes = shoes
else if(wear_suit && ((wear_suit.body_parts_covered & FEET) || (wear_suit.body_parts_covered & LEGS)))
leg_clothes = wear_suit
else if(w_uniform && ((w_uniform.body_parts_covered & FEET) || (w_uniform.body_parts_covered & LEGS)))
leg_clothes = w_uniform
if(leg_clothes)
burning_items |= leg_clothes
for(var/obj/item/burning in burning_items)
burning.fire_act((stacks * 25 * seconds_per_tick)) //damage taken is reduced to 2% of this value by fire_act()
/mob/living/carbon/human/on_fire_stack(seconds_per_tick, datum/status_effect/fire_handler/fire_stacks/fire_handler)
SEND_SIGNAL(src, COMSIG_HUMAN_BURNING)
burn_clothing(seconds_per_tick, fire_handler.stacks)
var/no_protection = FALSE
if(dna && dna.species)
no_protection = dna.species.handle_fire(src, seconds_per_tick, no_protection)
fire_handler.harm_human(seconds_per_tick, no_protection)

View File

@@ -154,22 +154,6 @@
/mob/living/carbon/human/handle_environment(datum/gas_mixture/environment)
dna.species.handle_environment(environment, src)
///FIRE CODE
/mob/living/carbon/human/handle_fire()
. = ..()
if(.) //if the mob isn't on fire anymore
return
if(dna)
. = dna.species.handle_fire(src) //do special handling based on the mob's species. TRUE = they are immune to the effects of the fire.
if(!last_fire_update)
last_fire_update = fire_stacks
if((fire_stacks > HUMAN_FIRE_STACK_ICON_NUM && last_fire_update <= HUMAN_FIRE_STACK_ICON_NUM) || (fire_stacks <= HUMAN_FIRE_STACK_ICON_NUM && last_fire_update > HUMAN_FIRE_STACK_ICON_NUM))
last_fire_update = fire_stacks
update_fire()
/mob/living/carbon/human/proc/get_thermal_protection()
var/thermal_protection = 0 //Simple check to estimate how protected we are against multiple temperatures
if(wear_suit)

View File

@@ -162,6 +162,9 @@ GLOBAL_LIST_EMPTY(features_by_species)
///what type of gas is breathed
var/breathid = "o2"
/// The icon_state of the fire overlay added when sufficently ablaze and standing. see onfire.dmi
var/fire_overlay = "human" //not used until monkey is added as a species type rather than a mob
//Do NOT remove by setting to null. use OR make a RESPECTIVE TRAIT (removing stomach? add the NOSTOMACH trait to your species)
//why does it work this way? because traits also disable the downsides of not having an organ, removing organs but not having the trait will make your species die
@@ -1970,9 +1973,9 @@ GLOBAL_LIST_EMPTY(features_by_species)
if(environment.get_moles(/datum/gas/water_vapor) > 10)//water vapour above a certain amount makes you wet
if(environment.get_moles(/datum/gas/water_vapor) > 40)//if there's a lot of water vapour, preterni ded
H.adjust_fire_stacks(-3)
H.adjust_wet_stacks(3)
else
H.adjust_fire_stacks(-2)
H.adjust_wet_stacks(2)
var/loc_temp = H.get_temperature(environment)
var/heat_capacity_factor = min(1, environment.heat_capacity() / environment.return_volume())
@@ -2090,67 +2093,8 @@ GLOBAL_LIST_EMPTY(features_by_species)
// FIRE //
//////////
/datum/species/proc/handle_fire(mob/living/carbon/human/H, no_protection = FALSE)
if(!Canignite_mob(H))
return TRUE
if(H.on_fire)
//the fire tries to damage the exposed clothes and items
var/list/burning_items = list()
var/list/obscured = H.check_obscured_slots(TRUE)
//HEAD//
if(H.glasses && !(ITEM_SLOT_EYES in obscured))
burning_items += H.glasses
if(H.wear_mask && !(ITEM_SLOT_MASK in obscured))
burning_items += H.wear_mask
if(H.wear_neck && !(ITEM_SLOT_NECK in obscured))
burning_items += H.wear_neck
if(H.ears && !(ITEM_SLOT_EARS in obscured))
burning_items += H.ears
if(H.head)
burning_items += H.head
//CHEST//
if(H.w_uniform && !(ITEM_SLOT_ICLOTHING in obscured))
burning_items += H.w_uniform
if(H.wear_suit)
burning_items += H.wear_suit
//ARMS & HANDS//
var/obj/item/clothing/arm_clothes = null
if(H.gloves && !(ITEM_SLOT_GLOVES in obscured))
arm_clothes = H.gloves
else if(H.wear_suit && ((H.wear_suit.body_parts_covered & HANDS) || (H.wear_suit.body_parts_covered & ARMS)))
arm_clothes = H.wear_suit
else if(H.w_uniform && ((H.w_uniform.body_parts_covered & HANDS) || (H.w_uniform.body_parts_covered & ARMS)))
arm_clothes = H.w_uniform
if(arm_clothes)
burning_items |= arm_clothes
//LEGS & FEET//
var/obj/item/clothing/leg_clothes = null
if(H.shoes && !(ITEM_SLOT_FEET in obscured))
leg_clothes = H.shoes
else if(H.wear_suit && ((H.wear_suit.body_parts_covered & FEET) || (H.wear_suit.body_parts_covered & LEGS)))
leg_clothes = H.wear_suit
else if(H.w_uniform && ((H.w_uniform.body_parts_covered & FEET) || (H.w_uniform.body_parts_covered & LEGS)))
leg_clothes = H.w_uniform
if(leg_clothes)
burning_items |= leg_clothes
for(var/X in burning_items)
var/obj/item/I = X
I.fire_act((H.fire_stacks * 50)) //damage taken is reduced to 2% of this value by fire_act()
var/thermal_protection = H.get_thermal_protection()
if(thermal_protection >= FIRE_IMMUNITY_MAX_TEMP_PROTECT && !no_protection)
return
if(thermal_protection >= FIRE_SUIT_MAX_TEMP_PROTECT && !no_protection)
H.adjust_bodytemperature(11)
else
H.adjust_bodytemperature(BODYTEMP_HEATING_MAX + (H.fire_stacks * 2))
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "on_fire", /datum/mood_event/on_fire)
/datum/species/proc/handle_fire(mob/living/carbon/human/H, seconds_per_tick, no_protection = FALSE)
return no_protection
/datum/species/proc/Canignite_mob(mob/living/carbon/human/H)
if(HAS_TRAIT(H, TRAIT_NOFIRE))

View File

@@ -142,28 +142,3 @@
if(wear_mask.clothing_flags & BLOCK_GAS_SMOKE_EFFECT)
return 1
/mob/living/carbon/monkey/handle_fire()
. = ..()
if(.) //if the mob isn't on fire anymore
return
//the fire tries to damage the exposed clothes and items
var/list/burning_items = list()
//HEAD//
var/list/obscured = check_obscured_slots(TRUE)
if(wear_mask && !(ITEM_SLOT_MASK in obscured))
burning_items += wear_mask
if(wear_neck && !(ITEM_SLOT_NECK in obscured))
burning_items += wear_neck
if(head)
burning_items += head
if(back)
burning_items += back
for(var/X in burning_items)
var/obj/item/I = X
I.fire_act((fire_stacks * 50)) //damage taken is reduced to 2% of this value by fire_act()
adjust_bodytemperature(BODYTEMP_HEATING_MAX)
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "on_fire", /datum/mood_event/on_fire)

View File

@@ -81,16 +81,28 @@
overlays_standing[HANDS_LAYER] = hands
apply_overlay(HANDS_LAYER)
/mob/living/carbon/update_fire_overlay(stacks, on_fire, last_icon_state, suffix = "")
var/fire_icon = "[dna?.species.fire_overlay || "human"]_[stacks > MOB_BIG_FIRE_STACK_THRESHOLD ? "big_fire" : "small_fire"][suffix]"
if(!GLOB.fire_appearances[fire_icon])
GLOB.fire_appearances[fire_icon] = mutable_appearance('icons/mob/effects/onfire.dmi', fire_icon, -FIRE_LAYER, appearance_flags = RESET_COLOR)
if((stacks > 0 && on_fire))
if(fire_icon == last_icon_state)
return last_icon_state
remove_overlay(FIRE_LAYER)
overlays_standing[FIRE_LAYER] = GLOB.fire_appearances[fire_icon]
apply_overlay(FIRE_LAYER)
return fire_icon
if(!last_icon_state)
return last_icon_state
/mob/living/carbon/update_fire(fire_icon = "Generic_mob_burning")
remove_overlay(FIRE_LAYER)
if(on_fire || islava(loc))
var/mutable_appearance/new_fire_overlay = mutable_appearance('icons/mob/OnFire.dmi', fire_icon, -FIRE_LAYER)
new_fire_overlay.appearance_flags = RESET_COLOR
overlays_standing[FIRE_LAYER] = new_fire_overlay
apply_overlay(FIRE_LAYER)
return null
/mob/living/carbon/update_damage_overlays()
remove_overlay(DAMAGE_LAYER)

View File

@@ -73,8 +73,6 @@
handle_traits() // eye, ear, brain damages
handle_status_effects() //all special effects, stun, knockdown, jitteryness, hallucination, sleeping, etc
handle_fire()
if(machine)
machine.check_eye(src)
@@ -108,23 +106,6 @@
/mob/living/proc/handle_environment(datum/gas_mixture/environment)
return
/mob/living/proc/handle_fire()
if(fire_stacks < 0) //If we've doused ourselves in water to avoid fire, dry off slowly
fire_stacks = min(0, fire_stacks + 1)//So we dry ourselves back to default, nonflammable.
if(!on_fire)
return TRUE //the mob is no longer on fire, no need to do the rest.
if(fire_stacks > 0)
adjust_fire_stacks(-0.1) //the fire is slowly consumed
else
extinguish_mob()
return TRUE //mob was put out, on_fire = FALSE via extinguish_mob(), no need to update everything down the chain.
var/datum/gas_mixture/G = loc.return_air() // Check if we're standing in an oxygenless environment
if(G.get_moles(/datum/gas/oxygen) < 1)
extinguish_mob() //If there's no oxygen in the tile we're on, put out the fire
return TRUE
var/turf/location = get_turf(src)
location.hotspot_expose(700, 50, 1)
//this updates all special effects: knockdown, druggy, stuttering, etc..
/mob/living/proc/handle_status_effects()

View File

@@ -1191,59 +1191,150 @@
return BODYTEMP_NORMAL + get_body_temp_normal_change()
//Mobs on Fire
/mob/living/proc/ignite_mob()
if(fire_stacks > 0 && !on_fire)
on_fire = 1
src.visible_message(span_warning("[src] catches fire!"), \
span_userdanger("You're set on fire!"))
new/obj/effect/dummy/lighting_obj/moblight/fire(src)
throw_alert("fire", /atom/movable/screen/alert/fire)
update_fire()
SEND_SIGNAL(src, COMSIG_LIVING_IGNITED,src)
return TRUE
return FALSE
/// Global list that containes cached fire overlays for mobs
GLOBAL_LIST_EMPTY(fire_appearances)
/mob/living/proc/ignite_mob(silent)
if(fire_stacks <= 0)
return FALSE
var/datum/status_effect/fire_handler/fire_stacks/fire_status = has_status_effect(/datum/status_effect/fire_handler/fire_stacks)
if(!fire_status || fire_status.on_fire)
return FALSE
return fire_status.ignite(silent)
/mob/living/update_fire()
var/datum/status_effect/fire_handler/fire_handler = has_status_effect(/datum/status_effect/fire_handler)
if(fire_handler)
fire_handler.update_overlay()
/**
* Extinguish all fire on the mob
*
* This removes all fire stacks, fire effects, alerts, and moods
* Signals the extinguishing.
*/
/mob/living/proc/extinguish_mob()
if(on_fire)
on_fire = 0
fire_stacks = 0
for(var/obj/effect/dummy/lighting_obj/moblight/fire/F in src)
qdel(F)
clear_alert("fire")
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "on_fire")
SEND_SIGNAL(src, COMSIG_LIVING_EXTINGUISHED, src)
update_fire()
var/datum/status_effect/fire_handler/fire_stacks/fire_status = has_status_effect(/datum/status_effect/fire_handler/fire_stacks)
if(!fire_status || !fire_status.on_fire)
return
/mob/living/proc/adjust_fire_stacks(add_fire_stacks) //Adjusting the amount of fire_stacks we have on person
if(fire_stacks > 0) //don't let people on fire instantly get -20 fire_stacks, but still let them extinguish themselves. Stops preternis from hurting themselves for trying to put out fire
fire_stacks = clamp(fire_stacks + add_fire_stacks, -1, 20)
else
fire_stacks = clamp(fire_stacks + add_fire_stacks, -20, 20)
if(on_fire && fire_stacks <= 0)
extinguish_mob()
remove_status_effect(/datum/status_effect/fire_handler/fire_stacks)
/**
* Adjust the amount of fire stacks on a mob
*
* This modifies the fire stacks on a mob.
*
* Vars:
* * stacks: int The amount to modify the fire stacks
* * fire_type: type Type of fire status effect that we apply, should be subtype of /datum/status_effect/fire_handler/fire_stacks
*/
/mob/living/proc/adjust_fire_stacks(stacks, fire_type = /datum/status_effect/fire_handler/fire_stacks)
if(stacks < 0)
stacks = max(-fire_stacks, stacks)
apply_status_effect(fire_type, stacks)
/mob/living/proc/adjust_wet_stacks(stacks, wet_type = /datum/status_effect/fire_handler/wet_stacks)
if(stacks < 0)
stacks = max(fire_stacks, stacks)
apply_status_effect(wet_type, stacks)
/**
* Set the fire stacks on a mob
*
* This sets the fire stacks on a mob, stacks are clamped between -20 and 20.
* If the fire stacks are reduced to 0 then we will extinguish the mob.
*
* Vars:
* * stacks: int The amount to set fire_stacks to
* * fire_type: type Type of fire status effect that we apply, should be subtype of /datum/status_effect/fire_handler/fire_stacks
* * remove_wet_stacks: bool If we remove all wet stacks upon doing this
*/
/mob/living/proc/set_fire_stacks(stacks, fire_type = /datum/status_effect/fire_handler/fire_stacks, remove_wet_stacks = TRUE)
if(stacks < 0) //Shouldn't happen, ever
CRASH("set_fire_stacks recieved negative [stacks] fire stacks")
if(remove_wet_stacks)
remove_status_effect(/datum/status_effect/fire_handler/wet_stacks)
if(stacks == 0)
remove_status_effect(fire_type)
return
apply_status_effect(fire_type, stacks, TRUE)
/mob/living/proc/set_wet_stacks(stacks, wet_type = /datum/status_effect/fire_handler/wet_stacks, remove_fire_stacks = TRUE)
if(stacks < 0)
CRASH("set_wet_stacks recieved negative [stacks] wet stacks")
if(remove_fire_stacks)
remove_status_effect(/datum/status_effect/fire_handler/fire_stacks)
if(stacks == 0)
remove_status_effect(wet_type)
return
apply_status_effect(wet_type, stacks, TRUE)
//Share fire evenly between the two mobs
//Called in MobBump() and Crossed()
/mob/living/proc/spreadFire(mob/living/L)
if(!istype(L))
/mob/living/proc/spreadFire(mob/living/spread_to)
if(!istype(spread_to))
return
if(on_fire)
if(L.on_fire) // If they were also on fire
var/firesplit = (fire_stacks + L.fire_stacks)/2
fire_stacks = firesplit
L.fire_stacks = firesplit
else // If they were not
fire_stacks /= 2
L.adjust_fire_stacks(fire_stacks)
if(L.ignite_mob()) // Ignite them
log_game("[key_name(src)] bumped into [key_name(L)] and set them on fire")
var/datum/status_effect/fire_handler/fire_stacks/fire_status = has_status_effect(/datum/status_effect/fire_handler/fire_stacks)
var/datum/status_effect/fire_handler/fire_stacks/their_fire_status = spread_to.has_status_effect(/datum/status_effect/fire_handler/fire_stacks)
if(fire_status && fire_status.on_fire)
if(their_fire_status && their_fire_status.on_fire)
var/firesplit = (fire_stacks + spread_to.fire_stacks) / 2
var/fire_type = (spread_to.fire_stacks > fire_stacks) ? their_fire_status.type : fire_status.type
set_fire_stacks(firesplit, fire_type)
spread_to.set_fire_stacks(firesplit, fire_type)
return
else if(L.on_fire) // If they were on fire and we were not
L.fire_stacks /= 2
adjust_fire_stacks(L.fire_stacks)
ignite_mob() // Ignite us
adjust_fire_stacks(-fire_stacks / 2, fire_status.type)
spread_to.adjust_fire_stacks(fire_stacks, fire_status.type)
if(spread_to.ignite_mob())
log_message("bumped into [key_name(spread_to)] and set them on fire.", LOG_ATTACK)
return
if(!their_fire_status || !their_fire_status.on_fire)
return
spread_to.adjust_fire_stacks(-spread_to.fire_stacks / 2, their_fire_status.type)
adjust_fire_stacks(spread_to.fire_stacks, their_fire_status.type)
ignite_mob()
/**
* Sets fire overlay of the mob.
*
* Vars:
* * stacks: Current amount of fire_stacks
* * on_fire: If we're lit on fire
* * last_icon_state: Holds last fire overlay icon state, used for optimization
* * suffix: Suffix for the fire icon state for special fire types
*
* This should return last_icon_state for the fire status efect
*/
/mob/living/proc/update_fire_overlay(stacks, on_fire, last_icon_state, suffix = "")
return last_icon_state
/**
* Handles effects happening when mob is on normal fire
*
* Vars:
* * seconds_per_tick
* * times_fired
* * fire_handler: Current fire status effect that called the proc
*/
/mob/living/proc/on_fire_stack(seconds_per_tick, datum/status_effect/fire_handler/fire_stacks/fire_handler)
return
//Mobs on Fire end
// used by secbot and monkeys Crossed

View File

@@ -70,27 +70,6 @@
else
throw_alert("charge", /atom/movable/screen/alert/nocell)
//Robots on fire
/mob/living/silicon/robot/handle_fire()
. = ..()
if(.) //if the mob isn't on fire anymore
return
if(fire_stacks > 0)
fire_stacks--
fire_stacks = max(0, fire_stacks)
else
extinguish_mob()
return TRUE
//adjustFireLoss(3)
/mob/living/silicon/robot/update_fire()
var/mutable_appearance/fire_overlay = mutable_appearance('icons/mob/OnFire.dmi', "Generic_mob_burning")
if(on_fire)
add_overlay(fire_overlay)
else
cut_overlay(fire_overlay)
/mob/living/silicon/robot/update_mobility()
if(stat || buckled || lockcharge)
mobility_flags &= ~MOBILITY_MOVE

View File

@@ -999,6 +999,26 @@
return FALSE
return TRUE
/mob/living/silicon/robot/update_fire_overlay(stacks, on_fire, last_icon_state, suffix = "")
var/fire_icon = "generic_fire[suffix]"
if(!GLOB.fire_appearances[fire_icon])
var/mutable_appearance/new_fire_overlay = mutable_appearance('icons/mob/effects/onfire.dmi', fire_icon, -FIRE_LAYER)
new_fire_overlay.appearance_flags = RESET_COLOR
GLOB.fire_appearances[fire_icon] = new_fire_overlay
if(stacks && on_fire)
if(last_icon_state == fire_icon)
return last_icon_state
add_overlay(GLOB.fire_appearances[fire_icon])
return fire_icon
if(!last_icon_state)
return last_icon_state
cut_overlay(GLOB.fire_appearances[fire_icon])
return null
/mob/living/silicon/robot/updatehealth()
..()

View File

@@ -370,9 +370,6 @@
// yogs end
return TRUE
/mob/living/simple_animal/handle_fire()
return TRUE
/mob/living/simple_animal/ignite_mob()
return FALSE

View File

@@ -1,18 +1,3 @@
/particles/embers
color = generator("color", "#FF2200", "#FF9933", UNIFORM_RAND)
spawning = 0.5
count = 30
lifespan = 30
fade = 5
position = generator("vector", list(-3,6,0), list(3,6,0), NORMAL_RAND)
gravity = list(0, 0.2, 0)
color_change = 0
friction = 0.2
drift = generator("vector", list(0.25,0,0), list(-0.25,0,0), UNIFORM_RAND)
#ifndef SPACEMAN_DMM
fadein = 10
#endif
///GENERIC FIRE EFEFCT
/particles/fire
width = 500
@@ -26,3 +11,36 @@
drift = generator("vector", list(0, -0.2), list(0, 0.2))
gravity = list(0, 0.65)
color = "white"
/particles/embers
icon = 'icons/effects/particles/generic.dmi'
icon_state = list("dot" = 4,"cross" = 1,"curl" = 1)
width = 64
height = 96
count = 500
spawning = 5
lifespan = 3 SECONDS
fade = 1 SECONDS
color = 0
color_change = 0.05
gradient = list("#FBAF4D", "#FCE6B6", "#FD481C")
position = generator("box", list(-12,-16,0), list(12,16,0), NORMAL_RAND)
drift = generator("vector", list(-0.1,0), list(0.1,0.025), UNIFORM_RAND)
spin = generator("num", list(-15,15), NORMAL_RAND)
scale = generator("vector", list(0.5,0.5), list(2,2), NORMAL_RAND)
// water is basically inverse fire, right?
// Water related particles.
/particles/droplets
icon = 'icons/effects/particles/generic.dmi'
icon_state = list("dot"=2,"drop"=1)
width = 32
height = 36
count = 5
spawning = 0.2
lifespan = 1 SECONDS
fade = 0.5 SECONDS
color = "#549EFF"
position = generator("box", list(-9,-9,0), list(9,18,0), NORMAL_RAND)
scale = generator("vector", list(0.9,0.9), list(1.1,1.1), NORMAL_RAND)
gravity = list(0, -0.9)

View File

@@ -4,71 +4,79 @@
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
anchored = TRUE
/// If we're inside something inside a mob, display off that mob too
#define PARTICLE_ATTACH_MOB (1<<0)
///objects can only have one particle on them at a time, so we use these abstract effects to hold and display the effects. You know, so multiple particle effects can exist at once.
///also because some objects do not display particles due to how their visuals are built
/obj/effect/abstract/particle_holder
anchored = TRUE
vis_flags = VIS_INHERIT_ID | VIS_INHERIT_PLANE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
name = "particle holder"
desc = "How are you reading this? Please make a bug report :)"
appearance_flags = KEEP_APART|KEEP_TOGETHER|TILE_BOUND|PIXEL_SCALE|LONG_GLIDE //movable appearance_flags plus KEEP_APART and KEEP_TOGETHER
vis_flags = VIS_INHERIT_PLANE
layer = ABOVE_ALL_MOB_LAYER
///typepath of the last location we're in, if it's different when moved then we need to update vis contents
var/last_attached_location_type
///the main item we're attached to at the moment, particle holders hold particles for something
var/datum/weakref/weak_attached
///besides the item we're also sometimes attached to other stuff! (items held emitting particles on a mob)
var/datum/weakref/weak_additional
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
anchored = TRUE
/// Holds info about how this particle emitter works
/// See \code\__DEFINES\particles.dm
var/particle_flags = NONE
///list of all particle emitters
var/list/emitters = list()
/obj/effect/abstract/particle_holder/Initialize(mapload)
var/atom/parent
/obj/effect/abstract/particle_holder/Initialize(mapload, particle_path = /particles/smoke, particle_flags = NONE)
. = ..()
if(!loc)
stack_trace("particle holder was created with no loc!")
return INITIALIZE_HINT_QDEL
if(ismovable(loc))
RegisterSignal(loc, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
RegisterSignal(loc, COMSIG_PARENT_QDELETING, PROC_REF(on_qdel))
weak_attached = WEAKREF(loc)
update_visual_contents(loc)
// We nullspace ourselves because some objects use their contents (e.g. storage) and some items may drop everything in their contents on deconstruct.
parent = loc
loc = null
// Mouse opacity can get set to opaque by some objects when placed into the object's contents (storage containers).
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
src.particle_flags = particle_flags
particles = new particle_path()
// /atom doesn't have vis_contents, /turf and /atom/movable do
var/atom/movable/lie_about_areas = parent
lie_about_areas.vis_contents += src
RegisterSignal(parent, COMSIG_PARENT_QDELETING, PROC_REF(parent_deleted))
if(particle_flags & PARTICLE_ATTACH_MOB)
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
on_move(parent, null, NORTH)
/obj/effect/abstract/particle_holder/Destroy(force)
var/atom/movable/attached = weak_attached?.resolve()
var/atom/movable/additional_attached
if(weak_additional)
additional_attached = weak_additional?.resolve()
if(attached)
attached.vis_contents -= src
UnregisterSignal(loc, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING))
if(additional_attached)
additional_attached.vis_contents -= src
QDEL_NULL(emitters)
QDEL_NULL(particles)
parent = null
return ..()
///signal called when parent is moved
/// Non movables don't delete contents on destroy, so we gotta do this
/obj/effect/abstract/particle_holder/proc/parent_deleted(datum/source)
SIGNAL_HANDLER
qdel(src)
/// signal called when a parent that's been hooked into this moves
/// does a variety of checks to ensure overrides work out properly
/obj/effect/abstract/particle_holder/proc/on_move(atom/movable/attached, atom/oldloc, direction)
SIGNAL_HANDLER
if(attached.loc.type != last_attached_location_type)
update_visual_contents(attached)
///signal called when parent is deleted
/obj/effect/abstract/particle_holder/proc/on_qdel(atom/movable/attached, force)
SIGNAL_HANDLER
qdel(src)//our parent is gone and we need to be as well
if(!(particle_flags & PARTICLE_ATTACH_MOB))
return
///logic proc for particle holders, aka where they move.
///subtypes of particle holders can override this for particles that should always be turf level or do special things when repositioning.
///this base subtype has some logic for items, as the loc of items becomes mobs very often hiding the particles
/obj/effect/abstract/particle_holder/proc/update_visual_contents(atom/movable/attached_to)
//remove old
if(weak_additional)
var/atom/movable/resolved_location = weak_additional?.resolve()
if(resolved_location)
resolved_location.vis_contents -= src
//add to new
if(isitem(attached_to) && ismob(attached_to.loc)) //special case we want to also be emitting from the mob
var/mob/particle_mob = attached_to.loc
last_attached_location_type = attached_to.loc
weak_additional = WEAKREF(particle_mob)
if(ismob(oldloc))
var/mob/particle_mob = oldloc
particle_mob.vis_contents -= src
// If we're sitting in a mob, we want to emit from it too, for vibes and shit
if(ismob(attached.loc))
var/mob/particle_mob = attached.loc
particle_mob.vis_contents += src
//readd to ourselves
attached_to.vis_contents |= src
/// Sets the particles position to the passed coordinate list (X, Y, Z)
/// See [https://www.byond.com/docs/ref/#/{notes}/particles] for position documentation
/obj/effect/abstract/particle_holder/proc/set_particle_position(list/pos)
particles.position = pos

View File

@@ -92,7 +92,7 @@
else if(drowning)
stop_drowning(L)
drowning = FALSE
L.adjust_fire_stacks(-3)
L.adjust_wet_stacks(3)
/datum/component/swimming/proc/is_drowning(mob/living/victim)
var/obj/item/pool/helditem = victim.get_active_held_item()

View File

@@ -192,7 +192,7 @@
M.AdjustUnconscious(-reac_volume*0.3 SECONDS)
M.AdjustSleeping(-reac_volume*0.5 SECONDS)
M.adjust_fire_stacks(-(reac_volume / 10) * M.get_permeability(null, TRUE))
M.adjust_wet_stacks((reac_volume / 10) * M.get_permeability(null, TRUE))
M.extinguish_mob() // permeability affects the negative fire stacks but not the extinguishing
..()

View File

@@ -291,7 +291,7 @@
/datum/reagent/firefighting_foam/reaction_mob(mob/living/M, methods=TOUCH, reac_volume)
if(methods & (VAPOR|TOUCH))
M.adjust_fire_stacks(-reac_volume)
M.adjust_wet_stacks(reac_volume)
M.extinguish_mob()
..()

View File

@@ -337,7 +337,7 @@
if(SLIME_ACTIVATE_MINOR)
to_chat(user, span_notice("You activate [src]. You start feeling colder!"))
user.extinguish_mob()
user.adjust_fire_stacks(-20)
user.adjust_wet_stacks(20)
user.reagents.add_reagent(/datum/reagent/consumable/frostoil,4)
user.reagents.add_reagent(/datum/reagent/medicine/cryoxadone,5)
return 100

Binary file not shown.

After

Width:  |  Height:  |  Size: 545 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

View File

@@ -758,6 +758,7 @@
#include "code\datums\status_effects\debuffs\drowsiness.dm"
#include "code\datums\status_effects\debuffs\drugginess.dm"
#include "code\datums\status_effects\debuffs\drunk.dm"
#include "code\datums\status_effects\debuffs\fire_stacks.dm"
#include "code\datums\status_effects\debuffs\hallucination.dm"
#include "code\datums\status_effects\debuffs\jitteriness.dm"
#include "code\datums\status_effects\debuffs\knuckleroot.dm"

View File

@@ -71,9 +71,10 @@
check_vampire_upgrade()
owner.special_role = "vampire"
owner.current.faction += "vampire"
var/mob/living/carbon/human/C = owner.current
if(istype(C))
var/obj/item/organ/brain/B = C.getorganslot(ORGAN_SLOT_BRAIN)
if(ishuman(owner.current))
var/mob/living/carbon/human/H = owner.current
RegisterSignal(H, COMSIG_HUMAN_BURNING, PROC_REF(handle_fire))
var/obj/item/organ/brain/B = H.getorganslot(ORGAN_SLOT_BRAIN)
if(B)
B.organ_flags &= ~ORGAN_VITAL
B.decoy_override = TRUE
@@ -86,6 +87,7 @@
owner.special_role = null
if(ishuman(owner.current))
var/mob/living/carbon/human/H = owner.current
UnregisterSignal(H, COMSIG_HUMAN_BURNING)
if(owner && H.hud_used && H.hud_used.vamp_blood_display)
H.hud_used.vamp_blood_display.invisibility = INVISIBILITY_ABSTRACT
for(var/O in objectives_given)
@@ -199,6 +201,11 @@
L.ignite_mob()
return
/datum/antagonist/vampire/proc/handle_fire()
var/mob/living/carbon/human/dude = owner.current
if(dude.on_fire && dude.stat == DEAD && !get_ability(/datum/vampire_passive/full))
dude.dust()
/datum/antagonist/vampire/proc/check_sun()
var/mob/living/carbon/C = owner.current
if(!C)

View File

@@ -67,13 +67,6 @@
if (vampire.total_blood >= 5 && vampire.usable_blood < vampire.total_blood)
vampire.usable_blood = min(vampire.usable_blood + 5, vampire.total_blood) // 5 units every 10 seconds
/mob/living/carbon/human/handle_fire()
. = ..()
if(mind)
var/datum/antagonist/vampire/L = mind.has_antag_datum(/datum/antagonist/vampire)
if(on_fire && stat == DEAD && L && !L.get_ability(/datum/vampire_passive/full))
dust()
/obj/item/storage/book/bible/attack(mob/living/M, mob/living/carbon/human/user, heal_mode = TRUE)
. = ..()
if(!(user.mind && user.mind.holy_role) && is_vampire(user))

View File

@@ -220,9 +220,8 @@
low_power_warning = FALSE
/datum/species/preternis/proc/handle_wetness(mob/living/carbon/human/H)
if(H.fire_stacks <= -1)
if(H.has_status_effect(/datum/status_effect/fire_handler/wet_stacks))
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "preternis_wet", /datum/mood_event/wet_preternis)
H.fire_stacks++ //makes them dry off faster so it's less tedious, more punchy
H.add_movespeed_modifier("preternis_water", update = TRUE, priority = 102, multiplicative_slowdown = 0.5, blacklisted_movetypes=(FLYING|FLOATING))
//damage has a flat amount with an additional amount based on how wet they are
H.adjustStaminaLoss(4 - (H.fire_stacks / 2))
@@ -236,6 +235,7 @@
if(prob(50))
playsound(get_turf(H), "sparks", 30, 1)
do_sparks(rand(1,3), FALSE, H)
H.adjust_wet_stacks(-1)
soggy = TRUE
H.throw_alert("preternis_wet", /atom/movable/screen/alert/preternis_wet)
else if(soggy)