mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-16 03:56:20 +00:00
## About The Pull Request Hey there, I think it's commonly held that clone damage sucks and is overused. One of the last places where it was in slot machine code as a type of "immutable" damage that would cause you to die if you didn't leave and get medical attention. It had a lot of silliness and I'm not sure if a lot of it was meant to work the way it was, but here we are. So, what's the changes? * The Cursed Slot Machine will give you a status effect that will "curse" you with repeated damage. After five curses, you get gibbed (similar to the old behavior of the machine). Each curse has it's own change to the status effect, with a lot of depth included. Let me know if the fluff messages about the status effect change sucks, I think it's neat though. * A person with the curse will smoke. I wanted this to look a bit more "steamy" or grey, but I think it's a decent way of communicating that shit is fucked up with that dude. * You also get a branded wound after your first failure at the slot machine. Ouchers. Should get it looked at by a doctor. * We also throw a nice screen alert and all of that jazz. * I also cleaned up all of the code relating to the slot machine (including a stupid double and), and did some tinkering with the status effects framework to get the desired effect I wanted. I hope you enjoy it as much as I did making it. We use cooldowns and stuff between slot machine pulls. * If _anyone_ wins on the slot machine, all curses/brands are lifted. Lucky jackpot! * A lot of the stuff in this code has a lot of vars that might not be modified codewise in case admins still want to jank with this for events. ## Why It's Good For The Game Clone damage stinks, and I don't really like it as a way to subvert the whole "oh you can't use legion cores to get your way". It's a cursed slot machine, and it should do long term damage so that even if you expend all of the resources on the station, it might all be for naught. It's a horrible price to pay in your search for that d20. I think the negative side effects are pretty OK as far as balance, earlier iterations of this concept had you die _way_ too fast. All in all, it's just way more of an interesting interaction than "you take damage and then go to medbay and then come back in the hopes of gambling a d20". ## Changelog 🆑 add: The Lavaland Cursed Slot Machine of Greed suddenly seems a lot more sinister... refactor: Instead of taking clone damage from the cursed slot machine, you now get a status effect with a number of curses associated with it. There's some interesting florid language associated with the status effect as a nicety until your eventual gibbing from chasing that prize. /🆑 I remain undecided if I should keep the curse limit uncapped (but have the damages increase rapidly after the 5-curse threshold), so I left it as the `gib()` from the old code. Let me know your thoughts, but I really don't like the thought that getting the fabled d20 is easy. --------- Co-authored-by: Fikou <23585223+Fikou@users.noreply.github.com>
209 lines
7.6 KiB
Plaintext
209 lines
7.6 KiB
Plaintext
/// Status effects are used to apply temporary or permanent effects to mobs.
|
|
/// This file contains their code, plus code for applying and removing them.
|
|
/datum/status_effect
|
|
/// The ID of the effect. ID is used in adding and removing effects to check for duplicates, among other things.
|
|
var/id = "effect"
|
|
/// When set initially / in on_creation, this is how long the status effect lasts in deciseconds.
|
|
/// While processing, this becomes the world.time when the status effect will expire.
|
|
/// -1 = infinite duration.
|
|
var/duration = -1
|
|
/// When set initially / in on_creation, this is how long between [proc/tick] calls in deciseconds.
|
|
/// Note that this cannot be faster than the processing subsystem you choose to fire the effect on. (See: [var/processing_speed])
|
|
/// While processing, this becomes the world.time when the next tick will occur.
|
|
/// -1 = will prevent ticks, and if duration is also unlimited (-1), stop processing wholesale.
|
|
var/tick_interval = 1 SECONDS
|
|
/// The mob affected by the status effect.
|
|
var/mob/living/owner
|
|
/// How many of the effect can be on one mob, and/or what happens when you try to add a duplicate.
|
|
var/status_type = STATUS_EFFECT_UNIQUE
|
|
/// If TRUE, we call [proc/on_remove] when owner is deleted. Otherwise, we call [proc/be_replaced].
|
|
var/on_remove_on_mob_delete = FALSE
|
|
/// The typepath to the alert thrown by the status effect when created.
|
|
/// Status effect "name"s and "description"s are shown to the owner here.
|
|
var/alert_type = /atom/movable/screen/alert/status_effect
|
|
/// The alert itself, created in [proc/on_creation] (if alert_type is specified).
|
|
var/atom/movable/screen/alert/status_effect/linked_alert
|
|
/// Used to define if the status effect should be using SSfastprocess or SSprocessing
|
|
var/processing_speed = STATUS_EFFECT_FAST_PROCESS
|
|
/// Do we self-terminate when a fullheal is called?
|
|
var/remove_on_fullheal = FALSE
|
|
/// If remove_on_fullheal is TRUE, what flag do we need to be removed?
|
|
var/heal_flag_necessary = HEAL_STATUS
|
|
/// 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))
|
|
|
|
/// Called from New() with any supplied status effect arguments.
|
|
/// Not guaranteed to exist by the end.
|
|
/// Returning FALSE from on_apply will stop on_creation and self-delete the effect.
|
|
/datum/status_effect/proc/on_creation(mob/living/new_owner, ...)
|
|
if(new_owner)
|
|
owner = new_owner
|
|
if(QDELETED(owner) || !on_apply())
|
|
qdel(src)
|
|
return
|
|
if(owner)
|
|
LAZYADD(owner.status_effects, src)
|
|
RegisterSignal(owner, COMSIG_LIVING_POST_FULLY_HEAL, PROC_REF(remove_effect_on_heal))
|
|
|
|
if(duration != -1)
|
|
duration = world.time + duration
|
|
if(tick_interval != -1)
|
|
tick_interval = world.time + tick_interval
|
|
|
|
if(alert_type)
|
|
var/atom/movable/screen/alert/status_effect/new_alert = owner.throw_alert(id, alert_type)
|
|
new_alert.attached_effect = src //so the alert can reference us, if it needs to
|
|
linked_alert = new_alert //so we can reference the alert, if we need to
|
|
|
|
if(duration > world.time || tick_interval > world.time) //don't process if we don't care
|
|
switch(processing_speed)
|
|
if(STATUS_EFFECT_FAST_PROCESS)
|
|
START_PROCESSING(SSfastprocess, src)
|
|
if(STATUS_EFFECT_NORMAL_PROCESS)
|
|
START_PROCESSING(SSprocessing, src)
|
|
|
|
update_particles()
|
|
|
|
return TRUE
|
|
|
|
/datum/status_effect/Destroy()
|
|
switch(processing_speed)
|
|
if(STATUS_EFFECT_FAST_PROCESS)
|
|
STOP_PROCESSING(SSfastprocess, src)
|
|
if(STATUS_EFFECT_NORMAL_PROCESS)
|
|
STOP_PROCESSING(SSprocessing, src)
|
|
if(owner)
|
|
linked_alert = null
|
|
owner.clear_alert(id)
|
|
LAZYREMOVE(owner.status_effects, src)
|
|
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.
|
|
// If you're adding processed effects, put them in [proc/tick]
|
|
// instead of extending / overriding the process() proc.
|
|
/datum/status_effect/process(seconds_per_tick)
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
if(QDELETED(owner))
|
|
qdel(src)
|
|
return
|
|
if(tick_interval != -1 && tick_interval < world.time)
|
|
var/tick_length = initial(tick_interval)
|
|
tick(tick_length / (1 SECONDS))
|
|
tick_interval = world.time + tick_length
|
|
if(QDELING(src))
|
|
// tick deleted us, no need to continue
|
|
return
|
|
if(duration != -1 && duration < world.time)
|
|
qdel(src)
|
|
|
|
/// Called whenever the effect is applied in on_created
|
|
/// Returning FALSE will cause it to delete itself during creation instead.
|
|
/datum/status_effect/proc/on_apply()
|
|
return TRUE
|
|
|
|
/// Gets and formats examine text associated with our status effect.
|
|
/// Return 'null' to have no examine text appear (default behavior).
|
|
/datum/status_effect/proc/get_examine_text()
|
|
return null
|
|
|
|
/**
|
|
* Called every tick from process().
|
|
* This is only called of tick_interval is not -1.
|
|
*
|
|
* Note that every tick =/= every processing cycle.
|
|
*
|
|
* * seconds_between_ticks = This is how many SECONDS that elapse between ticks.
|
|
* This is a constant value based upon the initial tick interval set on the status effect.
|
|
* It is similar to seconds_per_tick, from processing itself, but adjusted to the status effect's tick interval.
|
|
*/
|
|
/datum/status_effect/proc/tick(seconds_between_ticks)
|
|
return
|
|
|
|
/// Called whenever the buff expires or is removed (qdeleted)
|
|
/// Note that at the point this is called, it is out of the
|
|
/// owner's status_effects list, but owner is not yet null
|
|
/datum/status_effect/proc/on_remove()
|
|
return
|
|
|
|
/// Called instead of on_remove when a status effect
|
|
/// of status_type STATUS_EFFECT_REPLACE is replaced by itself,
|
|
/// or when a status effect with on_remove_on_mob_delete
|
|
/// set to FALSE has its mob deleted
|
|
/datum/status_effect/proc/be_replaced()
|
|
linked_alert = null
|
|
owner.clear_alert(id)
|
|
LAZYREMOVE(owner.status_effects, src)
|
|
owner = null
|
|
qdel(src)
|
|
|
|
/// Called before being fully removed (before on_remove)
|
|
/// Returning FALSE will cancel removal
|
|
/datum/status_effect/proc/before_remove()
|
|
return TRUE
|
|
|
|
/// Called when a status effect of status_type STATUS_EFFECT_REFRESH
|
|
/// has its duration refreshed in apply_status_effect - is passed New() args
|
|
/datum/status_effect/proc/refresh(effect, ...)
|
|
var/original_duration = initial(duration)
|
|
if(original_duration == -1)
|
|
return
|
|
duration = world.time + original_duration
|
|
|
|
/// Adds nextmove modifier multiplicatively to the owner while applied
|
|
/datum/status_effect/proc/nextmove_modifier()
|
|
return 1
|
|
|
|
/// Adds nextmove adjustment additiviely to the owner while applied
|
|
/datum/status_effect/proc/nextmove_adjust()
|
|
return 0
|
|
|
|
/// Signal proc for [COMSIG_LIVING_POST_FULLY_HEAL] to remove us on fullheal
|
|
/datum/status_effect/proc/remove_effect_on_heal(datum/source, heal_flags)
|
|
SIGNAL_HANDLER
|
|
|
|
if(!remove_on_fullheal)
|
|
return
|
|
|
|
if(!heal_flag_necessary || (heal_flags & heal_flag_necessary))
|
|
qdel(src)
|
|
|
|
/// Remove [seconds] of duration from the status effect, qdeling / ending if we eclipse the current world time.
|
|
/datum/status_effect/proc/remove_duration(seconds)
|
|
if(duration == -1) // Infinite duration
|
|
return FALSE
|
|
|
|
duration -= seconds
|
|
if(duration <= world.time)
|
|
qdel(src)
|
|
return TRUE
|
|
|
|
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 base type for status effect alerts
|
|
/atom/movable/screen/alert/status_effect
|
|
name = "Curse of Mundanity"
|
|
desc = "You don't feel any different..."
|
|
/// The status effect we're linked to
|
|
var/datum/status_effect/attached_effect
|
|
|
|
/atom/movable/screen/alert/status_effect/Destroy()
|
|
attached_effect = null //Don't keep a ref now
|
|
return ..()
|
|
|