Files
Bubberstation/code/datums/components
Emmett Gaines 456cd10d94 Radiation rework and subsystem (#30909)
* radiation rework and subsystem

* moves a few things to initialize and adds radiation insulation

* adds a radiation contamination mechanic and makes requested changes

I'm terrified by the possibilities from this

* radiated objects give off light

and hopefuly contamination is balanced

* fixes runtimes and an mc crash kek

removed the lighting part of contaminated objects
attempted some more balancing

* Collectors output power in process() gradualy

And some more balancing tweaks

* Excludes a bunch of things from becoming radioactive

* Ready for testmerge balancing

* Inverse square law was swapped

* testmerge balancing

fixes the geiger counter
buffs collector power gen
nerfs sm radiation
slightly buffs rad insulation
nerfs rad damage (and its burn)
raised the minimum radiation

* disabling the radiation subsystem won't build up rad wave datums forever

* rewrites how mobs handle radiation

upgrades geiger counter functionality
and more balance tweaks

* cleans up stuff and removes debug message

* Slight contamination buff

* Major rad wave performance boost

Also improves rad insulation
Buffs contamination, again

* Fixes insulation runtime

More balance and performance tweaks

* fixes rad collectors not receiving power

* The final balance commit

Fixes a major bug causing radiation to underperform
More geiger counter changes that will be changed more to add sounds

* Monkey business

* Geiger counter sounds

* cleanup and move components to their own initialize

* Some code cleanup

And forgotten changes

* Cleans up some trailing returns

* Mapping changes
2017-10-13 10:22:00 -04:00
..
2017-10-01 12:53:57 +02:00

Datum Component System (DCS)

Concept

Loosely adapted from /vg/. This is an entity component system for adding behaviours to datums when inheritance doesn't quite cut it. By using signals and events instead of direct inheritance, you can inject behaviours without hacky overloads. It requires a different method of thinking, but is not hard to use correctly. If a behaviour can have application across more than one thing. Make it generic, make it a component. Atom/mob/obj event? Give it a signal, and forward it's arguments with a SendSignal() call. Now every component that want's to can also know about this happening.

In the code

Slippery things

At the time of this writing, every object that is slippery overrides atom/Crossed does some checks, then slips the mob. Instead of all those Crossed overrides they could add a slippery component to all these objects. And have the checks in one proc that is run by the Crossed event

Powercells

A lot of objects have powercells. The get_cell() proc was added to give generic access to the cell var if it had one. This is just a specific use case of GetComponent()

Radios

The radio object as it is should not exist, given that more things use the concept of radios rather than the object itself. The actual function of the radio can exist in a component which all the things that use it (Request consoles, actual radios, the SM shard) can add to themselves.

Standos

Stands have a lot of procs which mimic mob procs. Rather than inserting hooks for all these procs in overrides, the same can be accomplished with signals

API

Vars

  1. /datum/var/list/datum_components (private)
    • Lazy associated list of type -> component/list of components.
  2. /datum/component/var/enabled (protected, boolean)
    • If the component is enabled. If not, it will not react to signals
    • TRUE by default
  3. /datum/component/var/dupe_mode (protected, enum)
    • How duplicate component types are handled when added to the datum.
      • COMPONENT_DUPE_HIGHLANDER (default): Old component will be deleted, new component will first have /datum/component/proc/InheritComponent(datum/component/old, FALSE) on it
      • COMPONENT_DUPE_ALLOWED: The components will be treated as separate, GetComponent() will return the first added
      • COMPONENT_DUPE_UNIQUE: New component will be deleted, old component will first have /datum/component/proc/InheritComponent(datum/component/new, TRUE) on it
  4. /datum/component/var/dupe_type (protected, type)
    • Definition of a duplicate component type
      • null means exact match on type
      • Any other type means that and all subtypes
  5. /datum/component/var/list/signal_procs (private)
    • Associated lazy list of signals -> /datum/callbacks that will be run when the parent datum recieves that signal
  6. /datum/component/var/datum/parent (protected, read-only)
    • The datum this component belongs to

Procs

  1. /datum/proc/GetComponent(component_type(type)) -> datum/component? (public, final)
    • Returns a reference to a component of component_type if it exists in the datum, null otherwise
  2. /datum/proc/GetComponents(component_type(type)) -> list (public, final)
    • Returns a list of references to all components of component_type that exist in the datum
  3. /datum/proc/GetExactComponent(component_type(type)) -> datum/component? (public, final)
    • Returns a reference to a component whose type MATCHES component_type if that component exists in the datum, null otherwise
  4. GET_COMPONENT(varname, component_type) OR GET_COMPONENT_FROM(varname, component_type, src)
    • Shorthand for var/component_type/varname = src.GetComponent(component_type)
  5. /datum/proc/AddComponent(component_type(type), ...) -> datum/component (public, final)
    • Creates an instance of component_type in the datum and passes ... to its Initialize() call
    • Sends the COMSIG_COMPONENT_ADDED signal to the datum
    • All components a datum owns are deleted with the datum
    • Returns the component that was created. Or the old component in a dupe situation where COMPONENT_DUPE_UNIQUE was set
  6. /datum/proc/LoadComponent(component_type(type), ...) -> datum/component (public, final)
    • Equivalent to calling GetComponent(component_type) where, if the result would be null, returns AddComponent(component_type, ...) instead
  7. /datum/proc/ComponentActivated(datum/component/C) (abstract, async)
    • Called on a component's parent after a signal recieved causes it to activate. src is the parameter
    • Will only be called if a component's callback returns TRUE
  8. /datum/proc/TakeComponent(datum/component/C) (public, final)
    • Properly transfers ownership of a component from one datum to another
    • Singals COMSIG_COMPONENT_REMOVING on the parent
    • Called on the datum you want to own the component with another datum's component
  9. /datum/proc/SendSignal(signal, ...) (public, final)
    • Call to send a signal to the components of the target datum
    • Extra arguments are to be specified in the signal definition
  10. /datum/component/New(datum/parent, ...) (private, final)
    • Runs internal setup for the component
    • Extra arguments are passed to Initialize()
  11. /datum/component/Initialize(...) (abstract, no-sleep)
    • Called by New() with the same argments excluding parent
    • Component does not exist in parent's datum_components list yet, although parent is set and may be used
    • Signals will not be recieved while this function is running
    • Component may be deleted after this function completes without being attached
  12. /datum/component/Destroy() (virtual, no-sleep)
    • Sends the COMSIG_COMPONENT_REMOVING signal to the parent datum if the parent isn't being qdeleted
    • Properly removes the component from parent and cleans up references
  13. /datum/component/proc/InheritComponent(datum/component/C, i_am_original(boolean)) (abstract, no-sleep)
    • Called on a component when a component of the same type was added to the same parent
    • See /datum/component/var/dupe_mode
    • C's type will always be the same of the called component
  14. /datum/component/proc/AfterComponentActivated() (abstract, async)
    • Called on a component that was activated after it's parent's ComponentActivated() is called
  15. /datum/component/proc/OnTransfer(datum/new_parent) (abstract, no-sleep)
    • Called before the new parent is assigned in TakeComponent(), after the remove signal, before the added signal
    • Allows the component to react to ownership transfers
  16. /datum/component/proc/_RemoveNoSignal() (private, final)
    • Internal, clears the parent var and removes the component from the parents component list
  17. /datum/component/proc/RegisterSignal(signal(string/list of strings), proc_ref(type), override(boolean)) (protected, final) (Consider removing for performance gainz)
    • If signal is a list it will be as if RegisterSignal was called for each of the entries with the same following arguments
    • Makes a component listen for the specified signal on it's parent datum.
    • When that signal is recieved proc_ref will be called on the component, along with associated arguments
    • Example proc ref: .proc/OnEvent
    • If a previous registration is overwritten by the call, a runtime occurs. Setting override to TRUE prevents this
    • These callbacks run asyncronously
    • Returning TRUE from these callbacks will trigger a TRUE return from the SendSignal() that initiated it

See/Define signals and their arguments in __DEFINES\components.dm