mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-13 11:12:14 +00:00
## About The Pull Request This PR fixes wrong usage of bitflags in a few places, where instead of bitfields lists were used. ## Why It's Good For The Game It will help prevent problems that can be a thing in the future, improving consistency of the codebase.
250 lines
9.6 KiB
Plaintext
250 lines
9.6 KiB
Plaintext
/**
|
|
* # Slip behaviour component
|
|
*
|
|
* Add this component to an object to make it a slippery object, slippery objects make mobs that cross them fall over.
|
|
* Items with this component that get picked up may give their parent mob the slip behaviour.
|
|
*
|
|
* Here is a simple example of adding the component behaviour to an object.area
|
|
*
|
|
* AddComponent(/datum/component/slippery, 80, (NO_SLIP_WHEN_WALKING | SLIDE))
|
|
*
|
|
* This adds slippery behaviour to the parent atom, with a 80 decisecond (~8 seconds) knockdown
|
|
* The lube flags control how the slip behaves, in this case, the mob wont slip if it's in walking mode (NO_SLIP_WHEN_WALKING)
|
|
* and if they do slip, they will slide a few tiles (SLIDE)
|
|
*
|
|
*
|
|
* This component has configurable behaviours, see the [Initialize proc for the argument listing][/datum/component/slippery/proc/Initialize].
|
|
*/
|
|
/datum/component/slippery
|
|
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
|
|
/// If the slip forces the crossing mob to drop held items.
|
|
var/force_drop_items = FALSE
|
|
/// How long the slip keeps the crossing mob knocked over (they can still crawl and use weapons) for.
|
|
var/knockdown_time = 0
|
|
/// How long the slip paralyzes (prevents the crossing mob doing anything) for.
|
|
var/paralyze_time = 0
|
|
/// How long the slip dazes (makes the crossing mob vulnerable to shove stuns) for.
|
|
var/daze_time = 3 SECONDS
|
|
/// Flags for how slippery the parent is. See [__DEFINES/mobs.dm]
|
|
var/lube_flags
|
|
/// Optional callback allowing you to define custom conditions for slipping
|
|
var/datum/callback/can_slip_callback
|
|
/// Optional call back that is called when a mob slips on this component
|
|
var/datum/callback/on_slip_callback
|
|
/// If parent is an item, this is the person currently holding/wearing the parent (or the parent if no one is holding it)
|
|
var/mob/living/holder
|
|
/// Whitelist bitfields of item slots bitflags the parent can be equipped in that make the holder slippery. If null or empty, it will always make the holder slippery.
|
|
var/slot_whitelist = ITEM_SLOT_OCLOTHING | ITEM_SLOT_ICLOTHING | ITEM_SLOT_GLOVES | ITEM_SLOT_FEET | ITEM_SLOT_HEAD | ITEM_SLOT_MASK | ITEM_SLOT_BELT | ITEM_SLOT_NECK
|
|
///what we give to connect_loc by default, makes slippable mobs moving over us slip
|
|
var/static/list/default_connections = list(
|
|
COMSIG_ATOM_ENTERED = PROC_REF(Slip),
|
|
)
|
|
|
|
///what we give to connect_loc if we're an item and get equipped by a mob, or if we're a mob. makes slippable mobs moving over the mob slip
|
|
var/static/list/mob_connections = list(
|
|
COMSIG_ATOM_ENTERED = PROC_REF(slip_on_mob),
|
|
)
|
|
|
|
/**
|
|
* Initialize the slippery component behaviour
|
|
*
|
|
* When applied to any atom in the game this will apply slipping behaviours to that atom
|
|
*
|
|
* Arguments:
|
|
* * knockdown - Length of time the knockdown applies (Deciseconds)
|
|
* * lube_flags - Controls the slip behaviour, they are listed starting [here][SLIDE]
|
|
* * datum/callback/on_slip_callback - Callback to define further custom controls on when slipping is applied
|
|
* * paralyze - length of time to paralyze the crossing mob for (Deciseconds)
|
|
* * daze - length of time to daze the crossing mob for (Deciseconds), default 3 seconds
|
|
* * force_drop - should the crossing mob drop items in its hands or not
|
|
* * slot_whitelist - flags controlling where on a mob this item can be equipped to make the parent mob slippery full list [here][ITEM_SLOT_OCLOTHING]
|
|
* * datum/callback/on_slip_callback - Callback to add custom behaviours as the crossing mob is slipped
|
|
*/
|
|
/datum/component/slippery/Initialize(
|
|
knockdown,
|
|
lube_flags = NONE,
|
|
datum/callback/on_slip_callback,
|
|
paralyze,
|
|
daze = 3 SECONDS,
|
|
force_drop = FALSE,
|
|
slot_whitelist,
|
|
datum/callback/can_slip_callback,
|
|
)
|
|
src.knockdown_time = max(knockdown, 0)
|
|
src.paralyze_time = max(paralyze, 0)
|
|
src.daze_time = max(daze, 0)
|
|
src.force_drop_items = force_drop
|
|
src.lube_flags = lube_flags
|
|
src.can_slip_callback = can_slip_callback
|
|
src.on_slip_callback = on_slip_callback
|
|
if(slot_whitelist)
|
|
src.slot_whitelist = slot_whitelist
|
|
|
|
add_connect_loc_behalf_to_parent()
|
|
if(!ismovable(parent))
|
|
RegisterSignal(parent, COMSIG_ATOM_ENTERED, PROC_REF(Slip))
|
|
else if(isitem(parent))
|
|
src.lube_flags |= SLIPPERY_WHEN_LYING_DOWN
|
|
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip))
|
|
RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(on_drop))
|
|
RegisterSignal(parent, COMSIG_ITEM_APPLY_FANTASY_BONUSES, PROC_REF(apply_fantasy_bonuses))
|
|
RegisterSignal(parent, COMSIG_ITEM_REMOVE_FANTASY_BONUSES, PROC_REF(remove_fantasy_bonuses))
|
|
|
|
/datum/component/slippery/Destroy(force)
|
|
can_slip_callback = null
|
|
on_slip_callback = null
|
|
holder = null
|
|
return ..()
|
|
|
|
/datum/component/slippery/proc/apply_fantasy_bonuses(obj/item/source, bonus)
|
|
SIGNAL_HANDLER
|
|
knockdown_time = source.modify_fantasy_variable("knockdown_time", knockdown_time, bonus)
|
|
if(bonus >= 5)
|
|
paralyze_time = source.modify_fantasy_variable("paralyze_time", paralyze_time, bonus)
|
|
LAZYSET(source.fantasy_modifications, "lube_flags", lube_flags)
|
|
lube_flags |= SLIDE
|
|
if(bonus >= 10)
|
|
lube_flags |= GALOSHES_DONT_HELP|SLIP_WHEN_CRAWLING
|
|
|
|
/datum/component/slippery/proc/remove_fantasy_bonuses(obj/item/source, bonus)
|
|
SIGNAL_HANDLER
|
|
knockdown_time = source.reset_fantasy_variable("knockdown_time", knockdown_time)
|
|
paralyze_time = source.reset_fantasy_variable("paralyze_time", paralyze_time)
|
|
var/previous_lube_flags = LAZYACCESS(source.fantasy_modifications, "lube_flags")
|
|
LAZYREMOVE(source.fantasy_modifications, "lube_flags")
|
|
if(!isnull(previous_lube_flags))
|
|
lube_flags = previous_lube_flags
|
|
|
|
/datum/component/slippery/proc/add_connect_loc_behalf_to_parent()
|
|
var/list/connections_to_use
|
|
if(isliving(parent))
|
|
connections_to_use = mob_connections
|
|
else if(ismovable(parent))
|
|
connections_to_use = default_connections
|
|
if(connections_to_use)
|
|
AddComponent(/datum/component/connect_loc_behalf, parent, connections_to_use)
|
|
|
|
/datum/component/slippery/InheritComponent(
|
|
datum/component/slippery/component,
|
|
i_am_original,
|
|
knockdown,
|
|
lube_flags = NONE,
|
|
datum/callback/on_slip_callback,
|
|
paralyze,
|
|
daze,
|
|
force_drop = FALSE,
|
|
slot_whitelist,
|
|
datum/callback/can_slip_callback,
|
|
)
|
|
if(component)
|
|
knockdown = component.knockdown_time
|
|
lube_flags = component.lube_flags
|
|
on_slip_callback = component.on_slip_callback
|
|
can_slip_callback = component.on_slip_callback
|
|
paralyze = component.paralyze_time
|
|
daze = component.daze_time
|
|
force_drop = component.force_drop_items
|
|
slot_whitelist = component.slot_whitelist
|
|
|
|
src.knockdown_time = max(knockdown, 0)
|
|
src.paralyze_time = max(paralyze, 0)
|
|
src.daze_time = max(daze, 0)
|
|
src.force_drop_items = force_drop
|
|
src.lube_flags = lube_flags
|
|
src.on_slip_callback = on_slip_callback
|
|
src.can_slip_callback = can_slip_callback
|
|
if(slot_whitelist)
|
|
src.slot_whitelist = slot_whitelist
|
|
/**
|
|
* The proc that does the sliping. Invokes the slip callback we have set.
|
|
*
|
|
* Arguments
|
|
* * source - the source of the signal
|
|
* * arrived - the atom/movable that is being slipped.
|
|
*/
|
|
/datum/component/slippery/proc/Slip(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs)
|
|
SIGNAL_HANDLER
|
|
if(!isliving(arrived))
|
|
return
|
|
if(lube_flags & SLIPPERY_TURF)
|
|
var/turf/turf = get_turf(source)
|
|
if(HAS_TRAIT(turf, TRAIT_TURF_IGNORE_SLIPPERY))
|
|
return
|
|
var/mob/living/victim = arrived
|
|
if(victim.movement_type & MOVETYPES_NOT_TOUCHING_GROUND)
|
|
return
|
|
if(can_slip_callback && !can_slip_callback.Invoke(holder, victim))
|
|
return
|
|
if(victim.slip(knockdown_time, parent, lube_flags, paralyze_time, daze_time, force_drop_items))
|
|
on_slip_callback?.Invoke(victim)
|
|
|
|
/**
|
|
* Gets called when COMSIG_ITEM_EQUIPPED is sent to parent.
|
|
* This proc register slip signals to the equipper.
|
|
* If we have a slot whitelist, we only register the signals if the slot is valid (ex: clown PDA only slips in ID or belt slot).
|
|
*
|
|
* Arguments
|
|
* * source - the source of the signal
|
|
* * equipper - the mob we're equipping the slippery thing to
|
|
* * slot - the slot we're equipping the slippery thing to on the equipper.
|
|
*/
|
|
/datum/component/slippery/proc/on_equip(datum/source, mob/equipper, slot)
|
|
SIGNAL_HANDLER
|
|
|
|
if((!slot || (slot & slot_whitelist)) && isliving(equipper))
|
|
holder = equipper
|
|
qdel(GetComponent(/datum/component/connect_loc_behalf))
|
|
AddComponent(/datum/component/connect_loc_behalf, holder, mob_connections)
|
|
RegisterSignal(holder, COMSIG_QDELETING, PROC_REF(holder_deleted))
|
|
|
|
/**
|
|
* Detects if the holder mob is deleted.
|
|
* If our holder mob is the holder set in this component, we null it.
|
|
*
|
|
* Arguments:
|
|
* * source - the source of the signal
|
|
* * possible_holder - the mob being deleted.
|
|
*/
|
|
/datum/component/slippery/proc/holder_deleted(datum/source, datum/possible_holder)
|
|
SIGNAL_HANDLER
|
|
|
|
if(possible_holder == holder)
|
|
holder = null
|
|
|
|
/**
|
|
* Gets called when COMSIG_ITEM_DROPPED is sent to parent.
|
|
* Makes our holder mob un-slippery.
|
|
*
|
|
* Arguments:
|
|
* * source - the source of the signal
|
|
* * user - the mob that was formerly wearing our slippery item.
|
|
*/
|
|
/datum/component/slippery/proc/on_drop(datum/source, mob/user)
|
|
SIGNAL_HANDLER
|
|
|
|
UnregisterSignal(user, COMSIG_QDELETING)
|
|
|
|
qdel(GetComponent(/datum/component/connect_loc_behalf))
|
|
add_connect_loc_behalf_to_parent()
|
|
|
|
holder = null
|
|
|
|
/**
|
|
* The slip proc, but for equipped items.
|
|
* Slips the person who crossed us if we're lying down and unbuckled.
|
|
*
|
|
* Arguments:
|
|
* * source - the source of the signal
|
|
* * arrived - the atom/movable that slipped on us.
|
|
*/
|
|
/datum/component/slippery/proc/slip_on_mob(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs)
|
|
SIGNAL_HANDLER
|
|
|
|
var/mob/living/living = holder || parent
|
|
if(!(lube_flags & SLIPPERY_WHEN_LYING_DOWN) || (living.body_position == LYING_DOWN && !living.buckled))
|
|
Slip(source, arrived)
|
|
|
|
/datum/component/slippery/UnregisterFromParent()
|
|
. = ..()
|
|
qdel(GetComponent(/datum/component/connect_loc_behalf))
|