mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-02-02 04:19:46 +00:00
Added it to a random timer as proof of concept. This is less performant than storing world.time in a variable, but it's a simple, quick, easy and dirty way to add a cooldown to something. Just create an ID and you need do no more besides using the macros. Helps with clarity and adding cooldowns on the fly.
263 lines
7.8 KiB
Plaintext
263 lines
7.8 KiB
Plaintext
/**
|
|
* The absolute base class for everything
|
|
*
|
|
* A datum instantiated has no physical world prescence, use an atom if you want something
|
|
* that actually lives in the world
|
|
*
|
|
* Be very mindful about adding variables to this class, they are inherited by every single
|
|
* thing in the entire game, and so you can easily cause memory usage to rise a lot with careless
|
|
* use of variables at this level
|
|
*/
|
|
/datum
|
|
/**
|
|
* Tick count time when this object was destroyed.
|
|
*
|
|
* If this is non zero then the object has been garbage collected and is awaiting either
|
|
* a hard del by the GC subsystme, or to be autocollected (if it has no references)
|
|
*/
|
|
var/gc_destroyed
|
|
|
|
/// Active timers with this datum as the target
|
|
var/list/active_timers
|
|
/// Status traits attached to this datum
|
|
var/list/status_traits
|
|
|
|
/**
|
|
* Components attached to this datum
|
|
*
|
|
* Lazy associated list in the structure of `type:component/list of components`
|
|
*/
|
|
var/list/datum_components
|
|
/**
|
|
* Any datum registered to receive signals from this datum is in this list
|
|
*
|
|
* Lazy associated list in the structure of `signal:registree/list of registrees`
|
|
*/
|
|
var/list/comp_lookup
|
|
/// Lazy associated list in the structure of `signals:proctype` that are run when the datum receives that signal
|
|
var/list/list/datum/callback/signal_procs
|
|
/**
|
|
* Is this datum capable of sending signals?
|
|
*
|
|
* Set to true when a signal has been registered
|
|
*/
|
|
var/signal_enabled = FALSE
|
|
|
|
/// Datum level flags
|
|
var/datum_flags = NONE
|
|
|
|
/// A weak reference to another datum
|
|
var/datum/weakref/weak_reference
|
|
|
|
/*
|
|
* Lazy associative list of currently active cooldowns.
|
|
*
|
|
* cooldowns [ COOLDOWN_INDEX ] = add_timer()
|
|
* add_timer() returns the truthy value of -1 when not stoppable, and else a truthy numeric index
|
|
*/
|
|
var/list/cooldowns
|
|
|
|
#ifdef TESTING
|
|
var/running_find_references
|
|
var/last_find_references = 0
|
|
#endif
|
|
|
|
#ifdef DATUMVAR_DEBUGGING_MODE
|
|
var/list/cached_vars
|
|
#endif
|
|
|
|
/**
|
|
* Called when a href for this datum is clicked
|
|
*
|
|
* Sends a [COMSIG_TOPIC] signal
|
|
*/
|
|
/datum/Topic(href, href_list[])
|
|
..()
|
|
SEND_SIGNAL(src, COMSIG_TOPIC, usr, href_list)
|
|
|
|
/**
|
|
* Default implementation of clean-up code.
|
|
*
|
|
* This should be overridden to remove all references pointing to the object being destroyed, if
|
|
* you do override it, make sure to call the parent and return it's return value by default
|
|
*
|
|
* Return an appropriate [QDEL_HINT][QDEL_HINT_QUEUE] to modify handling of your deletion;
|
|
* in most cases this is [QDEL_HINT_QUEUE].
|
|
*
|
|
* The base case is responsible for doing the following
|
|
* * Erasing timers pointing to this datum
|
|
* * Erasing compenents on this datum
|
|
* * Notifying datums listening to signals from this datum that we are going away
|
|
*
|
|
* Returns [QDEL_HINT_QUEUE]
|
|
*/
|
|
/datum/proc/Destroy(force=FALSE, ...)
|
|
SHOULD_CALL_PARENT(1)
|
|
tag = null
|
|
datum_flags &= ~DF_USE_TAG //In case something tries to REF us
|
|
weak_reference = null //ensure prompt GCing of weakref.
|
|
|
|
var/list/timers = active_timers
|
|
active_timers = null
|
|
for(var/thing in timers)
|
|
var/datum/timedevent/timer = thing
|
|
if (timer.spent)
|
|
continue
|
|
qdel(timer)
|
|
|
|
//BEGIN: ECS SHIT
|
|
signal_enabled = FALSE
|
|
|
|
var/list/dc = datum_components
|
|
if(dc)
|
|
var/all_components = dc[/datum/component]
|
|
if(length(all_components))
|
|
for(var/I in all_components)
|
|
var/datum/component/C = I
|
|
qdel(C, FALSE, TRUE)
|
|
else
|
|
var/datum/component/C = all_components
|
|
qdel(C, FALSE, TRUE)
|
|
dc.Cut()
|
|
|
|
var/list/lookup = comp_lookup
|
|
if(lookup)
|
|
for(var/sig in lookup)
|
|
var/list/comps = lookup[sig]
|
|
if(length(comps))
|
|
for(var/i in comps)
|
|
var/datum/component/comp = i
|
|
comp.UnregisterSignal(src, sig)
|
|
else
|
|
var/datum/component/comp = comps
|
|
comp.UnregisterSignal(src, sig)
|
|
comp_lookup = lookup = null
|
|
|
|
for(var/target in signal_procs)
|
|
UnregisterSignal(target, signal_procs[target])
|
|
//END: ECS SHIT
|
|
|
|
return QDEL_HINT_QUEUE
|
|
|
|
#ifdef DATUMVAR_DEBUGGING_MODE
|
|
/datum/proc/save_vars()
|
|
cached_vars = list()
|
|
for(var/i in vars)
|
|
if(i == "cached_vars")
|
|
continue
|
|
cached_vars[i] = vars[i]
|
|
|
|
/datum/proc/check_changed_vars()
|
|
. = list()
|
|
for(var/i in vars)
|
|
if(i == "cached_vars")
|
|
continue
|
|
if(cached_vars[i] != vars[i])
|
|
.[i] = list(cached_vars[i], vars[i])
|
|
|
|
/datum/proc/txt_changed_vars()
|
|
var/list/l = check_changed_vars()
|
|
var/t = "[src]([REF(src)]) changed vars:"
|
|
for(var/i in l)
|
|
t += "\"[i]\" \[[l[i][1]]\] --> \[[l[i][2]]\] "
|
|
t += "."
|
|
|
|
/datum/proc/to_chat_check_changed_vars(target = world)
|
|
to_chat(target, txt_changed_vars())
|
|
#endif
|
|
|
|
///Return a LIST for serialize_datum to encode! Not the actual json!
|
|
/datum/proc/serialize_list(list/options)
|
|
CRASH("Attempted to serialize datum [src] of type [type] without serialize_list being implemented!")
|
|
|
|
///Accepts a LIST from deserialize_datum. Should return src or another datum.
|
|
/datum/proc/deserialize_list(json, list/options)
|
|
CRASH("Attempted to deserialize datum [src] of type [type] without deserialize_list being implemented!")
|
|
|
|
///Serializes into JSON. Does not encode type.
|
|
/datum/proc/serialize_json(list/options)
|
|
. = serialize_list(options)
|
|
if(!islist(.))
|
|
. = null
|
|
else
|
|
. = json_encode(.)
|
|
|
|
///Deserializes from JSON. Does not parse type.
|
|
/datum/proc/deserialize_json(list/input, list/options)
|
|
var/list/jsonlist = json_decode(input)
|
|
. = deserialize_list(jsonlist)
|
|
if(!istype(., /datum))
|
|
. = null
|
|
|
|
///Convert a datum into a json blob
|
|
/proc/json_serialize_datum(datum/D, list/options)
|
|
if(!istype(D))
|
|
return
|
|
var/list/jsonlist = D.serialize_list(options)
|
|
if(islist(jsonlist))
|
|
jsonlist["DATUM_TYPE"] = D.type
|
|
return json_encode(jsonlist)
|
|
|
|
/// Convert a list of json to datum
|
|
/proc/json_deserialize_datum(list/jsonlist, list/options, target_type, strict_target_type = FALSE)
|
|
if(!islist(jsonlist))
|
|
if(!istext(jsonlist))
|
|
CRASH("Invalid JSON")
|
|
jsonlist = json_decode(jsonlist)
|
|
if(!islist(jsonlist))
|
|
CRASH("Invalid JSON")
|
|
if(!jsonlist["DATUM_TYPE"])
|
|
return
|
|
if(!ispath(jsonlist["DATUM_TYPE"]))
|
|
if(!istext(jsonlist["DATUM_TYPE"]))
|
|
return
|
|
jsonlist["DATUM_TYPE"] = text2path(jsonlist["DATUM_TYPE"])
|
|
if(!ispath(jsonlist["DATUM_TYPE"]))
|
|
return
|
|
if(target_type)
|
|
if(!ispath(target_type))
|
|
return
|
|
if(strict_target_type)
|
|
if(target_type != jsonlist["DATUM_TYPE"])
|
|
return
|
|
else if(!ispath(jsonlist["DATUM_TYPE"], target_type))
|
|
return
|
|
var/typeofdatum = jsonlist["DATUM_TYPE"] //BYOND won't directly read if this is just put in the line below, and will instead runtime because it thinks you're trying to make a new list?
|
|
var/datum/D = new typeofdatum
|
|
var/datum/returned = D.deserialize_list(jsonlist, options)
|
|
if(!istype(returned, /datum))
|
|
qdel(D)
|
|
else
|
|
return returned
|
|
|
|
/**
|
|
* Callback called by a timer to end an associative-list-indexed cooldown.
|
|
*
|
|
* Arguments:
|
|
* * source - datum storing the cooldown
|
|
* * index - string index storing the cooldown on the cooldowns associative list
|
|
*
|
|
* This sends a signal reporting the cooldown end.
|
|
*/
|
|
/proc/end_cooldown(datum/source, index)
|
|
if(QDELETED(source))
|
|
return
|
|
SEND_SIGNAL(source, COMSIG_CD_STOP(index))
|
|
TIMER_COOLDOWN_END(source, index)
|
|
|
|
|
|
/**
|
|
* Proc used by stoppable timers to end a cooldown before the time has ran out.
|
|
*
|
|
* Arguments:
|
|
* * source - datum storing the cooldown
|
|
* * index - string index storing the cooldown on the cooldowns associative list
|
|
*
|
|
* This sends a signal reporting the cooldown end, passing the time left as an argument.
|
|
*/
|
|
/proc/reset_cooldown(datum/source, index)
|
|
if(QDELETED(source))
|
|
return
|
|
SEND_SIGNAL(source, COMSIG_CD_RESET(index), S_TIMER_COOLDOWN_TIMELEFT(source, index))
|
|
TIMER_COOLDOWN_END(source, index)
|