diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index 6c21e55d11a..e9816ed3eb0 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -1,39 +1,91 @@
-//Update this whenever the db schema changes
-//make sure you add an update to the schema_version stable in the db changelog
+//! Defines for subsystems and overlays
+//!
+//! Lots of important stuff in here, make sure you have your brain switched on
+//! when editing this file
+
+//! ## DB defines
+/**
+ * DB major schema version
+ *
+ * Update this whenever the db schema changes
+ *
+ * make sure you add an update to the schema_version stable in the db changelog
+ */
#define DB_MAJOR_VERSION 5
+
+/**
+ * DB minor schema version
+ *
+ * Update this whenever the db schema changes
+ *
+ * make sure you add an update to the schema_version stable in the db changelog
+ */
#define DB_MINOR_VERSION 3
-//Timing subsystem
-//Don't run if there is an identical unique timer active
-//if the arguments to addtimer are the same as an existing timer, it doesn't create a new timer, and returns the id of the existing timer
+//! ## Timing subsystem
+/**
+ * Don't run if there is an identical unique timer active
+ *
+ * if the arguments to addtimer are the same as an existing timer, it doesn't create a new timer,
+ * and returns the id of the existing timer
+ */
#define TIMER_UNIQUE (1<<0)
-//For unique timers: Replace the old timer rather then not start this one
+
+///For unique timers: Replace the old timer rather then not start this one
#define TIMER_OVERRIDE (1<<1)
-//Timing should be based on how timing progresses on clients, not the sever.
-// tracking this is more expensive,
-// should only be used in conjuction with things that have to progress client side, such as animate() or sound()
+
+/**
+ * Timing should be based on how timing progresses on clients, not the server.
+ *
+ * Tracking this is more expensive,
+ * should only be used in conjuction with things that have to progress client side, such as
+ * animate() or sound()
+ */
#define TIMER_CLIENT_TIME (1<<2)
-//Timer can be stopped using deltimer()
+
+///Timer can be stopped using deltimer()
#define TIMER_STOPPABLE (1<<3)
-//To be used with TIMER_UNIQUE
-//prevents distinguishing identical timers with the wait variable
+
+///prevents distinguishing identical timers with the wait variable
+///
+///To be used with TIMER_UNIQUE
#define TIMER_NO_HASH_WAIT (1<<4)
-//Loops the timer repeatedly until qdeleted
-//In most cases you want a subsystem instead
+
+///Loops the timer repeatedly until qdeleted
+///
+///In most cases you want a subsystem instead, so don't use this unless you have a good reason
#define TIMER_LOOP (1<<5)
+///Empty ID define
#define TIMER_ID_NULL -1
-#define INITIALIZATION_INSSATOMS 0 //New should not call Initialize
-#define INITIALIZATION_INNEW_MAPLOAD 2 //New should call Initialize(TRUE)
-#define INITIALIZATION_INNEW_REGULAR 1 //New should call Initialize(FALSE)
+//! ## Initialization subsystem
-#define INITIALIZE_HINT_NORMAL 0 //Nothing happens
-#define INITIALIZE_HINT_LATELOAD 1 //Call LateInitialize
-#define INITIALIZE_HINT_QDEL 2 //Call qdel on the atom
+///New should not call Initialize
+#define INITIALIZATION_INSSATOMS 0
+///New should call Initialize(TRUE)
+#define INITIALIZATION_INNEW_MAPLOAD 2
+///New should call Initialize(FALSE)
+#define INITIALIZATION_INNEW_REGULAR 1
-//type and all subtypes should always call Initialize in New()
+//! ### Initialization hints
+
+///Nothing happens
+#define INITIALIZE_HINT_NORMAL 0
+/**
+ * call LateInitialize at the end of all atom Initalization
+ *
+ * The item will be added to the late_loaders list, this is iterated over after
+ * initalization of subsystems is complete and calls LateInitalize on the atom
+ * see [this file for the LateIntialize proc](atom.html#proc/LateInitialize)
+ */
+#define INITIALIZE_HINT_LATELOAD 1
+
+///Call qdel on the atom after intialization
+#define INITIALIZE_HINT_QDEL 2
+
+///type and all subtypes should always immediately call Initialize in New()
#define INITIALIZE_IMMEDIATE(X) ##X/New(loc, ...){\
..();\
if(!(flags_1 & INITIALIZED_1)) {\
@@ -123,7 +175,9 @@
+//! ## Overlays subsystem
+///Compile all the overlays for an atom from the cache lists
#define COMPILE_OVERLAYS(A)\
if (TRUE) {\
var/list/ad = A.add_overlays;\
diff --git a/code/datums/datum.dm b/code/datums/datum.dm
index d94281431e3..9b83d0bc9bc 100644
--- a/code/datums/datum.dm
+++ b/code/datums/datum.dm
@@ -1,12 +1,38 @@
+/**
+ * The absolute base class for everything
+ *
+ * A datum instantiated has no physical world prescence, use an atom if you want something
+ * that actually lives in the world
+ *
+ * Be very mindful about adding variables to this class, they are inherited by every single
+ * thing in the entire game, and so you can easily cause memory usage to rise a lot with careless
+ * use of variables at this level
+ */
/datum
- var/gc_destroyed //Time when this object was destroyed.
- var/list/active_timers //for SStimer
- var/list/datum_components //for /datum/components
+ /**
+ * Tick count time when this object was destroyed.
+ *
+ * If this is non zero then the object has been garbage collected and is awaiting either
+ * a hard del by the GC subsystme, or to be autocollected (if it has no references)
+ */
+ var/gc_destroyed
+
+ /// Active timers with this datum as the target
+ var/list/active_timers
+ /// Components attached to this datum
+ var/list/datum_components
+ /// Status traits attached to this datum
var/list/status_traits
- var/list/comp_lookup //it used to be for looking up components which had registered a signal but now anything can register
+ /// Any datum registered to receive signals from this datum is in this list
+ var/list/comp_lookup
+ /// List of callbacks for signal procs
var/list/list/datum/callback/signal_procs
+ /// Is this datum capable of sending signals?
var/signal_enabled = FALSE
+ /// Datum level flags
var/datum_flags = NONE
+
+ /// A weak reference to another datum
var/datum/weakref/weak_reference
#ifdef TESTING
@@ -18,13 +44,31 @@
var/list/cached_vars
#endif
+/**
+ * Called when a href for this datum is clicked
+ *
+ * Sends a COMSIG_TOPIC signal
+ */
/datum/Topic(href, href_list[])
..()
SEND_SIGNAL(src, COMSIG_TOPIC, usr, href_list)
-// Default implementation of clean-up code.
-// This should be overridden to remove all references pointing to the object being destroyed.
-// Return the appropriate QDEL_HINT; in most cases this is QDEL_HINT_QUEUE.
+/**
+ * Default implementation of clean-up code.
+ *
+ * This should be overridden to remove all references pointing to the object being destroyed, if
+ * you do override it, make sure to call the parent and return it's return value by default
+ *
+ * Return an appropriate QDEL_HINT to modify handling of your deletion;
+ * in most cases this is QDEL_HINT_QUEUE.
+ *
+ * The base case is responsible for doing the following
+ * * Erasing timers pointing to this datum
+ * * Erasing compenents on this datum
+ * * Notifying datums listening to signals from this datum that we are going away
+ *
+ * Returns QDEL_HINT_QUEUE
+ */
/datum/proc/Destroy(force=FALSE, ...)
tag = null
datum_flags &= ~DF_USE_TAG //In case something tries to REF us
@@ -99,15 +143,15 @@
to_chat(target, txt_changed_vars())
#endif
-//Return a LIST for serialize_datum to encode! Not the actual json!
+///Return a LIST for serialize_datum to encode! Not the actual json!
/datum/proc/serialize_list(list/options)
CRASH("Attempted to serialize datum [src] of type [type] without serialize_list being implemented!")
-//Accepts a LIST from deserialize_datum. Should return src or another datum.
+///Accepts a LIST from deserialize_datum. Should return src or another datum.
/datum/proc/deserialize_list(json, list/options)
CRASH("Attempted to deserialize datum [src] of type [type] without deserialize_list being implemented!")
-//Serializes into JSON. Does not encode type.
+///Serializes into JSON. Does not encode type.
/datum/proc/serialize_json(list/options)
. = serialize_list(options)
if(!islist(.))
@@ -115,13 +159,14 @@
else
. = json_encode(.)
-//Deserializes from JSON. Does not parse type.
+///Deserializes from JSON. Does not parse type.
/datum/proc/deserialize_json(list/input, list/options)
var/list/jsonlist = json_decode(input)
. = deserialize_list(jsonlist)
if(!istype(., /datum))
. = null
+///Convert a datum into a json blob
/proc/json_serialize_datum(datum/D, list/options)
if(!istype(D))
return
@@ -130,6 +175,7 @@
jsonlist["DATUM_TYPE"] = D.type
return json_encode(jsonlist)
+/// Convert a list of json to datum
/proc/json_deserialize_datum(list/jsonlist, list/options, target_type, strict_target_type = FALSE)
if(!islist(jsonlist))
if(!istext(jsonlist))
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index c033bad7183..73da7919e8d 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -1,13 +1,16 @@
-// Areas.dm
-
-
+/**
+ * # area
+ *
+ * A grouping of tiles into a logical space, mostly used by map editors
+ */
/area
level = null
name = "Space"
icon = 'icons/turf/areas.dmi'
icon_state = "unknown"
layer = AREA_LAYER
- plane = BLACKNESS_PLANE //Keeping this on the default plane, GAME_PLANE, will make area overlays fail to render on FLOOR_PLANE.
+ //Keeping this on the default plane, GAME_PLANE, will make area overlays fail to render on FLOOR_PLANE.
+ plane = BLACKNESS_PLANE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
invisibility = INVISIBILITY_LIGHTING
@@ -31,8 +34,10 @@
var/areasize = 0 //Size of the area in open turfs, only calculated for indoors areas.
- var/mood_bonus = 0 //Mood for being here
- var/mood_message = "This area is pretty nice!\n" //Mood message for being here, only shows up if mood_bonus != 0
+ /// Bonus mood for being in this area
+ var/mood_bonus = 0
+ /// Mood message for being here, only shows up if mood_bonus != 0
+ var/mood_message = "This area is pretty nice!\n"
var/power_equip = TRUE
var/power_light = TRUE
@@ -45,9 +50,12 @@
var/static_environ
var/has_gravity = 0
- var/noteleport = FALSE //Are you forbidden from teleporting to the area? (centcom, mobs, wizard, hand teleporter)
- var/hidden = FALSE //Hides area from player Teleport function.
- var/safe = FALSE //Is the area teleport-safe: no space / radiation / aggresive mobs / other dangers
+ ///Are you forbidden from teleporting to the area? (centcom, mobs, wizard, hand teleporter)
+ var/noteleport = FALSE
+ ///Hides area from player Teleport function.
+ var/hidden = FALSE
+ ///Is the area teleport-safe: no space / radiation / aggresive mobs / other dangers
+ var/safe = FALSE
/// If false, loading multiple maps with this area type will create multiple instances.
var/unique = TRUE
@@ -64,13 +72,28 @@
var/list/cameras
var/list/firealarms
var/firedoors_last_closed_on = 0
- var/xenobiology_compatible = FALSE //Can the Xenobio management console transverse this area by default?
- var/list/canSmoothWithAreas //typecache to limit the areas that atoms in this area can smooth with
+ /// Can the Xenobio management console transverse this area by default?
+ var/xenobiology_compatible = FALSE
+ /// typecache to limit the areas that atoms in this area can smooth with, used for shuttles IIRC
+ var/list/canSmoothWithAreas
-/*Adding a wizard area teleport list because motherfucking lag -- Urist*/
-/*I am far too lazy to make it a proper list of areas so I'll just make it run the usual telepot routine at the start of the game*/
+/**
+ * A list of teleport locations
+ *
+ * Adding a wizard area teleport list because motherfucking lag -- Urist
+ * I am far too lazy to make it a proper list of areas so I'll just make it run the usual telepot routine at the start of the game
+ */
GLOBAL_LIST_EMPTY(teleportlocs)
+/**
+ * Generate a list of turfs you can teleport to from the areas list
+ *
+ * Includes areas if they're not a shuttle or not not teleport or have no contents
+ *
+ * The chosen turf is the first item in the areas contents that is a station level
+ *
+ * The returned list of turfs is sorted by name
+ */
/proc/process_teleport_locs()
for(var/V in GLOB.sortedAreas)
var/area/AR = V
@@ -86,8 +109,11 @@ GLOBAL_LIST_EMPTY(teleportlocs)
sortTim(GLOB.teleportlocs, /proc/cmp_text_dsc)
-// ===
-
+/**
+ * Called when an area loads
+ *
+ * Adds the item to the GLOB.areas_by_type list based on area type
+ */
/area/New()
// This interacts with the map loader, so it needs to be set immediately
// rather than waiting for atoms to initialize.
@@ -95,6 +121,14 @@ GLOBAL_LIST_EMPTY(teleportlocs)
GLOB.areas_by_type[type] = src
return ..()
+/**
+ * Initalize this area
+ *
+ * intializes the dynamic area lighting and also registers the area with the z level via
+ * reg_in_areas_in_z
+ *
+ * returns INITIALIZE_HINT_LATELOAD
+ */
/area/Initialize()
icon_state = ""
layer = AREA_LAYER
@@ -128,9 +162,21 @@ GLOBAL_LIST_EMPTY(teleportlocs)
return INITIALIZE_HINT_LATELOAD
+/**
+ * Sets machine power levels in the area
+ */
/area/LateInitialize()
power_change() // all machines set to current power level, also updates icon
+/**
+ * Register this area as belonging to a z level
+ *
+ * Ensures the item is added to the SSmapping.areas_in_z list for this z
+ *
+ * It also goes through every item in this areas contents and sets the area level z to it
+ * breaking the exat first time it does this, this seems crazy but what would I know, maybe
+ * areas don't have a valid z themself or something
+ */
/area/proc/reg_in_areas_in_z()
if(contents.len)
var/list/areas_in_z = SSmapping.areas_in_z
@@ -149,12 +195,25 @@ GLOBAL_LIST_EMPTY(teleportlocs)
areas_in_z["[z]"] = list()
areas_in_z["[z]"] += src
+/**
+ * Destroy an area and clean it up
+ *
+ * Removes the area from GLOB.areas_by_type and also stops it processing on SSobj
+ *
+ * This is despite the fact that no code appears to put it on SSobj, but
+ * who am I to argue with old coders
+ */
/area/Destroy()
if(GLOB.areas_by_type[type] == src)
GLOB.areas_by_type[type] = null
STOP_PROCESSING(SSobj, src)
return ..()
+/**
+ * Generate a power alert for this area
+ *
+ * Sends to all ai players, alert consoles, drones and alarm monitor programs in the world
+ */
/area/proc/poweralert(state, obj/source)
if (state != poweralm)
poweralm = state
@@ -186,6 +245,11 @@ GLOBAL_LIST_EMPTY(teleportlocs)
else
p.triggerAlarm("Power", src, cameras, source)
+/**
+ * Generate an atmospheric alert for this area
+ *
+ * Sends to all ai players, alert consoles, drones and alarm monitor programs in the world
+ */
/area/proc/atmosalert(danger_level, obj/source)
if(danger_level != atmosalm)
if (danger_level==2)
@@ -221,6 +285,9 @@ GLOBAL_LIST_EMPTY(teleportlocs)
return 1
return 0
+/**
+ * Try to close all the firedoors in the area
+ */
/area/proc/ModifyFiredoors(opening)
if(firedoors)
firedoors_last_closed_on = world.time
@@ -239,6 +306,13 @@ GLOBAL_LIST_EMPTY(teleportlocs)
else if(!(D.density ^ opening))
INVOKE_ASYNC(D, (opening ? /obj/machinery/door/firedoor.proc/open : /obj/machinery/door/firedoor.proc/close))
+/**
+ * Generate an firealarm alert for this area
+ *
+ * Sends to all ai players, alert consoles, drones and alarm monitor programs in the world
+ *
+ * Also starts the area processing on SSobj
+ */
/area/proc/firealert(obj/source)
if(always_unpowered == 1) //no fire alarms in space/asteroid
return
@@ -265,6 +339,14 @@ GLOBAL_LIST_EMPTY(teleportlocs)
START_PROCESSING(SSobj, src)
+/**
+ * Reset the firealarm alert for this area
+ *
+ * resets the alert sent to all ai players, alert consoles, drones and alarm monitor programs
+ * in the world
+ *
+ * Also cycles the icons of all firealarms and deregisters the area from processing on SSOBJ
+ */
/area/proc/firereset(obj/source)
if (fire)
unset_fire_alarm_effects()
@@ -288,16 +370,31 @@ GLOBAL_LIST_EMPTY(teleportlocs)
STOP_PROCESSING(SSobj, src)
+/**
+ * If 100 ticks has elapsed, toggle all the firedoors closed again
+ */
/area/process()
if(firedoors_last_closed_on + 100 < world.time) //every 10 seconds
ModifyFiredoors(FALSE)
+/**
+ * Close and lock a door passed into this proc
+ *
+ * Does this need to exist on area? probably not
+ */
/area/proc/close_and_lock_door(obj/machinery/door/DOOR)
set waitfor = FALSE
DOOR.close()
if(DOOR.density)
DOOR.lock()
+/**
+ * Raise a burglar alert for this area
+ *
+ * Close and locks all doors in the area and alerts silicon mobs of a break in
+ *
+ * Alarm auto resets after 600 ticks
+ */
/area/proc/burglaralert(obj/trigger)
if(always_unpowered) //no burglar alarms in space/asteroid
return
@@ -314,6 +411,11 @@ GLOBAL_LIST_EMPTY(teleportlocs)
//Cancel silicon alert after 1 minute
addtimer(CALLBACK(SILICON, /mob/living/silicon.proc/cancelAlarm,"Burglar",src,trigger), 600)
+/**
+ * Trigger the fire alarm visual affects in an area
+ *
+ * Updates the fire light on fire alarms in the area and sets all lights to emergency mode
+ */
/area/proc/set_fire_alarm_effect()
fire = TRUE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
@@ -323,6 +425,11 @@ GLOBAL_LIST_EMPTY(teleportlocs)
for(var/obj/machinery/light/L in src)
L.update()
+/**
+ * unset the fire alarm visual affects in an area
+ *
+ * Updates the fire light on fire alarms in the area and sets all lights to emergency mode
+ */
/area/proc/unset_fire_alarm_effects()
fire = FALSE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
@@ -332,6 +439,12 @@ GLOBAL_LIST_EMPTY(teleportlocs)
for(var/obj/machinery/light/L in src)
L.update()
+/**
+ * Update the icon of the area
+ *
+ * Im not sure what the heck this does, somethign to do with weather being able to set icon
+ * states on areas?? where the heck would that even display?
+ */
/area/proc/update_icon()
var/weather_icon
for(var/V in SSweather.processing)
@@ -342,15 +455,19 @@ GLOBAL_LIST_EMPTY(teleportlocs)
if(!weather_icon)
icon_state = null
+/**
+ * Update the icon of the area (overridden to always be null for space
+ */
/area/space/update_icon()
icon_state = null
-/*
-#define EQUIP 1
-#define LIGHT 2
-#define ENVIRON 3
-*/
+/**
+ * Returns int 1 or 0 if the area has power for the given channel
+ *
+ * evalutes a mixture of variables mappers can set, requires_power, always_unpowered and then
+ * per channel power_equip, power_light, power_environ
+ */
/area/proc/powered(chan) // return true if the area has power to given channel
if(!requires_power)
@@ -367,16 +484,25 @@ GLOBAL_LIST_EMPTY(teleportlocs)
return 0
+/**
+ * Space is not powered ever, so this returns 0
+ */
/area/space/powered(chan) //Nope.avi
return 0
-// called when power status changes
-
+/**
+ * Called when the area power status changes
+ *
+ * Updates the area icon and calls power change on all machinees in the area
+ */
/area/proc/power_change()
for(var/obj/machinery/M in src) // for each machine in the area
M.power_change() // reverify power status (to update icons etc.)
update_icon()
+/**
+ * Return the usage of power per channel
+ */
/area/proc/usage(chan)
var/used = 0
switch(chan)
@@ -396,6 +522,14 @@ GLOBAL_LIST_EMPTY(teleportlocs)
used += static_environ
return used
+/**
+ * Add a static amount of power load to an area
+ *
+ * Possible channels
+ * *STATIC_EQUIP
+ * *STATIC_LIGHT
+ * *STATIC_ENVIRON
+ */
/area/proc/addStaticPower(value, powerchannel)
switch(powerchannel)
if(STATIC_EQUIP)
@@ -405,11 +539,19 @@ GLOBAL_LIST_EMPTY(teleportlocs)
if(STATIC_ENVIRON)
static_environ += value
+/**
+ * Clear all power usage in area
+ *
+ * Clears all power used for equipment, light and environment channels
+ */
/area/proc/clear_usage()
used_equip = 0
used_light = 0
used_environ = 0
+/**
+ * Add a power value amount to the stored used_x variables
+ */
/area/proc/use_power(amount, chan)
switch(chan)
@@ -420,7 +562,13 @@ GLOBAL_LIST_EMPTY(teleportlocs)
if(ENVIRON)
used_environ += amount
-
+/**
+ * Call back when an atom enters an area
+ *
+ * Sends signals COMSIG_AREA_ENTERED and COMSIG_ENTER_AREA (to the atom)
+ *
+ * If the area has ambience, then it plays some ambience music to the ambience channel
+ */
/area/Entered(atom/movable/M)
set waitfor = FALSE
SEND_SIGNAL(src, COMSIG_AREA_ENTERED, M)
@@ -448,13 +596,35 @@ GLOBAL_LIST_EMPTY(teleportlocs)
L.client.played = TRUE
addtimer(CALLBACK(L.client, /client/proc/ResetAmbiencePlayed), 600)
+/**
+ * Called when an atom exits an area
+ *
+ * Sends signals COMSIG_AREA_EXITED and COMSIG_EXIT_AREA (to the atom)
+ */
/area/Exited(atom/movable/M)
SEND_SIGNAL(src, COMSIG_AREA_EXITED, M)
SEND_SIGNAL(M, COMSIG_EXIT_AREA, src) //The atom that exits the area
+/**
+ * Reset the played var to false on the client
+ */
/client/proc/ResetAmbiencePlayed()
played = FALSE
+/**
+ * Returns true if this atom has gravity for the passed in turf
+ *
+ * Sends signals COMSIG_ATOM_HAS_GRAVITY and COMSIG_TURF_HAS_GRAVITY, both can force gravity with
+ * the forced gravity var
+ *
+ * Gravity situations:
+ * * No gravity if you're not in a turf
+ * * No gravity if this atom is in is a space turf
+ * * Gravity if the area it's in always has gravity
+ * * Gravity if there's a gravity generator on the z level
+ * * Gravity if the Z level has an SSMappingTrait for ZTRAIT_GRAVITY
+ * * otherwise no gravity
+ */
/atom/proc/has_gravity(turf/T)
if(!T || !isturf(T))
T = get_turf(src)
@@ -486,7 +656,11 @@ GLOBAL_LIST_EMPTY(teleportlocs)
max_grav = max(G.setting,max_grav)
return max_grav
return SSmapping.level_trait(T.z, ZTRAIT_GRAVITY)
-
+/**
+ * Setup an area (with the given name)
+ *
+ * Sets the area name, sets all status var's to false and adds the area to the sorted area list
+ */
/area/proc/setup(a_name)
name = a_name
power_equip = FALSE
@@ -496,7 +670,12 @@ GLOBAL_LIST_EMPTY(teleportlocs)
valid_territory = FALSE
blob_allowed = FALSE
addSorted()
-
+/**
+ * Set the area size of the area
+ *
+ * This is the number of open turfs in the area contents, or FALSE if the outdoors var is set
+ *
+ */
/area/proc/update_areasize()
if(outdoors)
return FALSE
@@ -504,12 +683,18 @@ GLOBAL_LIST_EMPTY(teleportlocs)
for(var/turf/open/T in contents)
areasize++
+/**
+ * Causes a runtime error
+ */
/area/AllowDrop()
CRASH("Bad op: area/AllowDrop() called")
+/**
+ * Causes a runtime error
+ */
/area/drop_location()
CRASH("Bad op: area/drop_location() called")
-// A hook so areas can modify the incoming args
+/// A hook so areas can modify the incoming args (of what??)
/area/proc/PlaceOnTopReact(list/new_baseturfs, turf/fake_turf_type, flags)
return flags
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 9f112ed4840..6d67ff54c15 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -1,44 +1,83 @@
+/**
+ * The base type for nearly all physical objects in SS13
+
+ * Lots and lots of functionality lives here, although in general we are striving to move
+ * as much as possible to the components/elements system
+ */
/atom
layer = TURF_LAYER
plane = GAME_PLANE
var/level = 2
- var/article // If non-null, overrides a/an/some in all cases
+ ///If non-null, overrides a/an/some in all cases
+ var/article
+
+ ///First atom flags var
var/flags_1 = NONE
+ ///Intearaction flags
var/interaction_flags_atom = NONE
+
+ ///Reagents holder
var/datum/reagents/reagents = null
- //This atom's HUD (med/sec, etc) images. Associative list.
+ ///This atom's HUD (med/sec, etc) images. Associative list.
var/list/image/hud_list = null
- //HUD images that this atom can provide.
+ ///HUD images that this atom can provide.
var/list/hud_possible
- //Value used to increment ex_act() if reactionary_explosions is on
+ ///Value used to increment ex_act() if reactionary_explosions is on
var/explosion_block = 0
- var/list/atom_colours //used to store the different colors on an atom
- //its inherent color, the colored paint applied on it, special color effect etc...
+ /**
+ * used to store the different colors on an atom
+ *
+ * its inherent color, the colored paint applied on it, special color effect etc...
+ */
+ var/list/atom_colours
- var/list/priority_overlays //overlays that should remain on top and not normally removed when using cut_overlay functions, like c4.
- var/list/remove_overlays // a very temporary list of overlays to remove
- var/list/add_overlays // a very temporary list of overlays to add
- var/list/managed_vis_overlays //vis overlays managed by SSvis_overlays to automaticaly turn them like other overlays
+ ///overlays that should remain on top and not normally removed when using cut_overlay functions, like c4.
+ var/list/priority_overlays
+ /// a very temporary list of overlays to remove
+ var/list/remove_overlays
+ /// a very temporary list of overlays to add
+ var/list/add_overlays
+ ///vis overlays managed by SSvis_overlays to automaticaly turn them like other overlays
+ var/list/managed_vis_overlays
+
+ ///Proximity monitor associated with this atom
var/datum/proximity_monitor/proximity_monitor
+ ///Cooldown tick timer for buckle messages
var/buckle_message_cooldown = 0
+ ///Last fingerprints to touch this atom
var/fingerprintslast
var/list/filter_data //For handling persistent filters
+ ///Economy cost of item
var/custom_price
+ ///Economy cost of item in premium vendor
var/custom_premium_price
+ //List of datums orbiting this atom
var/datum/component/orbiter/orbiters
- var/rad_flags = NONE // Will move to flags_1 when i can be arsed to
+ /// Will move to flags_1 when i can be arsed to (2019, has not done so)
+ var/rad_flags = NONE
+ /// Radiation insulation types
var/rad_insulation = RAD_NO_INSULATION
+/**
+ * Called when an atom is created in byond (built in engine proc)
+ *
+ * Not a lot happens here in SS13 code, as we offload most of the work to the
+ * [Intialization](atom.html#proc/Initialize) proc, mostly we run the preloader
+ * if the preloader is being used and then call InitAtom of which the ultimate
+ * result is that the Intialize proc is called.
+ *
+ * We also generate a tag here if the DF_USE_TAG flag is set on the atom
+ */
/atom/New(loc, ...)
//atom creation method that preloads variables at creation
if(GLOB.use_preloader && (src.type == GLOB._preloader.target_path))//in case the instanciated atom is creating other atoms in New()
@@ -54,17 +93,40 @@
//we were deleted
return
-//Called after New if the map is being loaded. mapload = TRUE
-//Called from base of New if the map is not being loaded. mapload = FALSE
-//This base must be called or derivatives must set initialized to TRUE
-//must not sleep
-//Other parameters are passed from New (excluding loc), this does not happen if mapload is TRUE
-//Must return an Initialize hint. Defined in __DEFINES/subsystems.dm
-
-//Note: the following functions don't call the base for optimization and must copypasta:
-// /turf/Initialize
-// /turf/open/space/Initialize
-
+/**
+ * The primary method that objects are setup in SS13 with
+ *
+ * we don't use New as we have better control over when this is called and we can choose
+ * to delay calls or hook other logic in and so forth
+ *
+ * During roundstart map parsing, atoms are queued for intialization in the base atom/New(),
+ * After the map has loaded, then Initalize is called on all atoms one by one. NB: this
+ * is also true for loading map templates as well, so they don't Initalize until all objects
+ * in the map file are parsed and present in the world
+ *
+ * If you're creating an object at any point after SSInit has run then this proc will be
+ * immediately be called from New.
+ *
+ * mapload: This parameter is true if the atom being loaded is either being intialized during
+ * the Atom subsystem intialization, or if the atom is being loaded from the map template.
+ * If the item is being created at runtime any time after the Atom subsystem is intialized then
+ * it's false.
+ *
+ * You must always call the parent of this proc, otherwise failures will occur as the item
+ * will not be seen as initalized (this can lead to all sorts of strange behaviour, like
+ * the item being completely unclickable)
+ *
+ * You must not sleep in this proc, or any subprocs
+ *
+ * Any parameters from new are passed through (excluding loc), naturally if you're loading from a map
+ * there are no other arguments
+ *
+ * Must return an [initialization hint](code/__DEFINES/subsystems.html) or a runtime will occur.
+ *
+ * Note: the following functions don't call the base for optimization and must copypasta handling:
+ * * /turf/Initialize
+ * * /turf/open/space/Initialize
+ */
/atom/proc/Initialize(mapload, ...)
if(flags_1 & INITIALIZED_1)
stack_trace("Warning: [src]([type]) initialized multiple times!")
@@ -88,14 +150,35 @@
return INITIALIZE_HINT_NORMAL
-//called if Initialize returns INITIALIZE_HINT_LATELOAD
+/**
+ * Late Intialization, for code that should run after all atoms have run Intialization
+ *
+ * To have your LateIntialize proc be called, your atoms [Initalization](atom.html#proc/Initialize)
+ * proc must return the hint
+ * [INITIALIZE_HINT_LATELOAD](code/__DEFINES/subsystems.html#define/INITIALIZE_HINT_LATELOAD)
+ * otherwise you will never be called.
+ *
+ * useful for doing things like finding other machines on GLOB.machines because you can guarantee
+ * that all atoms will actually exist in the "WORLD" at this time and that all their Intialization
+ * code has been run
+ */
/atom/proc/LateInitialize()
set waitfor = FALSE
-// Put your AddComponent() calls here
+/// Put your AddComponent() calls here
/atom/proc/ComponentInitialize()
return
+/**
+ * Top level of the destroy chain for most atoms
+ *
+ * Cleans up the following:
+ * * Removes alternate apperances from huds that see them
+ * * qdels the reagent holder from atoms if it exists
+ * * clears the orbiters list
+ * * clears overlays and priority overlays
+ * * clears the light object
+ */
/atom/Destroy()
if(alternate_appearances)
for(var/K in alternate_appearances)
@@ -117,9 +200,20 @@
/atom/proc/handle_ricochet(obj/item/projectile/P)
return
+///Can the mover object pass this atom, while heading for the target turf
/atom/proc/CanPass(atom/movable/mover, turf/target)
return !density
+/**
+ * Is this atom currently located on centcom
+ *
+ * Specifically, is it on the z level and within the centcom areas
+ *
+ * You can also be in a shuttleshuttle during endgame transit
+ *
+ * Used in gamemode to identify mobs who have escaped and for some other areas of the code
+ * who don't want atoms where they shouldn't be
+ */
/atom/proc/onCentCom()
var/turf/T = get_turf(src)
if(!T)
@@ -150,6 +244,13 @@
if(T in shuttle_area)
return TRUE
+/**
+ * Is the atom in any of the centcom syndicate areas
+ *
+ * Either in the syndie base on centcom, or any of their shuttles
+ *
+ * Also used in gamemode code for win conditions
+ */
/atom/proc/onSyndieBase()
var/turf/T = get_turf(src)
if(!T)
@@ -163,6 +264,7 @@
return FALSE
+///This atom has been hit by a hulkified mob in hulk mode (user)
/atom/proc/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
SEND_SIGNAL(src, COMSIG_ATOM_HULK_ATTACK, user)
if(does_attack_animation)
@@ -170,6 +272,18 @@
log_combat(user, src, "punched", "hulk powers")
user.do_attack_animation(src, ATTACK_EFFECT_SMASH)
+/**
+ * Ensure a list of atoms/reagents exists inside this atom
+ *
+ * Goes throught he list of passed in parts, if they're reagents, adds them to our reagent holder
+ * creating the reagent holder if it exists.
+ *
+ * If the part is a moveable atom and the previous location of the item was a mob/living,
+ * it calls the inventory handler transferItemToLoc for that mob/living and transfers the part
+ * to this atom
+ *
+ * Otherwise it simply forceMoves the atom into this atom
+ */
/atom/proc/CheckParts(list/parts_list)
for(var/A in parts_list)
if(istype(A, /datum/reagent))
@@ -185,68 +299,94 @@
else
M.forceMove(src)
-//common name
+///Hook for multiz???
/atom/proc/update_multiz(prune_on_fail = FALSE)
return FALSE
+///Take air from the passed in gas mixture datum
/atom/proc/assume_air(datum/gas_mixture/giver)
qdel(giver)
return null
+///Remove air from this atom
/atom/proc/remove_air(amount)
return null
+///Return the current air environment in this atom
/atom/proc/return_air()
if(loc)
return loc.return_air()
else
return null
+///Return the air if we can analyze it
/atom/proc/return_analyzable_air()
return null
+///Check if this atoms eye is still alive (probably)
/atom/proc/check_eye(mob/user)
return
/atom/proc/Bumped(atom/movable/AM)
set waitfor = FALSE
-// Convenience procs to see if a container is open for chemistry handling
+/// Convenience proc to see if a container is open for chemistry handling
/atom/proc/is_open_container()
return is_refillable() && is_drainable()
+/// Is this atom injectable into other atoms
/atom/proc/is_injectable(mob/user, allowmobs = TRUE)
return reagents && (reagents.flags & (INJECTABLE | REFILLABLE))
+/// Can we draw from this atom with an injectable atom
/atom/proc/is_drawable(mob/user, allowmobs = TRUE)
return reagents && (reagents.flags & (DRAWABLE | DRAINABLE))
+/// Can this atoms reagents be refilled
/atom/proc/is_refillable()
return reagents && (reagents.flags & REFILLABLE)
+/// Is this atom drainable of reagents
/atom/proc/is_drainable()
return reagents && (reagents.flags & DRAINABLE)
-
+/// Are you allowed to drop this atom
/atom/proc/AllowDrop()
return FALSE
/atom/proc/CheckExit()
return 1
+///Is this atom within 1 tile of another atom
/atom/proc/HasProximity(atom/movable/AM as mob|obj)
return
+/**
+ * React to an EMP of the given severity
+ *
+ * Default behaviour is to send the COMSIG_ATOM_EMP_ACT signal
+ *
+ * If the signal does not return protection, and there are attached wires then we call
+ * emp_pulse() on the wires
+ *
+ * We then return the protection value
+ */
/atom/proc/emp_act(severity)
var/protection = SEND_SIGNAL(src, COMSIG_ATOM_EMP_ACT, severity)
if(!(protection & EMP_PROTECT_WIRES) && istype(wires))
wires.emp_pulse()
return protection // Pass the protection value collected here upwards
+/**
+ * React to a hit by a projectile object
+ *
+ * Default behaviour is to send the COMSIG_ATOM_BULLET_ACT and then call on_hit() on the projectile
+ */
/atom/proc/bullet_act(obj/item/projectile/P, def_zone)
SEND_SIGNAL(src, COMSIG_ATOM_BULLET_ACT, P, def_zone)
. = P.on_hit(src, 0, def_zone)
+///Return true if we're inside the passed in atom
/atom/proc/in_contents_of(container)//can take class or object instance as argument
if(ispath(container))
if(istype(src.loc, container))
@@ -255,6 +395,12 @@
return TRUE
return FALSE
+/**
+ * Get the name of this object for examine
+ *
+ * You can override what is returned from this proc by registering to listen for the
+ * COMSIG_ATOM_GET_EXAMINE_NAME signal
+ */
/atom/proc/get_examine_name(mob/user)
. = "\a [src]"
var/list/override = list(gender == PLURAL ? "some" : "a", " ", "[name]")
@@ -264,9 +410,18 @@
if(SEND_SIGNAL(src, COMSIG_ATOM_GET_EXAMINE_NAME, user, override) & COMPONENT_EXNAME_CHANGED)
. = override.Join("")
+///Generate the full examine string of this atom (including icon for goonchat)
/atom/proc/get_examine_string(mob/user, thats = FALSE)
return "[icon2html(src, user)] [thats? "That's ":""][get_examine_name(user)]"
+/**
+ * Called when a mob examines (shift click or verb) this atom
+ *
+ * Default behaviour is to get the name and icon of the object and it's reagents where
+ * the TRANSPARENT flag is set on the reagents holder
+ *
+ * Produces a signal COMSIG_PARENT_EXAMINE
+ */
/atom/proc/examine(mob/user)
. = list("[get_examine_string(user, TRUE)].")
@@ -295,23 +450,41 @@
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, .)
+/**
+ * An atom we are buckled or is contained within us has tried to move
+ *
+ * Default behaviour is to send a warning that the user can't move while buckled as long
+ * as the buckle_message_cooldown has expired (50 ticks)
+ */
/atom/proc/relaymove(mob/user)
if(buckle_message_cooldown <= world.time)
buckle_message_cooldown = world.time + 50
to_chat(user, "You can't move while buckled to [src]!")
return
+/// Return true if this atoms contents should not have ex_act called on ex_act
/atom/proc/prevent_content_explosion()
return FALSE
+/// Handle what happens when your contents are exploded by a bomb
/atom/proc/contents_explosion(severity, target)
return //For handling the effects of explosions on contents that would not normally be effected
+/**
+ * React to being hit by an explosion
+ *
+ * Default behaviour is to call contents_explosion() and send the COMSIG_ATOM_EX_ACT signal
+ */
/atom/proc/ex_act(severity, target)
set waitfor = FALSE
contents_explosion(severity, target)
SEND_SIGNAL(src, COMSIG_ATOM_EX_ACT, severity, target)
+/**
+ * React to a hit by a blob objecd
+ *
+ * default behaviour is to send the COMSIG_ATOM_BLOB_ACT signal
+ */
/atom/proc/blob_act(obj/structure/blob/B)
SEND_SIGNAL(src, COMSIG_ATOM_BLOB_ACT, B)
return
@@ -320,23 +493,40 @@
SEND_SIGNAL(src, COMSIG_ATOM_FIRE_ACT, exposed_temperature, exposed_volume)
return
+/**
+ * React to being hit by a thrown object
+ *
+ * Default behaviour is to call hitby_react() on ourselves after 2 seconds if we are dense
+ * and under normal gravity.
+ *
+ * Im not sure why this the case, maybe to prevent lots of hitby's if the thrown object is
+ * deleted shortly after hitting something (during explosions or other massive events that
+ * throw lots of items around - singularity being a notable example)
+ */
/atom/proc/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
if(density && !has_gravity(AM)) //thrown stuff bounces off dense stuff in no grav, unless the thrown stuff ends up inside what it hit(embedding, bola, etc...).
addtimer(CALLBACK(src, .proc/hitby_react, AM), 2)
+/**
+ * We have have actually hit the passed in atom
+ *
+ * Default behaviour is to move back from the item that hit us
+ */
/atom/proc/hitby_react(atom/movable/AM)
if(AM && isturf(AM.loc))
step(AM, turn(AM.dir, 180))
+///Handle the atom being slipped over
/atom/proc/handle_slip(mob/living/carbon/C, knockdown_amount, obj/O, lube, paralyze, force_drop)
return
-//returns the mob's dna info as a list, to be inserted in an object's blood_DNA list
+///returns the mob's dna info as a list, to be inserted in an object's blood_DNA list
/mob/living/proc/get_blood_dna_list()
if(get_blood_id() != /datum/reagent/blood)
return
return list("ANIMAL DNA" = "Y-")
+///Get the mobs dna list
/mob/living/carbon/get_blood_dna_list()
if(get_blood_id() != /datum/reagent/blood)
return
@@ -353,7 +543,7 @@
/mob/living/silicon/get_blood_dna_list()
return list("MOTOR OIL" = "SAE 5W-30") //just a little flavor text.
-//to add a mob's dna info into an object's blood_DNA list.
+///to add a mob's dna info into an object's blood_dna list.
/atom/proc/transfer_mob_blood_dna(mob/living/L)
// Returns 0 if we have that blood already
var/new_blood_dna = L.get_blood_dna_list()
@@ -365,58 +555,120 @@
return FALSE
return TRUE
-//to add blood from a mob onto something, and transfer their dna info
+///to add blood from a mob onto something, and transfer their dna info
/atom/proc/add_mob_blood(mob/living/M)
var/list/blood_dna = M.get_blood_dna_list()
if(!blood_dna)
return FALSE
return add_blood_DNA(blood_dna)
+///wash cream off this object
+///
+///(for the love of space jesus please make this a component)
/atom/proc/wash_cream()
return TRUE
+///Is this atom in space
/atom/proc/isinspace()
if(isspaceturf(get_turf(src)))
return TRUE
else
return FALSE
+///Called when gravity returns after floating I think
/atom/proc/handle_fall()
return
+///Respond to the singularity eating this atom
/atom/proc/singularity_act()
return
+/**
+ * Respond to the singularity pulling on us
+ *
+ * Default behaviour is to send COMSIG_ATOM_SING_PULL and return
+ */
/atom/proc/singularity_pull(obj/singularity/S, current_size)
SEND_SIGNAL(src, COMSIG_ATOM_SING_PULL, S, current_size)
+
+/**
+ * Respond to acid being used on our atom
+ *
+ * Default behaviour is to send COMSIG_ATOM_ACID_ACT and return
+ */
/atom/proc/acid_act(acidpwr, acid_volume)
SEND_SIGNAL(src, COMSIG_ATOM_ACID_ACT, acidpwr, acid_volume)
+/**
+ * Respond to an emag being used on our atom
+ *
+ * Default behaviour is to send COMSIG_ATOM_EMAG_ACT and return
+ */
/atom/proc/emag_act()
SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT)
+/**
+ * Respond to a radioactive wave hitting this atom
+ *
+ * Default behaviour is to send COMSIG_ATOM_RAD_ACT and return
+ */
/atom/proc/rad_act(strength)
SEND_SIGNAL(src, COMSIG_ATOM_RAD_ACT, strength)
+/**
+ * Respond to narsie eating our atom
+ *
+ * Default behaviour is to send COMSIG_ATOM_NARSIE_ACT and return
+ */
/atom/proc/narsie_act()
SEND_SIGNAL(src, COMSIG_ATOM_NARSIE_ACT)
+/**
+ * Respond to ratvar eating our atom
+ *
+ * Default behaviour is to send COMSIG_ATOM_RATVAR_ACT and return
+ */
/atom/proc/ratvar_act()
SEND_SIGNAL(src, COMSIG_ATOM_RATVAR_ACT)
+///Return the values you get when an RCD eats you?
/atom/proc/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
return FALSE
+
+/**
+ * Respond to an RCD acting on our item
+ *
+ * Default behaviour is to send COMSIG_ATOM_RCD_ACT and return FALSE
+ */
/atom/proc/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode)
SEND_SIGNAL(src, COMSIG_ATOM_RCD_ACT, user, the_rcd, passed_mode)
return FALSE
+/**
+ * Implement the behaviour for when a user click drags a storage object to your atom
+ *
+ * This behaviour is usually to mass transfer, but this is no longer a used proc as it just
+ * calls the underyling /datum/component/storage dump act if a component exists
+ *
+ * TODO these should be purely component items that intercept the atom clicks higher in the
+ * call chain
+ */
/atom/proc/storage_contents_dump_act(obj/item/storage/src_object, mob/user)
if(GetComponent(/datum/component/storage))
return component_storage_contents_dump_act(src_object, user)
return FALSE
+/**
+ * Implement the behaviour for when a user click drags another storage item to you
+ *
+ * In this case we get as many of the tiems from the target items compoent storage and then
+ * put everything into ourselves (or our storage component)
+ *
+ * TODO these should be purely component items that intercept the atom clicks higher in the
+ * call chain
+ */
/atom/proc/component_storage_contents_dump_act(datum/component/storage/src_object, mob/user)
var/list/things = src_object.contents()
var/datum/progressbar/progress = new(user, things.len, src)
@@ -432,37 +684,63 @@
user.active_storage.show_to(user)
return TRUE
+///Get the best place to dump the items contained in the source storage item?
/atom/proc/get_dumping_location(obj/item/storage/source,mob/user)
return null
-//This proc is called on the location of an atom when the atom is Destroy()'d
+/**
+ * This proc is called when an atom in our contents has it's Destroy() called
+ *
+ * Default behaviour is to simply send COMSIG_ATOM_CONTENTS_DEL
+ */
/atom/proc/handle_atom_del(atom/A)
SEND_SIGNAL(src, COMSIG_ATOM_CONTENTS_DEL, A)
-//called when the turf the atom resides on is ChangeTurfed
+/**
+ * called when the turf the atom resides on is ChangeTurfed
+ *
+ * Default behaviour is to loop through atom contents and call their HandleTurfChange() proc
+ */
/atom/proc/HandleTurfChange(turf/T)
for(var/a in src)
var/atom/A = a
A.HandleTurfChange(T)
-//the vision impairment to give to the mob whose perspective is set to that atom (e.g. an unfocused camera giving you an impaired vision when looking through it)
+/**
+ * the vision impairment to give to the mob whose perspective is set to that atom
+ *
+ * (e.g. an unfocused camera giving you an impaired vision when looking through it)
+ */
/atom/proc/get_remote_view_fullscreens(mob/user)
return
-//the sight changes to give to the mob whose perspective is set to that atom (e.g. A mob with nightvision loses its nightvision while looking through a normal camera)
+/**
+ * the sight changes to give to the mob whose perspective is set to that atom
+ *
+ * (e.g. A mob with nightvision loses its nightvision while looking through a normal camera)
+ */
/atom/proc/update_remote_sight(mob/living/user)
return
-//Hook for running code when a dir change occurs
+/**
+ * Hook for running code when a dir change occurs
+ *
+ * Not recommended to use, listen for the COMSIG_ATOM_DIR_CHANGE signal instead (sent by this proc)
+ */
/atom/proc/setDir(newdir)
SEND_SIGNAL(src, COMSIG_ATOM_DIR_CHANGE, dir, newdir)
dir = newdir
+///Handle melee attack by a mech
/atom/proc/mech_melee_attack(obj/mecha/M)
return
-//If a mob logouts/logins in side of an object you can use this proc
+/**
+ * Called when the atom log's in or out
+ *
+ * Default behaviour is to call on_log on the location this atom is in
+ */
/atom/proc/on_log(login)
if(loc)
loc.on_log(login)
@@ -476,9 +754,7 @@
*/
-/*
- Adds an instance of colour_type to the atom's atom_colours list
-*/
+///Adds an instance of colour_type to the atom's atom_colours list
/atom/proc/add_atom_colour(coloration, colour_priority)
if(!atom_colours || !atom_colours.len)
atom_colours = list()
@@ -491,9 +767,7 @@
update_atom_colour()
-/*
- Removes an instance of colour_type from the atom's atom_colours list
-*/
+///Removes an instance of colour_type from the atom's atom_colours list
/atom/proc/remove_atom_colour(colour_priority, coloration)
if(!atom_colours)
atom_colours = list()
@@ -506,10 +780,7 @@
update_atom_colour()
-/*
- Resets the atom's color to null, and then sets it to the highest priority
- colour available
-*/
+///Resets the atom's color to null, and then sets it to the highest priority colour available
/atom/proc/update_atom_colour()
if(!atom_colours)
atom_colours = list()
@@ -525,6 +796,17 @@
color = C
return
+/**
+ * call back when a var is edited on this atom
+ *
+ * Can be used to implement special handling of vars
+ *
+ * At the atom level, if you edit a var named "color" it will add the atom colour with
+ * admin level priority to the atom colours list
+ *
+ * Also, if GLOB.Debug2 is FALSE, it sets the ADMIN_SPAWNED_1 flag on flags_1, which signifies
+ * the object has been admin edited
+ */
/atom/vv_edit_var(var_name, var_value)
if(!GLOB.Debug2)
flags_1 |= ADMIN_SPAWNED_1
@@ -533,6 +815,11 @@
if("color")
add_atom_colour(color, ADMIN_COLOUR_PRIORITY)
+/**
+ * Return the markup to for the dropdown list for the VV panel for this atom
+ *
+ * Override in subtypes to add custom VV handling in the VV panel
+ */
/atom/vv_get_dropdown()
. = ..()
. += "---"
@@ -544,29 +831,53 @@
.["Trigger EM pulse"] = "?_src_=vars;[HrefToken()];emp=[REF(src)]"
.["Trigger explosion"] = "?_src_=vars;[HrefToken()];explode=[REF(src)]"
+///Where atoms should drop if taken from this atom
/atom/proc/drop_location()
var/atom/L = loc
if(!L)
return null
return L.AllowDrop() ? L : L.drop_location()
+/**
+ * An atom has entered this atom's contents
+ *
+ * Default behaviour is to send the COMSIG_ATOM_ENTERED
+ */
/atom/Entered(atom/movable/AM, atom/oldLoc)
SEND_SIGNAL(src, COMSIG_ATOM_ENTERED, AM, oldLoc)
+/**
+ * An atom is attempting to exit this atom's contents
+ *
+ * Default behaviour is to send the COMSIG_ATOM_EXIT
+ *
+ * Return value should be set to FALSE if the moving atom is unable to leave,
+ * otherwise leave value the result of the parent call
+ */
/atom/Exit(atom/movable/AM, atom/newLoc)
. = ..()
if(SEND_SIGNAL(src, COMSIG_ATOM_EXIT, AM, newLoc) & COMPONENT_ATOM_BLOCK_EXIT)
return FALSE
+/**
+ * An atom has exited this atom's contents
+ *
+ * Default behaviour is to send the COMSIG_ATOM_EXITED
+ */
/atom/Exited(atom/movable/AM, atom/newLoc)
SEND_SIGNAL(src, COMSIG_ATOM_EXITED, AM, newLoc)
+///Return atom temperature
/atom/proc/return_temperature()
return
-// Tool behavior procedure. Redirects to tool-specific procs by default.
-// You can override it to catch all tool interactions, for use in complex deconstruction procs.
-// Just don't forget to return ..() in the end.
+/**
+ *Tool behavior procedure. Redirects to tool-specific procs by default.
+ *
+ * You can override it to catch all tool interactions, for use in complex deconstruction procs.
+ *
+ * Must return parent proc ..() in the end if overridden
+ */
/atom/proc/tool_act(mob/living/user, obj/item/I, tool_type)
switch(tool_type)
if(TOOL_CROWBAR)
@@ -584,13 +895,18 @@
if(TOOL_ANALYZER)
return analyzer_act(user, I)
-// Tool-specific behavior procs. To be overridden in subtypes.
+//! Tool-specific behavior procs. To be overridden in subtypes.
+///
+
+///Crowbar act
/atom/proc/crowbar_act(mob/living/user, obj/item/I)
return
+///Multitool act
/atom/proc/multitool_act(mob/living/user, obj/item/I)
return
+///Check if the multitool has an item in it's data buffer
/atom/proc/multitool_check_buffer(user, obj/item/I, silent = FALSE)
if(!istype(I, /obj/item/multitool))
if(user && !silent)
@@ -598,29 +914,35 @@
return FALSE
return TRUE
-
+///Screwdriver act
/atom/proc/screwdriver_act(mob/living/user, obj/item/I)
SEND_SIGNAL(src, COMSIG_ATOM_SCREWDRIVER_ACT, user, I)
+///Wrench act
/atom/proc/wrench_act(mob/living/user, obj/item/I)
return
+///Wirecutter act
/atom/proc/wirecutter_act(mob/living/user, obj/item/I)
return
+///Welder act
/atom/proc/welder_act(mob/living/user, obj/item/I)
return
+///Analyzer act
/atom/proc/analyzer_act(mob/living/user, obj/item/I)
return
+///Generate a tag for this atom
/atom/proc/GenerateTag()
return
+///Connect this atom to a shuttle
/atom/proc/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
return
-// Generic logging helper
+/// Generic logging helper
/atom/proc/log_message(message, message_type, color=null, log_globally=TRUE)
if(!log_globally)
return
@@ -663,13 +985,13 @@
stack_trace("Invalid individual logging type: [message_type]. Defaulting to [LOG_GAME] (LOG_GAME).")
log_game(log_text)
-// Helper for logging chat messages or other logs with arbitrary inputs (e.g. announcements)
+/// Helper for logging chat messages or other logs with arbitrary inputs (e.g. announcements)
/atom/proc/log_talk(message, message_type, tag=null, log_globally=TRUE, forced_by=null)
var/prefix = tag ? "([tag]) " : ""
var/suffix = forced_by ? " FORCED by [forced_by]" : ""
log_message("[prefix]\"[message]\"[suffix]", message_type, log_globally=log_globally)
-// Helper for logging of messages with only one sender and receiver
+/// Helper for logging of messages with only one sender and receiver
/proc/log_directed_talk(atom/source, atom/target, message, message_type, tag)
if(!tag)
stack_trace("Unspecified tag for private message")
@@ -679,15 +1001,15 @@
if(source != target)
target.log_talk(message, message_type, tag="[tag] from [key_name(source)]", log_globally=FALSE)
-/*
-Proc for attack log creation, because really why not
-1 argument is the actor performing the action
-2 argument is the target of the action
-3 is a verb describing the action (e.g. punched, throwed, kicked, etc.)
-4 is a tool with which the action was made (usually an item)
-5 is any additional text, which will be appended to the rest of the log line
-*/
-
+/**
+ * Log a combat message in the attack log
+ *
+ * 1 argument is the actor performing the action
+ * 2 argument is the target of the action
+ * 3 is a verb describing the action (e.g. punched, throwed, kicked, etc.)
+ * 4 is a tool with which the action was made (usually an item)
+ * 5 is any additional text, which will be appended to the rest of the log line
+ */
/proc/log_combat(atom/user, atom/target, what_done, atom/object=null, addition=null)
var/ssource = key_name(user)
var/starget = key_name(target)
@@ -711,7 +1033,6 @@ Proc for attack log creation, because really why not
var/reverse_message = "has been [what_done] by [ssource][postfix]"
target.log_message(reverse_message, LOG_ATTACK, color="orange", log_globally=FALSE)
-// Filter stuff
/atom/movable/proc/add_filter(name,priority,list/params)
if(!filter_data)
filter_data = list()
diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm
index 8a4205306e1..dd78c6761f4 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -1,3 +1,26 @@
+/**
+ * Run when a client is put in this mob or reconnets to byond and their client was on this mob
+ *
+ * Things it does:
+ * * Adds player to player_list
+ * * sets lastKnownIP
+ * * sets computer_id
+ * * logs the login
+ * * tells the world to update it's status (for player count)
+ * * create mob huds for the mob if needed
+ * * reset next_move to 1
+ * * parent call
+ * * if the client exists set the perspective to the mob loc
+ * * call on_log on the loc (sigh)
+ * * reload the huds for the mob
+ * * reload all full screen huds attached to this mob
+ * * load any global alternate apperances
+ * * sync the mind datum via sync_mind()
+ * * call any client login callbacks that exist
+ * * grant any actions the mob has to the client
+ * * calls [auto_deadmin_on_login](mob.html#proc/auto_deadmin_on_login)
+ * * send signal COMSIG_MOB_CLIENT_LOGIN
+ */
/mob/Login()
GLOB.player_list |= src
lastKnownIP = client.address
@@ -57,6 +80,17 @@
log_message("Client [key_name(src)] has taken ownership of mob [src]([src.type])", LOG_OWNERSHIP)
SEND_SIGNAL(src, COMSIG_MOB_CLIENT_LOGIN, client)
+/**
+ * Checks if the attached client is an admin and may deadmin them
+ *
+ * Configs:
+ * * flag/auto_deadmin_players
+ * * client.prefs?.toggles & DEADMIN_ALWAYS
+ * * User is antag and flag/auto_deadmin_antagonists or client.prefs?.toggles & DEADMIN_ANTAGONIST
+ * * or if their job demands a deadminning SSjob.handle_auto_deadmin_roles()
+ *
+ * Called from [login](mob.html#proc/Login)
+ */
/mob/proc/auto_deadmin_on_login() //return true if they're not an admin at the end.
if(!client?.holder)
return TRUE
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 820e6c072e0..ff49b57448d 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -1,3 +1,27 @@
+/**
+ * Delete a mob
+ *
+ * Removes mob from the following global lists
+ * * GLOB.mob_list
+ * * GLOB.dead_mob_list
+ * * GLOB.alive_mob_list
+ * * GLOB.all_clockwork_mobs
+ * * GLOB.mob_directory
+ *
+ * Unsets the focus var
+ *
+ * Clears alerts for this mob
+ *
+ * Resets all the observers perspectives to the tile this mob is on
+ *
+ * qdels any client colours in place on this mob
+ *
+ * Ghostizes the client attached to this mob
+ *
+ * Parent call
+ *
+ * Returns QDEL_HINT_HARDDEL (don't change this)
+ */
/mob/Destroy()//This makes sure that mobs with clients/keys are not just deleted from the game.
GLOB.mob_list -= src
GLOB.dead_mob_list -= src
@@ -19,6 +43,24 @@
..()
return QDEL_HINT_HARDDEL
+/**
+ * Intialize a mob
+ *
+ * Sends global signal COMSIG_GLOB_MOB_CREATED
+ *
+ * Adds to global lists
+ * * GLOB.mob_list
+ * * GLOB.mob_directory (by tag)
+ * * GLOB.dead_mob_list - if mob is dead
+ * * GLOB.alive_mob_list - if the mob is alive
+ *
+ * Other stuff:
+ * * Sets the mob focus to itself
+ * * Generates huds
+ * * If there are any global alternate apperances apply them to this mob
+ * * set a random nutrition level
+ * * Intialize the movespeed of the mob
+ */
/mob/Initialize()
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_MOB_CREATED, src)
GLOB.mob_list += src
@@ -39,9 +81,20 @@
update_config_movespeed()
update_movespeed(TRUE)
+/**
+ * Generate the tag for this mob
+ *
+ * This is simply "mob_"+ a global incrementing counter that goes up for every mob
+ */
/mob/GenerateTag()
tag = "mob_[next_mob_id++]"
+/**
+ * Prepare the huds for this atom
+ *
+ * Goes through hud_possible list and adds the images to the hud_list variable (if not already
+ * cached)
+ */
/atom/proc/prepare_huds()
hud_list = list()
for(var/hud in hud_possible)
@@ -54,6 +107,9 @@
I.appearance_flags = RESET_COLOR|RESET_TRANSFORM
hud_list[hud] = I
+/**
+ * Some kind of debug verb that gives atmosphere environment details
+ */
/mob/proc/Cell()
set category = "Admin"
set hidden = 1
@@ -72,9 +128,15 @@
to_chat(usr, t)
+/**
+ * Return the desc of this mob for a photo
+ */
/mob/proc/get_photo_description(obj/item/camera/camera)
return "a ... thing?"
+/**
+ * Show a message to this mob (visual)
+ */
/mob/proc/show_message(msg, type, alt_msg, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
if(!client)
@@ -105,15 +167,23 @@
else
to_chat(src, msg)
-// Show a message to all player mobs who sees this atom
-// Show a message to the src mob (if the src is a mob)
-// Use for atoms performing visible actions
-// message is output to anyone who can see, e.g. "The [src] does something!"
-// self_message (optional) is what the src mob sees e.g. "You do something!"
-// blind_message (optional) is what blind people will hear e.g. "You hear something!"
-// vision_distance (optional) define how many tiles away the message can be seen.
-// ignored_mob (optional) doesn't show any message to a given mob if TRUE.
-
+/**
+ * Generate a visible message from this atom
+ *
+ * Show a message to all player mobs who sees this atom
+ *
+ * Show a message to the src mob (if the src is a mob)
+ *
+ * Use for atoms performing visible actions
+ *
+ * message is output to anyone who can see, e.g. "The [src] does something!"
+ *
+ * Vars:
+ * * self_message (optional) is what the src mob sees e.g. "You do something!"
+ * * blind_message (optional) is what blind people will hear e.g. "You hear something!"
+ * * vision_distance (optional) define how many tiles away the message can be seen.
+ * * ignored_mob (optional) doesn't show any message to a given mob if TRUE.
+ */
/atom/proc/visible_message(message, self_message, blind_message, vision_distance, list/ignored_mobs)
var/turf/T = get_turf(src)
if(!T)
@@ -148,13 +218,17 @@
M.show_message(msg,1,blind_message,2)
-// Show a message to all mobs in earshot of this one
-// This would be for audible actions by the src mob
-// message is the message output to anyone who can hear.
-// self_message (optional) is what the src mob hears.
-// deaf_message (optional) is what deaf people will see.
-// hearing_distance (optional) is the range, how many tiles away the message can be heard.
-
+/**
+ * Show a message to all mobs in earshot of this one
+ *
+ * This would be for audible actions by the src mob
+ *
+ * vars:
+ * * message is the message output to anyone who can hear.
+ * * self_message (optional) is what the src mob hears.
+ * * deaf_message (optional) is what deaf people will see.
+ * * hearing_distance (optional) is the range, how many tiles away the message can be heard.
+ */
/mob/audible_message(message, deaf_message, hearing_distance, self_message)
var/range = 7
if(hearing_distance)
@@ -165,12 +239,16 @@
msg = self_message
M.show_message( msg, 2, deaf_message, 1)
-// Show a message to all mobs in earshot of this atom
-// Use for objects performing audible actions
-// message is the message output to anyone who can hear.
-// deaf_message (optional) is what deaf people will see.
-// hearing_distance (optional) is the range, how many tiles away the message can be heard.
-
+/**
+ * Show a message to all mobs in earshot of this atom
+ *
+ * Use for objects performing audible actions
+ *
+ * vars:
+ * * message is the message output to anyone who can hear.
+ * * deaf_message (optional) is what deaf people will see.
+ * * hearing_distance (optional) is the range, how many tiles away the message can be heard.
+ */
/atom/proc/audible_message(message, deaf_message, hearing_distance)
var/range = 7
if(hearing_distance)
@@ -178,16 +256,24 @@
for(var/mob/M in get_hearers_in_view(range, src))
M.show_message( message, 2, deaf_message, 1)
+///Get the item on the mob in the storage slot identified by the id passed in
/mob/proc/get_item_by_slot(slot_id)
return null
+///Is the mob restrained
/mob/proc/restrained(ignore_grab)
return
+///Is the mob incapacitated
/mob/proc/incapacitated(ignore_restraints = FALSE, ignore_grab = FALSE, check_immobilized = FALSE)
return
-//This proc is called whenever someone clicks an inventory ui slot.
+/**
+ * This proc is called whenever someone clicks an inventory ui slot.
+ *
+ * Mostly tries to put the item into the slot if possible, or call attack hand
+ * on the item in the slot if the users active hand is empty
+ */
/mob/proc/attack_ui(slot)
var/obj/item/W = get_active_held_item()
@@ -203,10 +289,17 @@
return 0
-//This is a SAFE proc. Use this instead of equip_to_slot()!
-//set qdel_on_fail to have it delete W if it fails to equip
-//set disable_warning to disable the 'you are unable to equip that' warning.
-//unset redraw_mob to prevent the mob from being redrawn at the end.
+/**
+ * Try to equip an item to a slot on the mob
+ *
+ * This is a SAFE proc. Use this instead of equip_to_slot()!
+ *
+ * set qdel_on_fail to have it delete W if it fails to equip
+ *
+ * set disable_warning to disable the 'you are unable to equip that' warning.
+ *
+ * unset redraw_mob to prevent the mob icons from being redrawn at the end.
+ */
/mob/proc/equip_to_slot_if_possible(obj/item/W, slot, qdel_on_fail = FALSE, disable_warning = FALSE, redraw_mob = TRUE, bypass_equip_delay_self = FALSE)
if(!istype(W))
return FALSE
@@ -220,18 +313,35 @@
equip_to_slot(W, slot, redraw_mob) //This proc should not ever fail.
return TRUE
-//This is an UNSAFE proc. It merely handles the actual job of equipping. All the checks on whether you can or can't equip need to be done before! Use mob_can_equip() for that task.
-//In most cases you will want to use equip_to_slot_if_possible()
+/**
+ * Actually equips an item to a slot (UNSAFE)
+ *
+ * This is an UNSAFE proc. It merely handles the actual job of equipping. All the checks on
+ * whether you can or can't equip need to be done before! Use mob_can_equip() for that task.
+ *
+ *In most cases you will want to use equip_to_slot_if_possible()
+ */
/mob/proc/equip_to_slot(obj/item/W, slot)
return
-//This is just a commonly used configuration for the equip_to_slot_if_possible() proc, used to equip people when the round starts and when events happen and such.
-//Also bypasses equip delay checks, since the mob isn't actually putting it on.
+/**
+ * Equip an item to the slot or delete
+ *
+ * This is just a commonly used configuration for the equip_to_slot_if_possible() proc, used to
+ * equip people when the round starts and when events happen and such.
+ *
+ * Also bypasses equip delay checks, since the mob isn't actually putting it on.
+ */
/mob/proc/equip_to_slot_or_del(obj/item/W, slot)
return equip_to_slot_if_possible(W, slot, TRUE, TRUE, FALSE, TRUE)
-//puts the item "W" into an appropriate slot in a human's inventory
-//returns 0 if it cannot, 1 if successful
+/**
+ * Auto equip the passed in item the appropriate slot based on equipment priority
+ *
+ * puts the item "W" into an appropriate slot in a human's inventory
+ *
+ * returns 0 if it cannot, 1 if successful
+ */
/mob/proc/equip_to_appropriate_slot(obj/item/W)
if(!istype(W))
return 0
@@ -254,9 +364,12 @@
return 1
return 0
-
-// reset_perspective(thing) set the eye to the thing (if it's equal to current default reset to mob perspective)
-// reset_perspective() set eye to common default : mob on turf, loc otherwise
+/**
+ * Reset the attached clients perspective (viewpoint)
+ *
+ * reset_perspective() set eye to common default : mob on turf, loc otherwise
+ * reset_perspective(thing) set the eye to the thing (if it's equal to current default reset to mob perspective)
+ */
/mob/proc/reset_perspective(atom/A)
if(client)
if(A)
@@ -288,10 +401,17 @@
client.eye = loc
return 1
+/// Show the mob's inventory to another mob
/mob/proc/show_inv(mob/user)
return
-//mob verbs are faster than object verbs. See https://secure.byond.com/forum/?post=1326139&page=2#comment8198716 for why this isn't atom/verb/examine()
+/**
+ * Examine a mob
+ *
+ * mob verbs are faster than object verbs. See
+ * [this byond forum post](https://secure.byond.com/forum/?post=1326139&page=2#comment8198716)
+ * for why this isn't atom/verb/examine()
+ */
/mob/verb/examinate(atom/A as mob|obj|turf in view()) //It used to be oview(12), but I can't really say why
set name = "Examine"
set category = "IC"
@@ -309,10 +429,19 @@
to_chat(src, result.Join("\n"))
SEND_SIGNAL(src, COMSIG_MOB_EXAMINATE, A)
-//same as above
-//note: ghosts can point, this is intended
-//visible_message will handle invisibility properly
-//overridden here and in /mob/dead/observer for different point span classes and sanity checks
+/**
+ * Point at an atom
+ *
+ * mob verbs are faster than object verbs. See
+ * [this byond forum post](https://secure.byond.com/forum/?post=1326139&page=2#comment8198716)
+ * for why this isn't atom/verb/pointed()
+ *
+ * note: ghosts can point, this is intended
+ *
+ * visible_message will handle invisibility properly
+ *
+ * overridden here and in /mob/dead/observer for different point span classes and sanity checks
+ */
/mob/verb/pointed(atom/A as mob|obj|turf in view())
set name = "Point To"
set category = "Object"
@@ -330,9 +459,11 @@
return TRUE
+///Can this mob resist (default FALSE)
/mob/proc/can_resist()
return FALSE //overridden in living.dm
+///Spin this mob around it's central axis
/mob/proc/spin(spintime, speed)
set waitfor = 0
var/D = dir
@@ -352,16 +483,23 @@
setDir(D)
spintime -= speed
+///Update the pulling hud icon
/mob/proc/update_pull_hud_icon()
if(hud_used)
if(hud_used.pull_icon)
hud_used.pull_icon.update_icon(src)
+///Update the resting hud icon
/mob/proc/update_rest_hud_icon()
if(hud_used)
if(hud_used.rest_icon)
hud_used.rest_icon.update_icon(src)
+/**
+ * Verb to activate the object in your held hand
+ *
+ * Calls attack self on the item and updates the inventory hud for hands
+ */
/mob/verb/mode()
set name = "Activate Held Object"
set category = "Object"
@@ -378,6 +516,11 @@
I.attack_self(src)
update_inv_hands()
+/**
+ * Get the notes of this mob
+ *
+ * This actually gets the mind datums notes
+ */
/mob/verb/memory()
set name = "Notes"
set category = "IC"
@@ -387,6 +530,9 @@
else
to_chat(src, "You don't have a mind datum for some reason, so you can't look at your notes, if you had any.")
+/**
+ * Add a note to the mind datum
+ */
/mob/verb/add_memory(msg as message)
set name = "Add Note"
set category = "IC"
@@ -399,6 +545,13 @@
else
to_chat(src, "You don't have a mind datum for some reason, so you can't add a note to it.")
+/**
+ * Allows you to respawn, abandoning your current mob
+ *
+ * This sends you back to the lobby creating a new dead mob
+ *
+ * Only works if flag/norespawn is allowed in config
+ */
/mob/verb/abandon_mob()
set name = "Respawn"
set category = "OOC"
@@ -433,7 +586,9 @@
return
-
+/**
+ * Sometimes helps if the user is stuck in another perspective or camera
+ */
/mob/verb/cancel_camera()
set name = "Cancel Camera View"
set category = "OOC"
@@ -452,7 +607,13 @@
set hidden = TRUE
set category = null
return
-
+/**
+ * Topic call back for any mob
+ *
+ * * Unset machines if "mach_close" sent
+ * * refresh the inventory of machines in range if "refresh" sent
+ * * handles the strip panel equip and unequip as well if "item" sent
+ */
/mob/Topic(href, href_list)
if(href_list["mach_close"])
var/t1 = text("window=[href_list["mach_close"]]")
@@ -495,6 +656,9 @@
/mob/proc/stripPanelEquip(obj/item/what, mob/who)
return
+/**
+ * Controls if a mouse drop succeeds (return null if it doesnt)
+ */
/mob/MouseDrop(mob/M)
. = ..()
if(M != usr)
@@ -505,16 +669,27 @@
return
if(isAI(M))
return
-
+/**
+ * Handle the result of a click drag onto this mob
+ *
+ * For mobs this just shows the inventory
+ */
/mob/MouseDrop_T(atom/dropping, atom/user)
. = ..()
if(ismob(dropping) && dropping != user)
var/mob/M = dropping
M.show_inv(user)
+///Is the mob muzzled (default false)
/mob/proc/is_muzzled()
return 0
+/**
+ * Output an update to the stat panel for the client
+ *
+ * calculates client ping, round id, server time, time dilation and other data about the round
+ * and puts it in the mob status panel on a regular loop
+ */
/mob/Stat()
..()
@@ -592,6 +767,11 @@
add_spells_to_statpanel(mind.spell_list)
add_spells_to_statpanel(mob_spell_list)
+/**
+ * Convert a list of spells into a displyable list for the statpanel
+ *
+ * Shows charge and other important info
+ */
/mob/proc/add_spells_to_statpanel(list/spells)
for(var/obj/effect/proc_holder/spell/S in spells)
if(S.can_be_cast_by(src))
@@ -606,6 +786,16 @@
#define MOB_FACE_DIRECTION_DELAY 1
// facing verbs
+/**
+ * Returns true if a mob can turn to face things
+ *
+ * Conditions:
+ * * client.last_turn > world.time
+ * * not dead or unconcious
+ * * not anchored
+ * * no transform not set
+ * * we are not restrained
+ */
/mob/proc/canface()
if(world.time < client.last_turn)
return FALSE
@@ -619,11 +809,13 @@
return FALSE
return TRUE
+///Checks mobility move as well as parent checks
/mob/living/canface()
if(!(mobility_flags & MOBILITY_MOVE))
return FALSE
return ..()
+///Hidden verb to turn east
/mob/verb/eastface()
set hidden = TRUE
if(!canface())
@@ -632,6 +824,7 @@
client.last_turn = world.time + MOB_FACE_DIRECTION_DELAY
return TRUE
+///Hidden verb to turn west
/mob/verb/westface()
set hidden = TRUE
if(!canface())
@@ -640,6 +833,7 @@
client.last_turn = world.time + MOB_FACE_DIRECTION_DELAY
return TRUE
+///Hidden verb to turn north
/mob/verb/northface()
set hidden = TRUE
if(!canface())
@@ -648,6 +842,7 @@
client.last_turn = world.time + MOB_FACE_DIRECTION_DELAY
return TRUE
+///Hidden verb to turn south
/mob/verb/southface()
set hidden = TRUE
if(!canface())
@@ -656,7 +851,8 @@
client.last_turn = world.time + MOB_FACE_DIRECTION_DELAY
return TRUE
-/mob/proc/IsAdvancedToolUser()//This might need a rename but it should replace the can this mob use things check
+///This might need a rename but it should replace the can this mob use things check
+/mob/proc/IsAdvancedToolUser()
return FALSE
/mob/proc/swap_hand()
@@ -668,24 +864,29 @@
/mob/proc/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) //For sec bot threat assessment
return 0
+///Get the ghost of this mob (from the mind)
/mob/proc/get_ghost(even_if_they_cant_reenter, ghosts_with_clients)
if(mind)
return mind.get_ghost(even_if_they_cant_reenter, ghosts_with_clients)
+///Force get the ghost from the mind
/mob/proc/grab_ghost(force)
if(mind)
return mind.grab_ghost(force = force)
+///Notify a ghost that it's body is being cloned
/mob/proc/notify_ghost_cloning(var/message = "Someone is trying to revive you. Re-enter your corpse if you want to be revived!", var/sound = 'sound/effects/genetics.ogg', var/atom/source = null, flashwindow)
var/mob/dead/observer/ghost = get_ghost()
if(ghost)
ghost.notify_cloning(message, sound, source, flashwindow)
return ghost
+///Add a spell to the mobs spell list
/mob/proc/AddSpell(obj/effect/proc_holder/spell/S)
mob_spell_list += S
S.action.Grant(src)
+///Remove a spell from the mobs spell list
/mob/proc/RemoveSpell(obj/effect/proc_holder/spell/spell)
if(!spell)
return
@@ -695,6 +896,7 @@
mob_spell_list -= S
qdel(S)
+///Return any anti magic atom on this mob that matches the magic type
/mob/proc/anti_magic_check(magic = TRUE, holy = FALSE, tinfoil = FALSE, chargecost = 1, self = FALSE)
if(!magic && !holy && !tinfoil)
return
@@ -707,7 +909,13 @@
if((magic && HAS_TRAIT(src, TRAIT_ANTIMAGIC)) || (holy && HAS_TRAIT(src, TRAIT_HOLY)))
return src
-//You can buckle on mobs if you're next to them since most are dense
+/**
+ * Buckle to another mob
+ *
+ * You can buckle on mobs if you're next to them since most are dense
+ *
+ * Turns you to face the other mob too
+ */
/mob/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE)
if(M.buckled)
return 0
@@ -721,18 +929,18 @@
return 0
return ..()
-//Default buckling shift visual for mobs
+///Call back post buckle to a mob to offset your visual height
/mob/post_buckle_mob(mob/living/M)
var/height = M.get_mob_buckling_height(src)
M.pixel_y = initial(M.pixel_y) + height
if(M.layer < layer)
M.layer = layer + 0.1
-
+///Call back post unbuckle from a mob, (reset your visual height here)
/mob/post_unbuckle_mob(mob/living/M)
M.layer = initial(M.layer)
M.pixel_y = initial(M.pixel_y)
-//returns the height in pixel the mob should have when buckled to another mob.
+///returns the height in pixel the mob should have when buckled to another mob.
/mob/proc/get_mob_buckling_height(mob/seat)
if(isliving(seat))
var/mob/living/L = seat
@@ -740,25 +948,30 @@
return 0
return 9
-//can the mob be buckled to something by default?
+///can the mob be buckled to something by default?
/mob/proc/can_buckle()
return 1
-//can the mob be unbuckled from something by default?
+///can the mob be unbuckled from something by default?
/mob/proc/can_unbuckle()
return 1
-//Can the mob interact() with an atom?
+///Can the mob interact() with an atom?
/mob/proc/can_interact_with(atom/A)
return IsAdminGhost(src) || Adjacent(A)
-//Can the mob use Topic to interact with machines
+///Can the mob use Topic to interact with machines
/mob/proc/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE)
return
+///Can this mob use storage
/mob/proc/canUseStorage()
return FALSE
-
+/**
+ * Check if the other mob has any factions the same as us
+ *
+ * If exact match is set, then all our factions must match exactly
+ */
/mob/proc/faction_check_mob(mob/target, exact_match)
if(exact_match) //if we need an exact match, we need to do some bullfuckery.
var/list/faction_src = faction.Copy()
@@ -769,7 +982,11 @@
faction_target -= "[REF(target)]" //same thing here.
return faction_check(faction_src, faction_target, TRUE)
return faction_check(faction, target.faction, FALSE)
-
+/*
+ * Compare two lists of factions, returning true if any match
+ *
+ * If exact match is passed through we only return true if both faction lists match equally
+ */
/proc/faction_check(list/faction_A, list/faction_B, exact_match)
var/list/match_list
if(exact_match)
@@ -783,8 +1000,13 @@
return FALSE
-//This will update a mob's name, real_name, mind.name, GLOB.data_core records, pda, id and traitor text
-//Calling this proc without an oldname will only update the mob and skip updating the pda, id and records ~Carn
+/**
+ * Fully update the name of a mob
+ *
+ * This will update a mob's name, real_name, mind.name, GLOB.data_core records, pda, id and traitor text
+ *
+ * Calling this proc without an oldname will only update the mob and skip updating the pda, id and records ~Carn
+ */
/mob/proc/fully_replace_character_name(oldname,newname)
log_message("[src] name changed from [oldname] to [newname]", LOG_OWNERSHIP)
if(!newname)
@@ -813,10 +1035,11 @@
obj.update_explanation_text()
return 1
-//Updates GLOB.data_core records with new name , see mob/living/carbon/human
+///Updates GLOB.data_core records with new name , see mob/living/carbon/human
/mob/proc/replace_records_name(oldname,newname)
return
+///update the ID name of this mob
/mob/proc/replace_identification_name(oldname,newname)
var/list/searching = GetAllContents()
var/search_id = 1
@@ -849,16 +1072,19 @@
/mob/proc/update_health_hud()
return
+///Update the lighting plane and sight of this mob (sends COMSIG_MOB_UPDATE_SIGHT)
/mob/proc/update_sight()
SEND_SIGNAL(src, COMSIG_MOB_UPDATE_SIGHT)
sync_lighting_plane_alpha()
+///Set the lighting plane hud alpha to the mobs lighting_alpha var
/mob/proc/sync_lighting_plane_alpha()
if(hud_used)
var/obj/screen/plane_master/lighting/L = hud_used.plane_masters["[LIGHTING_PLANE]"]
if (L)
L.alpha = lighting_alpha
+///Update the mouse pointer of the attached client in this mob
/mob/proc/update_mouse_pointer()
if (!client)
return
@@ -873,10 +1099,11 @@
client.mouse_pointer_icon = E.mouse_pointer
-
+///This mob is abile to read books
/mob/proc/is_literate()
return FALSE
+///Can this mob read (is literate and not blind)
/mob/proc/can_read(obj/O)
if(is_blind(src))
to_chat(src, "As you are trying to read [O], you suddenly feel very stupid!")
@@ -886,12 +1113,17 @@
return
return TRUE
+///Can this mob hold items
/mob/proc/can_hold_items()
return FALSE
+///Get the id card on this mob
/mob/proc/get_idcard(hand_first)
return
+/**
+ * Get the mob VV dropdown extras
+ */
/mob/vv_get_dropdown()
. = ..()
. += "---"
@@ -907,12 +1139,16 @@
.["Assume Direct Control"] = "?_src_=vars;[HrefToken()];direct_control=[REF(src)]"
.["Offer Control to Ghosts"] = "?_src_=vars;[HrefToken()];offer_control=[REF(src)]"
+/**
+ * extra var handling for the logging var
+ */
/mob/vv_get_var(var_name)
switch(var_name)
if("logging")
return debug_variable(var_name, logging, 0, src, FALSE)
. = ..()
+///Show the language menu for this mob
/mob/verb/open_language_menu()
set name = "Open Language Menu"
set category = "IC"
@@ -920,12 +1156,15 @@
var/datum/language_holder/H = get_language_holder()
H.open_language_menu(usr)
+///Adjust the nutrition of a mob
/mob/proc/adjust_nutrition(var/change) //Honestly FUCK the oldcoders for putting nutrition on /mob someone else can move it up because holy hell I'd have to fix SO many typechecks
nutrition = max(0, nutrition + change)
+///Force set the mob nutrition
/mob/proc/set_nutrition(var/change) //Seriously fuck you oldcoders.
nutrition = max(0, change)
+///Set the movement type of the mob and update it's movespeed
/mob/setMovetype(newval)
. = ..()
update_movespeed(FALSE)
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 3cc734b8f38..5d96ba1321f 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -1,3 +1,11 @@
+/**
+ * The mob, usually meant to be a creature of some type
+ *
+ * Has a client attached that is a living person (most of the time), although I have to admit
+ * sometimes it's hard to tell they're sentient
+ *
+ * Has a lot of the creature game world logic, such as health etc
+ */
/mob
datum_flags = DF_USE_TAG
density = TRUE
@@ -13,92 +21,181 @@
var/datum/mind/mind
var/static/next_mob_id = 0
- //MOVEMENT SPEED
+ /// List of movement speed modifiers applying to this mob
var/list/movespeed_modification //Lazy list, see mob_movespeed.dm
+ /// The calculated mob speed slowdown based on the modifiers list
var/cached_multiplicative_slowdown
- //ACTIONS
+ /// List of action hud items the user has
var/list/datum/action/actions = list()
+ /// A special action? No idea why this lives here
var/list/datum/action/chameleon_item_actions
- var/stat = CONSCIOUS //Whether a mob is alive or dead. TODO: Move this to living - Nodrak
+ /// Whether a mob is alive or dead. TODO: Move this to living - Nodrak (2019, still here)
+ var/stat = CONSCIOUS
- /*A bunch of this stuff really needs to go under their own defines instead of being globally attached to mob.
+ /* A bunch of this stuff really needs to go under their own defines instead of being globally attached to mob.
A variable should only be globally attached to turfs/objects/whatever, when it is in fact needed as such.
The current method unnecessarily clusters up the variable list, especially for humans (although rearranging won't really clean it up a lot but the difference will be noticable for other mobs).
I'll make some notes on where certain variable defines should probably go.
Changing this around would probably require a good look-over the pre-existing code.
*/
+
+ /// The zone this mob is currently targeting
var/zone_selected = null
var/computer_id = null
var/list/logging = list()
+
+ /// The machine the mob is interacting with (this is very bad old code btw)
var/obj/machinery/machine = null
+ /// Tick time the mob can next move
var/next_move = null
+
+ /**
+ * Magic var that stops you moving and interacting with anything
+ *
+ * Set when you're being turned into something else and also used in a bunch of places
+ * it probably shouldn't really be
+ */
var/notransform = null //Carbon
+
+ /// Is the mob blind
var/eye_blind = 0 //Carbon
+ /// Does the mob have blurry sight
var/eye_blurry = 0 //Carbon
+ /// What is the mobs real name (name is overridden for disguises etc)
var/real_name = null
+
+ /// can this mob move freely in space (should be a trait)
var/spacewalk = FALSE
+ /**
+ * back up of the real name during admin possession
+ *
+ * If an admin possesses an object it's real name is set to the admin name and this
+ * stores whatever the real name was previously. When possession ends, the real name
+ * is reset to this value
+ */
var/name_archive //For admin things like possession
+ /// Default body temperature
var/bodytemperature = BODYTEMP_NORMAL //310.15K / 98.6F
+ /// Drowsyness level of the mob
var/drowsyness = 0//Carbon
+ /// Dizziness level of the mob
var/dizziness = 0//Carbon
+ /// Jitteryness level of the mob
var/jitteriness = 0//Carbon
+ /// Hunger level of the mob
var/nutrition = NUTRITION_LEVEL_START_MIN // randomised in Initialize
+ /// Satiation level of the mob
var/satiety = 0//Carbon
+ /// How many ticks this mob has been over reating
var/overeatduration = 0 // How long this guy is overeating //Carbon
+
+ /// The current intent of the mob
var/a_intent = INTENT_HELP//Living
+ /// List of possible intents a mob can have
var/list/possible_a_intents = null//Living
+ /// The movement intent of the mob (run/wal)
var/m_intent = MOVE_INTENT_RUN//Living
+
+ /// The last known IP of the client who was in this mob
var/lastKnownIP = null
+
+ /// movable atoms buckled to this mob
var/atom/movable/buckled = null//Living
+ /// movable atom we are buckled to
var/atom/movable/buckling
//Hands
+ ///What hand is the active hand
var/active_hand_index = 1
- var/list/held_items = list() //len = number of hands, eg: 2 nulls is 2 empty hands, 1 item and 1 null is 1 full hand and 1 empty hand.
- //held_items[active_hand_index] is the actively held item, but please use get_active_held_item() instead, because OOP
+ /**
+ * list of items held in hands
+ *
+ * len = number of hands, eg: 2 nulls is 2 empty hands, 1 item and 1 null is 1 full hand
+ * and 1 empty hand.
+ *
+ * NB: contains nulls!
+ *
+ * held_items[active_hand_index] is the actively held item, but please use
+ * get_active_held_item() instead, because OOP
+ */
+ var/list/held_items = list()
//HUD things
+
+ /// Storage component (for mob inventory)
var/datum/component/storage/active_storage
+ /// Active hud
var/datum/hud/hud_used = null
+ /// I have no idea tbh
var/research_scanner = FALSE
+ /// Is the mob throw intent on
var/in_throw_mode = 0
+ /// What job does this mob have
var/job = null//Living
- var/list/faction = list("neutral") //A list of factions that this mob is currently in, for hostile mob targetting, amongst other things
- var/move_on_shuttle = 1 // Can move on the shuttle.
+ /// A list of factions that this mob is currently in, for hostile mob targetting, amongst other things
+ var/list/faction = list("neutral")
-//The last mob/living/carbon to push/drag/grab this mob (mostly used by slimes friend recognition)
+ /// Can this mob enter shuttles
+ var/move_on_shuttle = 1
+
+ ///The last mob/living/carbon to push/drag/grab this mob (exclusively used by slimes friend recognition)
var/mob/living/carbon/LAssailant = null
- var/list/mob_spell_list = list() //construct spells and mime spells. Spells that do not transfer from one mob to another and can not be lost in mindswap.
+ /**
+ * construct spells and mime spells.
+ *
+ * Spells that do not transfer from one mob to another and can not be lost in mindswap.
+ * obviously do not live in the mind
+ */
+ var/list/mob_spell_list = list()
- var/status_flags = CANSTUN|CANKNOCKDOWN|CANUNCONSCIOUS|CANPUSH //bitflags defining which status effects can be inflicted (replaces canknockdown, canstun, etc)
+
+ /// bitflags defining which status effects can be inflicted (replaces canknockdown, canstun, etc)
+ var/status_flags = CANSTUN|CANKNOCKDOWN|CANUNCONSCIOUS|CANPUSH
- var/digitalcamo = 0 // Can they be tracked by the AI?
- var/digitalinvis = 0 //Are they ivisible to the AI?
- var/image/digitaldisguise = null //what does the AI see instead of them?
+ /// Can they be tracked by the AI?
+ var/digitalcamo = 0
+ ///Are they ivisible to the AI?
+ var/digitalinvis = 0
+ ///what does the AI see instead of them?
+ var/image/digitaldisguise = null
- var/has_unlimited_silicon_privilege = 0 // Can they interact with station electronics
+ /// Can they interact with station electronics
+ var/has_unlimited_silicon_privilege = 0
- var/obj/control_object //Used by admins to possess objects. All mobs should have this var
- var/atom/movable/remote_control //Calls relaymove() to whatever it is
+ ///Used by admins to possess objects. All mobs should have this var
+ var/obj/control_object
- var/deathsound //leave null for no sound. used for *deathgasp
+ ///Calls relay_move() to whatever this is set to when the mob tries to move
+ var/atom/movable/remote_control
- var/turf/listed_turf = null //the current turf being examined in the stat panel
+ /**
+ * The sound made on death
+ *
+ * leave null for no sound. used for *deathgasp
+ */
+ var/deathsound
- var/list/observers = null //The list of people observing this mob.
+ ///the current turf being examined in the stat panel
+ var/turf/listed_turf = null
+ ///The list of people observing this mob.
+ var/list/observers = null
+
+ ///List of progress bars this mob is currently seeing for actions
var/list/progressbars = null //for stacking do_after bars
+ ///Allows a datum to intercept all click calls this mob is the source of
var/datum/click_intercept
- var/registered_z
+ ///THe z level this mob is currently registered in
+ var/registered_z = null
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 1903f49b644..952adb76f08 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -1,11 +1,13 @@
// see _DEFINES/is_helpers.dm for mob type checks
+///Find the mob at the bottom of a buckle chain
/mob/proc/lowest_buckled_mob()
. = src
if(buckled && ismob(buckled))
var/mob/Buckled = buckled
. = Buckled.lowest_buckled_mob()
+///Convert a PRECISE ZONE into the BODY_ZONE
/proc/check_zone(zone)
if(!zone)
return BODY_ZONE_CHEST
@@ -26,7 +28,12 @@
zone = BODY_ZONE_CHEST
return zone
-
+/**
+ * Return the zone or randomly, another valid zone
+ *
+ * probability controls the chance it chooses the passed in zone, or another random zone
+ * defaults to 80
+ */
/proc/ran_zone(zone, probability = 80)
if(prob(probability))
zone = check_zone(zone)
@@ -34,13 +41,21 @@
zone = pickweight(list(BODY_ZONE_HEAD = 1, BODY_ZONE_CHEST = 1, BODY_ZONE_L_ARM = 4, BODY_ZONE_R_ARM = 4, BODY_ZONE_L_LEG = 4, BODY_ZONE_R_LEG = 4))
return zone
+///Would this zone be above the neck
/proc/above_neck(zone)
var/list/zones = list(BODY_ZONE_HEAD, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_PRECISE_EYES)
if(zones.Find(zone))
return 1
else
return 0
-
+/**
+ * Convert random parts of a passed in message to stars
+ *
+ * * n - the string to convert
+ * * pr - probability any character gets changed
+ *
+ * This proc is dangerously laggy, avoid it or die
+ */
/proc/stars(n, pr)
n = html_encode(n)
if (pr == null)
@@ -62,7 +77,9 @@
if(n > MAX_BROADCAST_LEN)
t += "..." //signals missing text
return sanitize(t)
-
+/**
+ * Makes you speak like you're drunk
+ */
/proc/slur(n)
var/phrase = html_decode(n)
var/leng = lentext(phrase)
@@ -97,7 +114,7 @@
newphrase+="[newletter]";counter-=1
return newphrase
-
+/// Makes you talk like you got cult stunned, which is slurring but with some dark messages
/proc/cultslur(n) // Inflicted on victims of a stun talisman
var/phrase = html_decode(n)
var/leng = lentext(phrase)
@@ -139,7 +156,7 @@
newphrase+="[newletter]";counter-=1
return newphrase
-
+///Adds stuttering to the message passed in
/proc/stutter(n)
var/te = html_decode(n)
var/t = ""//placed before the message. Not really sure what it's for.
@@ -163,6 +180,7 @@
p++//for each letter p is increased to find where the next letter will be.
return copytext(sanitize(t),1,MAX_MESSAGE_LEN)
+///Convert a message to derpy speak
/proc/derpspeech(message, stuttering)
message = replacetext(message, " am ", " ")
message = replacetext(message, " is ", " ")
@@ -180,8 +198,12 @@
message = stutter(message)
return message
-/proc/Gibberish(t, p)//t is the inputted message, and any value higher than 70 for p will cause letters to be replaced instead of added
- /* Turn text into complete gibberish! */
+/**
+ * Turn text into complete gibberish!
+ *
+ * t is the inputted message, and any value higher than 70 for p will cause letters to be replaced instead of added
+ */
+/proc/Gibberish(t, p)
var/returntext = ""
for(var/i = 1, i <= length(t), i++)
@@ -198,12 +220,16 @@
return returntext
+/**
+ * Convert a message into leet non gaijin speak
+ *
+ * The difference with stutter is that this proc can stutter more than 1 letter
+ *
+ * The issue here is that anything that does not have a space is treated as one word (in many instances). For instance, "LOOKING," is a word, including the comma.
+ *
+ * It's fairly easy to fix if dealing with single letters but not so much with compounds of letters./N
+ */
/proc/ninjaspeak(n) //NINJACODE
-/*
-The difference with stutter is that this proc can stutter more than 1 letter
-The issue here is that anything that does not have a space is treated as one word (in many instances). For instance, "LOOKING," is a word, including the comma.
-It's fairly easy to fix if dealing with single letters but not so much with compounds of letters./N
-*/
var/te = html_decode(n)
var/t = ""
n = length(n)
@@ -226,7 +252,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
p=p+n_mod
return copytext(sanitize(t),1,MAX_MESSAGE_LEN)
-
+///Shake the camera of the person viewing the mob SO REAL!
/proc/shake_camera(mob/M, duration, strength=1)
if(!M || !M.client || duration < 1)
return
@@ -244,7 +270,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
animate(pixel_x=oldx, pixel_y=oldy, time=1)
-
+///Find if the message has the real name of any user mob in the mob_list
/proc/findname(msg)
if(!istext(msg))
msg = "[msg]"
@@ -254,13 +280,18 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
return M
return 0
+///Find the first name of a mob from the real name with regex
/mob/proc/first_name()
var/static/regex/firstname = new("^\[^\\s-\]+") //First word before whitespace or "-"
firstname.Find(real_name)
return firstname.match
-//change a mob's act-intent. Input the intent as a string such as "help" or use "right"/"left
+/**
+ * change a mob's act-intent.
+ *
+ * Input the intent as a string such as "help" or use "right"/"left
+ */
/mob/verb/a_intent_change(input as text)
set name = "a-intent"
set hidden = 1
@@ -293,17 +324,26 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
if(hud_used && hud_used.action_intent)
hud_used.action_intent.icon_state = "[a_intent]"
-
+///Checks if passed through item is blind
/proc/is_blind(A)
if(ismob(A))
var/mob/B = A
return B.eye_blind
return FALSE
+///Is the mob hallucinating?
/mob/proc/hallucinating()
return FALSE
-/proc/is_special_character(mob/M) // returns 1 for special characters and 2 for heroes of gamemode //moved out of admins.dm because things other than admin procs were calling this.
+
+// moved out of admins.dm because things other than admin procs were calling this.
+/**
+ * Is this mob special to the gamemode?
+ *
+ * returns 1 for special characters and 2 for heroes of gamemode
+ *
+ */
+/proc/is_special_character(mob/M)
if(!SSticker.HasRoundStarted())
return FALSE
if(!istype(M))
@@ -346,9 +386,29 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
return TRUE
return FALSE
+
/mob/proc/reagent_check(datum/reagent/R) // utilized in the species code
return 1
+
+/**
+ * Fancy notifications for ghosts
+ *
+ * The kitchen sink of notification procs
+ *
+ * Arguments:
+ * * message
+ * * ghost_sound sound to play
+ * * enter_link Href link to enter the ghost role being notified for
+ * * source The source of the notification
+ * * alert_overlay The alert overlay to show in the alert message
+ * * action What action to take upon the ghost interacting with the notification, defaults to NOTIFY_JUMP
+ * * flashwindow Flash the byond client window
+ * * ignore_key Ignore keys if they're in the GLOB.poll_ignore list
+ * * header The header of the notifiaction
+ * * notify_suiciders If it should notify suiciders (who do not qualify for many ghost roles)
+ * * notify_volume How loud the sound should be to spook the user
+ */
/proc/notify_ghosts(var/message, var/ghost_sound = null, var/enter_link = null, var/atom/source = null, var/mutable_appearance/alert_overlay = null, var/action = NOTIFY_JUMP, flashwindow = TRUE, ignore_mapload = TRUE, ignore_key, header = null, notify_suiciders = TRUE, var/notify_volume = 100) //Easy notification of ghosts.
if(ignore_mapload && SSatoms.initialized != INITIALIZATION_INNEW_REGULAR) //don't notify for objects created during a map load
return
@@ -382,6 +442,9 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
alert_overlay.plane = FLOAT_PLANE
A.add_overlay(alert_overlay)
+/**
+ * Heal a robotic body part on a mob
+ */
/proc/item_heal_robotic(mob/living/carbon/human/H, mob/user, brute_heal, burn_heal)
var/obj/item/bodypart/affecting = H.get_bodypart(check_zone(user.zone_selected))
if(affecting && affecting.status == BODYPART_ROBOTIC)
@@ -399,7 +462,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
else
to_chat(user, "[affecting] is already in good condition!")
-
+///Is the passed in mob an admin ghost
/proc/IsAdminGhost(var/mob/user)
if(!user) //Are they a mob? Auto interface updates call this with a null src
return
@@ -413,6 +476,11 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
return
return TRUE
+/**
+ * Offer control of the passed in mob to dead player
+ *
+ * Automatic logging and uses pollCandidatesForMob, how convenient
+ */
/proc/offer_control(mob/M)
to_chat(M, "Control of your mob has been offered to dead players.")
if(usr)
@@ -441,12 +509,14 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
message_admins("No ghosts were willing to take control of [ADMIN_LOOKUPFLW(M)])")
return FALSE
+///Is the mob a flying mob
/mob/proc/is_flying(mob/M = src)
if(M.movement_type & FLYING)
return 1
else
return 0
+///Clicks a random nearby mob with the source from this mob
/mob/proc/click_random_mob()
var/list/nearby_mobs = list()
for(var/mob/living/L in range(1, src))
@@ -456,7 +526,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
var/mob/living/T = pick(nearby_mobs)
ClickOn(T)
-// Logs a message in a mob's individual log, and in the global logs as well if log_globally is true
+/// Logs a message in a mob's individual log, and in the global logs as well if log_globally is true
/mob/log_message(message, message_type, color=null, log_globally = TRUE)
if(!LAZYLEN(message))
stack_trace("Empty message")
@@ -488,14 +558,25 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
..()
+///Can the mob hear
/mob/proc/can_hear()
. = TRUE
-//Examine text for traits shared by multiple types. I wish examine was less copypasted.
+/**
+ * Examine text for traits shared by multiple types.
+ *
+ * I wish examine was less copypasted. (oranges say, be the change you want to see buddy)
+ */
/mob/proc/common_trait_examine()
if(HAS_TRAIT(src, TRAIT_DISSECTED))
. += "This body has been dissected and analyzed. It is no longer worth experimenting on.
"
+/**
+ * Get the list of keywords for policy config
+ *
+ * This gets the type, mind assigned roles and antag datums as a list, these are later used
+ * to send the user relevant headadmin policy config
+ */
/mob/proc/get_policy_keywords()
. = list()
. += "[type]"
@@ -505,6 +586,6 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
for(var/datum/antagonist/A in mind.antag_datums)
. += "[A.type]"
-//Can the mob see reagents inside of containers?
+///Can the mob see reagents inside of containers?
/mob/proc/can_see_reagents()
return stat == DEAD || has_unlimited_silicon_privilege //Dead guys and silicons can always see reagents
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 4537bfcd8b1..485235b5d41 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -1,17 +1,36 @@
+///Can the atom pass this mob (always true for /mob)
/mob/CanPass(atom/movable/mover, turf/target)
return TRUE //There's almost no cases where non /living mobs should be used in game as actual mobs, other than ghosts.
-//DO NOT USE THIS UNLESS YOU ABSOLUTELY HAVE TO. THIS IS BEING PHASED OUT FOR THE MOVESPEED MODIFICATION SYSTEM.
-//See mob_movespeed.dm
+/**
+ * Get the current movespeed delay of the mob
+ *
+ * DO NOT OVERRIDE THIS UNLESS YOU ABSOLUTELY HAVE TO.
+ * THIS IS BEING PHASED OUT FOR THE MOVESPEED MODIFICATION SYSTEM.
+ * See mob_movespeed.dm
+ */
/mob/proc/movement_delay() //update /living/movement_delay() if you change this
return cached_multiplicative_slowdown
+/**
+ * If your mob is concious, drop the item in the active hand
+ *
+ * This is a hidden verb, likely for binding with winset for hotkeys
+ */
/client/verb/drop_item()
set hidden = 1
if(!iscyborg(mob) && mob.stat == CONSCIOUS)
mob.dropItemToGround(mob.get_active_held_item())
return
+/**
+ * force move the control_object of your client mob
+ *
+ * Used in admin possession and called from the client Move proc
+ * ensures the possessed object moves and not the admin mob
+ *
+ * Has no sanity other than checking density
+ */
/client/proc/Move_object(direct)
if(mob && mob.control_object)
if(mob.control_object.density)
@@ -25,6 +44,42 @@
#define MOVEMENT_DELAY_BUFFER 0.75
#define MOVEMENT_DELAY_BUFFER_DELTA 1.25
+/**
+ * Move a client in a direction
+ *
+ * Huge proc, has a lot of functionality
+ *
+ * Mostly it will despatch to the mob that you are the owner of to actually move
+ * in the physical realm
+ *
+ * Things that stop you moving as a mob:
+ * * world time being less than your next move_delay
+ * * not being in a mob, or that mob not having a loc
+ * * missing the n and direction parameters
+ * * being in remote control of an object (calls Moveobject instead)
+ * * being dead (it ghosts you instead)
+ *
+ * Things that stop you moving as a mob living (why even have OO if you're just shoving it all
+ * in the parent proc with istype checks right?):
+ * * having incorporeal_move set (calls Process_Incorpmove() instead)
+ * * being grabbed
+ * * being buckled (relaymove() is called to the buckled atom instead)
+ * * having your loc be some other mob (relaymove() is called on that mob instead)
+ * * Not having MOBILITY_MOVE
+ * * Failing Process_Spacemove() call
+ *
+ * At this point, if the mob is is confused, then a random direction and target turf will be calculated for you to travel to instead
+ *
+ * Now the parent call is made (to the byond builtin move), which moves you
+ *
+ * Some final move delay calculations (doubling if you moved diagonally successfully)
+ *
+ * if mob throwing is set I believe it's unset at this point via a call to finalize
+ *
+ * Finally if you're pulling an object and it's dense, you are turned 180 after the move
+ * (if you ask me, this should be at the top of the move so you don't dance around)
+ *
+ */
/client/Move(n, direct)
if(world.time < move_delay) //do not move anything ahead of this check please
return FALSE
@@ -107,9 +162,11 @@
if(P && !ismob(P) && P.density)
mob.setDir(turn(mob.dir, 180))
-///Process_Grab()
-///Called by client/Move()
-///Checks to see if you are being grabbed and if so attemps to break it
+/**
+ * Checks to see if you're being grabbed and if so attempts to break it
+ *
+ * Called by client/Move()
+ */
/client/proc/Process_Grab()
if(mob.pulledby)
if((mob.pulledby == mob.pulling) && (mob.pulledby.grab_state == GRAB_PASSIVE)) //Don't autoresist passive grabs if we're grabbing them too.
@@ -124,9 +181,19 @@
else
return mob.resist_grab(1)
-///Process_Incorpmove
-///Called by client/Move()
-///Allows mobs to run though walls
+/**
+ * Allows mobs to ignore density and phase through objects
+ *
+ * Called by client/Move()
+ *
+ * The behaviour depends on the incorporeal_move value of the mob
+ *
+ * * INCORPOREAL_MOVE_BASIC - forceMoved to the next tile with no stop
+ * * INCORPOREAL_MOVE_SHADOW - the same but leaves a cool effect path
+ * * INCORPOREAL_MOVE_JAUNT - the same but blocked by holy tiles
+ *
+ * You'll note this is another mob living level proc living at the client level
+ */
/client/proc/Process_Incorpmove(direct)
var/turf/mobloc = get_turf(mob)
if(!isliving(mob))
@@ -202,10 +269,15 @@
return TRUE
-///Process_Spacemove
-///Called by /client/Move()
-///For moving in space
-///return TRUE for movement 0 for none
+/**
+ * Handles mob/living movement in space (or no gravity)
+ *
+ * Called by /client/Move()
+ *
+ * return TRUE for movement or FALSE for none
+ *
+ * You can move in space if you have a spacewalk ability
+ */
/mob/Process_Spacemove(movement_dir = 0)
if(spacewalk || ..())
return TRUE
@@ -217,6 +289,9 @@
return TRUE
return FALSE
+/**
+ * Find movable atoms? near a mob that are viable for pushing off when moving
+ */
/mob/get_spacemove_backup()
for(var/A in orange(1, get_turf(src)))
if(isarea(A))
@@ -243,27 +318,42 @@
continue
. = AM
+/**
+ * Returns true if a mob has gravity
+ *
+ * I hate that this exists
+ */
/mob/proc/mob_has_gravity()
return has_gravity()
+/**
+ * Does this mob ignore gravity
+ */
/mob/proc/mob_negates_gravity()
return FALSE
-
+/// Called when this mob slips over, override as needed
/mob/proc/slip(knockdown_amount, obj/O, lube, paralyze, force_drop)
return
+/// Update the gravity status of this mob
/mob/proc/update_gravity()
return
-//bodypart selection - Cyberboss
-//8 toggles through head - eyes - mouth
+//bodypart selection verbs - Cyberboss
+//8:repeated presses toggles through head - eyes - mouth
//4: r-arm 5: chest 6: l-arm
//1: r-leg 2: groin 3: l-leg
+///Validate the client's mob has a valid zone selected
/client/proc/check_has_body_select()
return mob && mob.hud_used && mob.hud_used.zone_select && istype(mob.hud_used.zone_select, /obj/screen/zone_sel)
+/**
+ * Hidden verb to set the target zone of a mob to the head
+ *
+ * (bound to 8) - repeated presses toggles through head - eyes - mouth
+ */
/client/verb/body_toggle_head()
set name = "body-toggle-head"
set hidden = 1
@@ -283,6 +373,7 @@
var/obj/screen/zone_sel/selector = mob.hud_used.zone_select
selector.set_selected_zone(next_in_line, mob)
+///Hidden verb to target the right arm, bound to 4
/client/verb/body_r_arm()
set name = "body-r-arm"
set hidden = 1
@@ -293,6 +384,7 @@
var/obj/screen/zone_sel/selector = mob.hud_used.zone_select
selector.set_selected_zone(BODY_ZONE_R_ARM, mob)
+///Hidden verb to target the chest, bound to 5
/client/verb/body_chest()
set name = "body-chest"
set hidden = 1
@@ -303,6 +395,7 @@
var/obj/screen/zone_sel/selector = mob.hud_used.zone_select
selector.set_selected_zone(BODY_ZONE_CHEST, mob)
+///Hidden verb to target the left arm, bound to 6
/client/verb/body_l_arm()
set name = "body-l-arm"
set hidden = 1
@@ -313,6 +406,7 @@
var/obj/screen/zone_sel/selector = mob.hud_used.zone_select
selector.set_selected_zone(BODY_ZONE_L_ARM, mob)
+///Hidden verb to target the right leg, bound to 1
/client/verb/body_r_leg()
set name = "body-r-leg"
set hidden = 1
@@ -323,6 +417,7 @@
var/obj/screen/zone_sel/selector = mob.hud_used.zone_select
selector.set_selected_zone(BODY_ZONE_R_LEG, mob)
+///Hidden verb to target the groin, bound to 2
/client/verb/body_groin()
set name = "body-groin"
set hidden = 1
@@ -333,6 +428,7 @@
var/obj/screen/zone_sel/selector = mob.hud_used.zone_select
selector.set_selected_zone(BODY_ZONE_PRECISE_GROIN, mob)
+///Hidden verb to target the left leg, bound to 3
/client/verb/body_l_leg()
set name = "body-l-leg"
set hidden = 1
@@ -343,6 +439,7 @@
var/obj/screen/zone_sel/selector = mob.hud_used.zone_select
selector.set_selected_zone(BODY_ZONE_L_LEG, mob)
+///Verb to toggle the walk or run status
/client/verb/toggle_walk_run()
set name = "toggle-walk-run"
set hidden = TRUE
@@ -350,6 +447,11 @@
if(mob)
mob.toggle_move_intent(usr)
+/**
+ * Toggle the move intent of the mob
+ *
+ * triggers an update the move intent hud as well
+ */
/mob/proc/toggle_move_intent(mob/user)
if(m_intent == MOVE_INTENT_RUN)
m_intent = MOVE_INTENT_WALK
@@ -359,6 +461,7 @@
for(var/obj/screen/mov_intent/selector in hud_used.static_inventory)
selector.update_icon(src)
+///Moves a mob upwards in z level
/mob/verb/up()
set name = "Move Upwards"
set category = "IC"
@@ -366,6 +469,7 @@
if(zMove(UP, TRUE))
to_chat(src, "You move upwards.")
+///Moves a mob down a z level
/mob/verb/down()
set name = "Move Down"
set category = "IC"
@@ -373,6 +477,7 @@
if(zMove(DOWN, TRUE))
to_chat(src, "You move down.")
+///Move a mob between z levels, if it's valid to move z's on this turf
/mob/proc/zMove(dir, feedback = FALSE)
if(dir != UP && dir != DOWN)
return FALSE
@@ -388,5 +493,6 @@
forceMove(target)
return TRUE
+/// Can this mob move between z levels
/mob/proc/canZMove(direction, turf/target)
return FALSE
diff --git a/code/modules/mob/mob_movespeed.dm b/code/modules/mob/mob_movespeed.dm
index 0df79ec39ce..60af7098853 100644
--- a/code/modules/mob/mob_movespeed.dm
+++ b/code/modules/mob/mob_movespeed.dm
@@ -1,13 +1,40 @@
+/*! How move speed for mobs works
-/*Current movespeed modification list format: list(id = list(
- priority,
- flags,
- legacy slowdown/speedup amount,
- movetype_flags
- ))
+Move speed is now calculated by using a list of movespeed modifiers, which is a list itself (to avoid datum overhead)
+
+This gives us the ability to have multiple sources of movespeed, reliabily keep them applied and remove them when they should be
+
+THey can have unique sources and a bunch of extra fancy flags that control behaviour
+
+Previously trying to update move speed was a shot in the dark that usually meant mobs got stuck going faster or slower
+
+This list takes the following format
+
+```Current movespeed modification list format:
+ list(
+ id = list(
+ priority,
+ flags,
+ legacy slowdown/speedup amount,
+ movetype_flags
+ )
+ )
+```
+
+WHen update movespeed is called, the list of items is iterated, according to flags priority and a bunch of conditions
+this spits out a final calculated value which is used as a modifer to last_move + modifier for calculating when a mob
+can next move
+
+Key procs
+* [add_movespeed_modifier](mob.html#proc/add_movespeed_modifier)
+* [remove_movespeed_modifier](mob.html#proc/remove_movespeed_modifier)
+* [has_movespeed_modifier](mob.html#proc/has_movespeed_modifier)
+* [update_movespeed](mob.html#proc/update_movespeed)
*/
//ANY ADD/REMOVE DONE IN UPDATE_MOVESPEED MUST HAVE THE UPDATE ARGUMENT SET AS FALSE!
+
+///Add a move speed modifier to a mob
/mob/proc/add_movespeed_modifier(id, update=TRUE, priority=0, flags=NONE, override=FALSE, multiplicative_slowdown=0, movetypes=ALL, blacklisted_movetypes=NONE, conflict=FALSE)
var/list/temp = list(priority, flags, multiplicative_slowdown, movetypes, blacklisted_movetypes, conflict) //build the modification list
var/resort = TRUE
@@ -24,6 +51,7 @@
update_movespeed(resort)
return TRUE
+///Remove a move speed modifier from a mob
/mob/proc/remove_movespeed_modifier(id, update = TRUE)
if(!LAZYACCESS(movespeed_modification, id))
return FALSE
@@ -33,6 +61,7 @@
update_movespeed(FALSE)
return TRUE
+///Handles the special case of editing the movement var
/mob/vv_edit_var(var_name, var_value)
var/slowdown_edit = (var_name == NAMEOF(src, cached_multiplicative_slowdown))
var/diff
@@ -43,18 +72,22 @@
if(. && slowdown_edit && isnum(diff))
add_movespeed_modifier(MOVESPEED_ID_ADMIN_VAREDIT, TRUE, 100, override = TRUE, multiplicative_slowdown = diff)
+///Is there a movespeed modifier for this mob
/mob/proc/has_movespeed_modifier(id)
return LAZYACCESS(movespeed_modification, id)
+///Set or update the global movespeed config on a mob
/mob/proc/update_config_movespeed()
add_movespeed_modifier(MOVESPEED_ID_CONFIG_SPEEDMOD, FALSE, 100, override = TRUE, multiplicative_slowdown = get_config_multiplicative_speed())
+///Get the global config movespeed of a mob by type
/mob/proc/get_config_multiplicative_speed()
if(!islist(GLOB.mob_config_movespeed_type_lookup) || !GLOB.mob_config_movespeed_type_lookup[type])
return 0
else
return GLOB.mob_config_movespeed_type_lookup[type]
+///Go through the list of movespeed modifiers and calculate a final movespeed
/mob/proc/update_movespeed(resort = TRUE)
if(resort)
sort_movespeed_modlist()
@@ -78,9 +111,11 @@
. += amt
cached_multiplicative_slowdown = .
+///Get the move speed modifiers list of the mob
/mob/proc/get_movespeed_modifiers()
return movespeed_modification
+///Check if a movespeed modifier is identical to another
/mob/proc/movespeed_modifier_identical_check(list/mod1, list/mod2)
if(!islist(mod1) || !islist(mod2) || mod1.len < MOVESPEED_DATA_INDEX_MAX || mod2.len < MOVESPEED_DATA_INDEX_MAX)
return FALSE
@@ -89,18 +124,25 @@
return FALSE
return TRUE
+///Calculate the total slowdown of all movespeed modifiers
/mob/proc/total_multiplicative_slowdown()
. = 0
for(var/id in get_movespeed_modifiers())
var/list/data = movespeed_modification[id]
. += data[MOVESPEED_DATA_INDEX_MULTIPLICATIVE_SLOWDOWN]
+///Checks if a move speed modifier is valid and not missing any data
/proc/movespeed_data_null_check(list/data) //Determines if a data list is not meaningful and should be discarded.
. = TRUE
if(data[MOVESPEED_DATA_INDEX_MULTIPLICATIVE_SLOWDOWN])
. = FALSE
-/mob/proc/sort_movespeed_modlist() //Verifies it too. Sorts highest priority (first applied) to lowest priority (last applied)
+/**
+ * Sort the list of move speed modifiers
+ *
+ * Verifies it too. Sorts highest priority (first applied) to lowest priority (last applied)
+ */
+/mob/proc/sort_movespeed_modlist()
if(!movespeed_modification)
return
var/list/assembled = list()
@@ -121,4 +163,4 @@
if(!resolved)
assembled[our_id] = our_data
movespeed_modification = assembled
- UNSETEMPTY(movespeed_modification)
\ No newline at end of file
+ UNSETEMPTY(movespeed_modification)
diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm
index 4e8c90cb66a..7da198d2924 100644
--- a/code/modules/mob/say.dm
+++ b/code/modules/mob/say.dm
@@ -1,4 +1,6 @@
//Speech verbs.
+
+///Say verb
/mob/verb/say_verb(message as text)
set name = "Say"
set category = "IC"
@@ -8,7 +10,7 @@
if(message)
say(message)
-
+///Whisper verb
/mob/verb/whisper_verb(message as text)
set name = "Whisper"
set category = "IC"
@@ -17,9 +19,11 @@
return
whisper(message)
+///whisper a message
/mob/proc/whisper(message, datum/language/language=null)
say(message, language) //only living mobs actually whisper, everything else just talks
+///The me emote verb
/mob/verb/me_verb(message as text)
set name = "Me"
set category = "IC"
@@ -32,6 +36,7 @@
usr.emote("me",1,message,TRUE)
+///Speak as a dead person (ghost etc)
/mob/proc/say_dead(var/message)
var/name = real_name
var/alt_name = ""
@@ -75,17 +80,28 @@
log_talk(message, LOG_SAY, tag="DEAD")
deadchat_broadcast(rendered, source, follow_target = src, speaker_key = key)
+///Check if this message is an emote
/mob/proc/check_emote(message, forced)
if(copytext(message, 1, 2) == "*")
emote(copytext(message, 2), intentional = !forced)
return 1
+///Check if the mob has a hivemind channel
/mob/proc/hivecheck()
return 0
+///Check if the mob has a ling hivemind
/mob/proc/lingcheck()
return LINGHIVE_NONE
+/**
+ * Get the mode of a message
+ *
+ * Result can be
+ * * MODE_WHISPER (Quiet speech)
+ * * MODE_HEADSET (Common radio channel)
+ * * A department radio (lots of values here)
+ */
/mob/proc/get_message_mode(message)
var/key = copytext(message, 1, 2)
if(key == "#")
diff --git a/code/modules/mob/say_readme.dm b/code/modules/mob/say_readme.md
similarity index 94%
rename from code/modules/mob/say_readme.dm
rename to code/modules/mob/say_readme.md
index 6b0eb187adc..0e654f0ced1 100644
--- a/code/modules/mob/say_readme.dm
+++ b/code/modules/mob/say_readme.md
@@ -1,6 +1,7 @@
-/*=============================================================
-======================MIAUW'S SAY REWRITE======================
-===============================================================
+# Say code basics
+
+This document is a little dated but I believe it's accurate mostly (oranges 2019)
+# MIAUW'S SAY REWRITE
This is a basic explanation of how say() works. Read this if you don't understand something.
@@ -14,8 +15,9 @@ If you came here to see how to use saycode, all you will ever really need to cal
To have things react when other things speak around them, add the HEAR_1 flag to their flags variable and
override their Hear() proc.
-=======================PROCS & VARIABLES=======================
- Here follows a list of say()-related procs and variables.
+# PROCS & VARIABLES
+Here follows a list of say()-related procs and variables.
+```
global procs
get_radio_span(freq)
Returns the span class associated with that frequency.
@@ -76,7 +78,8 @@ global procs
Passes message_mode to say_quote.
say_quote(input, spans, message_mode)
- Adds a verb and quotes to a message. Also attaches span classes to a message. Verbs are determined by verb_say/verb_ask/verb_yell variables. Called on the speaker.
+ Adds a verb and quotes to a message. Also attaches span classes to a message.
+ Verbs are determined by verb_say/verb_ask/verb_yell variables. Called on the speaker.
/mob
say_dead(message)
@@ -145,8 +148,8 @@ global procs
Return 0 if no radio was spoken into.
IMPORTANT: remember to call ..() and check for ..()'s return value properly!
-
-============================RADIOS=============================
+```
+# RADIOS
I did not want to interfere with radios too much, but I sort of had to.
For future generations, here is how radio code works:
@@ -162,9 +165,10 @@ This is an associative list, and the numbers as strings are the keys. The values
To add a radio, simply use add_radio(radio, frequency). To remove a radio, use remove_radio(radio, frequency).
To remove a radio from ALL frequencies, use remove_radio_all(radio).
-VIRTUAL SPEAKERS:
+## VIRTUAL SPEAKERS:
Virtual speakers are simply atom/movables with a few extra variables.
If radio_freq is not null, the code will rely on the fact that the speaker is virtual. This means that several procs will return something:
+```
(all of these procs are defined at the atom/movable level and return "" at that level.)
GetJob()
Returns the job string variable of the virtual speaker.
@@ -174,7 +178,7 @@ If radio_freq is not null, the code will rely on the fact that the speaker is vi
Returns the source of the virtual speaker.
GetRadio()
Returns the radio that was spoken through by the source. Needed for AI tracking.
-
+```
This is fairly hacky, but it means that I can advoid using istypes. It's mainly relevant for AI tracking and AI job display.
-That's all, folks!*/
+That's all, folks!
diff --git a/code/modules/mob/status_procs.dm b/code/modules/mob/status_procs.dm
index 7a4f72b9b62..bc4197f6d3e 100644
--- a/code/modules/mob/status_procs.dm
+++ b/code/modules/mob/status_procs.dm
@@ -5,21 +5,23 @@
-/////////////////////////////////// JITTERINESS ////////////////////////////////////
-
+///Set the jitter of a mob
/mob/proc/Jitter(amount)
jitteriness = max(jitteriness,amount,0)
-/////////////////////////////////// DIZZINESS ////////////////////////////////////
-
+/**
+ * Set the dizzyness of a mob to a passed in amount
+ *
+ * Except if dizziness is already higher in which case it does nothing
+ */
/mob/proc/Dizzy(amount)
dizziness = max(dizziness,amount,0)
+///FOrce set the dizzyness of a mob
/mob/proc/set_dizziness(amount)
dizziness = max(amount, 0)
-/////////////////////////////////// EYE_BLIND ////////////////////////////////////
-
+///Blind a mobs eyes by amount
/mob/proc/blind_eyes(amount)
if(amount>0)
var/old_eye_blind = eye_blind
@@ -29,6 +31,11 @@
throw_alert("blind", /obj/screen/alert/blind)
overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
+/**
+ * Adjust a mobs blindness by an amount
+ *
+ * Will apply the blind alerts if needed
+ */
/mob/proc/adjust_blindness(amount)
if(amount>0)
var/old_eye_blind = eye_blind
@@ -49,7 +56,9 @@
if(!eye_blind)
clear_alert("blind")
clear_fullscreen("blind")
-
+/**
+ * Force set the blindness of a mob to some level
+ */
/mob/proc/set_blindness(amount)
if(amount>0)
var/old_eye_blind = eye_blind
@@ -71,21 +80,27 @@
clear_alert("blind")
clear_fullscreen("blind")
-/////////////////////////////////// EYE_BLURRY ////////////////////////////////////
-
+/**
+ * Make the mobs vision blurry
+ */
/mob/proc/blur_eyes(amount)
if(amount>0)
eye_blurry = max(amount, eye_blurry)
update_eye_blur()
+/**
+ * Adjust the current blurriness of the mobs vision by amount
+ */
/mob/proc/adjust_blurriness(amount)
eye_blurry = max(eye_blurry+amount, 0)
update_eye_blur()
+///Set the mobs blurriness of vision to an amount
/mob/proc/set_blurriness(amount)
eye_blurry = max(amount, 0)
update_eye_blur()
+///Apply the blurry overlays to a mobs clients screen
/mob/proc/update_eye_blur()
if(!client)
return
@@ -94,24 +109,23 @@
GW.backdrop(src)
OT.backdrop(src)
-/////////////////////////////////// DRUGGY ////////////////////////////////////
-
+///Adjust the drugginess of a mob
/mob/proc/adjust_drugginess(amount)
return
+///Set the drugginess of a mob
/mob/proc/set_drugginess(amount)
return
-/////////////////////////////////// GROSSED OUT ////////////////////////////////////
-
+///Adjust the disgust level of a mob
/mob/proc/adjust_disgust(amount)
return
+///Set the disgust level of a mob
/mob/proc/set_disgust(amount)
return
-/////////////////////////////////// TEMPERATURE ////////////////////////////////////
-
+///Adjust the body temperature of a mob, with min/max settings
/mob/proc/adjust_bodytemperature(amount,min_temp=0,max_temp=INFINITY)
if(bodytemperature >= min_temp && bodytemperature <= max_temp)
bodytemperature = CLAMP(bodytemperature + amount,min_temp,max_temp)
diff --git a/code/modules/modular_computers/documentation.md b/code/modules/modular_computers/documentation.md
index 246da7c3d9c..88d059da7a6 100644
--- a/code/modules/modular_computers/documentation.md
+++ b/code/modules/modular_computers/documentation.md
@@ -1,5 +1,7 @@
# Modular computer programs
+How module computer programs work
+
Ok. so a quick rundown on how to make a program. This is kind of a shitty documentation, but oh well I was asked to.
## Base setup