mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-18 21:15:21 +00:00
## About The Pull Request This PR replaces clone damage dealt by slimes with a new status effect, "Covered in Slime". The status effect is applied when you wrestle a slime off. The status effect has a chance of not applying if your biohazard protection on your head and chest is good enough. It deals brute damage over time and gets removed when you stand under the shower for about 10 seconds or when you are about to enter softcrit. As a direct consequence of adding this feature I added showers to the North Star and Birdshot Xenobiology Labs. I'm sorry, I'm sure you wanted to make a statement with this, but we kind of require them in there now. ## Why It's Good For The Game One source of clone damage eliminated whilst hopefully keeping a "unique" interaction when dealing with slimes. No other source of clone damage has been touched. Clone damage is a damage type that shouldn't exist anymore, it's a relic left from the era of cloning and it's so specific of a damage type that it rarely gets used as a result. It really should be a type of affliction (wound etc) instead of its own damage counter. However, some things in the game still depend on clone damage being around, so those needs to be addressed first. We start off with slimes in this PR. This status effect either lets you either continue with your work if you react fast enough or it forces you to medbay, giving a victim more control over the situation, as opposed to just being dealt a rare damage type that always forces you to go to medbay if you want it healed. ## Changelog 🆑 distributivgesetz add: Replaced slime clone damage with a "Covered in Slime" status effect that deals brute damage over time and can be washed off by standing under a shower. add: Northstar and Birdshot Xenobiology have been outfitted with a new shower. code: Replaced the magic strings in slime code with macros. Also included some warnings to anyone daring to touch the macros. /🆑
291 lines
8.1 KiB
Plaintext
291 lines
8.1 KiB
Plaintext
/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
|
|
if(isbasicmob(owner))
|
|
var/mob/living/basic/basic_owner = owner
|
|
if(!(basic_owner.basic_mob_flags & FLAMMABLE_MOB))
|
|
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(owner.fire_stack_decay_rate * seconds_between_ticks)
|
|
|
|
if(stacks <= 0)
|
|
qdel(src)
|
|
return TRUE
|
|
|
|
var/datum/gas_mixture/air = owner.loc.return_air()
|
|
if(!air.gases[/datum/gas/oxygen] || air.gases[/datum/gas/oxygen][MOLES] < 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)
|
|
victim.add_mood_event("on_fire", /datum/mood_event/on_fire)
|
|
victim.add_mob_memory(/datum/memory/was_burning)
|
|
|
|
/**
|
|
* 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
|
|
owner.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)
|