mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-20 03:30:01 +01:00
## About The Pull Request This PR refactors ``effect_system``s to be a bit easier to use by getting rid of ``set_up``, allowing ``attach()`` to be chained into ``start()`` and refactoring most direct system usages in our code to use helper procs. ``set_up`` was unnecessary and only existed to allow ``New``'s behavior to be fully overriden, which is not required if we split sparks/lightning/steam into a new ``/datum/effect_system/basic`` subtype which houses the effect spreading behavior. This allows us to roll all logic from ``set_up`` into ``New`` and cut down on code complexity. Chaining setup as ``system.attach(src).start()`` also helps a bit in case no helper method exists I've added ``do_chem_smoke`` and ``do_foam`` helpers, which respectively allow chemical smoke or foam to be spawned easily without having to manually create effect datums and reagent holders. Also turns out we've had some nonfunctional effect systems which either never set themselves up, or never started, so I fixed those while I was at it (mostly by moving them to aforementioned helper procs) ## Why It's Good For The Game Cleaner code, makes it significantly easier for users to work with. Also most of our effect system usage was copypasta which was passing booleans as numbers, while perfectly fine helper procs existed in our code. ## Changelog 🆑 refactor: Refactored sparks, foam, smoke, and other miscellaneous effect systems. refactor: Vapes now have consistent rigging with cigs using the new system. fix: Fixed some effects never working. /🆑
229 lines
8.6 KiB
Plaintext
229 lines
8.6 KiB
Plaintext
// Welcome to the jetpack component
|
|
// Apply this to something when you want it to be "like a jetpack"
|
|
// So propulsion through space on move, that sort of thing
|
|
/datum/component/jetpack
|
|
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
|
|
/// Checks to ensure if we can move
|
|
var/datum/callback/check_on_move
|
|
/// Checks to ensure we can activate
|
|
var/datum/callback/check_on_activation
|
|
/// If we should stabilize ourselves when not drifting
|
|
var/stabilize = FALSE
|
|
/// The signal we listen for as an activation
|
|
var/activation_signal
|
|
/// The signal we listen for as a de-activation
|
|
var/deactivation_signal
|
|
/// The return flag our parent expects for a failed activation
|
|
var/return_flag
|
|
/// The effect system for the jet pack trail
|
|
var/datum/effect_system/trail_follow/trail
|
|
/// The typepath to instansiate our trail as, when we need it
|
|
var/effect_type
|
|
/// Drift force applied each movement tick
|
|
var/drift_force
|
|
/// Force that applied when stabiliziation is active and the player isn't moving in the same direction as the jetpack
|
|
var/stabilization_force
|
|
/// Our current user
|
|
var/mob/user
|
|
/// Last tick on which we triggered, to prevent double-dipping
|
|
var/last_force_tick
|
|
/// Last tick on which we stabilized
|
|
var/last_stabilization_tick
|
|
|
|
/**
|
|
* Arguments:
|
|
* * stabilize - If we should drift when we finish moving, or sit stable in space]
|
|
* * drift_force - How much force is applied whenever the user tries to move
|
|
* * stabilization_force - How much force is applied per tick when we try to stabilize the user
|
|
* * activation_signal - Signal we activate on
|
|
* * deactivation_signal - Signal we deactivate on
|
|
* * return_flag - Flag to return if activation fails
|
|
* * check_on_move - Callback we call each time we attempt a move, we expect it to retun true if the move is ok, false otherwise. It expects an arg, TRUE if fuel should be consumed, FALSE othewise
|
|
* * effect_type - Type of trail_follow to spawn
|
|
*/
|
|
/datum/component/jetpack/Initialize(stabilize, drift_force = 1 NEWTONS, stabilization_force = 1 NEWTONS, activation_signal, deactivation_signal, return_flag, datum/callback/check_on_move, datum/callback/check_on_activation, datum/effect_system/trail_follow/effect_type)
|
|
. = ..()
|
|
if(!isatom(parent))
|
|
return COMPONENT_INCOMPATIBLE
|
|
if(!activation_signal) // Can't activate? go away
|
|
return COMPONENT_INCOMPATIBLE
|
|
|
|
RegisterSignal(parent, activation_signal, PROC_REF(activate))
|
|
if(deactivation_signal)
|
|
RegisterSignal(parent, deactivation_signal, PROC_REF(deactivate))
|
|
|
|
src.stabilize = stabilize
|
|
src.check_on_move = check_on_move
|
|
src.check_on_activation = check_on_activation
|
|
src.activation_signal = activation_signal
|
|
src.deactivation_signal = deactivation_signal
|
|
src.return_flag = return_flag
|
|
src.effect_type = effect_type
|
|
src.drift_force = drift_force
|
|
src.stabilization_force = stabilization_force
|
|
|
|
/datum/component/jetpack/InheritComponent(datum/component/component, original, stabilize, drift_force = 1 NEWTONS, stabilization_force = 1 NEWTONS, activation_signal, deactivation_signal, return_flag, datum/callback/check_on_move, datum/callback/check_on_activation, datum/effect_system/trail_follow/effect_type)
|
|
UnregisterSignal(parent, src.activation_signal)
|
|
if(src.deactivation_signal)
|
|
UnregisterSignal(parent, src.deactivation_signal)
|
|
RegisterSignal(parent, activation_signal, PROC_REF(activate))
|
|
if(deactivation_signal)
|
|
RegisterSignal(parent, deactivation_signal, PROC_REF(deactivate))
|
|
|
|
src.stabilize = stabilize
|
|
src.check_on_move = check_on_move
|
|
src.check_on_activation = check_on_activation
|
|
src.activation_signal = activation_signal
|
|
src.deactivation_signal = deactivation_signal
|
|
src.return_flag = return_flag
|
|
src.effect_type = effect_type
|
|
src.drift_force = drift_force
|
|
src.stabilization_force = stabilization_force
|
|
|
|
if(trail && trail.effect_type != effect_type)
|
|
setup_trail(trail.holder)
|
|
|
|
/datum/component/jetpack/Destroy(force)
|
|
if(trail)
|
|
QDEL_NULL(trail)
|
|
user = null
|
|
check_on_move = null
|
|
check_on_activation = null
|
|
return ..()
|
|
|
|
/datum/component/jetpack/proc/setup_trail(mob/user)
|
|
if(trail)
|
|
QDEL_NULL(trail)
|
|
trail = new effect_type(user)
|
|
trail.auto_process = FALSE
|
|
trail.start()
|
|
|
|
/datum/component/jetpack/proc/activate(datum/source, mob/new_user)
|
|
SIGNAL_HANDLER
|
|
|
|
if(!isnull(check_on_activation) && !check_on_activation.Invoke())
|
|
return return_flag
|
|
|
|
user = new_user
|
|
RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(move_react))
|
|
RegisterSignal(user, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(pre_move_react))
|
|
RegisterSignal(user, COMSIG_MOB_CLIENT_MOVE_NOGRAV, PROC_REF(on_client_move))
|
|
RegisterSignal(user, COMSIG_MOB_ATTEMPT_HALT_SPACEMOVE, PROC_REF(on_pushoff))
|
|
RegisterSignal(user, COMSIG_MOVABLE_DRIFT_BLOCK_INPUT, PROC_REF(on_input_block))
|
|
last_stabilization_tick = world.time
|
|
START_PROCESSING(SSnewtonian_movement, src)
|
|
if (effect_type)
|
|
setup_trail(user)
|
|
|
|
/datum/component/jetpack/proc/deactivate(datum/source, mob/old_user)
|
|
SIGNAL_HANDLER
|
|
|
|
UnregisterSignal(old_user, list(COMSIG_MOVABLE_PRE_MOVE, COMSIG_MOVABLE_MOVED, COMSIG_MOB_CLIENT_MOVE_NOGRAV, COMSIG_MOB_ATTEMPT_HALT_SPACEMOVE, COMSIG_MOVABLE_DRIFT_BLOCK_INPUT))
|
|
STOP_PROCESSING(SSnewtonian_movement, src)
|
|
user = null
|
|
|
|
if(trail)
|
|
QDEL_NULL(trail)
|
|
|
|
/datum/component/jetpack/proc/move_react(mob/source)
|
|
SIGNAL_HANDLER
|
|
if (!should_trigger(source))
|
|
return
|
|
|
|
if(source.client.intended_direction && check_on_move.Invoke(FALSE) && trail) //You use jet when press keys. yes.
|
|
trail.generate_effect()
|
|
|
|
/datum/component/jetpack/proc/should_trigger(mob/source)
|
|
if(!source || !source.client)//Don't allow jet self using
|
|
return FALSE
|
|
if(!isturf(source.loc))//You can't use jet in nowhere or from mecha/closet
|
|
return FALSE
|
|
if(!(source.movement_type & FLOATING) || source.buckled)//You don't want use jet in gravity or while buckled.
|
|
return FALSE
|
|
if(source.pulledby)//You don't must use jet if someone pull you
|
|
return FALSE
|
|
if(source.throwing)//You don't must use jet if you thrown
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/datum/component/jetpack/proc/pre_move_react(mob/source)
|
|
SIGNAL_HANDLER
|
|
if(!trail)
|
|
return FALSE
|
|
trail.oldposition = get_turf(source)
|
|
|
|
/datum/component/jetpack/process(seconds_per_tick)
|
|
if (last_stabilization_tick == world.time)
|
|
return
|
|
|
|
last_stabilization_tick = world.time
|
|
|
|
if (!should_trigger(user) || !stabilize || !check_on_move.Invoke(FALSE) || isnull(user.drift_handler))
|
|
return
|
|
|
|
var/max_drift_force = MOVE_DELAY_TO_DRIFT(user.cached_multiplicative_slowdown)
|
|
user.drift_handler.stabilize_drift(user.client.intended_direction ? dir2angle(user.client.intended_direction) : null, user.client.intended_direction ? max_drift_force : 0, stabilization_force * (seconds_per_tick * 1 SECONDS))
|
|
|
|
/datum/component/jetpack/proc/on_input_block(mob/source)
|
|
SIGNAL_HANDLER
|
|
|
|
if (!should_trigger(source))
|
|
return
|
|
|
|
if (!check_on_move.Invoke(TRUE))
|
|
return
|
|
|
|
return DRIFT_ALLOW_INPUT
|
|
|
|
/datum/component/jetpack/proc/on_client_move(mob/source, list/move_args)
|
|
SIGNAL_HANDLER
|
|
|
|
if (!should_trigger(source))
|
|
return
|
|
|
|
if (last_force_tick == world.time)
|
|
return
|
|
|
|
if (!check_on_move.Invoke(TRUE))
|
|
return
|
|
|
|
var/max_drift_force = MOVE_DELAY_TO_DRIFT(source.cached_multiplicative_slowdown)
|
|
var/applied_force = drift_force
|
|
var/move_dir = source.client.intended_direction
|
|
// Try to see if we can simulate pushing off a wall
|
|
var/atom/movable/backup = source.get_spacemove_backup(move_dir, FALSE, include_floors = TRUE)
|
|
if (backup && !(backup.dir & move_dir))
|
|
applied_force = max_drift_force
|
|
|
|
// We don't want to force the loop to fire before stabilizing if we're going to, otherwise its effects will be delayed until the next tick which is jank
|
|
var/force_stabilize = FALSE
|
|
if (last_stabilization_tick < world.time)
|
|
force_stabilize = TRUE
|
|
|
|
source.newtonian_move(dir2angle(move_dir), instant = TRUE, drift_force = applied_force, controlled_cap = max_drift_force, force_loop = !force_stabilize)
|
|
source.setDir(move_dir)
|
|
last_force_tick = world.time
|
|
|
|
if (force_stabilize)
|
|
// Newphys is an SS_TICKER subsystem and under ideal circumstances should be firing every tick, thus a period of world.tick_lag
|
|
// However, since our servers are jank, even SSinput can end up overtiming - which is also an SS_TICKER subsystem that just so
|
|
// happens to be what is calling this proc - so we can be assured that this is not above world.tick_lag, or at least should not be
|
|
process(world.tick_lag)
|
|
|
|
/datum/component/jetpack/proc/on_pushoff(mob/source, movement_dir, continuous_move, atom/backup)
|
|
SIGNAL_HANDLER
|
|
|
|
if (get_dir(source, backup) == movement_dir || source.loc == backup.loc)
|
|
return
|
|
|
|
if (!source.client?.intended_direction || source.client.intended_direction == get_dir(source, backup))
|
|
return
|
|
|
|
if (isnull(source.drift_handler))
|
|
return
|
|
|
|
if (!should_trigger(source) || !check_on_move.Invoke(FALSE))
|
|
return
|
|
|
|
return COMPONENT_PREVENT_SPACEMOVE_HALT
|