mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
[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:
@@ -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()
|
||||
|
||||
288
code/datums/status_effects/debuffs/fire_stacks.dm
Normal file
288
code/datums/status_effects/debuffs/fire_stacks.dm
Normal 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)
|
||||
@@ -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 //
|
||||
////////////////
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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!
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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!
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
..()
|
||||
|
||||
|
||||
@@ -370,9 +370,6 @@
|
||||
// yogs end
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/handle_fire()
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/ignite_mob()
|
||||
return FALSE
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
..()
|
||||
|
||||
|
||||
@@ -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()
|
||||
..()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
BIN
icons/effects/particles/generic.dmi
Normal file
BIN
icons/effects/particles/generic.dmi
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 545 B |
BIN
icons/mob/effects/onfire.dmi
Normal file
BIN
icons/mob/effects/onfire.dmi
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 152 KiB |
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user