Merge branch 'master' into hook-kill-v10-final-ultimate-final

This commit is contained in:
AffectedArc07
2020-06-26 12:30:43 +01:00
committed by GitHub
617 changed files with 7362 additions and 10731 deletions
+1 -1
View File
@@ -339,7 +339,7 @@
/datum/action/item_action/remove_tape/Trigger(attack_self = FALSE)
if(..())
GET_COMPONENT_FROM(DT, /datum/component/ducttape, target)
var/datum/component/ducttape/DT = target.GetComponent(/datum/component/ducttape)
DT.remove_tape(target, usr)
/datum/action/item_action/toggle_jetpack
+66
View File
@@ -0,0 +1,66 @@
#define ARMORID "armor-[melee]-[bullet]-[laser]-[energy]-[bomb]-[bio]-[rad]-[fire]-[acid]"
/proc/getArmor(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0)
. = locate(ARMORID)
if (!.)
. = new /datum/armor(melee, bullet, laser, energy, bomb, bio, rad, fire, acid)
/datum/armor
var/melee
var/bullet
var/laser
var/energy
var/bomb
var/bio
var/rad
var/fire
var/acid
/datum/armor/New(melee_value = 0, bullet_value = 0, laser_value = 0, energy_value = 0, bomb_value = 0, bio_value = 0, rad_value = 0, fire_value = 0, acid_value = 0)
melee = melee_value
bullet = bullet_value
laser = laser_value
energy = energy_value
bomb = bomb_value
bio = bio_value
rad = rad_value
fire = fire_value
acid = acid_value
tag = ARMORID
/datum/armor/proc/modifyRating(melee_value = 0, bullet_value = 0, laser_value = 0, energy_value = 0, bomb_value = 0, bio_value = 0, rad_value = 0, fire_value = 0, acid_value = 0)
return getArmor(melee + melee_value, bullet + bullet_value, laser + laser_value, energy + energy_value, bomb + bomb_value, bio + bio_value, rad + rad_value, fire + fire_value, acid + acid_value)
/datum/armor/proc/modifyAllRatings(modifier = 0)
return getArmor(melee + modifier, bullet + modifier, laser + modifier, energy + modifier, bomb + modifier, bio + modifier, rad + modifier, fire + modifier, acid + modifier)
/datum/armor/proc/setRating(melee_value, bullet_value, laser_value, energy_value, bomb_value, bio_value, rad_value, fire_value, acid_value)
return getArmor((isnull(melee_value) ? melee : melee_value),\
(isnull(bullet_value) ? bullet : bullet_value),\
(isnull(laser_value) ? laser : laser_value),\
(isnull(energy_value) ? energy : energy_value),\
(isnull(bomb_value) ? bomb : bomb_value),\
(isnull(bio_value) ? bio : bio_value),\
(isnull(rad_value) ? rad : rad_value),\
(isnull(fire_value) ? fire : fire_value),\
(isnull(acid_value) ? acid : acid_value))
/datum/armor/proc/getRating(rating)
return vars[rating]
/datum/armor/proc/getList()
return list("melee" = melee, "bullet" = bullet, "laser" = laser, "energy" = energy, "bomb" = bomb, "bio" = bio, "rad" = rad, "fire" = fire, "acid" = acid)
/datum/armor/proc/attachArmor(datum/armor/AA)
return getArmor(melee + AA.melee, bullet + AA.bullet, laser + AA.laser, energy + AA.energy, bomb + AA.bomb, bio + AA.bio, rad + AA.rad, fire + AA.fire, acid + AA.acid)
/datum/armor/proc/detachArmor(datum/armor/AA)
return getArmor(melee - AA.melee, bullet - AA.bullet, laser - AA.laser, energy - AA.energy, bomb - AA.bomb, bio - AA.bio, rad - AA.rad, fire - AA.fire, acid - AA.acid)
/datum/armor/vv_edit_var(var_name, var_value)
if (var_name == NAMEOF(src, tag))
return FALSE
. = ..()
tag = ARMORID // update tag in case armor values were edited
#undef ARMORID
+2 -2
View File
@@ -99,11 +99,11 @@
//Position the effect so the beam is one continous line
var/a
if(abs(Pixel_x)>32)
a = Pixel_x > 0 ? round(Pixel_x/32) : Ceiling(Pixel_x/32)
a = Pixel_x > 0 ? round(Pixel_x/32) : CEILING(Pixel_x/32, 1)
X.x += a
Pixel_x %= 32
if(abs(Pixel_y)>32)
a = Pixel_y > 0 ? round(Pixel_y/32) : Ceiling(Pixel_y/32)
a = Pixel_y > 0 ? round(Pixel_y/32) : CEILING(Pixel_y/32, 1)
X.y += a
Pixel_y %= 32
+26 -36
View File
@@ -4,7 +4,7 @@ GLOBAL_DATUM_INIT(crew_repository, /datum/repository/crew, new())
cache_data = list()
..()
/datum/repository/crew/proc/health_data(var/turf/T)
/datum/repository/crew/proc/health_data(turf/T)
var/list/crewmembers = list()
if(!T)
return crewmembers
@@ -18,50 +18,40 @@ GLOBAL_DATUM_INIT(crew_repository, /datum/repository/crew, new())
if(world.time < cache_entry.timestamp)
return cache_entry.data
var/tracked = scan()
for(var/obj/item/clothing/under/C in tracked)
for(var/thing in GLOB.human_list)
var/mob/living/carbon/human/H = thing
var/obj/item/clothing/under/C = H.w_uniform
if(!C || C.sensor_mode == SUIT_SENSOR_OFF || !C.has_sensor)
continue
var/turf/pos = get_turf(C)
if((C) && (C.has_sensor) && (pos) && (T && pos.z == T.z) && (C.sensor_mode != SUIT_SENSOR_OFF))
if(istype(C.loc, /mob/living/carbon/human))
var/mob/living/carbon/human/H = C.loc
if(H.w_uniform != C)
continue
if(!T || pos.z != T.z)
continue
var/list/crewmemberData = list("dead"=0, "oxy"=-1, "tox"=-1, "fire"=-1, "brute"=-1, "area"="", "x"=-1, "y"=-1, "ref" = "\ref[H]")
var/list/crewmemberData = list("dead"=0, "oxy"=-1, "tox"=-1, "fire"=-1, "brute"=-1, "area"="", "x"=-1, "y"=-1, "ref" = "\ref[H]")
crewmemberData["sensor_type"] = C.sensor_mode
crewmemberData["name"] = H.get_authentification_name(if_no_id="Unknown")
crewmemberData["rank"] = H.get_authentification_rank(if_no_id="Unknown", if_no_job="No Job")
crewmemberData["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job")
crewmemberData["sensor_type"] = C.sensor_mode
crewmemberData["name"] = H.get_authentification_name(if_no_id="Unknown")
crewmemberData["rank"] = H.get_authentification_rank(if_no_id="Unknown", if_no_job="No Job")
crewmemberData["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job")
if(C.sensor_mode >= SUIT_SENSOR_BINARY)
crewmemberData["dead"] = H.stat > UNCONSCIOUS
if(C.sensor_mode >= SUIT_SENSOR_BINARY)
crewmemberData["dead"] = H.stat > UNCONSCIOUS
if(C.sensor_mode >= SUIT_SENSOR_VITAL)
crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
crewmemberData["tox"] = round(H.getToxLoss(), 1)
crewmemberData["fire"] = round(H.getFireLoss(), 1)
crewmemberData["brute"] = round(H.getBruteLoss(), 1)
if(C.sensor_mode >= SUIT_SENSOR_VITAL)
crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
crewmemberData["tox"] = round(H.getToxLoss(), 1)
crewmemberData["fire"] = round(H.getFireLoss(), 1)
crewmemberData["brute"] = round(H.getBruteLoss(), 1)
if(C.sensor_mode >= SUIT_SENSOR_TRACKING)
var/area/A = get_area(H)
crewmemberData["area"] = sanitize(A.name)
crewmemberData["x"] = pos.x
crewmemberData["y"] = pos.y
if(C.sensor_mode >= SUIT_SENSOR_TRACKING)
var/area/A = get_area(H)
crewmemberData["area"] = sanitize(A.name)
crewmemberData["x"] = pos.x
crewmemberData["y"] = pos.y
crewmembers[++crewmembers.len] = crewmemberData
crewmembers[++crewmembers.len] = crewmemberData
crewmembers = sortByKey(crewmembers, "name")
cache_entry.timestamp = world.time + 5 SECONDS
cache_entry.data = crewmembers
return crewmembers
/datum/repository/crew/proc/scan()
var/list/tracked = list()
for(var/mob/living/carbon/human/H in GLOB.mob_list)
if(istype(H.w_uniform, /obj/item/clothing/under))
var/obj/item/clothing/under/C = H.w_uniform
if(C.has_sensor)
tracked |= C
return tracked
+3 -129
View File
@@ -2,134 +2,8 @@
## 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 `SEND_SIGNAL` call. Now every component that want's to can also know about this happening.
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
See [this thread](https://tgstation13.org/phpBB/viewtopic.php?f=5&t=22674) for an introduction to the system as a whole.
#### 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
### Defines
1. `COMPONENT_INCOMPATIBLE` Return this from `/datum/component/Initialize` or `datum/component/OnTransfer` to have the component be deleted if it's applied to an incorrect type. `parent` must not be modified if this is to be returned. This will be noted in the runtime logs
### Vars
1. `/datum/var/list/datum_components` (private)
* Lazy associated list of type -> component/list of components.
1. `/datum/var/list/comp_lookup` (private)
* Lazy associated list of signal -> registree/list of registrees
1. `/datum/var/list/signal_procs` (private)
* Associated lazy list of signals -> `/datum/callback`s that will be run when the parent datum receives that signal
1. `/datum/var/signal_enabled` (protected, boolean)
* If the datum is signal enabled. If not, it will not react to signals
* `FALSE` by default, set to `TRUE` when a signal is registered
1. `/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
* `COMPONENT_DUPE_UNIQUE_PASSARGS`: New component will never exist and instead its initialization arguments will be passed on to the old component.
1. `/datum/component/var/dupe_type` (protected, type)
* Definition of a duplicate component type
* `null` means exact match on `type` (default)
* Any other type means that and all subtypes
1. `/datum/component/var/datum/parent` (protected, read-only)
* The datum this component belongs to
* Never `null` in child procs
1. `report_signal_origin` (protected, boolean)
* If `TRUE`, will invoke the callback when signalled with the signal type as the first argument.
* `FALSE` by default.
### 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
1. `/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
1. `/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
1. `GET_COMPONENT(varname, component_type)` OR `GET_COMPONENT_FROM(varname, component_type, src)`
* Shorthand for `var/component_type/varname = src.GetComponent(component_type)`
1. `SEND_SIGNAL(target, sigtype, ...)` (public, final)
* Use to send signals to target datum
* Extra arguments are to be specified in the signal definition
* Returns a bitflag with signal specific information assembled from all activated components
* Arguments are packaged in a list and handed off to _SendSignal()
1. `/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
* If this tries to add an component to an incompatible type, the component will be deleted and the result will be `null`. This is very unperformant, try not to do it
* Properly handles duplicate situations based on the `dupe_mode` var
1. `/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
1. `/datum/proc/ComponentActivated(datum/component/C)` (abstract, async)
* Called on a component's `parent` after a signal received causes it to activate. `src` is the parameter
* Will only be called if a component's callback returns `TRUE`
1. `/datum/proc/TakeComponent(datum/component/C)` (public, final)
* Properly transfers ownership of a component from one datum to another
* Signals `COMSIG_COMPONENT_REMOVING` on the parent
* Called on the datum you want to own the component with another datum's component
1. `/datum/proc/_SendSignal(signal, list/arguments)` (private, final)
* Handles most of the actual signaling procedure
* Will runtime if used on datums with an empty component list
1. `/datum/proc/RegisterSignal(datum/target, signal(string/list of strings), proc_ref(type), override(boolean))` (protected, final)
* If signal is a list it will be as if RegisterSignal was called for each of the entries with the same following arguments
* Makes the datum listen for the specified `signal` on it's `parent` datum.
* When that signal is received `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
1. `/datum/component/New(datum/parent, ...)` (private, final)
* Runs internal setup for the component
* Extra arguments are passed to `Initialize()`
1. `/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 received while this function is running
* Component may be deleted after this function completes without being attached
* Do not call `qdel(src)` from this function
1. `/datum/component/Destroy(force(bool), silent(bool))` (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
* Setting `force` makes it not check for and remove the component from the parent
* Setting `silent` deletes the component without sending a `COMSIG_COMPONENT_REMOVING` signal
1. `/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
1. `/datum/component/proc/AfterComponentActivated()` (abstract, async)
* Called on a component that was activated after it's `parent`'s `ComponentActivated()` is called
1. `/datum/component/proc/OnTransfer(datum/new_parent)` (abstract, no-sleep)
* Called before `new_parent` is assigned to `parent` in `TakeComponent()`
* Allows the component to react to ownership transfers
1. `/datum/component/proc/_RemoveFromParent()` (private, final)
* Clears `parent` and removes the component from it's component list
1. `/datum/component/proc/_JoinParent` (private, final)
* Tries to add the component to it's `parent`s `datum_components` list
1. `/datum/component/proc/RegisterWithParent` (abstract, no-sleep)
* Used to register the signals that should be on the `parent` object
* Use this if you plan on the component transfering between parents
1. `/datum/component/proc/UnregisterFromParent` (abstract, no-sleep)
* Counterpart to `RegisterWithParent()`
* Used to unregister the signals that should only be on the `parent` object
### See/Define signals and their arguments in __DEFINES\components.dm
### See/Define signals and their arguments in [__DEFINES\dcs\signals.dm](../../__DEFINES/dcs/signals.dm)
+268 -44
View File
@@ -1,21 +1,87 @@
/**
* # Component
*
* The component datum
*
* A component should be a single standalone unit
* of functionality, that works by receiving signals from it's parent
* object to provide some single functionality (i.e a slippery component)
* that makes the object it's attached to cause people to slip over.
* Useful when you want shared behaviour independent of type inheritance
*/
/datum/component
/**
* Defines how duplicate existing components are handled when added to a datum
*
* See [COMPONENT_DUPE_*][COMPONENT_DUPE_ALLOWED] definitions for available options
*/
var/dupe_mode = COMPONENT_DUPE_HIGHLANDER
/**
* The type to check for duplication
*
* `null` means exact match on `type` (default)
*
* Any other type means that and all subtypes
*/
var/dupe_type
/// The datum this components belongs to
var/datum/parent
//only set to true if you are able to properly transfer this component
//At a minimum RegisterWithParent and UnregisterFromParent should be used
//Make sure you also implement PostTransfer for any post transfer handling
/**
* Only set to true if you are able to properly transfer this component
*
* At a minimum [RegisterWithParent][/datum/component/proc/RegisterWithParent] and [UnregisterFromParent][/datum/component/proc/UnregisterFromParent] should be used
*
* Make sure you also implement [PostTransfer][/datum/component/proc/PostTransfer] for any post transfer handling
*/
var/can_transfer = FALSE
/datum/component/New(datum/P, ...)
parent = P
var/list/arguments = args.Copy(2)
/**
* Create a new component.
*
* Additional arguments are passed to [Initialize()][/datum/component/proc/Initialize]
*
* Arguments:
* * datum/P the parent datum this component reacts to signals from
*/
/datum/component/New(list/raw_args)
parent = raw_args[1]
var/list/arguments = raw_args.Copy(2)
if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE)
stack_trace("Incompatible [type] assigned to a [parent.type]! args: [json_encode(arguments)]")
qdel(src, TRUE, TRUE)
CRASH("Incompatible [type] assigned to a [P.type]! args: [json_encode(arguments)]")
return
_JoinParent(P)
_JoinParent(parent)
/**
* Called during component creation with the same arguments as in new excluding parent.
*
* Do not call `qdel(src)` from this function, `return COMPONENT_INCOMPATIBLE` instead
*/
/datum/component/proc/Initialize(...)
return
/**
* Properly removes the component from `parent` and cleans up references
*
* Arguments:
* * force - makes it not check for and remove the component from the parent
* * silent - deletes the component without sending a [COMSIG_COMPONENT_REMOVING] signal
*/
/datum/component/Destroy(force=FALSE, silent=FALSE)
if(!force && parent)
_RemoveFromParent()
if(!silent)
SEND_SIGNAL(parent, COMSIG_COMPONENT_REMOVING, src)
parent = null
return ..()
/**
* Internal proc to handle behaviour of components when joining a parent
*/
/datum/component/proc/_JoinParent()
var/datum/P = parent
//lazy init the parent's dc list
@@ -51,21 +117,9 @@
RegisterWithParent()
// If you want/expect to be moving the component around between parents, use this to register on the parent for signals
/datum/component/proc/RegisterWithParent()
return
/datum/component/proc/Initialize(...)
return
/datum/component/Destroy(force=FALSE, silent=FALSE)
if(!force && parent)
_RemoveFromParent()
if(!silent)
SEND_SIGNAL(parent, COMSIG_COMPONENT_REMOVING, src)
parent = null
return ..()
/**
* Internal proc to handle behaviour when being removed from a parent
*/
/datum/component/proc/_RemoveFromParent()
var/datum/P = parent
var/list/dc = P.datum_components
@@ -84,10 +138,41 @@
UnregisterFromParent()
/**
* Register the component with the parent object
*
* Use this proc to register with your parent object
*
* Overridable proc that's called when added to a new parent
*/
/datum/component/proc/RegisterWithParent()
return
/**
* Unregister from our parent object
*
* Use this proc to unregister from your parent object
*
* Overridable proc that's called when removed from a parent
* *
*/
/datum/component/proc/UnregisterFromParent()
return
/datum/proc/RegisterSignal(datum/target, sig_type_or_types, proc_or_callback, override = FALSE)
/**
* Register to listen for a signal from the passed in target
*
* This sets up a listening relationship such that when the target object emits a signal
* the source datum this proc is called upon, will recieve a callback to the given proctype
* Return values from procs registered must be a bitfield
*
* Arguments:
* * datum/target The target to listen for signals from
* * sig_type_or_types Either a string signal name, or a list of signal names (strings)
* * proctype The proc to call back when the signal is emitted
* * override If a previous registration exists you must explicitly set this
*/
/datum/proc/RegisterSignal(datum/target, sig_type_or_types, proctype, override = FALSE)
if(QDELETED(src) || QDELETED(target))
return
@@ -100,15 +185,12 @@
if(!lookup)
target.comp_lookup = lookup = list()
if(!istype(proc_or_callback, /datum/callback)) //if it wasnt a callback before, it is now
proc_or_callback = CALLBACK(src, proc_or_callback)
var/list/sig_types = islist(sig_type_or_types) ? sig_type_or_types : list(sig_type_or_types)
for(var/sig_type in sig_types)
if(!override && procs[target][sig_type])
stack_trace("[sig_type] overridden. Use override = TRUE to suppress this warning")
procs[target][sig_type] = proc_or_callback
procs[target][sig_type] = proctype
if(!lookup[sig_type]) // Nothing has registered here yet
lookup[sig_type] = src
@@ -122,6 +204,17 @@
signal_enabled = TRUE
/**
* Stop listening to a given signal from target
*
* Breaks the relationship between target and source datum, removing the callback when the signal fires
*
* Doesn't care if a registration exists or not
*
* Arguments:
* * datum/target Datum to stop listening to signals from
* * sig_typeor_types Signal string key or list of signal keys to stop listening to specifically
*/
/datum/proc/UnregisterSignal(datum/target, sig_type_or_types)
var/list/lookup = target.comp_lookup
if(!signal_procs || !signal_procs[target] || !lookup)
@@ -129,6 +222,8 @@
if(!islist(sig_type_or_types))
sig_type_or_types = list(sig_type_or_types)
for(var/sig in sig_type_or_types)
if(!signal_procs[target][sig])
continue
switch(length(lookup[sig]))
if(2)
lookup[sig] = (lookup[sig]-src)[1]
@@ -151,41 +246,96 @@
if(!signal_procs[target].len)
signal_procs -= target
/**
* 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
*/
/datum/component/proc/InheritComponent(datum/component/C, i_am_original)
return
/**
* Called on a component when a component of the same type was added to the same parent with [COMPONENT_DUPE_SELECTIVE]
*
* See [/datum/component/var/dupe_mode]
*
* `C`'s type will always be the same of the called component
*
* return TRUE if you are absorbing the component, otherwise FALSE if you are fine having it exist as a duplicate component
*/
/datum/component/proc/CheckDupeComponent(datum/component/C, ...)
return
/**
* Callback Just before this component is transferred
*
* Use this to do any special cleanup you might need to do before being deregged from an object
*/
/datum/component/proc/PreTransfer()
return
/**
* Callback Just after a component is transferred
*
* Use this to do any special setup you need to do after being moved to a new object
*
* Do not call `qdel(src)` from this function, `return COMPONENT_INCOMPATIBLE` instead
*/
/datum/component/proc/PostTransfer()
return COMPONENT_INCOMPATIBLE //Do not support transfer by default as you must properly support it
/**
* Internal proc to create a list of our type and all parent types
*/
/datum/component/proc/_GetInverseTypeList(our_type = type)
//we can do this one simple trick
var/current_type = parent_type
. = list(our_type, current_type)
//and since most components are root level + 1, this won't even have to run
while(current_type != /datum/component)
while (current_type != /datum/component)
current_type = type2parent(current_type)
. += current_type
/**
* Internal proc to handle most all of the signaling procedure
*
* Will runtime if used on datums with an empty component list
*
* Use the [SEND_SIGNAL] define instead
*/
/datum/proc/_SendSignal(sigtype, list/arguments)
var/target = comp_lookup[sigtype]
if(!length(target))
var/datum/C = target
if(!C.signal_enabled)
return NONE
var/datum/callback/CB = C.signal_procs[src][sigtype]
return CB.InvokeAsync(arglist(arguments))
var/proctype = C.signal_procs[src][sigtype]
return NONE | CallAsync(C, proctype, arguments)
. = NONE
for(var/I in target)
var/datum/C = I
if(!C.signal_enabled)
continue
var/datum/callback/CB = C.signal_procs[src][sigtype]
. |= CB.InvokeAsync(arglist(arguments))
var/proctype = C.signal_procs[src][sigtype]
. |= CallAsync(C, proctype, arguments)
/datum/proc/GetComponent(c_type)
// The type arg is casted so initial works, you shouldn't be passing a real instance into this
/**
* Return any component assigned to this datum of the given type
*
* This will throw an error if it's possible to have more than one component of that type on the parent
*
* Arguments:
* * datum/component/c_type The typepath of the component you want to get a reference to
*/
/datum/proc/GetComponent(datum/component/c_type)
RETURN_TYPE(c_type)
if(initial(c_type.dupe_mode) == COMPONENT_DUPE_ALLOWED || initial(c_type.dupe_mode) == COMPONENT_DUPE_SELECTIVE)
stack_trace("GetComponent was called to get a component of which multiple copies could be on an object. This can easily break and should be changed. Type: \[[c_type]\]")
var/list/dc = datum_components
if(!dc)
return null
@@ -193,7 +343,19 @@
if(length(.))
return .[1]
/datum/proc/GetExactComponent(c_type)
// The type arg is casted so initial works, you shouldn't be passing a real instance into this
/**
* Return any component assigned to this datum of the exact given type
*
* This will throw an error if it's possible to have more than one component of that type on the parent
*
* Arguments:
* * datum/component/c_type The typepath of the component you want to get a reference to
*/
/datum/proc/GetExactComponent(datum/component/c_type)
RETURN_TYPE(c_type)
if(initial(c_type.dupe_mode) == COMPONENT_DUPE_ALLOWED || initial(c_type.dupe_mode) == COMPONENT_DUPE_SELECTIVE)
stack_trace("GetComponent was called to get a component of which multiple copies could be on an object. This can easily break and should be changed. Type: \[[c_type]\]")
var/list/dc = datum_components
if(!dc)
return null
@@ -205,6 +367,12 @@
return C
return null
/**
* Get all components of a given type that are attached to this datum
*
* Arguments:
* * c_type The component type path
*/
/datum/proc/GetComponents(c_type)
var/list/dc = datum_components
if(!dc)
@@ -213,7 +381,19 @@
if(!length(.))
return list(.)
/datum/proc/AddComponent(new_type, ...)
/**
* Creates an instance of `new_type` in the datum and attaches to it as parent
*
* Sends the [COMSIG_COMPONENT_ADDED] signal to the datum
*
* Returns the component that was created. Or the old component in a dupe situation where [COMPONENT_DUPE_UNIQUE] was set
*
* If this tries to add a component to an incompatible type, the component will be deleted and the result will be `null`. This is very unperformant, try not to do it
*
* Properly handles duplicate situations based on the `dupe_mode` var
*/
/datum/proc/_AddComponent(list/raw_args)
var/new_type = raw_args[1]
var/datum/component/nt = new_type
var/dm = initial(nt.dupe_mode)
var/dt = initial(nt.dupe_type)
@@ -228,7 +408,7 @@
new_comp = nt
nt = new_comp.type
args[1] = src
raw_args[1] = src
if(dm != COMPONENT_DUPE_ALLOWED)
if(!dt)
@@ -239,37 +419,62 @@
switch(dm)
if(COMPONENT_DUPE_UNIQUE)
if(!new_comp)
new_comp = new nt(arglist(args))
new_comp = new nt(raw_args)
if(!QDELETED(new_comp))
old_comp.InheritComponent(new_comp, TRUE)
QDEL_NULL(new_comp)
if(COMPONENT_DUPE_HIGHLANDER)
if(!new_comp)
new_comp = new nt(arglist(args))
new_comp = new nt(raw_args)
if(!QDELETED(new_comp))
new_comp.InheritComponent(old_comp, FALSE)
QDEL_NULL(old_comp)
if(COMPONENT_DUPE_UNIQUE_PASSARGS)
if(!new_comp)
var/list/arguments = args.Copy(2)
old_comp.InheritComponent(null, TRUE, arguments)
var/list/arguments = raw_args.Copy(2)
arguments.Insert(1, null, TRUE)
old_comp.InheritComponent(arglist(arguments))
else
old_comp.InheritComponent(new_comp, TRUE)
if(COMPONENT_DUPE_SELECTIVE)
var/list/arguments = raw_args.Copy()
arguments[1] = new_comp
var/make_new_component = TRUE
for(var/i in GetComponents(new_type))
var/datum/component/C = i
if(C.CheckDupeComponent(arglist(arguments)))
make_new_component = FALSE
QDEL_NULL(new_comp)
break
if(!new_comp && make_new_component)
new_comp = new nt(raw_args)
else if(!new_comp)
new_comp = new nt(arglist(args)) // There's a valid dupe mode but there's no old component, act like normal
new_comp = new nt(raw_args) // There's a valid dupe mode but there's no old component, act like normal
else if(!new_comp)
new_comp = new nt(arglist(args)) // Dupes are allowed, act like normal
new_comp = new nt(raw_args) // Dupes are allowed, act like normal
if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy
SEND_SIGNAL(src, COMSIG_COMPONENT_ADDED, new_comp)
return new_comp
return old_comp
/**
* Get existing component of type, or create it and return a reference to it
*
* Use this if the item needs to exist at the time of this call, but may not have been created before now
*
* Arguments:
* * component_type The typepath of the component to create or return
* * ... additional arguments to be passed when creating the component if it does not exist
*/
/datum/proc/LoadComponent(component_type, ...)
. = GetComponent(component_type)
if(!.)
return AddComponent(arglist(args))
return _AddComponent(args)
/**
* Removes the component from parent, ends up with a null parent
*/
/datum/component/proc/RemoveComponent()
if(!parent)
return
@@ -279,6 +484,14 @@
parent = null
SEND_SIGNAL(old_parent, COMSIG_COMPONENT_REMOVING, src)
/**
* Transfer this component to another parent
*
* Component is taken from source datum
*
* Arguments:
* * datum/component/target Target datum to transfer to
*/
/datum/proc/TakeComponent(datum/component/target)
if(!target || target.parent == src)
return
@@ -295,6 +508,14 @@
if(target == AddComponent(target))
target._JoinParent()
/**
* Transfer all components to target
*
* All components from source datum are taken
*
* Arguments:
* * /datum/target the target to move the components to
*/
/datum/proc/TransferComponents(datum/target)
var/list/dc = datum_components
if(!dc)
@@ -309,5 +530,8 @@
if(C.can_transfer)
target.TakeComponent(comps)
/**
* Return the object that is the host of any UI's that this component has
*/
/datum/component/nano_host()
return parent
+1 -1
View File
@@ -7,7 +7,7 @@
var/first_dir // This only stores the dir arg from init
/datum/component/decal/Initialize(_icon, _icon_state, _dir, _cleanable=CLEAN_GOD, _color, _layer=TURF_LAYER, _description, _alpha=255)
/datum/component/decal/Initialize(_icon, _icon_state, _dir, _cleanable = CLEAN_GOD, _color, _layer = TURF_LAYER, _description, _alpha = 255)
if(!isatom(parent) || !generate_appearance(_icon, _icon_state, _dir, _layer, _color, _alpha))
return COMPONENT_INCOMPATIBLE
first_dir = _dir
+23
View File
@@ -0,0 +1,23 @@
// This is just a bit of fun while making an example for global signal
/datum/component/edit_complainer
var/list/say_lines
/datum/component/edit_complainer/Initialize(list/text)
if(!ismovable(parent))
return COMPONENT_INCOMPATIBLE
var/static/list/default_lines = list(
"CentComm's profligacy frays another thread.",
"Another tug at the weave.",
"Who knows when the stresses will finally shatter the form?",
"Even now a light shines through the cracks.",
"CentComm once more twists knowledge beyond its authority.",
"There is an uncertain air in the mansus.",
)
say_lines = text || default_lines
RegisterSignal(SSdcs, COMSIG_GLOB_VAR_EDIT, .proc/var_edit_react)
/datum/component/edit_complainer/proc/var_edit_react(datum/source, list/arguments)
var/atom/movable/master = parent
master.atom_say(pick(say_lines))
-5
View File
@@ -1,5 +0,0 @@
/datum/component/jestosterone
var/mind_type //Is the affected mob a clown / mime?
/datum/component/jestosterone/Initialize(mind_type_arg)
mind_type = mind_type_arg
+2 -2
View File
@@ -32,12 +32,12 @@
This proc will fire after the parent is hit by a hand labeler which is trying to apply another label.
Since the parent already has a label, it will remove the old one from the parent's name, and apply the new one.
*/
/datum/component/label/InheritComponent(datum/component/label/new_comp , i_am_original, list/arguments)
/datum/component/label/InheritComponent(datum/component/label/new_comp , i_am_original, _label_name)
remove_label()
if(new_comp)
label_name = new_comp.label_name
else
label_name = arguments[1]
label_name = _label_name
apply_label()
/**
+56
View File
@@ -0,0 +1,56 @@
/**
* # Slip Component
*
* This is a component that can be applied to any movable atom (mob or obj).
*
* While the atom has this component, any human mob that walks over it will have a chance to slip.
* Duration, tiles moved, and so on, depend on what variables are passed in when the component is added.
*
*/
/datum/component/slippery
/// Text that gets displayed in the slip proc, i.e. "user slips on [description]"
var/description
/// The amount of stun to apply after slip.
var/stun
/// The amount of weaken to apply after slip.
var/weaken
/// The chance that walking over the parent will slip you.
var/slip_chance
/// The amount of tiles someone will be moved after slip.
var/slip_tiles
/// TRUE If this slip can be avoided by walking.
var/walking_is_safe
/// FALSE if you want no slip shoes to make you immune to the slip
var/slip_always
/// The verb that players will see when someone slips on the parent. In the form of "You [slip_verb]ped on".
var/slip_verb
/datum/component/slippery/Initialize(_description, _stun = 0, _weaken = 0, _slip_chance = 100, _slip_tiles = 0, _walking_is_safe = TRUE, _slip_always = FALSE, _slip_verb = "slip")
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
description = _description
stun = max(0, _stun)
weaken = max(0, _weaken)
slip_chance = max(0, _slip_chance)
slip_tiles = max(0, _slip_tiles)
walking_is_safe = _walking_is_safe
slip_always = _slip_always
slip_verb = _slip_verb
/datum/component/slippery/RegisterWithParent()
RegisterSignal(parent, list(COMSIG_MOVABLE_CROSSED, COMSIG_ATOM_ENTERED), .proc/Slip)
/datum/component/slippery/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_MOVABLE_CROSSED, COMSIG_ATOM_ENTERED))
/**
Called whenever the parent recieves either the `MOVABLE_CROSSED` signal or the `ATOM_ENTERED` signal.
Calls the `victim`'s `slip()` proc with the component's variables as arguments.
Additionally calls the parent's `after_slip()` proc on the `victim`.
*/
/datum/component/slippery/proc/Slip(datum/source, mob/living/carbon/human/victim)
if(istype(victim) && prob(slip_chance) && victim.slip(description, stun, weaken, slip_tiles, walking_is_safe, slip_always, slip_verb))
var/atom/movable/owner = parent
owner.after_slip(victim)
+1 -1
View File
@@ -16,7 +16,7 @@
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
RegisterSignal(parent, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_BLOB_ACT, COMSIG_ATOM_HULK_ATTACK, COMSIG_PARENT_ATTACKBY), .proc/play_squeak)
if(ismovableatom(parent))
if(ismovable(parent))
RegisterSignal(parent, list(COMSIG_MOVABLE_BUMP, COMSIG_MOVABLE_IMPACT), .proc/play_squeak)
RegisterSignal(parent, COMSIG_MOVABLE_CROSSED, .proc/play_squeak_crossed)
RegisterSignal(parent, COMSIG_MOVABLE_DISPOSING, .proc/disposing_react)
+55
View File
@@ -0,0 +1,55 @@
/datum/component/swarming
var/offset_x = 0
var/offset_y = 0
var/is_swarming = FALSE
var/list/swarm_members = list()
/datum/component/swarming/Initialize(max_x = 24, max_y = 24)
if(!ismovable(parent))
return COMPONENT_INCOMPATIBLE
offset_x = rand(-max_x, max_x)
offset_y = rand(-max_y, max_y)
RegisterSignal(parent, COMSIG_MOVABLE_CROSSED, .proc/join_swarm)
RegisterSignal(parent, COMSIG_MOVABLE_UNCROSSED, .proc/leave_swarm)
/datum/component/swarming/Destroy()
for(var/other in swarm_members)
var/datum/component/swarming/other_swarm = other
other_swarm.swarm_members -= src
if(!other_swarm.swarm_members.len)
other_swarm.unswarm()
swarm_members = null
return ..()
/datum/component/swarming/proc/join_swarm(datum/source, atom/movable/AM)
var/datum/component/swarming/other_swarm = AM.GetComponent(/datum/component/swarming)
if(!other_swarm)
return
swarm()
swarm_members |= other_swarm
other_swarm.swarm()
other_swarm.swarm_members |= src
/datum/component/swarming/proc/leave_swarm(datum/source, atom/movable/AM)
var/datum/component/swarming/other_swarm = AM.GetComponent(/datum/component/swarming)
if(!other_swarm || !(other_swarm in swarm_members))
return
swarm_members -= other_swarm
if(!swarm_members.len)
unswarm()
other_swarm.swarm_members -= src
if(!other_swarm.swarm_members.len)
other_swarm.unswarm()
/datum/component/swarming/proc/swarm()
var/atom/movable/owner = parent
if(!is_swarming)
is_swarming = TRUE
animate(owner, pixel_x = owner.pixel_x + offset_x, pixel_y = owner.pixel_y + offset_y, time = 2)
/datum/component/swarming/proc/unswarm()
var/atom/movable/owner = parent
if(is_swarming)
animate(owner, pixel_x = owner.pixel_x - offset_x, pixel_y = owner.pixel_y - offset_y, time = 2)
is_swarming = FALSE
-15
View File
@@ -1,15 +0,0 @@
/datum/component/waddling
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
/datum/component/waddling/Initialize()
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE
RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED), .proc/Waddle)
/datum/component/waddling/proc/Waddle()
var/mob/living/L = parent
if(L.incapacitated() || L.lying)
return
animate(L, pixel_z = 4, time = 0)
animate(pixel_z = 0, transform = turn(matrix(), pick(-12, 0, 12)), time=2)
animate(pixel_z = 0, transform = matrix(), time = 0)
+9 -1
View File
@@ -126,11 +126,19 @@
AddDisease(D)
/**
* Forces the mob to contract a virus. If the mob can have viruses. Ignores clothing and other protection
* Returns TRUE if it succeeds. False if it doesn't
*
* Arguments:
* * D - the disease the mob will try to contract
*/
//Same as ContractDisease, except never overidden clothes checks
/mob/proc/ForceContractDisease(datum/disease/D)
if(!CanContractDisease(D))
return 0
return FALSE
AddDisease(D)
return TRUE
/mob/living/carbon/human/CanContractDisease(datum/disease/D)
+5 -6
View File
@@ -171,7 +171,6 @@ GLOBAL_LIST_INIT(advance_cures, list(
if(!symptoms || !symptoms.len)
CRASH("We did not have any symptoms before generating properties.")
return
var/list/properties = list("resistance" = 1, "stealth" = 0, "stage_rate" = 1, "transmittable" = 1, "severity" = 0)
@@ -196,9 +195,9 @@ GLOBAL_LIST_INIT(advance_cures, list(
visibility_flags = HIDDEN_SCANNER|HIDDEN_PANDEMIC
// The more symptoms we have, the less transmittable it is but some symptoms can make up for it.
SetSpread(Clamp(2 ** (properties["transmittable"] - symptoms.len), BLOOD, AIRBORNE))
permeability_mod = max(Ceiling(0.4 * properties["transmittable"]), 1)
cure_chance = 15 - Clamp(properties["resistance"], -5, 5) // can be between 10 and 20
SetSpread(clamp(2 ** (properties["transmittable"] - symptoms.len), BLOOD, AIRBORNE))
permeability_mod = max(CEILING(0.4 * properties["transmittable"], 1), 1)
cure_chance = 15 - clamp(properties["resistance"], -5, 5) // can be between 10 and 20
stage_prob = max(properties["stage_rate"], 2)
SetSeverity(properties["severity"])
GenerateCure(properties)
@@ -245,7 +244,7 @@ GLOBAL_LIST_INIT(advance_cures, list(
// Will generate a random cure, the less resistance the symptoms have, the harder the cure.
/datum/disease/advance/proc/GenerateCure(list/properties = list())
if(properties && properties.len)
var/res = Clamp(properties["resistance"] - (symptoms.len / 2), 1, GLOB.advance_cures.len)
var/res = clamp(properties["resistance"] - (symptoms.len / 2), 1, GLOB.advance_cures.len)
// to_chat(world, "Res = [res]")
cures = list(GLOB.advance_cures[res])
@@ -396,7 +395,7 @@ GLOBAL_LIST_INIT(advance_cures, list(
for(var/datum/disease/advance/AD in GLOB.active_diseases)
AD.Refresh()
for(var/mob/living/carbon/human/H in shuffle(GLOB.living_mob_list))
for(var/mob/living/carbon/human/H in shuffle(GLOB.alive_mob_list))
if(!is_station_level(H.z))
continue
if(!H.HasDisease(D))
@@ -33,7 +33,7 @@ Bonus
if(3, 4)
to_chat(M, "<span class='warning'>[pick("You hear a ringing in your ear.", "Your ears pop.")]</span>")
if(5)
if(!(M.disabilities & DEAF))
if(!(DEAF in M.mutations))
to_chat(M, "<span class='userdanger'>Your ears pop and begin ringing loudly!</span>")
M.BecomeDeaf()
spawn(200)
@@ -35,7 +35,7 @@ BONUS
switch(A.stage)
if(5)
H.s_tone = -85
H.update_body(0)
H.update_body()
else
H.visible_message("<span class='warning'>[H] looks a bit pale...</span>", "<span class='notice'>Your skin suddenly appears lighter...</span>")
@@ -79,7 +79,7 @@ BONUS
switch(A.stage)
if(5)
H.s_tone = 85
H.update_body(0)
H.update_body()
else
H.visible_message("<span class='warning'>[H] looks a bit dark...</span>", "<span class='notice'>Your skin suddenly appears darker...</span>")
+55
View File
@@ -0,0 +1,55 @@
/**
* A holder for simple behaviour that can be attached to many different types
*
* Only one element of each type is instanced during game init.
* Otherwise acts basically like a lightweight component.
*/
/datum/element
/// Option flags for element behaviour
var/element_flags = NONE
/**
* The index of the first attach argument to consider for duplicate elements
*
* Is only used when flags contains [ELEMENT_BESPOKE]
*
* This is infinity so you must explicitly set this
*/
var/id_arg_index = INFINITY
/// Activates the functionality defined by the element on the given target datum
/datum/element/proc/Attach(datum/target)
SHOULD_CALL_PARENT(1)
if(type == /datum/element)
return ELEMENT_INCOMPATIBLE
SEND_SIGNAL(target, COMSIG_ELEMENT_ATTACH, src)
if(element_flags & ELEMENT_DETACH)
RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/Detach, override = TRUE)
/// Deactivates the functionality defines by the element on the given datum
/datum/element/proc/Detach(datum/source, force)
SEND_SIGNAL(source, COMSIG_ELEMENT_DETACH, src)
SHOULD_CALL_PARENT(1)
UnregisterSignal(source, COMSIG_PARENT_QDELETING)
/datum/element/Destroy(force)
if(!force)
return QDEL_HINT_LETMELIVE
SSdcs.elements_by_type -= type
return ..()
//DATUM PROCS
/// Finds the singleton for the element type given and attaches it to src
/datum/proc/_AddElement(list/arguments)
var/datum/element/ele = SSdcs.GetElement(arguments)
arguments[1] = src
if(ele.Attach(arglist(arguments)) == ELEMENT_INCOMPATIBLE)
CRASH("Incompatible [arguments[1]] assigned to a [type]! args: [json_encode(args)]")
/**
* Finds the singleton for the element type given and detaches it from src
* You only need additional arguments beyond the type if you're using [ELEMENT_BESPOKE]
*/
/datum/proc/_RemoveElement(list/arguments)
var/datum/element/ele = SSdcs.GetElement(arguments)
ele.Detach(src)
+25
View File
@@ -0,0 +1,25 @@
/datum/element/waddling
/datum/element/waddling/Attach(datum/target)
. = ..()
if(!ismovable(target))
return ELEMENT_INCOMPATIBLE
if(isliving(target))
RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/LivingWaddle)
else
RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/Waddle)
/datum/element/waddling/Detach(datum/source, force)
. = ..()
UnregisterSignal(source, COMSIG_MOVABLE_MOVED)
/datum/element/waddling/proc/LivingWaddle(mob/living/target)
if(target.incapacitated() || target.lying)
return
Waddle(target)
/datum/element/waddling/proc/Waddle(atom/movable/target)
animate(target, pixel_z = 4, time = 0)
var/prev_trans = matrix(target.transform)
animate(pixel_z = 0, transform = turn(target.transform, pick(-12, 0, 12)), time = 2)
animate(pixel_z = 0, transform = prev_trans, time = 0)
+176 -289
View File
@@ -7,33 +7,22 @@ What are the archived variables for?
#define SPECIFIC_HEAT_TOXIN 200
#define SPECIFIC_HEAT_AIR 20
#define SPECIFIC_HEAT_CDO 30
#define HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,toxins) \
(carbon_dioxide*SPECIFIC_HEAT_CDO + (oxygen+nitrogen)*SPECIFIC_HEAT_AIR + toxins*SPECIFIC_HEAT_TOXIN)
#define SPECIFIC_HEAT_N2O 40
#define SPECIFIC_HEAT_AGENT_B 300
#define HEAT_CAPACITY_CALCULATION(oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b) \
(carbon_dioxide * SPECIFIC_HEAT_CDO + (oxygen + nitrogen) * SPECIFIC_HEAT_AIR + toxins * SPECIFIC_HEAT_TOXIN + sleeping_agent * SPECIFIC_HEAT_N2O + agent_b * SPECIFIC_HEAT_AGENT_B)
#define MINIMUM_HEAT_CAPACITY 0.0003
#define QUANTIZE(variable) (round(variable,0.0001))
/datum/gas
var/moles = 0
var/specific_heat = 0
var/moles_archived = 0
/datum/gas/sleeping_agent
specific_heat = 40
/datum/gas/oxygen_agent_b
specific_heat = 300
/datum/gas/volatile_fuel
specific_heat = 30
#define QUANTIZE(variable) (round(variable, 0.0001))
/datum/gas_mixture
var/oxygen = 0
var/carbon_dioxide = 0
var/nitrogen = 0
var/toxins = 0
var/sleeping_agent = 0
var/agent_b = 0
var/volume = CELL_VOLUME
@@ -41,13 +30,12 @@ What are the archived variables for?
var/last_share
var/list/datum/gas/trace_gases = list()
var/tmp/oxygen_archived
var/tmp/carbon_dioxide_archived
var/tmp/nitrogen_archived
var/tmp/toxins_archived
var/tmp/sleeping_agent_archived
var/tmp/agent_b_archived
var/tmp/temperature_archived
@@ -55,35 +43,24 @@ What are the archived variables for?
//PV=nRT - related procedures
/datum/gas_mixture/proc/heat_capacity()
var/heat_capacity = HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,toxins)
for(var/gas in trace_gases)
var/datum/gas/trace_gas = gas
heat_capacity += trace_gas.moles*trace_gas.specific_heat
return heat_capacity
return HEAT_CAPACITY_CALCULATION(oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b)
/datum/gas_mixture/proc/heat_capacity_archived()
var/heat_capacity_archived = HEAT_CAPACITY_CALCULATION(oxygen_archived,carbon_dioxide_archived,nitrogen_archived,toxins_archived)
for(var/gas in trace_gases)
var/datum/gas/trace_gas = gas
heat_capacity_archived += trace_gas.moles_archived*trace_gas.specific_heat
return heat_capacity_archived
return HEAT_CAPACITY_CALCULATION(oxygen_archived, carbon_dioxide_archived, nitrogen_archived, toxins_archived, sleeping_agent_archived, agent_b_archived)
/datum/gas_mixture/proc/total_moles()
var/moles = oxygen + carbon_dioxide + nitrogen + toxins
for(var/gas in trace_gases)
var/datum/gas/trace_gas = gas
moles += trace_gas.moles
var/moles = oxygen + carbon_dioxide + nitrogen + toxins + sleeping_agent + agent_b
return moles
/datum/gas_mixture/proc/total_trace_moles()
var/moles = sleeping_agent + agent_b
return moles
/datum/gas_mixture/proc/return_pressure()
if(volume>0)
return total_moles()*R_IDEAL_GAS_EQUATION*temperature/volume
if(volume > 0)
return total_moles() * R_IDEAL_GAS_EQUATION * temperature / volume
return 0
@@ -96,7 +73,7 @@ What are the archived variables for?
/datum/gas_mixture/proc/thermal_energy()
return temperature*heat_capacity()
return temperature * heat_capacity()
//Procedures used for very specific events
@@ -105,28 +82,23 @@ What are the archived variables for?
/datum/gas_mixture/proc/react(atom/dump_location)
var/reacting = 0 //set to 1 if a notable reaction occured (used by pipe_network)
if(trace_gases.len > 0)
if(temperature > 900)
if(toxins > MINIMUM_HEAT_CAPACITY && carbon_dioxide > MINIMUM_HEAT_CAPACITY)
var/datum/gas/oxygen_agent_b/trace_gas = locate(/datum/gas/oxygen_agent_b/) in trace_gases
if(trace_gas)
var/reaction_rate = min(carbon_dioxide*0.75, toxins*0.25, trace_gas.moles*0.05)
if(agent_b && temperature > 900)
if(toxins > MINIMUM_HEAT_CAPACITY && carbon_dioxide > MINIMUM_HEAT_CAPACITY)
var/reaction_rate = min(carbon_dioxide * 0.75, toxins * 0.25, agent_b * 0.05)
carbon_dioxide -= reaction_rate
oxygen += reaction_rate
carbon_dioxide -= reaction_rate
oxygen += reaction_rate
trace_gas.moles -= reaction_rate*0.05
agent_b -= reaction_rate * 0.05
temperature += (reaction_rate*20000)/heat_capacity()
temperature += (reaction_rate * 20000) / heat_capacity()
reacting = 1
reacting = 1
fuel_burnt = 0
if(temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
// to_chat(world, "pre [temperature], [oxygen], [toxins]")
if(fire() > 0)
reacting = 1
// to_chat(world, "post [temperature], [oxygen], [toxins]")
return reacting
@@ -134,24 +106,6 @@ What are the archived variables for?
var/energy_released = 0
var/old_heat_capacity = heat_capacity()
var/datum/gas/volatile_fuel/fuel_store = locate(/datum/gas/volatile_fuel/) in trace_gases
if(fuel_store) //General volatile gas burn
var/burned_fuel = 0
if(oxygen < fuel_store.moles)
burned_fuel = oxygen
fuel_store.moles -= burned_fuel
oxygen = 0
else
burned_fuel = fuel_store.moles
oxygen -= fuel_store.moles
trace_gases -= fuel_store
fuel_store = null
energy_released += FIRE_CARBON_ENERGY_RELEASED * burned_fuel
carbon_dioxide += burned_fuel
fuel_burnt += burned_fuel
//Handle plasma burning
if(toxins > MINIMUM_HEAT_CAPACITY)
var/plasma_burn_rate = 0
@@ -161,13 +115,13 @@ What are the archived variables for?
if(temperature > PLASMA_UPPER_TEMPERATURE)
temperature_scale = 1
else
temperature_scale = (temperature-PLASMA_MINIMUM_BURN_TEMPERATURE)/(PLASMA_UPPER_TEMPERATURE-PLASMA_MINIMUM_BURN_TEMPERATURE)
temperature_scale = (temperature - PLASMA_MINIMUM_BURN_TEMPERATURE) / (PLASMA_UPPER_TEMPERATURE-PLASMA_MINIMUM_BURN_TEMPERATURE)
if(temperature_scale > 0)
oxygen_burn_rate = OXYGEN_BURN_RATE_BASE - temperature_scale
if(oxygen > toxins*PLASMA_OXYGEN_FULLBURN)
plasma_burn_rate = (toxins*temperature_scale)/PLASMA_BURN_RATE_DELTA
if(oxygen > toxins * PLASMA_OXYGEN_FULLBURN)
plasma_burn_rate = (toxins * temperature_scale) / PLASMA_BURN_RATE_DELTA
else
plasma_burn_rate = (temperature_scale*(oxygen/PLASMA_OXYGEN_FULLBURN))/PLASMA_BURN_RATE_DELTA
plasma_burn_rate = (temperature_scale * (oxygen / PLASMA_OXYGEN_FULLBURN)) / PLASMA_BURN_RATE_DELTA
if(plasma_burn_rate > MINIMUM_HEAT_CAPACITY)
toxins -= plasma_burn_rate
oxygen -= plasma_burn_rate*oxygen_burn_rate
@@ -175,12 +129,12 @@ What are the archived variables for?
energy_released += FIRE_PLASMA_ENERGY_RELEASED * (plasma_burn_rate)
fuel_burnt += (plasma_burn_rate)*(1+oxygen_burn_rate)
fuel_burnt += (plasma_burn_rate) * (1 + oxygen_burn_rate)
if(energy_released > 0)
var/new_heat_capacity = heat_capacity()
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
temperature = (temperature*old_heat_capacity + energy_released)/new_heat_capacity
temperature = (temperature * old_heat_capacity + energy_released) / new_heat_capacity
return fuel_burnt
@@ -231,10 +185,8 @@ What are the archived variables for?
carbon_dioxide_archived = carbon_dioxide
nitrogen_archived = nitrogen
toxins_archived = toxins
for(var/gas in trace_gases)
var/datum/gas/trace_gas = gas
trace_gas.moles_archived = trace_gas.moles
sleeping_agent_archived = sleeping_agent
agent_b_archived = agent_b
temperature_archived = temperature
@@ -244,55 +196,45 @@ What are the archived variables for?
if(!giver)
return 0
if(abs(temperature-giver.temperature)>MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
if(abs(temperature - giver.temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/self_heat_capacity = heat_capacity()
var/giver_heat_capacity = giver.heat_capacity()
var/combined_heat_capacity = giver_heat_capacity + self_heat_capacity
if(combined_heat_capacity != 0)
temperature = (giver.temperature*giver_heat_capacity + temperature*self_heat_capacity)/combined_heat_capacity
temperature = (giver.temperature * giver_heat_capacity + temperature * self_heat_capacity) / combined_heat_capacity
oxygen += giver.oxygen
carbon_dioxide += giver.carbon_dioxide
nitrogen += giver.nitrogen
toxins += giver.toxins
for(var/gas in giver.trace_gases)
var/datum/gas/trace_gas = gas
var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases
if(!corresponding)
corresponding = new trace_gas.type()
trace_gases += corresponding
corresponding.moles += trace_gas.moles
sleeping_agent += giver.sleeping_agent
agent_b += giver.agent_b
return 1
/datum/gas_mixture/remove(amount)
var/sum = total_moles()
amount = min(amount,sum) //Can not take more air than tile has!
amount = min(amount, sum) //Can not take more air than tile has!
if(amount <= 0)
return null
var/datum/gas_mixture/removed = new
removed.oxygen = QUANTIZE((oxygen/sum)*amount)
removed.nitrogen = QUANTIZE((nitrogen/sum)*amount)
removed.carbon_dioxide = QUANTIZE((carbon_dioxide/sum)*amount)
removed.toxins = QUANTIZE((toxins/sum)*amount)
removed.oxygen = QUANTIZE((oxygen / sum) * amount)
removed.nitrogen = QUANTIZE((nitrogen/ sum) * amount)
removed.carbon_dioxide = QUANTIZE((carbon_dioxide / sum) * amount)
removed.toxins = QUANTIZE((toxins / sum) * amount)
removed.sleeping_agent = QUANTIZE((sleeping_agent / sum) * amount)
removed.agent_b = QUANTIZE((agent_b / sum) * amount)
oxygen -= removed.oxygen
nitrogen -= removed.nitrogen
carbon_dioxide -= removed.carbon_dioxide
toxins -= removed.toxins
for(var/gas in trace_gases)
var/datum/gas/trace_gas = gas
var/datum/gas/corresponding = new trace_gas.type()
removed.trace_gases += corresponding
corresponding.moles = (trace_gas.moles/sum)*amount
trace_gas.moles -= corresponding.moles
sleeping_agent -= removed.sleeping_agent
agent_b -= removed.agent_b
removed.temperature = temperature
@@ -307,23 +249,19 @@ What are the archived variables for?
var/datum/gas_mixture/removed = new
removed.oxygen = QUANTIZE(oxygen*ratio)
removed.nitrogen = QUANTIZE(nitrogen*ratio)
removed.carbon_dioxide = QUANTIZE(carbon_dioxide*ratio)
removed.toxins = QUANTIZE(toxins*ratio)
removed.oxygen = QUANTIZE(oxygen * ratio)
removed.nitrogen = QUANTIZE(nitrogen * ratio)
removed.carbon_dioxide = QUANTIZE(carbon_dioxide * ratio)
removed.toxins = QUANTIZE(toxins * ratio)
removed.sleeping_agent = QUANTIZE(sleeping_agent * ratio)
removed.agent_b = QUANTIZE(agent_b * ratio)
oxygen -= removed.oxygen
nitrogen -= removed.nitrogen
carbon_dioxide -= removed.carbon_dioxide
toxins -= removed.toxins
for(var/gas in trace_gases)
var/datum/gas/trace_gas = gas
var/datum/gas/corresponding = new trace_gas.type()
removed.trace_gases += corresponding
corresponding.moles = trace_gas.moles*ratio
trace_gas.moles -= corresponding.moles
sleeping_agent -= removed.sleeping_agent
agent_b -= removed.agent_b
removed.temperature = temperature
@@ -334,14 +272,8 @@ What are the archived variables for?
carbon_dioxide = sample.carbon_dioxide
nitrogen = sample.nitrogen
toxins = sample.toxins
trace_gases.len=null
for(var/gas in sample.trace_gases)
var/datum/gas/trace_gas = gas
var/datum/gas/corresponding = new trace_gas.type()
trace_gases += corresponding
corresponding.moles = trace_gas.moles
sleeping_agent = sample.sleeping_agent
agent_b = sample.agent_b
temperature = sample.temperature
@@ -352,6 +284,8 @@ What are the archived variables for?
carbon_dioxide = model.carbon_dioxide
nitrogen = model.nitrogen
toxins = model.toxins
sleeping_agent = model.sleeping_agent
agent_b = model.agent_b
//acounts for changes in temperature
var/turf/model_parent = model.parent_type
@@ -361,26 +295,25 @@ What are the archived variables for?
return 1
/datum/gas_mixture/check_turf(turf/model, atmos_adjacent_turfs = 4)
var/delta_oxygen = (oxygen_archived - model.oxygen)/(atmos_adjacent_turfs+1)
var/delta_carbon_dioxide = (carbon_dioxide_archived - model.carbon_dioxide)/(atmos_adjacent_turfs+1)
var/delta_nitrogen = (nitrogen_archived - model.nitrogen)/(atmos_adjacent_turfs+1)
var/delta_toxins = (toxins_archived - model.toxins)/(atmos_adjacent_turfs+1)
var/delta_oxygen = (oxygen_archived - model.oxygen) / (atmos_adjacent_turfs + 1)
var/delta_carbon_dioxide = (carbon_dioxide_archived - model.carbon_dioxide) / (atmos_adjacent_turfs + 1)
var/delta_nitrogen = (nitrogen_archived - model.nitrogen) / (atmos_adjacent_turfs + 1)
var/delta_toxins = (toxins_archived - model.toxins) / (atmos_adjacent_turfs + 1)
var/delta_sleeping_agent = (sleeping_agent_archived - model.sleeping_agent) / (atmos_adjacent_turfs + 1)
var/delta_agent_b = (agent_b_archived - model.agent_b) / (atmos_adjacent_turfs + 1)
var/delta_temperature = (temperature_archived - model.temperature)
if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)))
if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_sleeping_agent) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_sleeping_agent) >= sleeping_agent_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_agent_b) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_agent_b) >= agent_b_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)))
return 0
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND)
return 0
for(var/gas in trace_gases)
var/datum/gas/trace_gas = gas
if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4)
return 0
return 1
/datum/gas_mixture/proc/check_turf_total(turf/model) //I want this proc to die a painful death
@@ -388,30 +321,32 @@ What are the archived variables for?
var/delta_carbon_dioxide = (carbon_dioxide - model.carbon_dioxide)
var/delta_nitrogen = (nitrogen - model.nitrogen)
var/delta_toxins = (toxins - model.toxins)
var/delta_sleeping_agent = (sleeping_agent - model.sleeping_agent)
var/delta_agent_b = (agent_b - model.agent_b)
var/delta_temperature = (temperature - model.temperature)
if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins*MINIMUM_AIR_RATIO_TO_SUSPEND)))
if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_sleeping_agent) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_sleeping_agent) >= sleeping_agent * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_agent_b) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_agent_b) >= agent_b * MINIMUM_AIR_RATIO_TO_SUSPEND)))
return 0
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND)
return 0
for(var/gas in trace_gases)
var/datum/gas/trace_gas = gas
if(trace_gas.moles > MINIMUM_AIR_TO_SUSPEND*4)
return 0
return 1
/datum/gas_mixture/share(datum/gas_mixture/sharer, atmos_adjacent_turfs = 4)
if(!sharer) return 0
var/delta_oxygen = QUANTIZE(oxygen_archived - sharer.oxygen_archived)/(atmos_adjacent_turfs+1)
var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - sharer.carbon_dioxide_archived)/(atmos_adjacent_turfs+1)
var/delta_nitrogen = QUANTIZE(nitrogen_archived - sharer.nitrogen_archived)/(atmos_adjacent_turfs+1)
var/delta_toxins = QUANTIZE(toxins_archived - sharer.toxins_archived)/(atmos_adjacent_turfs+1)
if(!sharer)
return 0
var/delta_oxygen = QUANTIZE(oxygen_archived - sharer.oxygen_archived) / (atmos_adjacent_turfs + 1)
var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - sharer.carbon_dioxide_archived) / (atmos_adjacent_turfs + 1)
var/delta_nitrogen = QUANTIZE(nitrogen_archived - sharer.nitrogen_archived) / (atmos_adjacent_turfs + 1)
var/delta_toxins = QUANTIZE(toxins_archived - sharer.toxins_archived) / (atmos_adjacent_turfs + 1)
var/delta_sleeping_agent = QUANTIZE(sleeping_agent_archived - sharer.sleeping_agent_archived) / (atmos_adjacent_turfs + 1)
var/delta_agent_b = QUANTIZE(agent_b_archived - sharer.agent_b_archived) / (atmos_adjacent_turfs + 1)
var/delta_temperature = (temperature_archived - sharer.temperature_archived)
@@ -423,28 +358,42 @@ What are the archived variables for?
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/delta_air = delta_oxygen+delta_nitrogen
var/delta_air = delta_oxygen + delta_nitrogen
if(delta_air)
var/air_heat_capacity = SPECIFIC_HEAT_AIR*delta_air
var/air_heat_capacity = SPECIFIC_HEAT_AIR * delta_air
if(delta_air > 0)
heat_capacity_self_to_sharer += air_heat_capacity
else
heat_capacity_sharer_to_self -= air_heat_capacity
if(delta_carbon_dioxide)
var/carbon_dioxide_heat_capacity = SPECIFIC_HEAT_CDO*delta_carbon_dioxide
var/carbon_dioxide_heat_capacity = SPECIFIC_HEAT_CDO * delta_carbon_dioxide
if(delta_carbon_dioxide > 0)
heat_capacity_self_to_sharer += carbon_dioxide_heat_capacity
else
heat_capacity_sharer_to_self -= carbon_dioxide_heat_capacity
if(delta_toxins)
var/toxins_heat_capacity = SPECIFIC_HEAT_TOXIN*delta_toxins
var/toxins_heat_capacity = SPECIFIC_HEAT_TOXIN * delta_toxins
if(delta_toxins > 0)
heat_capacity_self_to_sharer += toxins_heat_capacity
else
heat_capacity_sharer_to_self -= toxins_heat_capacity
if(delta_sleeping_agent)
var/sleeping_agent_heat_capacity = SPECIFIC_HEAT_N2O * delta_sleeping_agent
if(delta_sleeping_agent > 0)
heat_capacity_self_to_sharer += sleeping_agent_heat_capacity
else
heat_capacity_sharer_to_self -= sleeping_agent_heat_capacity
if(delta_agent_b)
var/agent_b_heat_capacity = SPECIFIC_HEAT_AGENT_B * delta_agent_b
if(delta_agent_b > 0)
heat_capacity_self_to_sharer += agent_b_heat_capacity
else
heat_capacity_sharer_to_self -= agent_b_heat_capacity
old_self_heat_capacity = heat_capacity()
old_sharer_heat_capacity = sharer.heat_capacity()
@@ -460,83 +409,40 @@ What are the archived variables for?
toxins -= delta_toxins
sharer.toxins += delta_toxins
var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins)
last_share = abs(delta_oxygen) + abs(delta_carbon_dioxide) + abs(delta_nitrogen) + abs(delta_toxins)
sleeping_agent -= delta_sleeping_agent
sharer.sleeping_agent += delta_sleeping_agent
var/list/trace_types_considered = list()
agent_b -= delta_agent_b
sharer.agent_b += delta_agent_b
for(var/gas in trace_gases)
var/datum/gas/trace_gas = gas
var/datum/gas/corresponding = locate(trace_gas.type) in sharer.trace_gases
var/delta = 0
if(corresponding)
delta = QUANTIZE(trace_gas.moles_archived - corresponding.moles_archived)/(atmos_adjacent_turfs+1)
else
corresponding = new trace_gas.type()
sharer.trace_gases += corresponding
delta = trace_gas.moles_archived/(atmos_adjacent_turfs+1)
trace_gas.moles -= delta
corresponding.moles += delta
if(delta)
var/individual_heat_capacity = trace_gas.specific_heat*delta
if(delta > 0)
heat_capacity_self_to_sharer += individual_heat_capacity
else
heat_capacity_sharer_to_self -= individual_heat_capacity
moved_moles += delta
last_share += abs(delta)
trace_types_considered += trace_gas.type
for(var/gas in sharer.trace_gases)
var/datum/gas/trace_gas = gas
if(trace_gas.type in trace_types_considered)
continue
var/datum/gas/corresponding
var/delta = 0
corresponding = new trace_gas.type()
trace_gases += corresponding
delta = trace_gas.moles_archived/5
trace_gas.moles -= delta
corresponding.moles += delta
//Guaranteed transfer from sharer to self
var/individual_heat_capacity = trace_gas.specific_heat*delta
heat_capacity_sharer_to_self += individual_heat_capacity
moved_moles += -delta
last_share += abs(delta)
var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins + delta_sleeping_agent + delta_agent_b)
last_share = abs(delta_oxygen) + abs(delta_carbon_dioxide) + abs(delta_nitrogen) + abs(delta_toxins) + abs(delta_sleeping_agent) + abs(delta_agent_b)
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/new_self_heat_capacity = old_self_heat_capacity + heat_capacity_sharer_to_self - heat_capacity_self_to_sharer
var/new_sharer_heat_capacity = old_sharer_heat_capacity + heat_capacity_self_to_sharer - heat_capacity_sharer_to_self
if(new_self_heat_capacity > MINIMUM_HEAT_CAPACITY)
temperature = (old_self_heat_capacity*temperature - heat_capacity_self_to_sharer*temperature_archived + heat_capacity_sharer_to_self*sharer.temperature_archived)/new_self_heat_capacity
temperature = (old_self_heat_capacity * temperature - heat_capacity_self_to_sharer * temperature_archived + heat_capacity_sharer_to_self * sharer.temperature_archived) / new_self_heat_capacity
if(new_sharer_heat_capacity > MINIMUM_HEAT_CAPACITY)
sharer.temperature = (old_sharer_heat_capacity*sharer.temperature-heat_capacity_sharer_to_self*sharer.temperature_archived + heat_capacity_self_to_sharer*temperature_archived)/new_sharer_heat_capacity
sharer.temperature = (old_sharer_heat_capacity * sharer.temperature - heat_capacity_sharer_to_self * sharer.temperature_archived + heat_capacity_self_to_sharer * temperature_archived) / new_sharer_heat_capacity
if(abs(old_sharer_heat_capacity) > MINIMUM_HEAT_CAPACITY)
if(abs(new_sharer_heat_capacity/old_sharer_heat_capacity - 1) < 0.10) // <10% change in sharer heat capacity
if(abs(new_sharer_heat_capacity / old_sharer_heat_capacity - 1) < 0.10) // <10% change in sharer heat capacity
temperature_share(sharer, OPEN_HEAT_TRANSFER_COEFFICIENT)
if((delta_temperature > MINIMUM_TEMPERATURE_TO_MOVE) || abs(moved_moles) > MINIMUM_MOLES_DELTA_TO_MOVE)
var/delta_pressure = temperature_archived*(total_moles() + moved_moles) - sharer.temperature_archived*(sharer.total_moles() - moved_moles)
return delta_pressure*R_IDEAL_GAS_EQUATION/volume
var/delta_pressure = temperature_archived * (total_moles() + moved_moles) - sharer.temperature_archived * (sharer.total_moles() - moved_moles)
return delta_pressure * R_IDEAL_GAS_EQUATION / volume
/datum/gas_mixture/mimic(turf/model, atmos_adjacent_turfs = 4)
var/delta_oxygen = QUANTIZE(oxygen_archived - model.oxygen)/(atmos_adjacent_turfs+1)
var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - model.carbon_dioxide)/(atmos_adjacent_turfs+1)
var/delta_nitrogen = QUANTIZE(nitrogen_archived - model.nitrogen)/(atmos_adjacent_turfs+1)
var/delta_toxins = QUANTIZE(toxins_archived - model.toxins)/(atmos_adjacent_turfs+1)
var/delta_oxygen = QUANTIZE(oxygen_archived - model.oxygen) / (atmos_adjacent_turfs + 1)
var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - model.carbon_dioxide) / (atmos_adjacent_turfs + 1)
var/delta_nitrogen = QUANTIZE(nitrogen_archived - model.nitrogen) / (atmos_adjacent_turfs + 1)
var/delta_toxins = QUANTIZE(toxins_archived - model.toxins) / (atmos_adjacent_turfs + 1)
var/delta_sleeping_agent = QUANTIZE(sleeping_agent_archived - model.sleeping_agent) / (atmos_adjacent_turfs + 1)
var/delta_agent_b = QUANTIZE(agent_b_archived - model.agent_b) / (atmos_adjacent_turfs + 1)
var/delta_temperature = (temperature_archived - model.temperature)
@@ -546,57 +452,54 @@ What are the archived variables for?
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/delta_air = delta_oxygen+delta_nitrogen
var/delta_air = delta_oxygen + delta_nitrogen
if(delta_air)
var/air_heat_capacity = SPECIFIC_HEAT_AIR*delta_air
heat_transferred -= air_heat_capacity*model.temperature
var/air_heat_capacity = SPECIFIC_HEAT_AIR * delta_air
heat_transferred -= air_heat_capacity * model.temperature
heat_capacity_transferred -= air_heat_capacity
if(delta_carbon_dioxide)
var/carbon_dioxide_heat_capacity = SPECIFIC_HEAT_CDO*delta_carbon_dioxide
heat_transferred -= carbon_dioxide_heat_capacity*model.temperature
var/carbon_dioxide_heat_capacity = SPECIFIC_HEAT_CDO * delta_carbon_dioxide
heat_transferred -= carbon_dioxide_heat_capacity * model.temperature
heat_capacity_transferred -= carbon_dioxide_heat_capacity
if(delta_toxins)
var/toxins_heat_capacity = SPECIFIC_HEAT_TOXIN*delta_toxins
heat_transferred -= toxins_heat_capacity*model.temperature
var/toxins_heat_capacity = SPECIFIC_HEAT_TOXIN * delta_toxins
heat_transferred -= toxins_heat_capacity * model.temperature
heat_capacity_transferred -= toxins_heat_capacity
if(delta_sleeping_agent)
var/sleeping_agent_heat_capacity = SPECIFIC_HEAT_N2O * delta_sleeping_agent
heat_transferred -= sleeping_agent_heat_capacity * model.temperature
heat_capacity_transferred -= sleeping_agent_heat_capacity
if(delta_agent_b)
var/agent_b_heat_capacity = SPECIFIC_HEAT_AGENT_B * delta_agent_b
heat_transferred -= agent_b_heat_capacity * model.temperature
heat_capacity_transferred -= agent_b_heat_capacity
old_self_heat_capacity = heat_capacity()
oxygen -= delta_oxygen
carbon_dioxide -= delta_carbon_dioxide
nitrogen -= delta_nitrogen
toxins -= delta_toxins
sleeping_agent -= delta_sleeping_agent
agent_b -= delta_agent_b
var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins)
last_share = abs(delta_oxygen) + abs(delta_carbon_dioxide) + abs(delta_nitrogen) + abs(delta_toxins)
if(trace_gases.len)
for(var/gas in trace_gases)
var/datum/gas/trace_gas = gas
var/delta = 0
delta = trace_gas.moles_archived/(atmos_adjacent_turfs+1)
trace_gas.moles -= delta
var/heat_cap_transferred = delta*trace_gas.specific_heat
heat_transferred += heat_cap_transferred*temperature_archived
heat_capacity_transferred += heat_cap_transferred
moved_moles += delta
moved_moles += abs(delta)
var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins + delta_sleeping_agent + delta_agent_b)
last_share = abs(delta_oxygen) + abs(delta_carbon_dioxide) + abs(delta_nitrogen) + abs(delta_toxins) + abs(delta_sleeping_agent) + abs(delta_agent_b)
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/new_self_heat_capacity = old_self_heat_capacity - heat_capacity_transferred
if(new_self_heat_capacity > MINIMUM_HEAT_CAPACITY)
temperature = (old_self_heat_capacity*temperature - heat_capacity_transferred*temperature_archived)/new_self_heat_capacity
temperature = (old_self_heat_capacity * temperature - heat_capacity_transferred * temperature_archived) / new_self_heat_capacity
temperature_mimic(model, model.thermal_conductivity)
if((delta_temperature > MINIMUM_TEMPERATURE_TO_MOVE) || abs(moved_moles) > MINIMUM_MOLES_DELTA_TO_MOVE)
var/delta_pressure = temperature_archived*(total_moles() + moved_moles) - model.temperature*(model.oxygen+model.carbon_dioxide+model.nitrogen+model.toxins)
return delta_pressure*R_IDEAL_GAS_EQUATION/volume
var/delta_pressure = temperature_archived * (total_moles() + moved_moles) - model.temperature * (model.oxygen + model.carbon_dioxide + model.nitrogen + model.toxins + model.sleeping_agent + model.agent_b)
return delta_pressure * R_IDEAL_GAS_EQUATION / volume
else
return 0
@@ -608,11 +511,11 @@ What are the archived variables for?
var/sharer_heat_capacity = sharer.heat_capacity_archived()
if((sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
var/heat = conduction_coefficient*delta_temperature* \
(self_heat_capacity*sharer_heat_capacity/(self_heat_capacity+sharer_heat_capacity))
var/heat = conduction_coefficient*delta_temperature * \
(self_heat_capacity * sharer_heat_capacity / (self_heat_capacity + sharer_heat_capacity))
temperature -= heat/self_heat_capacity
sharer.temperature += heat/sharer_heat_capacity
temperature -= heat / self_heat_capacity
sharer.temperature += heat / sharer_heat_capacity
/datum/gas_mixture/temperature_mimic(turf/model, conduction_coefficient)
var/delta_temperature = (temperature - model.temperature)
@@ -620,10 +523,10 @@ What are the archived variables for?
var/self_heat_capacity = heat_capacity()
if((model.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
var/heat = conduction_coefficient*delta_temperature* \
(self_heat_capacity*model.heat_capacity/(self_heat_capacity+model.heat_capacity))
var/heat = conduction_coefficient * delta_temperature * \
(self_heat_capacity * model.heat_capacity / (self_heat_capacity + model.heat_capacity))
temperature -= heat/self_heat_capacity
temperature -= heat / self_heat_capacity
/datum/gas_mixture/temperature_turf_share(turf/simulated/sharer, conduction_coefficient)
var/delta_temperature = (temperature_archived - sharer.temperature)
@@ -631,52 +534,36 @@ What are the archived variables for?
var/self_heat_capacity = heat_capacity()
if((sharer.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
var/heat = conduction_coefficient*delta_temperature* \
(self_heat_capacity*sharer.heat_capacity/(self_heat_capacity+sharer.heat_capacity))
var/heat = conduction_coefficient * delta_temperature * \
(self_heat_capacity * sharer.heat_capacity / (self_heat_capacity + sharer.heat_capacity))
temperature -= heat/self_heat_capacity
sharer.temperature += heat/sharer.heat_capacity
temperature -= heat / self_heat_capacity
sharer.temperature += heat / sharer.heat_capacity
/datum/gas_mixture/compare(datum/gas_mixture/sample)
if((abs(oxygen-sample.oxygen) > MINIMUM_AIR_TO_SUSPEND) && \
((oxygen < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.oxygen) || (oxygen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.oxygen)))
if((abs(oxygen - sample.oxygen) > MINIMUM_AIR_TO_SUSPEND) && \
((oxygen < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.oxygen) || (oxygen > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.oxygen)))
return 0
if((abs(nitrogen-sample.nitrogen) > MINIMUM_AIR_TO_SUSPEND) && \
((nitrogen < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.nitrogen) || (nitrogen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.nitrogen)))
if((abs(nitrogen - sample.nitrogen) > MINIMUM_AIR_TO_SUSPEND) && \
((nitrogen < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.nitrogen) || (nitrogen > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.nitrogen)))
return 0
if((abs(carbon_dioxide-sample.carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && \
((carbon_dioxide < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide) || (carbon_dioxide > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide)))
if((abs(carbon_dioxide - sample.carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && \
((carbon_dioxide < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.carbon_dioxide) || (carbon_dioxide > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.carbon_dioxide)))
return 0
if((abs(toxins-sample.toxins) > MINIMUM_AIR_TO_SUSPEND) && \
((toxins < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.toxins) || (toxins > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.toxins)))
if((abs(toxins - sample.toxins) > MINIMUM_AIR_TO_SUSPEND) && \
((toxins < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.toxins) || (toxins > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.toxins)))
return 0
if((abs(sleeping_agent - sample.sleeping_agent) > MINIMUM_AIR_TO_SUSPEND) && \
((sleeping_agent < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.sleeping_agent) || (sleeping_agent > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.sleeping_agent)))
return 0
if((abs(agent_b - sample.agent_b) > MINIMUM_AIR_TO_SUSPEND) && \
((agent_b < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.agent_b) || (agent_b > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.agent_b)))
return 0
if(total_moles() > MINIMUM_AIR_TO_SUSPEND)
if((abs(temperature-sample.temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) && \
((temperature < (1-MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature) || (temperature > (1+MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature)))
if((abs(temperature - sample.temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) && \
((temperature < (1 - MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND) * sample.temperature) || (temperature > (1 + MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND) * sample.temperature)))
return 0
for(var/gas in sample.trace_gases)
var/datum/gas/trace_gas = gas
if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND)
var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases
if(corresponding)
if((abs(trace_gas.moles - corresponding.moles) > MINIMUM_AIR_TO_SUSPEND) && \
((corresponding.moles < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*trace_gas.moles) || (corresponding.moles > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*trace_gas.moles)))
return 0
else
return 0
for(var/gas in trace_gases)
var/datum/gas/trace_gas = gas
if(trace_gas.moles > MINIMUM_AIR_TO_SUSPEND)
var/datum/gas/corresponding = locate(trace_gas.type) in sample.trace_gases
if(corresponding)
if((abs(trace_gas.moles - corresponding.moles) > MINIMUM_AIR_TO_SUSPEND) && \
((trace_gas.moles < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*corresponding.moles) || (trace_gas.moles > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*corresponding.moles)))
return 0
else
return 0
return 1
@@ -691,12 +578,12 @@ What are the archived variables for?
//Does handle trace gases!
/datum/gas_mixture/proc/get_breath_partial_pressure(gas_pressure)
return (gas_pressure*R_IDEAL_GAS_EQUATION*temperature)/BREATH_VOLUME
return (gas_pressure * R_IDEAL_GAS_EQUATION * temperature) / BREATH_VOLUME
//Reverse of the above
/datum/gas_mixture/proc/get_true_breath_pressure(breath_pp)
return (breath_pp*BREATH_VOLUME)/(R_IDEAL_GAS_EQUATION*temperature)
return (breath_pp * BREATH_VOLUME) / (R_IDEAL_GAS_EQUATION * temperature)
//Mathematical proofs:
/*
@@ -1,152 +0,0 @@
/*
README:
The global_iterator datum is supposed to provide a simple and robust way to
create some constantly "looping" processes with ability to stop and restart them at will.
Generally, the only thing you want to play with (meaning, redefine) is the process() proc.
It must contain all the things you want done.
Control functions:
new - used to create datum. First argument (optional) - var list(to use in process() proc) as list,
second (optional) - autostart control.
If autostart == TRUE, the loop will be started immediately after datum creation.
start(list/arguments) - starts the loop. Takes arguments(optional) as a list, which is then used
by process() proc. Returns null if datum already active, 1 if loop started succesfully and 0 if there's
an error in supplied arguments (not list or empty list).
stop() - stops the loop. Returns null if datum is already inactive and 1 on success.
set_delay(new_delay) - sets the delay between iterations. Pretty selfexplanatory.
Returns 0 on error(new_delay is not numerical), 1 otherwise.
set_process_args(list/arguments) - passes the supplied arguments to the process() proc.
active() - Returns 1 if datum is active, 0 otherwise.
toggle() - toggles datum state. Returns new datum state (see active()).
Misc functions:
get_last_exec_time() - Returns the time of last iteration.
get_last_exec_time_as_text() - Returns the time of last iteration as text
Control vars:
delay - delay between iterations
check_for_null - if equals TRUE, on each iteration the supplied arguments will be checked for nulls.
If some varible equals null (and null only), the loop is stopped.
Usefull, if some var unexpectedly becomes null - due to object deletion, for example.
Of course, you can also check the variables inside process() proc to prevent runtime errors.
Data storage vars:
result - stores the value returned by process() proc
*/
/datum/global_iterator
var/control_switch = 0
var/delay = 10
var/list/arg_list = new
var/last_exec = null
var/check_for_null = 1
var/forbid_garbage = 0
var/result
var/state = 0
/datum/global_iterator/New(list/arguments=null,autostart=1)
delay = delay>0?(delay):1
if(forbid_garbage) //prevents garbage collection with tag != null
tag = "\ref[src]"
set_process_args(arguments)
if(autostart)
start()
return
/datum/global_iterator/proc/main()
state = 1
while(src && control_switch)
last_exec = world.timeofday
if(check_for_null && has_null_args())
stop()
return 0
result = process(arglist(arg_list))
for(var/sleep_time=delay;sleep_time>0;sleep_time--) //uhh, this is ugly. But I see no other way to terminate sleeping proc. Such disgrace.
if(!control_switch)
return 0
sleep(1)
return 0
/datum/global_iterator/proc/start(list/arguments=null)
if(active())
return
if(arguments)
if(!set_process_args(arguments))
return 0
if(!state_check()) //the main loop is sleeping, wait for it to terminate.
return
control_switch = 1
spawn()
state = main()
return 1
/datum/global_iterator/proc/stop()
if(!active())
return
control_switch = 0
spawn(-1) //report termination error but don't wait for state_check().
state_check()
return 1
/datum/global_iterator/proc/state_check()
var/lag = 0
while(state)
sleep(1)
if(++lag>10)
CRASH("The global_iterator loop \ref[src] failed to terminate in designated timeframe. This may be caused by server lagging.")
return 1
/datum/global_iterator/process()
return
/datum/global_iterator/proc/active()
return control_switch
/datum/global_iterator/proc/has_null_args()
if(null in arg_list)
return 1
return 0
/datum/global_iterator/proc/set_delay(new_delay)
if(isnum(new_delay))
delay = max(1, round(new_delay))
return 1
else
return 0
/datum/global_iterator/proc/get_last_exec_time()
return (last_exec||0)
/datum/global_iterator/proc/get_last_exec_time_as_text()
return (time2text(last_exec)||"Wasn't executed yet")
/datum/global_iterator/proc/set_process_args(list/arguments)
if(arguments && istype(arguments, /list) && arguments.len)
arg_list = arguments
return 1
else
// to_chat(world, "<span class='warning'>Invalid arguments supplied for [src.type], ref = \ref[src]</span>")
return 0
/datum/global_iterator/proc/toggle_null_checks()
check_for_null = !check_for_null
return check_for_null
/datum/global_iterator/proc/toggle()
if(!stop())
start()
return active()
+1 -1
View File
@@ -211,7 +211,7 @@
var/datum/gas_mixture/A = F.air
// Can most things breathe?
if(A.trace_gases.len)
if(A.sleeping_agent)
continue
if(A.oxygen < 16)
continue
-1
View File
@@ -148,7 +148,6 @@
eye.eye_user = user
eye.name = "Camera Eye ([user.name])"
user.remote_control = eye
user.remote_view = 1
user.reset_perspective(eye)
eye.setLoc(get_turf(H))
+2 -2
View File
@@ -1688,7 +1688,7 @@
if(H.w_uniform)
jumpsuit = H.w_uniform
jumpsuit.color = team_color
H.update_inv_w_uniform(0,0)
H.update_inv_w_uniform()
add_attack_logs(missionary, current, "Converted to a zealot for [convert_duration/600] minutes")
addtimer(CALLBACK(src, .proc/remove_zealot, jumpsuit), convert_duration) //deconverts after the timer expires
@@ -1705,7 +1705,7 @@
jumpsuit.color = initial(jumpsuit.color) //reset the jumpsuit no matter where our mind is
if(ishuman(current)) //but only try updating us if we are still a human type since it is a human proc
var/mob/living/carbon/human/H = current
H.update_inv_w_uniform(0,0)
H.update_inv_w_uniform()
to_chat(current, "<span class='warning'><b>You seem to have forgotten the events of the past 10 minutes or so, and your head aches a bit as if someone beat it savagely with a stick.</b></span>")
to_chat(current, "<span class='warning'><b>This means you don't remember who you were working for or what you were doing.</b></span>")
+1 -1
View File
@@ -39,7 +39,7 @@
if(user.client)
user.client.images += bar
progress = Clamp(progress, 0, goal)
progress = clamp(progress, 0, goal)
bar.icon_state = "prog_bar_[round(((progress / goal) * 100), 5)]"
if(!shown)
user.client.images += bar
+2 -2
View File
@@ -237,10 +237,10 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
if(action)
action.UpdateButtonIcon()
/obj/effect/proc_holder/spell/proc/perform(list/targets, recharge = 1, mob/user = usr) //if recharge is started is important for the trigger spells
/obj/effect/proc_holder/spell/proc/perform(list/targets, recharge = 1, mob/user = usr, make_attack_logs = TRUE) //if recharge is started is important for the trigger spells
before_cast(targets)
invocation()
if(user && user.ckey)
if(user && user.ckey && make_attack_logs)
add_attack_logs(user, targets, "cast the spell [name]", ATKLOG_ALL)
spawn(0)
if(charge_type == "recharge" && recharge)
+6 -6
View File
@@ -36,10 +36,10 @@
unEquip(gloves, 1)
if(!istype(wear_mask, /obj/item/clothing/mask/cursedclown)) //Infinite loops otherwise
unEquip(wear_mask, 1)
equip_to_slot_if_possible(new /obj/item/clothing/under/cursedclown, slot_w_uniform, 1, 1, 1)
equip_to_slot_if_possible(new /obj/item/clothing/gloves/cursedclown, slot_gloves, 1, 1, 1)
equip_to_slot_if_possible(new /obj/item/clothing/mask/cursedclown, slot_wear_mask, 1, 1, 1)
equip_to_slot_if_possible(new /obj/item/clothing/shoes/cursedclown, slot_shoes, 1, 1, 1)
equip_to_slot_if_possible(new /obj/item/clothing/under/cursedclown, slot_w_uniform, TRUE, TRUE)
equip_to_slot_if_possible(new /obj/item/clothing/gloves/cursedclown, slot_gloves, TRUE, TRUE)
equip_to_slot_if_possible(new /obj/item/clothing/mask/cursedclown, slot_wear_mask, TRUE, TRUE)
equip_to_slot_if_possible(new /obj/item/clothing/shoes/cursedclown, slot_shoes, TRUE, TRUE)
/mob/living/carbon/human/proc/makeAntiCluwne()
to_chat(src, "<span class='danger'>You don't feel very funny.</span>")
@@ -83,5 +83,5 @@
unEquip(gloves, 1)
qdel(G)
equip_to_slot_if_possible(new /obj/item/clothing/under/lawyer/black, slot_w_uniform, 1, 1, 1)
equip_to_slot_if_possible(new /obj/item/clothing/shoes/black, slot_shoes, 1, 1, 1)
equip_to_slot_if_possible(new /obj/item/clothing/under/lawyer/black, slot_w_uniform, TRUE, TRUE)
equip_to_slot_if_possible(new /obj/item/clothing/shoes/black, slot_shoes, TRUE, TRUE)
-1
View File
@@ -142,7 +142,6 @@
return 0
fakefire()
forceMove(get_turf(src))
reset_perspective()
visible_message("<span class='warning'><B>[src] appears in a firey blaze!</B></span>")
playsound(get_turf(src), 'sound/misc/exit_blood.ogg', 100, 1, -1)
spawn(15)
-5
View File
@@ -2,7 +2,6 @@
name = "Genetic"
desc = "This spell inflicts a set of mutations and disabilities upon the target."
var/disabilities = 0 //bits
var/list/mutations = list() //mutation strings
var/duration = 100 //deciseconds
/*
@@ -20,16 +19,12 @@
for(var/mob/living/target in targets)
for(var/x in mutations)
target.mutations.Add(x)
/* if(x == HULK && ishuman(target))
target:hulk_time=world.time + duration */
target.disabilities |= disabilities
target.update_mutations() //update target's mutation overlays
var/mob/living/carbon/human/H = target
if(ishuman(target))
H.update_body()
spawn(duration)
target.mutations.Remove(mutations)
target.disabilities &= ~disabilities
target.update_mutations()
if(ishuman(target))
H.update_body()
+1 -1
View File
@@ -43,6 +43,6 @@
"<span class='danger'>Your face burns up, and shortly after the fire you realise you have the face of a horse!</span>")
if(!target.unEquip(target.wear_mask))
qdel(target.wear_mask)
target.equip_to_slot_if_possible(magichead, slot_wear_mask, 1, 1)
target.equip_to_slot_if_possible(magichead, slot_wear_mask, TRUE, TRUE)
target.flash_eyes()
+5 -2
View File
@@ -13,6 +13,11 @@
action_icon_state = "knock"
sound = 'sound/magic/knock.ogg'
// Knock doesn't need to generate an attack log for every turf, set `make_attack_logs` to FALSE and just create a custom one.
/obj/effect/proc_holder/spell/aoe_turf/knock/perform(list/targets, recharge, mob/user)
add_attack_logs(user, user, "cast the spell [name]", ATKLOG_ALL)
return ..(targets, recharge, user, make_attack_logs = FALSE)
/obj/effect/proc_holder/spell/aoe_turf/knock/cast(list/targets, mob/user = usr)
for(var/turf/T in targets)
for(var/obj/machinery/door/door in T.contents)
@@ -30,8 +35,6 @@
SC.locked = 0
C.open()
return
/obj/effect/proc_holder/spell/aoe_turf/knock/greater
name = "Greater Knock"
desc = "On first cast, will remove access restrictions on all airlocks on the station, and announce this spell's use to the station. On any further cast, will open all doors in sight. Cannot be refunded once bought!"
+4 -4
View File
@@ -104,12 +104,12 @@
if(target.hand) //left active hand
if(!target.equip_to_slot_if_possible(item_to_retrieve, slot_l_hand, 0, 1, 1))
if(!target.equip_to_slot_if_possible(item_to_retrieve, slot_r_hand, 0, 1, 1))
if(!target.equip_to_slot_if_possible(item_to_retrieve, slot_l_hand, FALSE, TRUE))
if(!target.equip_to_slot_if_possible(item_to_retrieve, slot_r_hand, FALSE, TRUE))
butterfingers = 1
else //right active hand
if(!target.equip_to_slot_if_possible(item_to_retrieve, slot_r_hand, 0, 1, 1))
if(!target.equip_to_slot_if_possible(item_to_retrieve, slot_l_hand, 0, 1, 1))
if(!target.equip_to_slot_if_possible(item_to_retrieve, slot_r_hand, FALSE, TRUE))
if(!target.equip_to_slot_if_possible(item_to_retrieve, slot_l_hand, FALSE, TRUE))
butterfingers = 1
if(butterfingers)
item_to_retrieve.loc = target.loc
+4 -4
View File
@@ -27,12 +27,12 @@
var/hand_handled = 1
attached_hand = new hand_path(src)
if(user.hand) //left active hand
if(!user.equip_to_slot_if_possible(attached_hand, slot_l_hand, 0, 1, 1))
if(!user.equip_to_slot_if_possible(attached_hand, slot_r_hand, 0, 1, 1))
if(!user.equip_to_slot_if_possible(attached_hand, slot_l_hand, FALSE, TRUE))
if(!user.equip_to_slot_if_possible(attached_hand, slot_r_hand, FALSE, TRUE))
hand_handled = 0
else //right active hand
if(!user.equip_to_slot_if_possible(attached_hand, slot_r_hand, 0, 1, 1))
if(!user.equip_to_slot_if_possible(attached_hand, slot_l_hand, 0, 1, 1))
if(!user.equip_to_slot_if_possible(attached_hand, slot_r_hand, FALSE, TRUE))
if(!user.equip_to_slot_if_possible(attached_hand, slot_l_hand, FALSE, TRUE))
hand_handled = 0
if(!hand_handled)
qdel(attached_hand)
+2 -2
View File
@@ -304,7 +304,7 @@
sound = 'sound/magic/blind.ogg'
/obj/effect/proc_holder/spell/targeted/genetic/blind
disabilities = BLIND
mutations = list(BLINDNESS)
duration = 300
sound = 'sound/magic/blind.ogg'
@@ -423,7 +423,7 @@
M.Weaken(stun_amt)
to_chat(M, "<span class='userdanger'>You're thrown back by a mystical force!</span>")
spawn(0)
AM.throw_at(throwtarget, ((Clamp((maxthrow - (Clamp(distfromcaster - 2, 0, distfromcaster))), 3, maxthrow))), 1)//So stuff gets tossed around at the same time.
AM.throw_at(throwtarget, ((clamp((maxthrow - (clamp(distfromcaster - 2, 0, distfromcaster))), 3, maxthrow))), 1)//So stuff gets tossed around at the same time.
/obj/effect/proc_holder/spell/targeted/sacred_flame
name = "Sacred Flame"
+3 -2
View File
@@ -5,7 +5,7 @@
/datum/status_effect
var/id = "effect" //Used for screen alerts.
var/duration = -1 //How long the status effect lasts in DECISECONDS. Enter -1 for an effect that never ends unless removed through some means.
var/tick_interval = 10 //How many deciseconds between ticks, approximately. Leave at 10 for every second.
var/tick_interval = 10 //How many deciseconds between ticks, approximately. Leave at 10 for every second. Setting this to -1 will stop processing if duration is also unlimited.
var/mob/living/owner //The mob affected by the status effect.
var/status_type = STATUS_EFFECT_UNIQUE //How many of the effect can be on one mob, and what happens when you try to add another
var/on_remove_on_mob_delete = FALSE //if we call on_remove() when the mob is deleted
@@ -31,7 +31,8 @@
var/obj/screen/alert/status_effect/A = owner.throw_alert(id, alert_type)
A.attached_effect = src //so the alert can reference us, if it needs to
linked_alert = A //so we can reference the alert, if we need to
START_PROCESSING(SSfastprocess, src)
if(duration > 0 || initial(tick_interval) > 0) //don't process if we don't care
START_PROCESSING(SSfastprocess, src)
return TRUE
/datum/status_effect/Destroy()
+1 -2
View File
@@ -31,7 +31,6 @@ GLOBAL_LIST_INIT(wireColours, list("red", "blue", "green", "black", "orange", "b
src.holder = holder
if(!istype(holder, holder_type))
CRASH("Our holder is null/the wrong type!")
return
// Generate new wires
if(random)
@@ -87,7 +86,7 @@ GLOBAL_LIST_INIT(wireColours, list("red", "blue", "green", "black", "orange", "b
if(ishuman(user))
var/mob/living/carbon/human/H = user
var/obj/item/organ/internal/eyes/eyes = H.get_int_organ(/obj/item/organ/internal/eyes)
if(eyes && H.disabilities & COLOURBLIND)
if(eyes && (COLOURBLIND in H.mutations))
replace_colours = eyes.replace_colours