Files
Bubberstation/code/game/atom/atom_act.dm
EnterTheJake d8c8b79c44 Rust Heretic rework: THE PUKENING. (#83006)
## About The Pull Request
Turf rusting is now based on knowledge instead of RNG; toxic damage on
spells has been replaced with disgust; rust walkers are a bit easier to
summon and show up early in the tree.

Rust ascension spread has been massively increased and immunities while
on Rust have been updated.
## Why It's Good For The Game

This is a massive list of changes, but the tl:dr is Rust heretic design
is pretty barebones and dated in its current state. I'm going to try my
best to explain why that is and why it needs to change.

###  RNG on rusting is bad

**Problem** : quite a lot of turfs cannot be rusted, and reinforced
turfs rusting is tied to RNG, the emergency shuttle floors are also
unrustable, making an ascended heretic not threatening at all to an
escaping crew.

**Solution**: Heretic rusting prowess is now tied to knowledge
progression; reinf wall rusting is no longer tied to RNG; the emergency
shuttle is now rustable if you have accrued enough knowledge.

**Explanation** : I've been adopting the code from a previous PR that
sadly didn't make the light of day.

Link: https://github.com/tgstation/tgstation/pull/65361

The goal is to have Heretic rusting be more consistent, so that if you
ascend the shuttle is no longer a safe refuge.

**Grasp Of Rust**: Basic floors and walls.
**Mark Of Rust**: Reinf floors and walls (takes 3 applications of rust
to fully destroy).
**Toxic Blade** Titanium and Plastitanium( still takes 3 applications of
rust to destroy).
**Ascension**: almost everything save for admin walls, glass, and
silver.

### A territorial antagonist with no tools to defend its turf

**Problem**: Rust heretic is forced into a territorial playstyle, but
it's heavily diminished by rusted turfs not having any negative effect
on the crew whatsoever, Toxic damage on plume and blade is also kind of
bad and has no synergy with the rest of the kit.

Lastly, while fitting to the theme of Rust; mark detonation destroying
clothes and items can end up being more harmful to the heretic, as
destroying a secoff's flashbang will result in you getting stunned and
killed.

**Solution**: Rusted floors are no longer safe for the crew; walking
over Rust will add a small buildup of disgust, silicons will receive
ticking damage, Toxic damage on Rust skills has been replaced with
disgust buildup and a chem purge effect to prevent the crew from
cheesing the debuff with sol dry.

**Explaination** "The goal behind this change is to prevent the crew to
just be able to walk willy nilly into an eldritchly decayed area without
repercussions, plus I feel like disgust is a fitting debuff for Rusties
for a number of reasons.

1) Lore wise, your goal is to turn the entire station into a garbage
dump.

2) It fits for fighting a territorial antagonist, it's not immediately
threatening on its own, but if you overstay your welcome, it has dire
consequences.

3) We don't really do much with disgust as a status effect, far as i
know, this'll be the first iteration of it being used for an antagonist
toolset.

4) It gives reason to the crew to act hostile towards the Heretic, as
you are essentially making their work area inhabitable.

I've also Slightly increased the healing on leeching walk and gave it
some minor temperature regulation (you won't be able to outtemp space
cold).

### Rust Walkers

**Problem**: Rust walkers might as well not exist in their current
state; they are one of the latest heretic unlocks, and the recipe for
summoning one is INSANE now that you cannot decapitate mobs anymore.

**Solution**: Rust walkers pop up a bit earlier in the tree; the ritual
to summon them has more reasonable reagents (wires, pools of vomit, iron
sheets) and they have increased health.

**Explanation**: : There is not a lot to add to this. without walkers,
Rust heretics are fairly slow at spreading rust, by making rust walkers
have reasonable summoning reagents, we ease that problem; lastly i've
slightly bumped their hp, as i felt 75 hp was a bit low.

### Underwhelming ascension

**Problem**: The spread rate from the ascension is downright ATROCIOUS
in its current state, i actually ran multiple tests on different maps,
on Metastation it can take up to 40 minutes for the rust to spread to
the entire station, considering an ascended heretic results in an
immediate shuttle call, it's unecceptable in its current form.

Solution: Rust spread is now a hybridization between old ascension and
Wizard tranformation ritual.

**Explanation**: The spread rate in its current form is painstakingly
slow and has a tendency to reach one corner of the map and compound on
itself, i've borrowed the code from the wizard final ritual
"transformation" and gave it my own spin so that given enough time it
will cover the station more or less evenly, it can now spread through
all z levels.

Video example: https://www.youtube.com/watch?v=jZ5zMrNM6Jw

I've also updated the immunities you gain on ascension to ignore
slowdown and stasis from Cryogelidia.

The whole point of rust ascension is to become immune to crowd control,
i've seen far too many ascended heretics die to a single bola or cryo
syringe, that's pretty lame so i fixed that.

Lastly, aggressive spread has had its radius reduced in exchange for the
spread being consistent now; cooldown is also halved when you ascend, to
better help the heretic go on the offensive.
2024-05-16 14:55:45 -04:00

238 lines
8.5 KiB
Plaintext

/*
* +++++++++++++++++++++++++++++++++++++++++ ABOUT THIS FILE +++++++++++++++++++++++++++++++++++++++++++++
* Not everything here necessarily has the name pattern of [x]_act()
* This is a file for various atom procs that simply get called when something is happening to that atom.
* If you're adding something here, you likely want a signal and SHOULD_CALL_PARENT(TRUE)
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/
/**
* Respond to fire being used on our atom
*
* Default behaviour is to send [COMSIG_ATOM_FIRE_ACT] and return
*/
/atom/proc/fire_act(exposed_temperature, exposed_volume)
SEND_SIGNAL(src, COMSIG_ATOM_FIRE_ACT, exposed_temperature, exposed_volume)
return FALSE
/**
* Sends [COMSIG_ATOM_EXTINGUISH] signal, which properly removes burning component if it is present.
*
* Default behaviour is to send [COMSIG_ATOM_ACID_ACT] and return
*/
/atom/proc/extinguish()
SHOULD_CALL_PARENT(TRUE)
return SEND_SIGNAL(src, COMSIG_ATOM_EXTINGUISH)
/**
* React to being hit by an explosion
*
* Should be called through the [EX_ACT] wrapper macro.
* The wrapper takes care of the [COMSIG_ATOM_EX_ACT] signal.
* as well as calling [/atom/proc/contents_explosion].
*
* Returns TRUE by default, and behavior should be implemented on children procs on a per-atom basis. Should only return FALSE if we resist the explosion for any reason.
* We assume that the default is TRUE because all atoms should be considered destructible in some manner unless they explicitly opt out (in our current framework).
* However, the return value itself doesn't have any external consumers, it's only so children procs can listen to the value from their parent procs (due to the nature of the [EX_ACT] macro).
* Thus, the return value only matters on overrides of this proc, and the only thing that truly matters is the code that is executed (applying damage, calling damage procs, etc.)
*
*/
/atom/proc/ex_act(severity, target)
set waitfor = FALSE
return TRUE
/// Handle what happens when your contents are exploded by a bomb
/atom/proc/contents_explosion(severity, target)
return //For handling the effects of explosions on contents that would not normally be effected
/**
* React to a hit by a blob objecd
*
* default behaviour is to send the [COMSIG_ATOM_BLOB_ACT] signal
*/
/atom/proc/blob_act(obj/structure/blob/attacking_blob)
var/blob_act_result = SEND_SIGNAL(src, COMSIG_ATOM_BLOB_ACT, attacking_blob)
if (blob_act_result & COMPONENT_CANCEL_BLOB_ACT)
return FALSE
return TRUE
/**
* React to an EMP of the given severity
*
* Default behaviour is to send the [COMSIG_ATOM_PRE_EMP_ACT] and [COMSIG_ATOM_EMP_ACT] signal
*
* If the pre-signal does not return protection, and there are attached wires then we call
* [emp_pulse][/datum/wires/proc/emp_pulse] on the wires
*
* We then return the protection value
*/
/atom/proc/emp_act(severity)
// SKYRAT EDIT - REMOVAL
//SHOULD_CALL_PARENT(TRUE)
var/protection = SEND_SIGNAL(src, COMSIG_ATOM_PRE_EMP_ACT, severity)
if(!(protection & EMP_PROTECT_WIRES) && istype(wires))
wires.emp_pulse()
SEND_SIGNAL(src, COMSIG_ATOM_EMP_ACT, severity, protection)
return protection // Pass the protection value collected here upwards
/**
* React to a hit by a projectile object
*
* @params
* * hitting_projectile - projectile
* * def_zone - zone hit
* * piercing_hit - is this hit piercing or normal?
*/
/atom/proc/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit = FALSE)
SHOULD_CALL_PARENT(TRUE)
var/sigreturn = SEND_SIGNAL(src, COMSIG_ATOM_PRE_BULLET_ACT, hitting_projectile, def_zone)
if(sigreturn & COMPONENT_BULLET_PIERCED)
return BULLET_ACT_FORCE_PIERCE
if(sigreturn & COMPONENT_BULLET_BLOCKED)
return BULLET_ACT_BLOCK
if(sigreturn & COMPONENT_BULLET_ACTED)
return BULLET_ACT_HIT
SEND_SIGNAL(src, COMSIG_ATOM_BULLET_ACT, hitting_projectile, def_zone)
if(QDELETED(hitting_projectile)) // Signal deleted it?
return BULLET_ACT_BLOCK
return hitting_projectile.on_hit(
target = src,
// This armor check only matters for the visuals and messages in on_hit(), it's not actually used to reduce damage since
// only living mobs use armor to reduce damage, but on_hit() is going to need the value no matter what is shot.
blocked = check_projectile_armor(def_zone, hitting_projectile),
pierce_hit = piercing_hit,
)
/**
* React to being hit by a thrown object
*
* Default behaviour is to call [hitby_react][/atom/proc/hitby_react] on ourselves after 2 seconds if we are dense
* and under normal gravity.
*
* Im not sure why this the case, maybe to prevent lots of hitby's if the thrown object is
* deleted shortly after hitting something (during explosions or other massive events that
* throw lots of items around - singularity being a notable example)
*/
/atom/proc/hitby(atom/movable/hitting_atom, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
SEND_SIGNAL(src, COMSIG_ATOM_HITBY, hitting_atom, skipcatch, hitpush, blocked, throwingdatum)
if(density && !has_gravity(hitting_atom)) //thrown stuff bounces off dense stuff in no grav, unless the thrown stuff ends up inside what it hit(embedding, bola, etc...).
addtimer(CALLBACK(src, PROC_REF(hitby_react), hitting_atom), 0.2 SECONDS)
/**
* We have have actually hit the passed in atom
*
* Default behaviour is to move back from the item that hit us
*/
/atom/proc/hitby_react(atom/movable/harmed_atom)
if(harmed_atom && isturf(harmed_atom.loc))
step(harmed_atom, REVERSE_DIR(harmed_atom.dir))
///Handle the atom being slipped over
/atom/proc/handle_slip(mob/living/carbon/slipped_carbon, knockdown_amount, obj/slipping_object, lube, paralyze, force_drop)
return
///Used for making a sound when a mob involuntarily falls into the ground.
/atom/proc/handle_fall(mob/faller)
return
///Respond to the singularity eating this atom
/atom/proc/singularity_act()
return
/**
* Respond to the singularity pulling on us
*
* Default behaviour is to send [COMSIG_ATOM_SING_PULL] and return
*/
/atom/proc/singularity_pull(obj/singularity/singularity, current_size)
SEND_SIGNAL(src, COMSIG_ATOM_SING_PULL, singularity, current_size)
/**
* Respond to acid being used on our atom
*
* Default behaviour is to send [COMSIG_ATOM_ACID_ACT] and return
*/
/atom/proc/acid_act(acidpwr, acid_volume)
SEND_SIGNAL(src, COMSIG_ATOM_ACID_ACT, acidpwr, acid_volume)
return FALSE
/**
* Respond to an emag being used on our atom
*
* Args:
* * mob/user: The mob that used the emag. Nullable.
* * obj/item/card/emag/emag_card: The emag that was used. Nullable.
*
* Returns:
* TRUE if the emag had any effect, falsey otherwise.
*/
/atom/proc/emag_act(mob/user, obj/item/card/emag/emag_card)
return (SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT, user, emag_card))
/**
* Respond to narsie eating our atom
*
* Default behaviour is to send [COMSIG_ATOM_NARSIE_ACT] and return
*/
/atom/proc/narsie_act()
SEND_SIGNAL(src, COMSIG_ATOM_NARSIE_ACT)
/**
* Respond to an electric bolt action on our item
*
* Default behaviour is to return, we define here to allow for cleaner code later on
*/
/atom/proc/zap_act(power, zap_flags)
return
/**
* Called when the atom log's in or out
*
* Default behaviour is to call on_log on the location this atom is in
*/
/atom/proc/on_log(login)
if(loc)
loc.on_log(login)
/**
* Causes effects when the atom gets hit by a rust effect from heretics
*
* Override this if you want custom behaviour in whatever gets hit by the rust
* /turf/rust_turf should be used instead for overriding rust on turfs
*/
/atom/proc/rust_heretic_act()
return
///wrapper proc that passes our mob's rust_strength to the target we are rusting
/mob/living/proc/do_rust_heretic_act(atom/target)
var/datum/antagonist/heretic/heretic_data = IS_HERETIC(src)
target.rust_heretic_act(heretic_data?.rust_strength)
/mob/living/basic/heretic_summon/rust_walker/do_rust_heretic_act(atom/target)
target.rust_heretic_act(4)
///Called when something resists while this atom is its loc
/atom/proc/container_resist_act(mob/living/user)
return
/**
* Respond to an RCD acting on our item
*
* Default behaviour is to send [COMSIG_ATOM_RCD_ACT] and return FALSE
*/
/atom/proc/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, list/rcd_data)
SEND_SIGNAL(src, COMSIG_ATOM_RCD_ACT, user, the_rcd, rcd_data["[RCD_DESIGN_MODE]"])
return FALSE
///Return the values you get when an RCD eats you?
/atom/proc/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
return FALSE
///This atom has been hit by a hulkified mob in hulk mode (user)
/atom/proc/attack_hulk(mob/living/carbon/human/user)
SEND_SIGNAL(src, COMSIG_ATOM_HULK_ATTACK, user)