diff --git a/code/__DEFINES/maths.dm b/code/__DEFINES/maths.dm
index b6d1b771..cfb90f13 100644
--- a/code/__DEFINES/maths.dm
+++ b/code/__DEFINES/maths.dm
@@ -217,3 +217,12 @@
#define RULE_OF_THREE(a, b, x) ((a*x)/b)
// )
+
+#define MANHATTAN_DISTANCE(a, b) (abs(a.x - b.x) + abs(a.y - b.y))
+
+#define LOGISTIC_FUNCTION(L,k,x,x_0) (L/(1+(NUM_E**(-k*(x-x_0)))))
+
+/// Make sure something is a boolean TRUE/FALSE 1/0 value, since things like bitfield & bitflag doesn't always give 1s and 0s.
+#define FORCE_BOOLEAN(x) ((x)? TRUE : FALSE)
+
+#define TILES_TO_PIXELS(tiles) (tiles * PIXELS)
diff --git a/code/__DEFINES/procpath.dm b/code/__DEFINES/procpath.dm
new file mode 100644
index 00000000..642ca3ea
--- /dev/null
+++ b/code/__DEFINES/procpath.dm
@@ -0,0 +1,26 @@
+/// Represents a proc or verb path.
+///
+/// Despite having no DM-defined static type, proc paths have some variables,
+/// listed below. These are not modifiable, but for a given procpath P,
+/// `new P(null, "Name", "Desc")` can be used to create a new procpath with the
+/// same code but new `name` and `desc` values. The other variables cannot be
+/// changed in this way.
+///
+/// This type exists only to act as an annotation, providing reasonable static
+/// typing for procpaths. Previously, types like `/atom/verb` were used, with
+/// the `name` and `desc` vars of `/atom` thus being accessible. Proc and verb
+/// paths will fail `istype` and `ispath` checks against `/procpath`.
+/procpath
+ // Although these variables are effectively const, if they are marked const
+ // below, their accesses are optimized away.
+
+ /// A text string of the verb's name.
+ var/name as text
+ /// The verb's help text or description.
+ var/desc as text
+ /// The category or tab the verb will appear in.
+ var/category as text
+ /// Only clients/mobs with `see_invisibility` higher can use the verb.
+ var/invisibility as num
+ /// Whether or not the verb appears in statpanel and commandbar when you press space
+ var/hidden as num
diff --git a/code/__DEFINES/spaceman_dmm.dm b/code/__DEFINES/spaceman_dmm.dm
index b9c0544b..10d586dc 100644
--- a/code/__DEFINES/spaceman_dmm.dm
+++ b/code/__DEFINES/spaceman_dmm.dm
@@ -6,10 +6,14 @@
#define RETURN_TYPE(X) set SpacemanDMM_return_type = X
#define SHOULD_CALL_PARENT(X) set SpacemanDMM_should_call_parent = X
#define UNLINT(X) SpacemanDMM_unlint(X)
+ #define SHOULD_NOT_OVERRIDE(X) set SpacemanDMM_should_not_override = X
+ #define SHOULD_NOT_SLEEP(X) set SpacemanDMM_should_not_sleep = X
#else
#define RETURN_TYPE(X)
#define SHOULD_CALL_PARENT(X)
#define UNLINT(X) X
+ #define SHOULD_NOT_OVERRIDE(X)
+ #define SHOULD_NOT_SLEEP(X)
#endif
/world/proc/enable_debugger()
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index f4e0c316..f2ef5638 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -84,6 +84,7 @@
#define INIT_ORDER_MINOR_MAPPING -40
#define INIT_ORDER_PATH -50
#define INIT_ORDER_PERSISTENCE -95
+#define INIT_ORDER_STATPANELS -98
#define INIT_ORDER_CHAT -100 //Should be last to ensure chat remains smooth during init.
// Subsystem fire priority, from lowest to highest priority
diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm
index 05c93878..ec1abadd 100644
--- a/code/__HELPERS/roundend.dm
+++ b/code/__HELPERS/roundend.dm
@@ -337,7 +337,7 @@
if(!previous)
var/list/report_parts = list(personal_report(C), GLOB.common_report)
content = report_parts.Join()
- C.verbs -= /client/proc/show_previous_roundend_report
+ remove_verb(C, /client/proc/show_previous_roundend_report)
fdel(filename)
text2file(content, filename)
else
diff --git a/code/__HELPERS/verbs.dm b/code/__HELPERS/verbs.dm
new file mode 100644
index 00000000..60dcaeda
--- /dev/null
+++ b/code/__HELPERS/verbs.dm
@@ -0,0 +1,96 @@
+/**
+ * handles adding verbs and updating the stat panel browser
+ *
+ * pass the verb type path to this instead of adding it directly to verbs so the statpanel can update
+ * Arguments:
+ * * target - Who the verb is being added to, client or mob typepath
+ * * verb - typepath to a verb, or a list of verbs, supports lists of lists
+ */
+/proc/add_verb(client/target, verb_or_list_to_add)
+ if(!target)
+ CRASH("add_verb called without a target")
+ if(IsAdminAdvancedProcCall())
+ return
+ var/mob/mob_target = null
+
+ if(ismob(target))
+ mob_target = target
+ target = mob_target.client
+ else if(!istype(target, /client))
+ CRASH("add_verb called on a non-mob and non-client")
+ var/list/verbs_list = list()
+ if(!islist(verb_or_list_to_add))
+ verbs_list += verb_or_list_to_add
+ else
+ var/list/verb_listref = verb_or_list_to_add
+ var/list/elements_to_process = verb_listref.Copy()
+ while(length(elements_to_process))
+ var/element_or_list = elements_to_process[length(elements_to_process)] //Last element
+ elements_to_process.len--
+ if(islist(element_or_list))
+ elements_to_process += element_or_list //list/a += list/b adds the contents of b into a, not the reference to the list itself
+ else
+ verbs_list += element_or_list
+
+ if(mob_target)
+ mob_target.verbs += verbs_list
+ if(!target)
+ return //Our work is done.
+ else
+ target.verbs += verbs_list
+
+ var/list/output_list = list()
+ for(var/thing in verbs_list)
+ var/procpath/verb_to_add = thing
+ output_list[++output_list.len] = list(verb_to_add.category, verb_to_add.name)
+ output_list = url_encode(json_encode(output_list))
+
+ target << output("[output_list];", "statbrowser:add_verb_list")
+
+/**
+ * handles removing verb and sending it to browser to update, use this for removing verbs
+ *
+ * pass the verb type path to this instead of removing it from verbs so the statpanel can update
+ * Arguments:
+ * * target - Who the verb is being removed from, client or mob typepath
+ * * verb - typepath to a verb, or a list of verbs, supports lists of lists
+ */
+/proc/remove_verb(client/target, verb_or_list_to_remove)
+ if(IsAdminAdvancedProcCall())
+ return
+
+ var/mob/mob_target = null
+ if(ismob(target))
+ mob_target = target
+ target = mob_target.client
+ else if(!istype(target, /client))
+ CRASH("remove_verb called on a non-mob and non-client")
+
+ var/list/verbs_list = list()
+ if(!islist(verb_or_list_to_remove))
+ verbs_list += verb_or_list_to_remove
+ else
+ var/list/verb_listref = verb_or_list_to_remove
+ var/list/elements_to_process = verb_listref.Copy()
+ while(length(elements_to_process))
+ var/element_or_list = elements_to_process[length(elements_to_process)] //Last element
+ elements_to_process.len--
+ if(islist(element_or_list))
+ elements_to_process += element_or_list //list/a += list/b adds the contents of b into a, not the reference to the list itself
+ else
+ verbs_list += element_or_list
+
+ if(mob_target)
+ mob_target.verbs -= verbs_list
+ if(!target)
+ return //Our work is done.
+ else
+ target.verbs -= verbs_list
+
+ var/list/output_list = list()
+ for(var/thing in verbs_list)
+ var/procpath/verb_to_remove = thing
+ output_list[++output_list.len] = list(verb_to_remove.category, verb_to_remove.name)
+ output_list = url_encode(json_encode(output_list))
+
+ target << output("[output_list];", "statbrowser:remove_verb_list")
\ No newline at end of file
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 46ae8e39..c04a98a4 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -75,6 +75,9 @@
if(notransform)
return
+ if(SEND_SIGNAL(src, COMSIG_MOB_CLICKON, A, params) & COMSIG_MOB_CANCEL_CLICKON)
+ return
+
var/list/modifiers = params2list(params)
if(modifiers["shift"] && modifiers["middle"])
ShiftMiddleClickOn(A)
@@ -351,8 +354,10 @@
Unused except for AI
*/
/mob/proc/AltClickOn(atom/A)
- if(!A.AltClick(src))
- altclick_listed_turf(A)
+ . = SEND_SIGNAL(src, COMSIG_MOB_ALTCLICKON, A)
+ if(. & COMSIG_MOB_CANCEL_CLICKON)
+ return
+ A.AltClick(src)
/mob/proc/altclick_listed_turf(atom/A)
var/turf/T = get_turf(A)
@@ -361,7 +366,9 @@
listed_turf = null
else if(TurfAdjacent(T))
listed_turf = T
- client.statpanel = T.name
+ client << output("[url_encode(json_encode(T.name))];", "statbrowser:create_listedturf")
+
+
/mob/living/carbon/AltClickOn(atom/A)
if(!stat && mind && iscarbon(A) && A != src)
@@ -373,7 +380,18 @@
..()
/atom/proc/AltClick(mob/user)
- . = SEND_SIGNAL(src, COMSIG_CLICK_ALT, user)
+ SEND_SIGNAL(src, COMSIG_CLICK_ALT, user)
+ var/turf/T = get_turf(src)
+ if(T && (isturf(loc) || isturf(src)) && user.TurfAdjacent(T))
+ user.listed_turf = T
+ user.client << output("[url_encode(json_encode(T.name))];", "statbrowser:create_listedturf")
+
+/atom/proc/AltClickNoInteract(mob/user, atom/A)
+ var/turf/T = get_turf(A)
+ if(T && user.TurfAdjacent(T))
+ user.listed_turf = T
+ user.client << output("[url_encode(json_encode(T.name))];", "statbrowser:create_listedturf")
+
/mob/proc/TurfAdjacent(turf/T)
return T.Adjacent(src)
diff --git a/code/_onclick/hud/credits.dm b/code/_onclick/hud/credits.dm
index 2cd0dded..31ea453d 100644
--- a/code/_onclick/hud/credits.dm
+++ b/code/_onclick/hud/credits.dm
@@ -11,7 +11,7 @@
var/icon/credits_icon = new(CREDITS_PATH)
LAZYINITLIST(credits)
var/list/_credits = credits
- verbs += /client/proc/ClearCredits
+ add_verb(src, /client/proc/ClearCredits)
var/static/list/credit_order_for_this_round
if(isnull(credit_order_for_this_round))
credit_order_for_this_round = list("Thanks for playing!") + (shuffle(icon_states(credits_icon)) - "Thanks for playing!")
@@ -21,13 +21,13 @@
_credits += new /obj/screen/credit(null, I, src, credits_icon)
sleep(CREDIT_SPAWN_SPEED)
sleep(CREDIT_ROLL_SPEED - CREDIT_SPAWN_SPEED)
- verbs -= /client/proc/ClearCredits
+ remove_verb(src, /client/proc/ClearCredits)
qdel(credits_icon)
/client/proc/ClearCredits()
set name = "Hide Credits"
set category = "OOC"
- verbs -= /client/proc/ClearCredits
+ remove_verb(src, /client/proc/ClearCredits)
QDEL_LIST(credits)
credits = null
diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm
index 5a3cca96..ba69f4b6 100644
--- a/code/controllers/configuration/configuration.dm
+++ b/code/controllers/configuration/configuration.dm
@@ -178,10 +178,10 @@
var/list/banned_edits = list(NAMEOF(src, entries_by_type), NAMEOF(src, entries), NAMEOF(src, directory))
return !(var_name in banned_edits) && ..()
-/datum/controller/configuration/stat_entry()
- if(!statclick)
- statclick = new/obj/effect/statclick/debug(null, "Edit", src)
- stat("[name]:", statclick)
+
+/datum/controller/configuration/stat_entry(msg)
+ msg = "Edit"
+ return msg
/datum/controller/configuration/proc/Get(entry_type)
var/datum/config_entry/E = entry_type
diff --git a/code/controllers/controller.dm b/code/controllers/controller.dm
index 06547d12..90f0976f 100644
--- a/code/controllers/controller.dm
+++ b/code/controllers/controller.dm
@@ -16,4 +16,4 @@
/datum/controller/proc/Recover()
-/datum/controller/proc/stat_entry()
\ No newline at end of file
+/datum/controller/proc/stat_entry(msg)
\ No newline at end of file
diff --git a/code/controllers/failsafe.dm b/code/controllers/failsafe.dm
index 3ce770b6..a260ed4e 100644
--- a/code/controllers/failsafe.dm
+++ b/code/controllers/failsafe.dm
@@ -95,8 +95,6 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe)
/datum/controller/failsafe/proc/defcon_pretty()
return defcon
-/datum/controller/failsafe/stat_entry()
- if(!statclick)
- statclick = new/obj/effect/statclick/debug(null, "Initializing...", src)
-
- stat("Failsafe Controller:", statclick.update("Defcon: [defcon_pretty()] (Interval: [Failsafe.processing_interval] | Iteration: [Failsafe.master_iteration])"))
+/datum/controller/failsafe/stat_entry(msg)
+ msg = "Defcon: [defcon_pretty()] (Interval: [Failsafe.processing_interval] | Iteration: [Failsafe.master_iteration])"
+ return msg
\ No newline at end of file
diff --git a/code/controllers/globals.dm b/code/controllers/globals.dm
index a085b264..6b5fb294 100644
--- a/code/controllers/globals.dm
+++ b/code/controllers/globals.dm
@@ -24,11 +24,9 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
//fuck off kevinz
return QDEL_HINT_IWILLGC
-/datum/controller/global_vars/stat_entry()
- if(!statclick)
- statclick = new/obj/effect/statclick/debug(null, "Initializing...", src)
-
- stat("Globals:", statclick.update("Edit"))
+/datum/controller/global_vars/stat_entry(msg)
+ msg = "Edit"
+ return msg
/datum/controller/global_vars/vv_edit_var(var_name, var_value)
if(gvars_datum_protected_varlist[var_name])
diff --git a/code/controllers/master.dm b/code/controllers/master.dm
index 125da84a..76a3b1eb 100644
--- a/code/controllers/master.dm
+++ b/code/controllers/master.dm
@@ -54,7 +54,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
var/static/restart_clear = 0
var/static/restart_timeout = 0
var/static/restart_count = 0
-
+
var/static/random_seed
//current tick limit, assigned before running a subsystem.
@@ -69,7 +69,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
if(!random_seed)
random_seed = (TEST_RUN_PARAMETER in world.params) ? 29051994 : rand(1, 1e9)
rand_seed(random_seed)
-
+
var/list/_subsystems = list()
subsystems = _subsystems
if (Master != src)
@@ -584,12 +584,9 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
-/datum/controller/master/stat_entry()
- if(!statclick)
- statclick = new/obj/effect/statclick/debug(null, "Initializing...", src)
-
- stat("Byond:", "(FPS:[world.fps]) (TickCount:[world.time/world.tick_lag]) (TickDrift:[round(Master.tickdrift,1)]([round((Master.tickdrift/(world.time/world.tick_lag))*100,0.1)]%))")
- stat("Master Controller:", statclick.update("(TickRate:[Master.processing]) (Iteration:[Master.iteration])"))
+/datum/controller/master/stat_entry(msg)
+ msg = "(TickRate:[Master.processing]) (Iteration:[Master.iteration]) (TickLimit: [round(Master.current_ticklimit, 0.1)])"
+ return msg
/datum/controller/master/StartLoadingMap()
//disallow more than one map to load at once, multithreading it will just cause race conditions
diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm
index 4fe0812c..d9d818ac 100644
--- a/code/controllers/subsystem.dm
+++ b/code/controllers/subsystem.dm
@@ -165,10 +165,9 @@
log_world(msg)
return time
-//hook for printing stats to the "MC" statuspanel for admins to see performance and related stats etc.
+
/datum/controller/subsystem/stat_entry(msg)
- if(!statclick)
- statclick = new/obj/effect/statclick/debug(null, "Initializing...", src)
+
@@ -177,11 +176,7 @@
else
msg = "OFFLINE\t[msg]"
- var/title = name
- if (can_fire)
- title = "\[[state_letter()]][title]"
-
- stat(title, statclick.update(msg))
+ return msg
/datum/controller/subsystem/proc/state_letter()
switch (state)
diff --git a/code/controllers/subsystem/acid.dm b/code/controllers/subsystem/acid.dm
index e3c41596..21fb4349 100644
--- a/code/controllers/subsystem/acid.dm
+++ b/code/controllers/subsystem/acid.dm
@@ -7,9 +7,9 @@ SUBSYSTEM_DEF(acid)
var/list/currentrun = list()
var/list/processing = list()
-/datum/controller/subsystem/acid/stat_entry()
- ..("P:[processing.len]")
-
+/datum/controller/subsystem/acid/stat_entry(msg)
+ msg = "P:[length(processing)]"
+ return ..()
/datum/controller/subsystem/acid/fire(resumed = 0)
if (!resumed)
diff --git a/code/controllers/subsystem/adjacent_air.dm b/code/controllers/subsystem/adjacent_air.dm
index 8395eda7..ccbf8ffc 100644
--- a/code/controllers/subsystem/adjacent_air.dm
+++ b/code/controllers/subsystem/adjacent_air.dm
@@ -6,12 +6,13 @@ SUBSYSTEM_DEF(adjacent_air)
priority = FIRE_PRIORITY_ATMOS_ADJACENCY
var/list/queue = list()
-/datum/controller/subsystem/adjacent_air/stat_entry()
+/datum/controller/subsystem/adjacent_air/stat_entry(msg)
#ifdef TESTING
- ..("P:[length(queue)], S:[GLOB.atmos_adjacent_savings[1]], T:[GLOB.atmos_adjacent_savings[2]]")
+ msg = "P:[length(queue)], S:[GLOB.atmos_adjacent_savings[1]], T:[GLOB.atmos_adjacent_savings[2]]"
#else
- ..("P:[length(queue)]")
+ msg = "P:[length(queue)]"
#endif
+ return ..()
/datum/controller/subsystem/adjacent_air/Initialize()
while(length(queue))
diff --git a/code/controllers/subsystem/augury.dm b/code/controllers/subsystem/augury.dm
index 1b1c7bc3..53c86004 100644
--- a/code/controllers/subsystem/augury.dm
+++ b/code/controllers/subsystem/augury.dm
@@ -9,7 +9,8 @@ SUBSYSTEM_DEF(augury)
var/list/observers_given_action = list()
/datum/controller/subsystem/augury/stat_entry(msg)
- ..("W:[watchers.len]|D:[doombringers.len]")
+ msg = "W:[watchers.len]|D:[length(doombringers)]"
+ return ..()
/datum/controller/subsystem/augury/proc/register_doom(atom/A, severity)
doombringers[A] = severity
diff --git a/code/controllers/subsystem/disease.dm b/code/controllers/subsystem/disease.dm
index 9be1d8d9..4fe5533e 100644
--- a/code/controllers/subsystem/disease.dm
+++ b/code/controllers/subsystem/disease.dm
@@ -20,7 +20,8 @@ SUBSYSTEM_DEF(disease)
return ..()
/datum/controller/subsystem/disease/stat_entry(msg)
- ..("P:[active_diseases.len]")
+ msg = "P:[length(active_diseases)]"
+ return ..()
/datum/controller/subsystem/disease/proc/get_disease_name(id)
var/datum/disease/advance/A = archive_diseases[id]
diff --git a/code/controllers/subsystem/fire_burning.dm b/code/controllers/subsystem/fire_burning.dm
index db6dc651..6ac42f8c 100644
--- a/code/controllers/subsystem/fire_burning.dm
+++ b/code/controllers/subsystem/fire_burning.dm
@@ -7,9 +7,9 @@ SUBSYSTEM_DEF(fire_burning)
var/list/currentrun = list()
var/list/processing = list()
-/datum/controller/subsystem/fire_burning/stat_entry()
- ..("P:[processing.len]")
-
+/datum/controller/subsystem/fire_burning/stat_entry(msg)
+ msg = "P:[length(processing)]"
+ return ..()
/datum/controller/subsystem/fire_burning/fire(resumed = 0)
if (!resumed)
diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm
index f8ca1e7e..328818fd 100644
--- a/code/controllers/subsystem/garbage.dm
+++ b/code/controllers/subsystem/garbage.dm
@@ -57,7 +57,7 @@ SUBSYSTEM_DEF(garbage)
msg += "TGR:[round((totalgcs/(totaldels+totalgcs))*100, 0.01)]%"
msg += " P:[pass_counts.Join(",")]"
msg += "|F:[fail_counts.Join(",")]"
- ..(msg)
+ return ..()
/datum/controller/subsystem/garbage/Shutdown()
//Adds the del() log to the qdel log file
diff --git a/code/controllers/subsystem/idlenpcpool.dm b/code/controllers/subsystem/idlenpcpool.dm
index 8992fa7b..03b7931d 100644
--- a/code/controllers/subsystem/idlenpcpool.dm
+++ b/code/controllers/subsystem/idlenpcpool.dm
@@ -8,10 +8,11 @@ SUBSYSTEM_DEF(idlenpcpool)
var/list/currentrun = list()
var/static/list/idle_mobs_by_zlevel[][]
-/datum/controller/subsystem/idlenpcpool/stat_entry()
+/datum/controller/subsystem/idlenpcpool/stat_entry(msg)
var/list/idlelist = GLOB.simple_animals[AI_IDLE]
var/list/zlist = GLOB.simple_animals[AI_Z_OFF]
- ..("IdleNPCS:[idlelist.len]|Z:[zlist.len]")
+ msg = "IdleNPCS:[length(idlelist)]|Z:[length(zlist)]"
+ return ..()
/datum/controller/subsystem/idlenpcpool/proc/MaxZChanged()
if (!islist(idle_mobs_by_zlevel))
diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm
index 9048d77b..3d525e05 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -395,7 +395,7 @@ SUBSYSTEM_DEF(job)
if(!joined_late)
var/obj/S = null
for(var/obj/effect/landmark/start/sloc in GLOB.start_landmarks_list)
- if(sloc.name != rank)
+ if(sloc.name != rank && sloc.type != job.override_roundstart_spawn)
S = sloc //so we can revert to spawning them on top of eachother if something goes wrong
continue
if(locate(/mob/living) in sloc.loc)
diff --git a/code/controllers/subsystem/lighting.dm b/code/controllers/subsystem/lighting.dm
index 12b467b6..7eff66eb 100644
--- a/code/controllers/subsystem/lighting.dm
+++ b/code/controllers/subsystem/lighting.dm
@@ -7,10 +7,13 @@ SUBSYSTEM_DEF(lighting)
wait = 2
init_order = INIT_ORDER_LIGHTING
flags = SS_TICKER
+ var/static/list/sources_queue = list() // List of lighting sources queued for update.
+ var/static/list/corners_queue = list() // List of lighting corners queued for update.
+ var/static/list/objects_queue = list() // List of lighting objects queued for update.
-/datum/controller/subsystem/lighting/stat_entry()
- ..("L:[GLOB.lighting_update_lights.len]|C:[GLOB.lighting_update_corners.len]|O:[GLOB.lighting_update_objects.len]")
-
+/datum/controller/subsystem/lighting/stat_entry(msg)
+ msg = "L:[length(sources_queue)]|C:[length(corners_queue)]|O:[length(objects_queue)]"
+ return ..()
/datum/controller/subsystem/lighting/Initialize(timeofday)
if(!initialized)
diff --git a/code/controllers/subsystem/machines.dm b/code/controllers/subsystem/machines.dm
index c4b09d1b..04b65410 100644
--- a/code/controllers/subsystem/machines.dm
+++ b/code/controllers/subsystem/machines.dm
@@ -22,9 +22,10 @@ SUBSYSTEM_DEF(machines)
NewPN.add_cable(PC)
propagate_network(PC,PC.powernet)
-/datum/controller/subsystem/machines/stat_entry()
- ..("M:[processing.len]|PN:[powernets.len]")
+/datum/controller/subsystem/machines/stat_entry(msg)
+ msg = "M:[length(processing)]|PN:[length(powernets)]"
+ return ..()
/datum/controller/subsystem/machines/fire(resumed = 0)
if (!resumed)
diff --git a/code/controllers/subsystem/mobs.dm b/code/controllers/subsystem/mobs.dm
index aac9f9d3..1e8efff0 100644
--- a/code/controllers/subsystem/mobs.dm
+++ b/code/controllers/subsystem/mobs.dm
@@ -10,8 +10,9 @@ SUBSYSTEM_DEF(mobs)
var/static/list/cubemonkeys = list()
var/static/list/cheeserats = list()
-/datum/controller/subsystem/mobs/stat_entry()
- ..("P:[GLOB.mob_living_list.len]")
+/datum/controller/subsystem/mobs/stat_entry(msg)
+ msg = "P:[length(GLOB.mob_living_list)]"
+ return ..()
/datum/controller/subsystem/mobs/proc/MaxZChanged()
if (!islist(clients_by_zlevel))
diff --git a/code/controllers/subsystem/npcpool.dm b/code/controllers/subsystem/npcpool.dm
index 7fd35124..5e8fc1f5 100644
--- a/code/controllers/subsystem/npcpool.dm
+++ b/code/controllers/subsystem/npcpool.dm
@@ -6,9 +6,10 @@ SUBSYSTEM_DEF(npcpool)
var/list/currentrun = list()
-/datum/controller/subsystem/npcpool/stat_entry()
+/datum/controller/subsystem/npcpool/stat_entry(msg)
var/list/activelist = GLOB.simple_animals[AI_ON]
- ..("NPCS:[activelist.len]")
+ msg = "NPCS:[length(activelist)]"
+ return ..()
/datum/controller/subsystem/npcpool/fire(resumed = FALSE)
diff --git a/code/controllers/subsystem/overlays.dm b/code/controllers/subsystem/overlays.dm
index 20eb2af0..f8f7a16b 100644
--- a/code/controllers/subsystem/overlays.dm
+++ b/code/controllers/subsystem/overlays.dm
@@ -21,10 +21,9 @@ SUBSYSTEM_DEF(overlays)
fire(mc_check = FALSE)
return ..()
-
-/datum/controller/subsystem/overlays/stat_entry()
- ..("Ov:[length(queue)]")
-
+/datum/controller/subsystem/overlays/stat_entry(msg)
+ msg = "Ov:[length(queue)]"
+ return ..()
/datum/controller/subsystem/overlays/Shutdown()
text2file(render_stats(stats), "[GLOB.log_directory]/overlay.log")
diff --git a/code/controllers/subsystem/processing/processing.dm b/code/controllers/subsystem/processing/processing.dm
index c5d6dfa1..637b0499 100644
--- a/code/controllers/subsystem/processing/processing.dm
+++ b/code/controllers/subsystem/processing/processing.dm
@@ -10,8 +10,9 @@ SUBSYSTEM_DEF(processing)
var/list/processing = list()
var/list/currentrun = list()
-/datum/controller/subsystem/processing/stat_entry()
- ..("[stat_tag]:[processing.len]")
+/datum/controller/subsystem/processing/stat_entry(msg)
+ msg = "[stat_tag]:[length(processing)]"
+ return ..()
/datum/controller/subsystem/processing/fire(resumed = 0)
if (!resumed)
diff --git a/code/controllers/subsystem/spacedrift.dm b/code/controllers/subsystem/spacedrift.dm
index f23f41b7..b6cec58b 100644
--- a/code/controllers/subsystem/spacedrift.dm
+++ b/code/controllers/subsystem/spacedrift.dm
@@ -8,9 +8,9 @@ SUBSYSTEM_DEF(spacedrift)
var/list/currentrun = list()
var/list/processing = list()
-/datum/controller/subsystem/spacedrift/stat_entry()
- ..("P:[processing.len]")
-
+/datum/controller/subsystem/spacedrift/stat_entry(msg)
+ msg = "P:[length(processing)]"
+ return ..()
/datum/controller/subsystem/spacedrift/fire(resumed = 0)
if (!resumed)
diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm
new file mode 100644
index 00000000..b6fa8c53
--- /dev/null
+++ b/code/controllers/subsystem/statpanel.dm
@@ -0,0 +1,118 @@
+SUBSYSTEM_DEF(statpanels)
+ name = "Stat Panels"
+ wait = 4
+ init_order = INIT_ORDER_STATPANELS
+ runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
+ var/list/currentrun = list()
+ var/encoded_global_data
+ var/mc_data_encoded
+ var/list/cached_images = list()
+
+/datum/controller/subsystem/statpanels/fire(resumed = FALSE)
+ if (!resumed)
+ var/datum/map_config/cached = SSmapping.next_map_config
+ var/round_time = world.time - SSticker.round_start_time
+ var/list/global_data = list(
+ "Map: [SSmapping.config?.map_name || "Loading..."]",
+ cached ? "Next Map: [cached.map_name]" : null,
+ "Round ID: [GLOB.round_id ? GLOB.round_id : "NULL"]",
+ "Server Time: [time2text(world.timeofday, "YYYY-MM-DD hh:mm:ss")]",
+ "Round Time: [round_time > MIDNIGHT_ROLLOVER ? "[round(round_time/MIDNIGHT_ROLLOVER)]:[worldtime2text()]" : worldtime2text()]",
+ "Station Time: [station_time_timestamp()]",
+ "Time Dilation: [round(SStime_track.time_dilation_current,1)]% AVG:([round(SStime_track.time_dilation_avg_fast,1)]%, [round(SStime_track.time_dilation_avg,1)]%, [round(SStime_track.time_dilation_avg_slow,1)]%)"
+ )
+
+ if(SSshuttle.emergency)
+ var/ETA = SSshuttle.emergency.getModeStr()
+ if(ETA)
+ global_data += "[ETA] [SSshuttle.emergency.getTimerStr()]"
+ encoded_global_data = url_encode(json_encode(global_data))
+
+ var/list/mc_data = list(
+ list("CPU:", world.cpu),
+ list("Instances:", "[num2text(world.contents.len, 10)]"),
+ list("World Time:", "[world.time]"),
+ list("Globals:", GLOB.stat_entry(), "\ref[GLOB]"),
+ list("[config]:", config.stat_entry(), "\ref[config]"),
+ list("Byond:", "(FPS:[world.fps]) (TickCount:[world.time/world.tick_lag]) (TickDrift:[round(Master.tickdrift,1)]([round((Master.tickdrift/(world.time/world.tick_lag))*100,0.1)]%))"),
+ list("Master Controller:", Master.stat_entry(), "\ref[Master]"),
+ list("Failsafe Controller:", Failsafe.stat_entry(), "\ref[Failsafe]"),
+ list("","")
+ )
+ for(var/ss in Master.subsystems)
+ var/datum/controller/subsystem/sub_system = ss
+ mc_data[++mc_data.len] = list("\[[sub_system.state_letter()]][sub_system.name]", sub_system.stat_entry(), "\ref[sub_system]")
+ mc_data[++mc_data.len] = list("Camera Net", "Cameras: [GLOB.cameranet.cameras.len] | Chunks: [GLOB.cameranet.chunks.len]", "\ref[GLOB.cameranet]")
+ mc_data_encoded = url_encode(json_encode(mc_data))
+ src.currentrun = GLOB.clients.Copy()
+
+ var/list/currentrun = src.currentrun
+ while(length(currentrun))
+ var/client/target = currentrun[length(currentrun)]
+ currentrun.len--
+ var/ping_str = url_encode("Ping: [round(target.lastping, 1)]ms (Average: [round(target.avgping, 1)]ms)")
+ var/other_str = url_encode(json_encode(target.mob.get_status_tab_items()))
+ target << output("[encoded_global_data];[ping_str];[other_str]", "statbrowser:update")
+ if(!target.holder)
+ target << output("", "statbrowser:remove_admin_tabs")
+ else
+ var/turf/eye_turf = get_turf(target.eye)
+ var/coord_entry = url_encode(COORD(eye_turf))
+ target << output("[mc_data_encoded];[coord_entry];[url_encode(target.holder.href_token)]", "statbrowser:update_mc")
+ var/list/ahelp_tickets = GLOB.ahelp_tickets.stat_entry()
+ target << output("[url_encode(json_encode(ahelp_tickets))];", "statbrowser:update_tickets")
+ if(!length(GLOB.sdql2_queries))
+ target << output("", "statbrowser:remove_sqdl2")
+ else
+ var/list/sqdl2A = list()
+ sqdl2A[++sqdl2A.len] = list("", "Access Global SDQL2 List", REF(GLOB.sdql2_vv_statobj))
+ var/list/sqdl2B = list()
+ sqdl2A += sqdl2B
+ target << output(url_encode(json_encode(sqdl2A)), "statbrowser:update_sqdl2")
+ var/list/proc_holders = target.mob.get_proc_holders()
+ target.spell_tabs.Cut()
+ for(var/phl in proc_holders)
+ var/list/proc_holder_list = phl
+ target.spell_tabs |= proc_holder_list[1]
+ var/proc_holders_encoded = ""
+ if(length(proc_holders))
+ proc_holders_encoded = url_encode(json_encode(proc_holders))
+ target << output("[url_encode(json_encode(target.spell_tabs))];[proc_holders_encoded]", "statbrowser:update_spells")
+ if(target.mob?.listed_turf)
+ var/mob/target_mob = target.mob
+ if(!target_mob.TurfAdjacent(target_mob.listed_turf))
+ target << output("", "statbrowser:remove_listedturf")
+ target_mob.listed_turf = null
+ else
+ var/list/overrides = list()
+ var/list/turfitems = list()
+ for(var/img in target.images)
+ var/image/target_image = img
+ if(!target_image.loc || target_image.loc.loc != target_mob.listed_turf || !target_image.override)
+ continue
+ overrides += target_image.loc
+ if(!(REF(target_mob.listed_turf) in cached_images))
+ target << browse_rsc(getFlatIcon(target_mob.listed_turf, no_anim = TRUE), "[REF(target_mob.listed_turf)].png")
+ cached_images += REF(target_mob.listed_turf)
+ turfitems[++turfitems.len] = list("[target_mob.listed_turf]", REF(target_mob.listed_turf), "[REF(target_mob.listed_turf)].png")
+ for(var/tc in target_mob.listed_turf)
+ var/atom/movable/turf_content = tc
+ if(turf_content.mouse_opacity == MOUSE_OPACITY_TRANSPARENT)
+ continue
+ if(turf_content.invisibility > target_mob.see_invisible)
+ continue
+ if(turf_content in overrides)
+ continue
+ if(turf_content.IsObscured())
+ continue
+ if(length(turfitems) < 30) // only create images for the first 30 items on the turf, for performance reasons
+ if(!(REF(turf_content) in cached_images))
+ target << browse_rsc(getFlatIcon(turf_content, no_anim = TRUE), "[REF(turf_content)].png")
+ cached_images += REF(turf_content)
+ turfitems[++turfitems.len] = list("[turf_content.name]", REF(turf_content), "[REF(turf_content)].png")
+ else
+ turfitems[++turfitems.len] = list("[turf_content.name]", REF(turf_content))
+ turfitems = url_encode(json_encode(turfitems))
+ target << output("[turfitems];", "statbrowser:update_listedturf")
+ if(MC_TICK_CHECK)
+ return
\ No newline at end of file
diff --git a/code/controllers/subsystem/tgui.dm b/code/controllers/subsystem/tgui.dm
index dacbac40..9fc689ff 100644
--- a/code/controllers/subsystem/tgui.dm
+++ b/code/controllers/subsystem/tgui.dm
@@ -16,8 +16,9 @@ SUBSYSTEM_DEF(tgui)
/datum/controller/subsystem/tgui/Shutdown()
close_all_uis()
-/datum/controller/subsystem/tgui/stat_entry()
- ..("P:[processing_uis.len]")
+/datum/controller/subsystem/tgui/stat_entry(msg)
+ msg = "P:[length(open_uis)]"
+ return ..()
/datum/controller/subsystem/tgui/fire(resumed = 0)
if (!resumed)
diff --git a/code/controllers/subsystem/throwing.dm b/code/controllers/subsystem/throwing.dm
index 908b8944..b491cc3c 100644
--- a/code/controllers/subsystem/throwing.dm
+++ b/code/controllers/subsystem/throwing.dm
@@ -11,9 +11,9 @@ SUBSYSTEM_DEF(throwing)
var/list/currentrun
var/list/processing = list()
-/datum/controller/subsystem/throwing/stat_entry()
- ..("P:[processing.len]")
-
+/datum/controller/subsystem/throwing/stat_entry(msg)
+ msg = "P:[length(processing)]"
+ return ..()
/datum/controller/subsystem/throwing/fire(resumed = 0)
if (!resumed)
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index 810882ff..0f4b34f4 100644
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -402,6 +402,7 @@ SUBSYSTEM_DEF(ticker)
if(living.client)
var/obj/screen/splash/S = new(living.client, TRUE)
S.Fade(TRUE)
+ living.client.init_verbs()
livings += living
if(livings.len)
addtimer(CALLBACK(src, .proc/release_characters, livings), 30, TIMER_CLIENT_TIME)
@@ -677,7 +678,7 @@ SUBSYSTEM_DEF(ticker)
if(!round_end_sound)
round_end_sound = pick(\
'sound/roundend/iwishtherewassomethingmore.ogg',
- 'sound/roundend/likeisaid.ogg',
+ 'sound/roundend/likeisaid.ogg',
'sound/roundend/whatarottenwaytodie.ogg',
'sound/roundend/whatashame.ogg',
'sound/roundend/newroundsexy.ogg',
diff --git a/code/controllers/subsystem/timer.dm b/code/controllers/subsystem/timer.dm
index d0eb0b9c..90ee4b48 100644
--- a/code/controllers/subsystem/timer.dm
+++ b/code/controllers/subsystem/timer.dm
@@ -34,7 +34,8 @@ SUBSYSTEM_DEF(timer)
bucket_resolution = world.tick_lag
/datum/controller/subsystem/timer/stat_entry(msg)
- ..("B:[bucket_count] P:[length(second_queue)] H:[length(hashes)] C:[length(clienttime_timers)] S:[length(timer_id_dict)]")
+ msg = "B:[bucket_count] P:[length(second_queue)] H:[length(hashes)] C:[length(clienttime_timers)] S:[length(timer_id_dict)]"
+ return ..()
/datum/controller/subsystem/timer/fire(resumed = FALSE)
var/lit = last_invoke_tick
diff --git a/code/datums/components/rotation.dm b/code/datums/components/rotation.dm
index c4ed0031..84a56ace 100644
--- a/code/datums/components/rotation.dm
+++ b/code/datums/components/rotation.dm
@@ -12,6 +12,48 @@
var/rotation_flags = NONE
var/default_rotation_direction = ROTATION_CLOCKWISE
+/*
+/proc/add_verb(client/target, verb_or_list_to_add)
+ if(!target)
+ CRASH("add_verb called without a target")
+ if(IsAdminAdvancedProcCall())
+ return
+ var/mob/mob_target = null
+
+ if(ismob(target))
+ mob_target = target
+ target = mob_target.client
+ else if(!istype(target, /client))
+ CRASH("add_verb called on a non-mob and non-client")
+ var/list/verbs_list = list()
+ if(!islist(verb_or_list_to_add))
+ verbs_list += verb_or_list_to_add
+ else
+ var/list/verb_listref = verb_or_list_to_add
+ var/list/elements_to_process = verb_listref.Copy()
+ while(length(elements_to_process))
+ var/element_or_list = elements_to_process[length(elements_to_process)] //Last element
+ elements_to_process.len--
+ if(islist(element_or_list))
+ elements_to_process += element_or_list //list/a += list/b adds the contents of b into a, not the reference to the list itself
+ else
+ verbs_list += element_or_list
+
+ if(mob_target)
+ mob_target.verbs += verbs_list
+ if(!target)
+ return //Our work is done.
+ else
+ target.verbs += verbs_list
+
+ var/list/output_list = list()
+ for(var/thing in verbs_list)
+ var/procpath/verb_to_add = thing
+ //output_list[++output_list.len] = list(verb_to_add.category, verb_to_add.name)
+ output_list = url_encode(json_encode(output_list))
+
+ target << output("[output_list];", "statbrowser:add_verb_list")
+*/
/datum/component/simple_rotation/Initialize(rotation_flags = NONE ,can_user_rotate,can_be_rotated,after_rotation)
if(!ismovableatom(parent))
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 0e4e9319..8712851a 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -128,6 +128,9 @@
transfer_martial_arts(new_character)
if(active || force_key_move)
new_character.key = key //now transfer the key to link the client to our new body
+ if(new_character.client)
+ //LAZYCLEARLIST(new_character.client.recent_examines)
+ new_character.client.init_verbs() // re-initialize character specific verbs
//CIT CHANGE - makes arousal update when transfering bodies
if(isliving(new_character)) //New humans and such are by default enabled arousal. Let's always use the new mind's prefs.
@@ -771,6 +774,7 @@
if(istype(S, spell))
spell_list -= S
qdel(S)
+ current?.client << output(null, "statbrowser:check_spells")
/datum/mind/proc/RemoveAllSpells()
for(var/obj/effect/proc_holder/S in spell_list)
diff --git a/code/datums/ruins/lavaland.dm b/code/datums/ruins/lavaland.dm
index f68e189a..ec69fdb9 100644
--- a/code/datums/ruins/lavaland.dm
+++ b/code/datums/ruins/lavaland.dm
@@ -239,5 +239,5 @@
id = "lunaraltar"
description = "Millenia ago, the humanoids of this strange land used to offer sacrifices here..."
suffix = "lavaland_surface_lunaraltar.dmm"
- allow_duplicates = FALSE
+ allow_duplicates = TRUE
cost = 10
diff --git a/code/datums/wires/robot.dm b/code/datums/wires/robot.dm
index 5e0d0d77..1ab1dd5c 100644
--- a/code/datums/wires/robot.dm
+++ b/code/datums/wires/robot.dm
@@ -38,7 +38,7 @@
new_ai = select_active_ai(R)
R.notify_ai(DISCONNECT)
if(new_ai && (new_ai != R.connected_ai))
- R.connected_ai = new_ai
+ R.set_connected_ai(new_ai)
if(R.shell)
R.undeploy() //If this borg is an AI shell, disconnect the controlling AI and assign ti to a new AI
R.notify_ai(AI_SHELL)
@@ -67,7 +67,7 @@
R.notify_ai(DISCONNECT)
if(R.shell)
R.undeploy()
- R.connected_ai = null
+ R.set_connected_ai(null)
if(WIRE_LAWSYNC) // Cut the law wire, and the borg will no longer receive law updates from its AI. Repair and it will re-sync.
if(mend)
if(!R.emagged)
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index d3c530cb..04314dd7 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -873,3 +873,20 @@ Proc for attack log creation, because really why not
/atom/proc/intercept_zImpact(atom/movable/AM, levels = 1)
. |= SEND_SIGNAL(src, COMSIG_ATOM_INTERCEPT_Z_FALL, AM, levels)
+///Passes Stat Browser Panel clicks to the game and calls client click on an atom
+/atom/Topic(href, list/href_list)
+ . = ..()
+ if(!usr?.client)
+ return
+ var/client/usr_client = usr.client
+ var/list/paramslist = list()
+ if(href_list["statpanel_item_shiftclick"])
+ paramslist["shift"] = "1"
+ if(href_list["statpanel_item_ctrlclick"])
+ paramslist["ctrl"] = "1"
+ if(href_list["statpanel_item_altclick"])
+ paramslist["alt"] = "1"
+ if(href_list["statpanel_item_click"])
+ // first of all make sure we valid
+ var/mouseparams = list2params(paramslist)
+ usr_client.Click(src, loc, null, mouseparams)
\ No newline at end of file
diff --git a/code/game/gamemodes/sandbox/h_sandbox.dm b/code/game/gamemodes/sandbox/h_sandbox.dm
index c5946719..bcdee791 100644
--- a/code/game/gamemodes/sandbox/h_sandbox.dm
+++ b/code/game/gamemodes/sandbox/h_sandbox.dm
@@ -9,7 +9,8 @@ GLOBAL_VAR_INIT(hsboxspawn, TRUE)
sandbox.owner = src.ckey
if(src.client.holder)
sandbox.admin = 1
- verbs += new/mob/proc/sandbox_panel
+ add_verb(src, /mob/proc/sandbox_panel)
+
/mob/proc/sandbox_panel()
set name = "Sandbox Panel"
if(sandbox)
diff --git a/code/game/machinery/aug_manipulator.dm b/code/game/machinery/aug_manipulator.dm
index 72655cde..17dad525 100644
--- a/code/game/machinery/aug_manipulator.dm
+++ b/code/game/machinery/aug_manipulator.dm
@@ -8,7 +8,7 @@
max_integrity = 200
var/obj/item/bodypart/storedpart
var/initial_icon_state
- var/static/list/style_list_icons = list("standard" = 'icons/mob/augmentation/augments.dmi', "engineer" = 'icons/mob/augmentation/augments_engineer.dmi', "security" = 'icons/mob/augmentation/augments_security.dmi', "mining" = 'icons/mob/augmentation/augments_mining.dmi')
+ var/static/list/style_list_icons = list("standard" = 'icons/mob/augmentation/augments.dmi', "engineer" = 'icons/mob/augmentation/augments_engineer.dmi', "security" = 'icons/mob/augmentation/augments_security.dmi', "mining" = 'icons/mob/augmentation/augments_mining.dmi', "bootypeace female" = 'icons/mob/augmentation/augments_lewdf.dmi', "bootypeace male" = 'icons/mob/augmentation/augments_lewdm.dmi', "bootypeace intersex" = 'icons/mob/augmentation/augments_lewds.dmi', "bootypeace bob hair (HEAD ONLY)" = 'icons/mob/augmentation/augments_lewdbobhair.dmi', "bootybimbo ponytail (HEAD ONLY)" = 'icons/mob/augmentation/augments_bimbohair.dmi', "bootybimbo female" = 'icons/mob/augmentation/augments_lewdbimbof.dmi', "bootybimbo male" = 'icons/mob/augmentation/augments_lewdbimbom.dmi', "bootybimbo intersex" = 'icons/mob/augmentation/augments_lewdbimbos.dmi')
/obj/machinery/aug_manipulator/examine(mob/user)
. = ..()
diff --git a/code/game/machinery/transformer.dm b/code/game/machinery/transformer.dm
index 3ff2424d..5c9d5076 100644
--- a/code/game/machinery/transformer.dm
+++ b/code/game/machinery/transformer.dm
@@ -101,7 +101,7 @@
// So he can't jump out the gate right away.
R.SetLockdown()
if(masterAI)
- R.connected_ai = masterAI
+ R.set_connected_ai(masterAI)
R.lawsync()
R.lawupdate = 1
addtimer(CALLBACK(src, .proc/unlock_new_robot, R), 50)
diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm
index bb53f686..1ea8b361 100644
--- a/code/game/objects/items/cigs_lighters.dm
+++ b/code/game/objects/items/cigs_lighters.dm
@@ -50,6 +50,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
attack_verb = list("burnt","singed")
START_PROCESSING(SSobj, src)
update_icon()
+ playsound(src, 'sound/items/match.ogg', 50, 1, -1)
/obj/item/match/proc/matchburnout()
if(lit)
diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm
index a4f286bf..946b3cac 100644
--- a/code/game/objects/items/defib.dm
+++ b/code/game/objects/items/defib.dm
@@ -628,11 +628,12 @@
H.adjustOxyLoss(H.health - HALFWAYCRITDEATH, 0)
else
var/overall_damage = total_brute + total_burn + H.getToxLoss() + H.getOxyLoss()
- var/mobhealth = H.health
- H.adjustOxyLoss((mobhealth - HALFWAYCRITDEATH) * (H.getOxyLoss() / overall_damage), 0)
- H.adjustToxLoss((mobhealth - HALFWAYCRITDEATH) * (H.getToxLoss() / overall_damage), 0)
- H.adjustFireLoss((mobhealth - HALFWAYCRITDEATH) * (total_burn / overall_damage), 0)
- H.adjustBruteLoss((mobhealth - HALFWAYCRITDEATH) * (total_brute / overall_damage), 0)
+ if(overall_damage)
+ var/mobhealth = H.health
+ H.adjustOxyLoss((mobhealth - HALFWAYCRITDEATH) * (H.getOxyLoss() / overall_damage), 0)
+ H.adjustToxLoss((mobhealth - HALFWAYCRITDEATH) * (H.getToxLoss() / overall_damage), 0)
+ H.adjustFireLoss((mobhealth - HALFWAYCRITDEATH) * (total_burn / overall_damage), 0)
+ H.adjustBruteLoss((mobhealth - HALFWAYCRITDEATH) * (total_brute / overall_damage), 0)
H.updatehealth() // Previous "adjust" procs don't update health, so we do it manually.
user.visible_message("[req_defib ? "[defib]" : "[src]"] pings: Resuscitation successful.")
playsound(src, 'sound/machines/defib_success.ogg', 50, 0)
diff --git a/code/game/objects/items/grenades/spawnergrenade.dm b/code/game/objects/items/grenades/spawnergrenade.dm
index bc32b158..466caf93 100644
--- a/code/game/objects/items/grenades/spawnergrenade.dm
+++ b/code/game/objects/items/grenades/spawnergrenade.dm
@@ -47,5 +47,5 @@
name = "clustaur grenade"
icon_state = "clustaur"
item_state = "clustaur"
- deliveryamt = 10
+ deliveryamt = 5
spawner_type = /obj/item/reagent_containers/glass/beaker/waterbottle/wataur
\ No newline at end of file
diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm
index 5b4a4386..811d5f24 100644
--- a/code/game/objects/items/robot/robot_parts.dm
+++ b/code/game/objects/items/robot/robot_parts.dm
@@ -282,11 +282,11 @@
O.locked = panel_locked
if(!aisync)
lawsync = 0
- O.connected_ai = null
+ O.set_connected_ai(null)
else
O.notify_ai(NEW_BORG)
if(forced_ai)
- O.connected_ai = forced_ai
+ O.set_connected_ai(forced_ai)
if(!lawsync)
O.lawupdate = 0
if(M.laws.id == DEFAULT_AI_LAWID)
@@ -338,10 +338,10 @@
if(!aisync)
lawsync = FALSE
- O.connected_ai = null
+ O.set_connected_ai(null)
else
if(forced_ai)
- O.connected_ai = forced_ai
+ O.set_connected_ai(forced_ai)
O.notify_ai(AI_SHELL)
if(!lawsync)
O.lawupdate = FALSE
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 013883fe..7121aaac 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -426,7 +426,7 @@
"}
if(GLOB.master_mode == "secret")
dat += "(Force Secret Mode)
"
-
+
if(GLOB.master_mode == "dynamic")
if(SSticker.current_state <= GAME_STATE_PREGAME)
dat += "(Force Roundstart Rulesets)
"
@@ -987,6 +987,7 @@
SSblackbox.record_feedback("tally", "admin_verb", 1, "Ghost Drag Control")
tomob.ckey = frommob.ckey
+ tomob.client?.init_verbs()
qdel(frommob)
return 1
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 0ab823e2..3a24d7aa 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -74,6 +74,7 @@ GLOBAL_LIST_INIT(admin_verbs_admin, world.AVerbsAdmin())
/client/proc/addbunkerbypass,
/client/proc/revokebunkerbypass,
/client/proc/stop_sounds,
+ /client/proc/debugstatpanel,
/client/proc/hide_verbs, /*hides all our adminverbs*/
/client/proc/hide_most_verbs, /*hides all our hideable adminverbs*/
/datum/admins/proc/open_borgopanel
@@ -256,36 +257,36 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
control_freak = CONTROL_FREAK_SKIN | CONTROL_FREAK_MACROS
var/rights = holder.rank.rights
- verbs += GLOB.admin_verbs_default
+ add_verb(src, GLOB.admin_verbs_default)
if(rights & R_BUILDMODE)
- verbs += /client/proc/togglebuildmodeself
+ add_verb(src, /client/proc/togglebuildmodeself)
if(rights & R_ADMIN)
- verbs += GLOB.admin_verbs_admin
+ add_verb(src, GLOB.admin_verbs_admin)
if(rights & R_BAN)
- verbs += GLOB.admin_verbs_ban
+ add_verb(src, GLOB.admin_verbs_ban)
if(rights & R_FUN)
- verbs += GLOB.admin_verbs_fun
+ add_verb(src, GLOB.admin_verbs_fun)
if(rights & R_SERVER)
- verbs += GLOB.admin_verbs_server
+ add_verb(src, GLOB.admin_verbs_server)
if(rights & R_DEBUG)
- verbs += GLOB.admin_verbs_debug
+ add_verb(src, GLOB.admin_verbs_debug)
if(rights & R_POSSESS)
- verbs += GLOB.admin_verbs_possess
+ add_verb(src, GLOB.admin_verbs_possess)
if(rights & R_PERMISSIONS)
- verbs += GLOB.admin_verbs_permissions
+ add_verb(src, GLOB.admin_verbs_permissions)
if(rights & R_STEALTH)
- verbs += /client/proc/stealth
+ add_verb(src, /client/proc/stealth)
if(rights & R_ADMIN)
- verbs += GLOB.admin_verbs_poll
+ add_verb(src, GLOB.admin_verbs_poll)
if(rights & R_SOUNDS)
- verbs += GLOB.admin_verbs_sounds
+ add_verb(src, GLOB.admin_verbs_sounds)
if(CONFIG_GET(string/invoke_youtubedl))
- verbs += /client/proc/play_web_sound
+ add_verb(src, /client/proc/play_web_sound)
if(rights & R_SPAWN)
- verbs += GLOB.admin_verbs_spawn
+ add_verb(src, GLOB.admin_verbs_spawn)
/client/proc/remove_admin_verbs()
- verbs.Remove(
+ remove_verb(src, list(
GLOB.admin_verbs_default,
/client/proc/togglebuildmodeself,
GLOB.admin_verbs_admin,
@@ -304,14 +305,14 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
GLOB.admin_verbs_debug_mapping,
/client/proc/disable_debug_verbs,
/client/proc/readmin
- )
+ ))
/client/proc/hide_most_verbs()//Allows you to keep some functionality while hiding some verbs
set name = "Adminverbs - Hide Most"
set category = "Admin"
verbs.Remove(/client/proc/hide_most_verbs, GLOB.admin_verbs_hideable)
- verbs += /client/proc/show_verbs
+ add_verb(src, /client/proc/show_verbs)
to_chat(src, "Most of your adminverbs have been hidden.")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Hide Most Adminverbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -322,7 +323,7 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
set category = "Admin"
remove_admin_verbs()
- verbs += /client/proc/show_verbs
+ add_verb(src, /client/proc/show_verbs)
to_chat(src, "Almost all of your adminverbs have been hidden.")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Hide All Adminverbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -332,7 +333,7 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
set name = "Adminverbs - Show"
set category = "Admin"
- verbs -= /client/proc/show_verbs
+ remove_verb(src, /client/proc/show_verbs)
add_admin_verbs()
to_chat(src, "All of your adminverbs are now visible.")
@@ -365,6 +366,7 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
message_admins("[key_name_admin(usr)] admin ghosted.")
var/mob/body = mob
body.ghostize(1)
+ init_verbs()
if(body && !body.key)
body.key = "@[key]" //Haaaaaaaack. But the people have spoken. If it breaks; blame adminbus
SSblackbox.record_feedback("tally", "admin_verb", 1, "Admin Ghost") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -717,3 +719,10 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
log_admin("[key_name(usr)] has [AI_Interact ? "activated" : "deactivated"] Admin AI Interact")
message_admins("[key_name_admin(usr)] has [AI_Interact ? "activated" : "deactivated"] their AI interaction")
+
+
+/client/proc/debugstatpanel()
+ set name = "Debug Stat Panel"
+ set category = "Debug"
+
+ src << output("", "statbrowser:create_debug")
\ No newline at end of file
diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm
index f9bed188..04c1909c 100644
--- a/code/modules/admin/holder2.dm
+++ b/code/modules/admin/holder2.dm
@@ -93,7 +93,7 @@ GLOBAL_PROTECT(href_token)
var/client/C
if ((C = owner) || (C = GLOB.directory[target]))
disassociate()
- C.verbs += /client/proc/readmin
+ add_verb(C, /client/proc/readmin)
/datum/admins/proc/associate(client/C)
if(IsAdminAdvancedProcCall())
@@ -113,7 +113,8 @@ GLOBAL_PROTECT(href_token)
owner = C
owner.holder = src
owner.add_admin_verbs() //TODO <--- todo what? the proc clearly exists and works since its the backbone to our entire admin system
- owner.verbs -= /client/proc/readmin
+ remove_verb(owner, /client/proc/readmin)
+ owner.init_verbs() //re-initialize the verb list
GLOB.admins |= C
/datum/admins/proc/disassociate()
@@ -125,6 +126,7 @@ GLOBAL_PROTECT(href_token)
if(owner)
GLOB.admins -= owner
owner.remove_admin_verbs()
+ owner.init_verbs()
owner.holder = null
owner = null
diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm
index 41496b35..3e83974d 100644
--- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm
+++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm
@@ -393,11 +393,14 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
delete_click = new(null, "INITIALIZING", src)
if(!action_click)
action_click = new(null, "INITIALIZNG", src)
- stat("[id] ", delete_click.update("DELETE QUERY | STATE : [text_state()] | ALL/ELIG/FIN \
+
+ var/list/L = list()
+ L[++L.len] = list("[id] ", "[delete_click.update("DELETE QUERY | STATE : [text_state()] | ALL/ELIG/FIN \
[islist(obj_count_all)? length(obj_count_all) : (isnull(obj_count_all)? "0" : obj_count_all)]/\
[islist(obj_count_eligible)? length(obj_count_eligible) : (isnull(obj_count_eligible)? "0" : obj_count_eligible)]/\
- [islist(obj_count_finished)? length(obj_count_finished) : (isnull(obj_count_finished)? "0" : obj_count_finished)] - [get_query_text()]"))
- stat(" ", action_click.update("[SDQL2_IS_RUNNING? "HALT" : "RUN"]"))
+ [islist(obj_count_finished)? length(obj_count_finished) : (isnull(obj_count_finished)? "0" : obj_count_finished)] - [get_query_text()]")]", REF(delete_click))
+ L[++L.len] = list(" ", "[action_click.update("[SDQL2_IS_RUNNING? "HALT" : "RUN"]")]", REF(action_click))
+ return L
/datum/SDQL2_query/proc/delete_click()
admin_del(usr)
@@ -1161,10 +1164,18 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
return istype(thing, /datum) || istype(thing, /client)
/obj/effect/statclick/SDQL2_delete/Click()
+ if(!usr.client?.holder)
+ message_admins("[key_name_admin(usr)] non-holder clicked on a statclick! ([src])")
+ log_game("[key_name(usr)] non-holder clicked on a statclick! ([src])")
+ return
var/datum/SDQL2_query/Q = target
Q.delete_click()
/obj/effect/statclick/SDQL2_action/Click()
+ if(!usr.client?.holder)
+ message_admins("[key_name_admin(usr)] non-holder clicked on a statclick! ([src])")
+ log_game("[key_name(usr)] non-holder clicked on a statclick! ([src])")
+ return
var/datum/SDQL2_query/Q = target
Q.action_click()
@@ -1172,4 +1183,13 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
name = "VIEW VARIABLES"
/obj/effect/statclick/SDQL2_VV_all/Click()
+ if(!usr.client?.holder)
+ message_admins("[key_name_admin(usr)] non-holder clicked on a statclick! ([src])")
+ log_game("[key_name(usr)] non-holder clicked on a statclick! ([src])")
+ return
usr.client.debug_variables(GLOB.sdql2_queries)
+
+ if(!usr.client?.holder)
+ message_admins("[key_name_admin(usr)] non-holder clicked on a statclick! ([src])")
+ log_game("[key_name(usr)] non-holder clicked on a statclick! ([src])")
+ return
\ No newline at end of file
diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm
index b24ce6d1..256bdaf0 100644
--- a/code/modules/admin/verbs/adminhelp.dm
+++ b/code/modules/admin/verbs/adminhelp.dm
@@ -89,18 +89,23 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
//Tickets statpanel
/datum/admin_help_tickets/proc/stat_entry()
+ SHOULD_CALL_PARENT(TRUE)
+ SHOULD_NOT_SLEEP(TRUE)
+ var/list/L = list()
var/num_disconnected = 0
- stat("Active Tickets:", astatclick.update("[active_tickets.len]"))
+ L[++L.len] = list("Active Tickets:", "[astatclick.update("[active_tickets.len]")]", null, REF(astatclick))
+ astatclick.update("[active_tickets.len]")
for(var/I in active_tickets)
var/datum/admin_help/AH = I
if(AH.initiator)
- stat("#[AH.id]. [AH.initiator_key_name]:", AH.statclick.update())
+ L[++L.len] = list("#[AH.id]. [AH.initiator_key_name]:", "[AH.statclick.update()]", REF(AH))
else
++num_disconnected
if(num_disconnected)
- stat("Disconnected:", astatclick.update("[num_disconnected]"))
- stat("Closed Tickets:", cstatclick.update("[closed_tickets.len]"))
- stat("Resolved Tickets:", rstatclick.update("[resolved_tickets.len]"))
+ L[++L.len] = list("Disconnected:", "[astatclick.update("[num_disconnected]")]", null, REF(astatclick))
+ L[++L.len] = list("Closed Tickets:", "[cstatclick.update("[closed_tickets.len]")]", null, REF(cstatclick))
+ L[++L.len] = list("Resolved Tickets:", "[rstatclick.update("[resolved_tickets.len]")]", null, REF(rstatclick))
+ return L
//Reassociate still open ticket if one exists
/datum/admin_help_tickets/proc/ClientLogin(client/C)
@@ -137,6 +142,13 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
/obj/effect/statclick/ticket_list/Click()
GLOB.ahelp_tickets.BrowseTickets(current_state)
+
+//called by admin topic
+/obj/effect/statclick/ticket_list/proc/Action()
+ Click()
+
+
+
//
//TICKET DATUM
//
@@ -221,7 +233,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
//Removes the ahelp verb and returns it after 30 seconds
/datum/admin_help/proc/TimeoutVerb()
- initiator.verbs -= /client/verb/adminhelp
+ remove_verb(initiator, /client/verb/adminhelp)
initiator.adminhelptimerid = addtimer(CALLBACK(initiator, /client/proc/giveadminhelpverb), 300, TIMER_STOPPABLE) //30 seconds cooldown of admin helps
//private
@@ -492,7 +504,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
//
/client/proc/giveadminhelpverb()
- src.verbs |= /client/verb/adminhelp
+ add_verb(src, /client/verb/adminhelp)
deltimer(adminhelptimerid)
adminhelptimerid = 0
diff --git a/code/modules/admin/verbs/borgpanel.dm b/code/modules/admin/verbs/borgpanel.dm
index c0445d58..1a5c7d33 100644
--- a/code/modules/admin/verbs/borgpanel.dm
+++ b/code/modules/admin/verbs/borgpanel.dm
@@ -199,7 +199,7 @@
borg.notify_ai(DISCONNECT)
if(borg.shell)
borg.undeploy()
- borg.connected_ai = newai
+ borg.set_connected_ai(newai)
borg.notify_ai(TRUE)
message_admins("[key_name_admin(user)] slaved [ADMIN_LOOKUPFLW(borg)] to the AI [ADMIN_LOOKUPFLW(newai)].")
log_admin("[key_name(user)] slaved [key_name(borg)] to the AI [key_name(newai)].")
@@ -207,7 +207,7 @@
borg.notify_ai(DISCONNECT)
if(borg.shell)
borg.undeploy()
- borg.connected_ai = null
+ borg.set_connected_ai(null)
message_admins("[key_name_admin(user)] freed [ADMIN_LOOKUPFLW(borg)] from being slaved to an AI.")
log_admin("[key_name(user)] freed [key_name(borg)] from being slaved to an AI.")
if (borg.lawupdate)
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index 699b2d50..8450793f 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -493,6 +493,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
log_admin("[key_name(usr)] assumed direct control of [M].")
var/mob/adminmob = src.mob
M.ckey = src.ckey
+ init_verbs()
if( isobserver(adminmob) )
qdel(adminmob)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Assume Direct Control") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm
index 3a0b1e97..bb005a6b 100644
--- a/code/modules/admin/verbs/mapping.dm
+++ b/code/modules/admin/verbs/mapping.dm
@@ -205,15 +205,15 @@ GLOBAL_LIST_EMPTY(dirty_vars)
set name = "Debug verbs - Enable"
if(!check_rights(R_DEBUG))
return
- verbs -= /client/proc/enable_debug_verbs
- verbs.Add(/client/proc/disable_debug_verbs, GLOB.admin_verbs_debug_mapping)
+ remove_verb(src, /client/proc/enable_debug_verbs)
+ add_verb(src, list(/client/proc/disable_debug_verbs, GLOB.admin_verbs_debug_mapping))
SSblackbox.record_feedback("tally", "admin_verb", 1, "Enable Debug Verbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/disable_debug_verbs()
set category = "Debug"
set name = "Debug verbs - Disable"
- verbs.Remove(/client/proc/disable_debug_verbs, GLOB.admin_verbs_debug_mapping)
- verbs += /client/proc/enable_debug_verbs
+ remove_verb(src, list(/client/proc/disable_debug_verbs, GLOB.admin_verbs_debug_mapping))
+ add_verb(src, /client/proc/enable_debug_verbs)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Disable Debug Verbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/count_objects_on_z_level()
diff --git a/code/modules/admin/verbs/possess.dm b/code/modules/admin/verbs/possess.dm
index 445de4c4..ee4d1265 100644
--- a/code/modules/admin/verbs/possess.dm
+++ b/code/modules/admin/verbs/possess.dm
@@ -48,6 +48,6 @@
set desc = "Give this guy possess/release verbs"
set category = "Debug"
set name = "Give Possessing Verbs"
- M.verbs += /proc/possess
- M.verbs += /proc/release
+ add_verb(M, /proc/possess)
+ add_verb(M, /proc/release)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Give Possessing Verbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
diff --git a/code/modules/antagonists/blob/blob/overmind.dm b/code/modules/antagonists/blob/blob/overmind.dm
index 01882821..57ae1d4c 100644
--- a/code/modules/antagonists/blob/blob/overmind.dm
+++ b/code/modules/antagonists/blob/blob/overmind.dm
@@ -223,19 +223,16 @@ GLOBAL_LIST_EMPTY(blob_nodes)
/mob/camera/blob/blob_act(obj/structure/blob/B)
return
-/mob/camera/blob/Stat()
- ..()
- if(statpanel("Status"))
- if(blob_core)
- stat(null, "Core Health: [blob_core.obj_integrity]")
- stat(null, "Power Stored: [blob_points]/[max_blob_points]")
- stat(null, "Blobs to Win: [blobs_legit.len]/[blobwincount]")
- if(free_chem_rerolls)
- stat(null, "You have [free_chem_rerolls] Free Chemical Reroll\s Remaining")
- if(!placed)
- if(manualplace_min_time)
- stat(null, "Time Before Manual Placement: [max(round((manualplace_min_time - world.time)*0.1, 0.1), 0)]")
- stat(null, "Time Before Automatic Placement: [max(round((autoplace_max_time - world.time)*0.1, 0.1), 0)]")
+/mob/camera/blob/get_status_tab_items()
+ . = ..()
+ if(blob_core)
+ . += "Core Health: [blob_core.obj_integrity]"
+ . += "Power Stored: [blob_points]/[max_blob_points]"
+ . += "Blobs to Win: [blobs_legit.len]/[blobwincount]"
+ if(!placed)
+ if(manualplace_min_time)
+ . += "Time Before Manual Placement: [max(round((manualplace_min_time - world.time)*0.1, 0.1), 0)]"
+ . += "Time Before Automatic Placement: [max(round((autoplace_max_time - world.time)*0.1, 0.1), 0)]"
/mob/camera/blob/Move(NewLoc, Dir = 0)
if(placed)
diff --git a/code/modules/antagonists/changeling/powers/absorb.dm b/code/modules/antagonists/changeling/powers/absorb.dm
index 5cb4faa8..b3d5d683 100644
--- a/code/modules/antagonists/changeling/powers/absorb.dm
+++ b/code/modules/antagonists/changeling/powers/absorb.dm
@@ -60,6 +60,8 @@
if(user.nutrition < NUTRITION_LEVEL_WELL_FED)
user.nutrition = min((user.nutrition + target.nutrition), NUTRITION_LEVEL_WELL_FED)
+ if(user.thirst < THIRST_LEVEL_QUENCHED)
+ user.thirst = min((user.thirst + target.thirst), THIRST_LEVEL_QUENCHED)
if(target.mind)//if the victim has got a mind
// Absorb a lizard, speak Draconic.
diff --git a/code/modules/antagonists/disease/disease_abilities.dm b/code/modules/antagonists/disease/disease_abilities.dm
index 7b30d10c..812f7c4a 100644
--- a/code/modules/antagonists/disease/disease_abilities.dm
+++ b/code/modules/antagonists/disease/disease_abilities.dm
@@ -76,7 +76,7 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
resistance += initial(S.resistance)
stage_speed += initial(S.stage_speed)
transmittable += initial(S.transmittable)
- threshold_block += initial(S.threshold_desc)
+ threshold_block += initial(S.threshold_desc)
stat_block = "Resistance: [resistance]
Stealth: [stealth]
Stage Speed: [stage_speed]
Transmissibility: [transmittable]
"
if(symptoms.len == 1) //lazy boy's dream
name = initial(S.name)
@@ -194,8 +194,6 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
/datum/disease_ability/action/sneeze
name = "Voluntary Sneezing"
actions = list(/datum/action/cooldown/disease_sneeze)
- cost = 2
- required_total_points = 3
short_desc = "Force the host you are following to sneeze, spreading your infection to those in front of them."
long_desc = "Force the host you are following to sneeze with extra force, spreading your infection to any victims in a 4 meter cone in front of your host.
Cooldown: 20 seconds"
@@ -232,8 +230,6 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
/datum/disease_ability/action/infect
name = "Secrete Infection"
actions = list(/datum/action/cooldown/disease_infect)
- cost = 2
- required_total_points = 3
short_desc = "Cause all objects your host is touching to become infectious for a limited time, spreading your infection to anyone who touches them."
long_desc = "Cause the host you are following to excrete an infective substance from their pores, causing all objects touching their skin to transmit your infection to anyone who touches them for the next 30 seconds. This includes the floor, if they are not wearing shoes, and any items they are holding, if they are not wearing gloves.
Cooldown: 40 seconds"
@@ -274,22 +270,19 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
//healing costs more so you have to techswitch from naughty disease otherwise we'd have friendly disease for easy greentext (no fun!)
/datum/disease_ability/symptom/mild
- cost = 2
- required_total_points = 4
category = "Symptom (Weak)"
/datum/disease_ability/symptom/medium
- cost = 4
- required_total_points = 8
category = "Symptom"
/datum/disease_ability/symptom/medium/heal
cost = 5
+ required_total_points = 5
category = "Symptom (+)"
/datum/disease_ability/symptom/powerful
cost = 4
- required_total_points = 16
+ required_total_points = 10
category = "Symptom (Strong)"
/datum/disease_ability/symptom/powerful/heal
diff --git a/code/modules/antagonists/disease/disease_mob.dm b/code/modules/antagonists/disease/disease_mob.dm
index e824c5c9..ff935f32 100644
--- a/code/modules/antagonists/disease/disease_mob.dm
+++ b/code/modules/antagonists/disease/disease_mob.dm
@@ -84,17 +84,16 @@ the new instance inside the host to be updated to the template's stats.
to_chat(src, "You have [DisplayTimeText(freemove_end - world.time)] to select your first host. Click on a human to select your host.")
-/mob/camera/disease/Stat()
- ..()
- if(statpanel("Status"))
- if(freemove)
- stat("Host Selection Time: [round((freemove_end - world.time)/10)]s")
- else
- stat("Adaptation Points: [points]/[total_points]")
- stat("Hosts: [disease_instances.len]")
- var/adapt_ready = next_adaptation_time - world.time
- if(adapt_ready > 0)
- stat("Adaptation Ready: [round(adapt_ready/10, 0.1)]s")
+/mob/camera/disease/get_status_tab_items()
+
+ if(freemove)
+ . += "Host Selection Time: [round((freemove_end - world.time)/10)]s"
+ else
+ . += "Adaptation Points: [points]/[total_points]"
+ . += "Hosts: [disease_instances.len]"
+ var/adapt_ready = next_adaptation_time - world.time
+ if(adapt_ready > 0)
+ . += "Adaptation Ready: [round(adapt_ready/10, 0.1)]s"
/mob/camera/disease/examine(mob/user)
diff --git a/code/modules/antagonists/nightmare/nightmare.dm b/code/modules/antagonists/nightmare/nightmare.dm
index 41a3f181..847ceeb6 100644
--- a/code/modules/antagonists/nightmare/nightmare.dm
+++ b/code/modules/antagonists/nightmare/nightmare.dm
@@ -1,4 +1,21 @@
+#define LIGHTSTOBREAK_MINIMUM 25
+#define LIGHTSTOBREAK_MAXIMUM 75
+#define LIGHTSTOBREAK_THRESHOLD 50
+#define LIGHTSTOBREAK_MAX_CHANCE 50
+#define LIGHTSTOBREAK_AREA_MIN 1
+#define LIGHTSTOBREAK_AREA_MAX 2
+
/datum/antagonist/nightmare
name = "Nightmare"
show_in_antagpanel = FALSE
- show_name_in_check_antagonists = TRUE
\ No newline at end of file
+ show_name_in_check_antagonists = TRUE
+
+/datum/antagonist/nightmare/on_gain()
+ owner.objectives += forge_objective()
+ owner.objectives += new /datum/objective/survive
+
+/datum/antagonist/nightmare/proc/forge_objective()
+ var/datum/objective/break_lights/O = new
+ O.mode = prob(50) ? TRUE : FALSE
+ antag_memory = "Objectives:
1. [O.apply_rules()]
2. Stay alive until the end."
+ return O
diff --git a/code/modules/antagonists/nightmare/nightmare_objectives.dm b/code/modules/antagonists/nightmare/nightmare_objectives.dm
new file mode 100644
index 00000000..dbcadc5e
--- /dev/null
+++ b/code/modules/antagonists/nightmare/nightmare_objectives.dm
@@ -0,0 +1,105 @@
+/datum/objective/break_lights
+ var/mode = FALSE //If true, break all lights in determined area
+ var/list/area_targets = list() //Which areas we have to keep lights broken
+ target_amount = LIGHTSTOBREAK_AREA_MIN
+ var/lightsbroken = 0
+
+ var/safe_areas = list(
+ /area/space,
+ /area/maintenance/solars,
+ /area/maintenance/central, //HOP/Conference room APC
+ /area/ai_monitored,
+ /area/shuttle,
+ /area/engine/engine_smes,
+ /area/security/prison, //If you get unlucky, you'll have to break the lights in armory
+ /area/security/execution)
+
+/datum/objective/break_lights/proc/apply_rules()
+ if(mode)
+ var/list/valid_areas = list()
+ for(var/obj/machinery/power/apc/C in GLOB.apcs_list)
+ if(C.cell && is_station_level(C.z))
+ var/is_safearea = 1
+ for(var/A in safe_areas)
+ if(istype(C.area, A))
+ is_safearea = 0
+ break
+ if(is_safearea)
+ valid_areas += C.area
+ var/I = rand(LIGHTSTOBREAK_AREA_MIN, LIGHTSTOBREAK_AREA_MAX)
+ for(var/N in 1 to I)
+ var/area2add = pick(valid_areas)
+ if(!locate(area2add) in area_targets)
+ area_targets += area2add
+ else
+ target_amount = rand(LIGHTSTOBREAK_MINIMUM, LIGHTSTOBREAK_MAXIMUM)
+ if(prob(LIGHTSTOBREAK_MAX_CHANCE))
+ if(target_amount > LIGHTSTOBREAK_THRESHOLD)
+ target_amount = LIGHTSTOBREAK_MAXIMUM
+ else if(target_amount > LIGHTSTOBREAK_THRESHOLD)
+ target_amount = LIGHTSTOBREAK_THRESHOLD
+ explanation_text = update_explanation_text()
+ return explanation_text
+
+/datum/objective/break_lights/update_explanation_text()
+ ..()
+ if(mode)
+ if(!area_targets.len)
+ return "Uh oh! Something broke! Report this."
+ . += "There must not be any light sources in the "
+ if(area_targets.len == 1)
+ var/area/A = area_targets[1]
+ . += "[A.name]"
+ else if(area_targets.len == 2)
+ var/area/A = area_targets[1]
+ var/area/B = area_targets[2]
+ . += "[A.name] and [B.name]"
+ else //Won't get here because of define values, but during development you can get here. leaving this here for future purposes
+ var/i = 1
+ for(var/area/A in area_targets)
+ if(i != area_targets.len) . += "[A.name], "
+ else . += "and [A.name]"
+
+ . += " before the end."
+ else
+ . += "Break at least [target_amount] lights with your light eater."
+
+/datum/objective/break_lights/check_completion()
+ if(completed)
+ return TRUE //An attempt to stop this from being called twice
+ if(!mode)
+ if(lightsbroken >= target_amount)
+ completed = TRUE
+ else
+ var/list/valid_turfs = list()
+ for(var/area/target in area_targets)
+ var/list/cached_area = get_area_turfs(target.type)
+ for(var/turf/A in cached_area)
+ if(!is_station_level(A.z))
+ continue
+ valid_turfs += A
+ for(var/turf/T in valid_turfs)
+ for(var/atom/C in T.contents)
+ /*if(!C?.visibility) //Doesn't compile, add this another time
+ continue*/
+ if(C.light_range > 0)
+ if(C.light_power <= SHADOW_SPECIES_LIGHT_THRESHOLD*2) //Give some leniency for not destroying that unbreakable requests console
+ completed = TRUE
+ else
+ completed = FALSE
+ break
+ if(!completed)
+ break
+
+ return completed
+
+/datum/objective/break_lights/area
+ mode = TRUE
+
+
+#undef LIGHTSTOBREAK_MINIMUM
+#undef LIGHTSTOBREAK_MAXIMUM
+#undef LIGHTSTOBREAK_THRESHOLD
+#undef LIGHTSTOBREAK_MAX_CHANCE
+#undef LIGHTSTOBREAK_AREA_MIN
+#undef LIGHTSTOBREAK_AREA_MAX
diff --git a/code/modules/antagonists/revenant/revenant.dm b/code/modules/antagonists/revenant/revenant.dm
index f4418a62..2fa4952a 100644
--- a/code/modules/antagonists/revenant/revenant.dm
+++ b/code/modules/antagonists/revenant/revenant.dm
@@ -124,12 +124,12 @@
update_health_hud()
..()
-/mob/living/simple_animal/revenant/Stat()
- ..()
- if(statpanel("Status"))
- stat(null, "Current essence: [essence]/[essence_regen_cap]E")
- stat(null, "Stolen essence: [essence_accumulated]E")
- stat(null, "Stolen perfect souls: [perfectsouls]")
+
+/mob/living/simple_animal/revenant/get_status_tab_items()
+ . = ..()
+ . += "Current essence: [essence]/[essence_regen_cap]E"
+ . += "Stolen essence: [essence_accumulated]E"
+ . += "Stolen perfect souls: [perfectsouls]"
/mob/living/simple_animal/revenant/update_health_hud()
if(hud_used)
diff --git a/code/modules/antagonists/swarmer/swarmer.dm b/code/modules/antagonists/swarmer/swarmer.dm
index 9f663fc5..02ddf315 100644
--- a/code/modules/antagonists/swarmer/swarmer.dm
+++ b/code/modules/antagonists/swarmer/swarmer.dm
@@ -107,7 +107,7 @@
/mob/living/simple_animal/hostile/swarmer/Initialize()
. = ..()
- verbs -= /mob/living/verb/pulled
+ remove_verb(src, /mob/living/verb/pulled)
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
diag_hud.add_to_hud(src)
@@ -123,10 +123,9 @@
holder.pixel_y = I.Height() - world.icon_size
holder.icon_state = "hudstat"
-/mob/living/simple_animal/hostile/swarmer/Stat()
- ..()
- if(statpanel("Status"))
- stat("Resources:",resources)
+/mob/living/simple_animal/hostile/swarmer/get_status_tab_items()
+ . = ..()
+ . += "Resources: [resources]"
/mob/living/simple_animal/hostile/swarmer/emp_act()
. = ..()
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
index 0d9b2a64..9fd0850f 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
@@ -89,6 +89,7 @@
if(!panel_open)
return
anchored = !anchored
+ move_resist = anchored? INFINITY : 100
I.play_tool_sound(src)
if(generator)
disconnectFromGenerator()
diff --git a/code/modules/awaymissions/mission_code/wildwest.dm b/code/modules/awaymissions/mission_code/wildwest.dm
index 505b9a1e..f13341fa 100644
--- a/code/modules/awaymissions/mission_code/wildwest.dm
+++ b/code/modules/awaymissions/mission_code/wildwest.dm
@@ -105,7 +105,7 @@
if("Immortality")
to_chat(user, "Your wish is granted, but at a terrible cost...")
to_chat(user, "The Wish Granter punishes you for your selfishness, claiming your soul and warping your body to match the darkness in your heart.")
- user.verbs += /mob/living/carbon/proc/immortality
+ add_verb(user, /mob/living/carbon/proc/immortality)
user.set_species(/datum/species/shadow)
if("To Kill")
to_chat(user, "Your wish is granted, but at a terrible cost...")
diff --git a/code/modules/cargo/packs/engine.dm b/code/modules/cargo/packs/engine.dm
index fd5c711b..44eb0ad5 100644
--- a/code/modules/cargo/packs/engine.dm
+++ b/code/modules/cargo/packs/engine.dm
@@ -169,12 +169,22 @@
crate_name = "tesla generator crate"
/datum/supply_pack/engine/teg
- name = "Thermoelectric Generator"
- desc = "Contains your very own Thermoelectric Generator. Time to turn cargo into a blazing hellfire, perhaps?"
- cost = 4000
- contains = list(/obj/machinery/power/generator)
+ name = "Thermoelectric Generator Assembly"
+ desc = "Contains your very own Thermoelectric Generator Assembly. Time to turn cargo into a blazing hellfire, perhaps?"
+ cost = 3000
+ contains = list(/obj/item/paper/teg,
+ /obj/item/circuitboard/machine/generator,
+ /obj/item/circuitboard/machine/circulator,
+ /obj/item/circuitboard/machine/circulator,
+ /obj/item/stack/cable_coil,
+ /obj/item/stack/sheet/metal/twenty)
crate_name = "thermoelectric generator crate"
+/obj/item/paper/teg
+ info = "*The seemingly useful notes have been scribbled over with red and black crayon. Hmm.*"
+ name = "TEG Instructions"
+ color = "red"
+
/datum/supply_pack/engine/energy_harvester
name = "Energy Harvesting Module"
desc = "A Device which upon connection to a node, will harvest the energy and send it to engineerless stations in return for credits, derived from a syndicate powersink model."
diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm
index 53170805..792e40ad 100644
--- a/code/modules/client/client_defines.dm
+++ b/code/modules/client/client_defines.dm
@@ -4,6 +4,10 @@
//BLACK MAGIC THINGS//
//////////////////////
parent_type = /datum
+
+
+ /// hides the byond verb panel as we use our own custom version
+ show_verb_panel = FALSE
////////////////
//ADMIN THINGS//
////////////////
@@ -24,6 +28,12 @@
var/move_delay = 0
var/area = null
+
+
+ /// list of tabs containing spells and abilities
+ var/list/spell_tabs = list()
+ /// list of tabs containing verbs
+ var/list/verb_tabs = list()
///////////////
//SOUND STUFF//
///////////////
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 23bfebb2..04b714f1 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -197,7 +197,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
debug_tools_allowed = TRUE
//END CITADEL EDIT
else if(GLOB.deadmins[ckey])
- verbs += /client/proc/readmin
+ add_verb(src, /client/proc/readmin)
connecting_admin = TRUE
if(CONFIG_GET(flag/autoadmin))
if(!GLOB.admin_datums[ckey])
@@ -243,7 +243,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
fps = 40
if(fexists(roundend_report_file()))
- verbs += /client/proc/show_previous_roundend_report
+ add_verb(src, /client/proc/show_previous_roundend_report)
var/full_version = "[byond_version].[byond_build ? byond_build : "xxx"]"
log_access("Login: [key_name(src)] from [address ? address : "localhost"]-[computer_id] || BYOND v[full_version]")
@@ -304,6 +304,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
set_macros()
chatOutput.start() // Starts the chat
+ src << browse(file('html/statbrowser.html'), "window=statbrowser") //starts stats tab
if(alert_mob_dupe_login)
spawn()
@@ -798,9 +799,9 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
/client/proc/add_verbs_from_config()
if(CONFIG_GET(flag/see_own_notes))
- verbs += /client/proc/self_notes
+ add_verb(src, /client/proc/self_notes)
if(CONFIG_GET(flag/use_exp_tracking))
- verbs += /client/proc/self_playtime
+ add_verb(src, /client/proc/self_playtime)
#undef UPLOAD_LIMIT
@@ -865,6 +866,31 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
y = CLAMP(y+change, min,max)
change_view("[x]x[y]")
+/// compiles a full list of verbs and sends it to the browser
+/client/proc/init_verbs()
+ if(IsAdminAdvancedProcCall())
+ return
+ var/list/verblist = list()
+
+ var/list/verbstoprocess = verbs.Copy()
+ if(mob)
+ verbstoprocess += mob.verbs
+ for(var/AM in mob.contents)
+ var/atom/movable/thing = AM
+ verbstoprocess += thing.verbs
+ verb_tabs.Cut()
+ for(var/thing in verbstoprocess)
+ var/procpath/verb_to_init = thing
+ if(!verb_to_init)
+ continue
+ if(verb_to_init.hidden)
+ continue
+ if(!istext(verb_to_init.category))
+ continue
+ verb_tabs |= verb_to_init.category
+ verblist[++verblist.len] = list(verb_to_init.category, verb_to_init.name)
+ src << output("[url_encode(json_encode(verb_tabs))];[url_encode(json_encode(verblist))]", "statbrowser:init_verbs")
+
/client/proc/change_view(new_size)
if (isnull(new_size))
CRASH("change_view called without argument.")
diff --git a/code/modules/client/darkmode.dm b/code/modules/client/darkmode.dm
index f806e5c9..ad8e5ef0 100644
--- a/code/modules/client/darkmode.dm
+++ b/code/modules/client/darkmode.dm
@@ -37,6 +37,7 @@ Thanks to spacemaniac and mcdonald for help with the JS side of this.
winset(src, "say", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]")
winset(src, "asset_cache_browser", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]")
winset(src, "tooltip", "background-color = [COLOR_WHITEMODE_BACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]")
+ src << output(null, "statbrowser:set_light_theme")
/client/proc/force_dark_theme() //Inversely, if theyre using white theme and want to swap to the superior dark theme, let's get WINSET() ing
//Main windows
@@ -62,4 +63,5 @@ Thanks to spacemaniac and mcdonald for help with the JS side of this.
//Etc.
winset(src, "say", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]")
winset(src, "asset_cache_browser", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]")
- winset(src, "tooltip", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]")
\ No newline at end of file
+ winset(src, "tooltip", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]")
+ src << output(null, "statbrowser:set_dark_theme")
\ No newline at end of file
diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm
index 1465a0c9..087c434b 100644
--- a/code/modules/client/verbs/ooc.dm
+++ b/code/modules/client/verbs/ooc.dm
@@ -366,3 +366,10 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8")
pct += delta
winset(src, "mainwindow.split", "splitter=[pct]")
+
+
+/client/verb/fix_stat_panel()
+ set name = "Fix Stat Panel"
+ set hidden = TRUE
+
+ init_verbs()
\ No newline at end of file
diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm
index 120e690c..23d1d686 100644
--- a/code/modules/clothing/glasses/hud.dm
+++ b/code/modules/clothing/glasses/hud.dm
@@ -47,17 +47,13 @@
name = "prescription health scanner HUD"
desc = "A heads-up display, made with a prescription lens, that scans the humans in view and provides accurate data about their health status."
icon_state = "healthhud"
- hud_type = DATA_HUD_MEDICAL_ADVANCED
vision_correction = 1
- glass_colour_type = /datum/client_colour/glass_colour/lightblue
/obj/item/clothing/glasses/hud/health/gar
name = "gar health scanner HUD"
desc = "When you're scared, that's all the more reason to move forward!"
icon_state = "garh"
item_state = "garh"
- hud_type = DATA_HUD_MEDICAL_ADVANCED
- glass_colour_type = /datum/client_colour/glass_colour/lightblue
force = 10
throwforce = 10
throw_speed = 4
@@ -100,9 +96,7 @@
name = "prescription diagnostic HUD"
desc = "A heads-up display capable of analyzing the integrity and status of robotics and exosuits. This one has a prescription lens."
icon_state = "diagnostichud"
- hud_type = DATA_HUD_DIAGNOSTIC_BASIC
vision_correction = 1
- glass_colour_type = /datum/client_colour/glass_colour/lightorange
/obj/item/clothing/glasses/hud/diagnostic/night
name = "night vision diagnostic HUD"
@@ -124,9 +118,7 @@
name = "prescription security HUD"
desc = "A heads-up display that scans the humans in view and provides accurate data about their ID status and security records. This one has a prescription lens so you can see the banana peal that slipped you."
icon_state = "securityhud"
- hud_type = DATA_HUD_SECURITY_ADVANCED
vision_correction = 1
- glass_colour_type = /datum/client_colour/glass_colour/red
/obj/item/clothing/glasses/hud/security/chameleon
name = "chameleon security HUD"
diff --git a/code/modules/events/aurora_caelus.dm b/code/modules/events/aurora_caelus.dm
index b941a978..a32532d1 100644
--- a/code/modules/events/aurora_caelus.dm
+++ b/code/modules/events/aurora_caelus.dm
@@ -12,10 +12,11 @@
/datum/round_event/aurora_caelus
announceWhen = 1
- startWhen = 9
+ startWhen = 8 //Delayed with sleep()
endWhen = 50
var/list/aurora_colors = list("#ffd980", "#eaff80", "#eaff80", "#ffd980", "#eaff80", "#A2FFC7", "#9400D3", "#FFC0CB")
var/aurora_progress = 0 //this cycles from 1 to 8, slowly changing colors from gentle green to gentle blue
+ var/list/applicable_areas = list()
/datum/round_event/aurora_caelus/announce()
priority_announce("[station_name()]: A harmless cloud of ions is approaching your station, and will exhaust their energy battering the hull. Kinaris Command has approved a short break for all employees to relax and observe this very rare event. During this time, starlight will be bright but gentle, shifting between quiet green and blue colors. We will also play quiet music for you to enjoy and relax. Any staff who would like to view these lights for themselves may proceed to the area nearest to them with viewing ports to open space. We hope you enjoy the lights.",
@@ -25,38 +26,67 @@
var/mob/M = V
if((M.client.prefs.toggles & SOUND_MIDI) && is_station_level(M.z))
M.playsound_local(M, 'sound/ambience/aurora_caelus_new.ogg', 40, FALSE, pressure_affected = FALSE) //ogg is "The Fire is Gone" by Heaven Pierce Her, used in the videogame ULTRAKILL. All respects and credits to the equivalent artists who worked on it.
+ start_checking()
+
+/datum/round_event/aurora_caelus/proc/start_checking()
+ var/list/turfs_to_check = list()
+ var/x = 1
+ var/y = 1
+ while(TRUE)
+ turfs_to_check += locate(x,y,2) //If the station z-level ever gets changed, change this too. I couldn't find if there's an easy way to get it
+ x++
+ if(x > 255)
+ x = 0
+ y++
+ if(y > 255)
+ break
+ if(!turfs_to_check)
+ CRASH("Aurora Caelus called, but there's no space!")
+ var/tlen = turfs_to_check.len
+ var/i = 0
+ while(i < tlen)
+ i++
+ var/turf/T = turfs_to_check[i]
+ if(!istype(T, /turf/open/space))
+ continue
+ if(i%2500 == 0)
+ sleep(1) //try to spread the lag around a bit
+ var/sure = (!istype(get_step(T, NORTH)?.loc, /area/space)||\
+ !istype(get_step(T, NORTHEAST)?.loc, /area/space)||\
+ !istype(get_step(T, EAST)?.loc, /area/space)||\
+ !istype(get_step(T, SOUTHEAST)?.loc, /area/space)||\
+ !istype(get_step(T, SOUTH)?.loc, /area/space)||\
+ !istype(get_step(T, SOUTHWEST)?.loc, /area/space)||\
+ !istype(get_step(T, WEST)?.loc, /area/space)||\
+ !istype(get_step(T, NORTHWEST)?.loc, /area/space)) //Better than using range()
+ if(sure)
+ applicable_areas += T
/datum/round_event/aurora_caelus/start()
- for(var/area in GLOB.sortedAreas)
- var/area/A = area
- if(initial(A.dynamic_lighting) == DYNAMIC_LIGHTING_IFSTARLIGHT)
- for(var/turf/open/space/S in A)
- S.set_light(S.light_range * 6, S.light_power * 1)
+ for(var/turf/S in applicable_areas)
+ S.set_light(6, 0.8, l_color = aurora_colors[1])
/datum/round_event/aurora_caelus/tick()
if(activeFor % 5 == 0)
aurora_progress++
+ if(aurora_progress > LAZYLEN(aurora_colors))
+ aurora_progress = 1
var/aurora_color = aurora_colors[aurora_progress]
- for(var/area in GLOB.sortedAreas)
- var/area/A = area
- if(initial(A.dynamic_lighting) == DYNAMIC_LIGHTING_IFSTARLIGHT)
- for(var/turf/open/space/S in A)
- S.set_light(l_color = aurora_color)
+ for(var/turf/S in applicable_areas)
+ S.set_light(l_color = aurora_color)
/datum/round_event/aurora_caelus/end()
- for(var/area in GLOB.sortedAreas)
- var/area/A = area
- if(initial(A.dynamic_lighting) == DYNAMIC_LIGHTING_IFSTARLIGHT)
- for(var/turf/open/space/S in A)
- fade_to_black(S)
priority_announce("The aurora caelus event is now ending. Starlight conditions will slowly return to normal. When this has concluded, please return to your workplace and continue work as normal. Have a pleasant shift, [station_name()], and thank you for watching with us.",
- sound = 'sound/misc/notice2.ogg',
- sender_override = "Kinaris Meteorology Division")
+ sound = 'sound/misc/notice2.ogg',
+ sender_override = "Kinaris Meteorology Division")
+ for(var/S in applicable_areas)
+ fade_to_black(S)
/datum/round_event/aurora_caelus/proc/fade_to_black(turf/open/space/S)
set waitfor = FALSE
- var/new_light = initial(S.light_range)
- while(S.light_range > new_light)
- S.set_light(S.light_range - 0.2)
- sleep(30)
- S.set_light(new_light, initial(S.light_power), initial(S.light_color))
+ var/i = 0.8
+ while(i>0)
+ S.set_light(l_power=i)
+ sleep(10)
+ i -= 0.05 //16 seconds
+ S.set_light(initial(S.light_range), initial(S.light_power), initial(S.light_color))
diff --git a/code/modules/events/wizard/ghost.dm b/code/modules/events/wizard/ghost.dm
index d5366c57..c288953e 100644
--- a/code/modules/events/wizard/ghost.dm
+++ b/code/modules/events/wizard/ghost.dm
@@ -21,6 +21,6 @@
/datum/round_event/wizard/possession/start()
for(var/mob/dead/observer/G in GLOB.player_list)
- G.verbs += /mob/dead/observer/verb/boo
- G.verbs += /mob/dead/observer/verb/possess
+ add_verb(G, /mob/dead/observer/verb/boo)
+ add_verb(G, /mob/dead/observer/verb/possess)
to_chat(G, "You suddenly feel a welling of new spooky powers...")
diff --git a/code/modules/food_and_drinks/recipes/drinks_recipes.dm b/code/modules/food_and_drinks/recipes/drinks_recipes.dm
index 473267fc..f807a491 100644
--- a/code/modules/food_and_drinks/recipes/drinks_recipes.dm
+++ b/code/modules/food_and_drinks/recipes/drinks_recipes.dm
@@ -885,7 +885,7 @@
id = /datum/reagent/consumable/ethanol/hotlime_miami
results = list(/datum/reagent/consumable/ethanol/hotlime_miami = 2)
required_reagents = list(/datum/reagent/medicine/ephedrine = 1, /datum/reagent/consumable/ethanol/pina_colada = 1)
-
+
/datum/chemical_reaction/commander_and_chief
name = "Commander and Chief"
id = /datum/reagent/consumable/ethanol/commander_and_chief
@@ -899,3 +899,15 @@
results = list(/datum/reagent/consumable/wockyslush = 5)
required_reagents = list(/datum/reagent/toxin/fentanyl = 1, /datum/reagent/consumable/ice = 1, /datum/reagent/consumable/lemon_lime = 1)
mix_message = "That thang bleedin’ P!"
+
+/datum/chemical_reaction/cum_in_a_hot_tub
+ name = "Cum in a Hot Tub"
+ id = /datum/reagent/consumable/ethanol/cum_in_a_hot_tub
+ results = list(/datum/reagent/consumable/ethanol/cum_in_a_hot_tub = 3)
+ required_reagents = list(/datum/reagent/consumable/ethanol/vodka = 2, /datum/reagent/consumable/ethanol/white_russian = 1, /datum/reagent/consumable/ethanol/irish_cream = 0.1)
+
+/datum/chemical_reaction/cum_in_a_hot_tub/semen
+ name = "Cum in a Hot Tub"
+ id = /datum/reagent/consumable/ethanol/cum_in_a_hot_tub/semen
+ results = list(/datum/reagent/consumable/ethanol/cum_in_a_hot_tub/semen = 3)
+ required_reagents = list(/datum/reagent/consumable/ethanol/vodka = 2, /datum/reagent/consumable/semen = 1, /datum/reagent/consumable/ethanol/irish_cream = 0.1)
diff --git a/code/modules/hydroponics/hydro_chemreact.dm b/code/modules/hydroponics/hydro_chemreact.dm
deleted file mode 100644
index b0821ae3..00000000
--- a/code/modules/hydroponics/hydro_chemreact.dm
+++ /dev/null
@@ -1,264 +0,0 @@
-/obj/machinery/hydroponics/proc/applyFertilizer(datum/reagents/S, mob/user)
- // Ambrosia Gaia produces earthsblood.
- if(S.has_reagent(/datum/reagent/medicine/earthsblood))
- self_sufficiency_progress += S.get_reagent_amount(/datum/reagent/medicine/earthsblood)
- if(self_sufficiency_progress >= self_sufficiency_req)
- become_self_sufficient()
- else if(!self_sustaining)
- to_chat(user, "[src] warms as it might on a spring day under a genuine Sun.")
-
- // Requires 5 mutagen to possibly change species.// Poor man's mutagen.
- if(S.has_reagent(/datum/reagent/toxin/mutagen, 5) || S.has_reagent(/datum/reagent/radium, 10) || S.has_reagent(/datum/reagent/uranium, 10))
- switch(rand(100))
- if(91 to 100)
- adjustHealth(-10)
- to_chat(user, "The plant shrivels and burns.")
- if(81 to 90)
- mutatespecie()
- if(66 to 80)
- hardmutate()
- if(41 to 65)
- mutate()
- if(21 to 41)
- to_chat(user, "The plants don't seem to react...")
- if(11 to 20)
- mutateweed()
- if(1 to 10)
- mutatepest(user)
- else
- to_chat(user, "Nothing happens...")
-
- // 2 or 1 units is enough to change the yield and other stats.// Can change the yield and other stats, but requires more than mutagen
- else if(S.has_reagent(/datum/reagent/toxin/mutagen, 2) || S.has_reagent(/datum/reagent/radium, 5) || S.has_reagent(/datum/reagent/uranium, 5))
- hardmutate()
- else if(S.has_reagent(/datum/reagent/toxin/mutagen, 1) || S.has_reagent(/datum/reagent/radium, 2) || S.has_reagent(/datum/reagent/uranium, 2))
- mutate()
-
- // Nutriments
- if(S.has_reagent(/datum/reagent/plantnutriment/eznutriment, 1))
- yieldmod = 1
- mutmod = 1
- adjustNutri(round(S.get_reagent_amount(/datum/reagent/plantnutriment/eznutriment) * 1))
- if(S.has_reagent(/datum/reagent/plantnutriment/left4zednutriment, 1))
- yieldmod = 0
- mutmod = 2
- adjustNutri(round(S.get_reagent_amount(/datum/reagent/plantnutriment/left4zednutriment) * 1))
- if(S.has_reagent(/datum/reagent/plantnutriment/robustharvestnutriment, 1))
- yieldmod = 1.3
- mutmod = 0
- adjustNutri(round(S.get_reagent_amount(/datum/reagent/plantnutriment/robustharvestnutriment) * 1))
-
-
-
-
-/obj/machinery/hydroponics/proc/applyChemicals(datum/reagents/S, mob/user)
- if(!myseed)
- return
- myseed.on_chem_reaction(S) //In case seeds have some special interactions with special chems, currently only used by vines
-
- // After handling the mutating, we now handle the damage from adding crude radioactives...
- if(S.has_reagent(/datum/reagent/uranium, 1))
- adjustHealth(-round(S.get_reagent_amount(/datum/reagent/uranium) * 1))
- adjustToxic(round(S.get_reagent_amount(/datum/reagent/uranium) * 2))
- if(S.has_reagent(/datum/reagent/radium, 1))
- adjustHealth(-round(S.get_reagent_amount(/datum/reagent/radium) * 1))
- adjustToxic(round(S.get_reagent_amount(/datum/reagent/radium) * 3)) // Radium is harsher (OOC: also easier to produce)
-
- if(S.has_reagent(/datum/reagent/plantnutriment/endurogrow, 1))
- var/total_transferred = S.get_reagent_amount(/datum/reagent/plantnutriment/endurogrow)
- if(total_transferred >= 20)
- myseed.adjust_potency(-round(total_transferred / 10))
- myseed.adjust_yield(-round(total_transferred / 20))
- myseed.adjust_endurance(round(total_transferred / 60))
- else
- to_chat(user, "The plants don't seem to react...")
-
- if(S.has_reagent(/datum/reagent/plantnutriment/liquidearthquake, 1))
- var/total_transferred = S.get_reagent_amount(/datum/reagent/plantnutriment/liquidearthquake)
- if(total_transferred >= 20)
- myseed.adjust_weed_chance(round(total_transferred / 10))
- myseed.adjust_weed_rate(round(total_transferred / 60))
- myseed.adjust_production(round(total_transferred / 60))
- else
- to_chat(user, "The plants don't seem to react...")
-
- // Antitoxin binds shit pretty well. So the tox goes significantly down
- if(S.has_reagent(/datum/reagent/medicine/charcoal, 1))
- adjustToxic(-round(S.get_reagent_amount(/datum/reagent/medicine/charcoal) * 2))
-
- // Toxins, not good for anything
- if(S.has_reagent(/datum/reagent/toxin, 1))
- adjustToxic(round(S.get_reagent_amount(/datum/reagent/toxin) * 2))
-
- // Milk is good for humans, but bad for plants. The sugars canot be used by plants, and the milk fat fucks up growth. Not shrooms though. I can't deal with this now...
- if(S.has_reagent(/datum/reagent/consumable/milk, 1))
- adjustNutri(round(S.get_reagent_amount(/datum/reagent/consumable/milk) * 0.1))
- adjustWater(round(S.get_reagent_amount(/datum/reagent/consumable/milk) * 0.9))
-
- // Beer is a chemical composition of alcohol and various other things. It's a shitty nutrient but hey, it's still one. Also alcohol is bad, mmmkay?
- if(S.has_reagent(/datum/reagent/consumable/ethanol/beer, 1))
- adjustHealth(-round(S.get_reagent_amount(/datum/reagent/consumable/ethanol/beer) * 0.05))
- adjustNutri(round(S.get_reagent_amount(/datum/reagent/consumable/ethanol/beer) * 0.25))
- adjustWater(round(S.get_reagent_amount(/datum/reagent/consumable/ethanol/beer) * 0.7))
-
- // Fluorine one of the most corrosive and deadly gasses
- if(S.has_reagent(/datum/reagent/fluorine, 1))
- adjustHealth(-round(S.get_reagent_amount(/datum/reagent/fluorine) * 2))
- adjustToxic(round(S.get_reagent_amount(/datum/reagent/fluorine) * 2.5))
- adjustWater(-round(S.get_reagent_amount(/datum/reagent/fluorine) * 0.5))
- adjustWeeds(-rand(1,4))
-
- // Chlorine one of the most corrosive and deadly gasses
- if(S.has_reagent(/datum/reagent/chlorine, 1))
- adjustHealth(-round(S.get_reagent_amount(/datum/reagent/chlorine) * 1))
- adjustToxic(round(S.get_reagent_amount(/datum/reagent/chlorine) * 1.5))
- adjustWater(-round(S.get_reagent_amount(/datum/reagent/chlorine) * 0.5))
- adjustWeeds(-rand(1,3))
-
- // White Phosphorous + water -> phosphoric acid. That's not a good thing really.
- // Phosphoric salts are beneficial though. And even if the plant suffers, in the long run the tray gets some nutrients. The benefit isn't worth that much.
- if(S.has_reagent(/datum/reagent/phosphorus, 1))
- adjustHealth(-round(S.get_reagent_amount(/datum/reagent/phosphorus) * 0.75))
- adjustNutri(round(S.get_reagent_amount(/datum/reagent/phosphorus) * 0.1))
- adjustWater(-round(S.get_reagent_amount(/datum/reagent/phosphorus) * 0.5))
- adjustWeeds(-rand(1,2))
-
- // Plants should not have sugar, they can't use it and it prevents them getting water/nutients, it is good for mold though...
- if(S.has_reagent(/datum/reagent/consumable/sugar, 1))
- adjustWeeds(rand(1,2))
- adjustPests(rand(1,2))
- adjustNutri(round(S.get_reagent_amount(/datum/reagent/consumable/sugar) * 0.1))
-
- // It is water!
- if(S.has_reagent(/datum/reagent/water, 1))
- adjustWater(round(S.get_reagent_amount(/datum/reagent/water) * 1))
-
- // Holy water. Mostly the same as water, it also heals the plant a little with the power of the spirits~
- if(S.has_reagent(/datum/reagent/water/holywater, 1))
- adjustWater(round(S.get_reagent_amount(/datum/reagent/water/holywater) * 1))
- adjustHealth(round(S.get_reagent_amount(/datum/reagent/water/holywater) * 0.1))
-
- // A variety of nutrients are dissolved in club soda, without sugar.
- // These nutrients include carbon, oxygen, hydrogen, phosphorous, potassium, sulfur and sodium, all of which are needed for healthy plant growth.
- if(S.has_reagent(/datum/reagent/consumable/sodawater, 1))
- adjustWater(round(S.get_reagent_amount(/datum/reagent/consumable/sodawater) * 1))
- adjustHealth(round(S.get_reagent_amount(/datum/reagent/consumable/sodawater) * 0.1))
- adjustNutri(round(S.get_reagent_amount(/datum/reagent/consumable/sodawater) * 0.1))
-
- // Sulphuric Acid
- if(S.has_reagent(/datum/reagent/toxin/acid, 1))
- adjustHealth(-round(S.get_reagent_amount(/datum/reagent/toxin/acid) * 1))
- adjustToxic(round(S.get_reagent_amount(/datum/reagent/toxin/acid) * 1.5))
- adjustWeeds(-rand(1,2))
-
- // Acid
- if(S.has_reagent(/datum/reagent/toxin/acid/fluacid, 1))
- adjustHealth(-round(S.get_reagent_amount(/datum/reagent/toxin/acid/fluacid) * 2))
- adjustToxic(round(S.get_reagent_amount(/datum/reagent/toxin/acid/fluacid) * 3))
- adjustWeeds(-rand(1,4))
-
- // Plant-B-Gone is just as bad
- if(S.has_reagent(/datum/reagent/toxin/plantbgone, 1))
- adjustHealth(-round(S.get_reagent_amount(/datum/reagent/toxin/plantbgone) * 5))
- adjustToxic(round(S.get_reagent_amount(/datum/reagent/toxin/plantbgone) * 6))
- adjustWeeds(-rand(4,8))
-
- // Napalm, not known for being good for anything organic
- if(S.has_reagent(/datum/reagent/napalm, 1))
- if(!(myseed.resistance_flags & FIRE_PROOF))
- adjustHealth(-round(S.get_reagent_amount(/datum/reagent/napalm) * 6))
- adjustToxic(round(S.get_reagent_amount(/datum/reagent/napalm) * 7))
- adjustWeeds(-rand(5,9))
-
- //Weed Spray
- if(S.has_reagent(/datum/reagent/toxin/plantbgone/weedkiller, 1))
- adjustToxic(round(S.get_reagent_amount(/datum/reagent/toxin/plantbgone/weedkiller) * 0.5))
- //old toxicity was 4, each spray is default 10 (minimal of 5) so 5 and 2.5 are the new ammounts
- adjustWeeds(-rand(1,2))
-
- //Pest Spray
- if(S.has_reagent(/datum/reagent/toxin/pestkiller, 1))
- adjustToxic(round(S.get_reagent_amount(/datum/reagent/toxin/pestkiller) * 0.5))
- adjustPests(-rand(1,2))
-
- // Healing
- if(S.has_reagent(/datum/reagent/medicine/cryoxadone, 1))
- adjustHealth(round(S.get_reagent_amount(/datum/reagent/medicine/cryoxadone) * 3))
- adjustToxic(-round(S.get_reagent_amount(/datum/reagent/medicine/cryoxadone) * 3))
-
- // Ammonia is bad ass.
- if(S.has_reagent(/datum/reagent/ammonia, 1))
- adjustHealth(round(S.get_reagent_amount(/datum/reagent/ammonia) * 0.5))
- adjustNutri(round(S.get_reagent_amount(/datum/reagent/ammonia) * 1))
- if(myseed)
- myseed.adjust_yield(round(S.get_reagent_amount(/datum/reagent/ammonia) * 0.01))
-
- // Saltpetre is used for gardening IRL, to simplify highly, it speeds up growth and strengthens plants
- if(S.has_reagent(/datum/reagent/saltpetre, 1))
- var/salt = S.get_reagent_amount(/datum/reagent/saltpetre)
- adjustHealth(round(salt * 0.25))
- if (myseed)
- myseed.adjust_production(-round(salt/100)-prob(salt%100))
- myseed.adjust_potency(round(salt*0.5))
- // Ash is also used IRL in gardening, as a fertilizer enhancer and weed killer
- if(S.has_reagent(/datum/reagent/ash, 1))
- adjustHealth(round(S.get_reagent_amount(/datum/reagent/ash) * 0.25))
- adjustNutri(round(S.get_reagent_amount(/datum/reagent/ash) * 0.5))
- adjustWeeds(-1)
-
- // Diethylamine is more bad ass, and pests get hurt by the corrosive nature of it, not the plant.
- if(S.has_reagent(/datum/reagent/diethylamine, 1))
- adjustHealth(round(S.get_reagent_amount(/datum/reagent/diethylamine) * 1))
- adjustNutri(round(S.get_reagent_amount(/datum/reagent/diethylamine) * 2))
- if(myseed)
- myseed.adjust_yield(round(S.get_reagent_amount(/datum/reagent/diethylamine) * 0.02))
- adjustPests(-rand(1,2))
-
- // Enduro Grow sacrifices potency + yield for endurance
- if(S.has_reagent(/datum/reagent/plantnutriment/endurogrow, 1))
- myseed.adjust_potency(-round(S.get_reagent_amount(/datum/reagent/plantnutriment/endurogrow) * 0.1))
- myseed.adjust_yield(-round(S.get_reagent_amount(/datum/reagent/plantnutriment/endurogrow) * 0.075))
- myseed.adjust_endurance(round(S.get_reagent_amount(/datum/reagent/plantnutriment/endurogrow) * 0.35))
-
- // Liquid Earthquake increases production speed but increases weeds
- if(S.has_reagent(/datum/reagent/plantnutriment/liquidearthquake, 1))
- myseed.adjust_weed_rate(round(S.get_reagent_amount(/datum/reagent/plantnutriment/liquidearthquake) * 0.1))
- myseed.adjust_weed_chance(round(S.get_reagent_amount(/datum/reagent/plantnutriment/liquidearthquake) * 0.3))
- myseed.adjust_production(round(S.get_reagent_amount(/datum/reagent/plantnutriment/liquidearthquake) * 0.075))
-
- // Nutriment Compost, effectively
- if(S.has_reagent(/datum/reagent/consumable/nutriment, 1))
- adjustHealth(round(S.get_reagent_amount(/datum/reagent/consumable/nutriment) * 0.5))
- adjustNutri(round(S.get_reagent_amount(/datum/reagent/consumable/nutriment) * 1))
-
- // Virusfood Compost for EVERYTHING
- if(S.has_reagent(/datum/reagent/toxin/mutagen/mutagenvirusfood, 1))
- adjustNutri(round(S.get_reagent_amount(/datum/reagent/toxin/mutagen/mutagenvirusfood) * 0.5))
- adjustHealth(-round(S.get_reagent_amount(/datum/reagent/toxin/mutagen/mutagenvirusfood) * 0.5))
-
- // Blood
- if(S.has_reagent(/datum/reagent/blood, 1))
- adjustNutri(round(S.get_reagent_amount(/datum/reagent/blood) * 1))
- adjustPests(rand(2,4))
-
- // Strange reagent
- if(S.has_reagent(/datum/reagent/medicine/strange_reagent, 1))
- spawnplant()
-
- // Adminordrazine the best stuff there is. For testing/debugging.
- if(S.has_reagent(/datum/reagent/medicine/adminordrazine, 1))
- adjustWater(round(S.get_reagent_amount(/datum/reagent/medicine/adminordrazine) * 1))
- adjustHealth(round(S.get_reagent_amount(/datum/reagent/medicine/adminordrazine) * 1))
- adjustNutri(round(S.get_reagent_amount(/datum/reagent/medicine/adminordrazine) * 1))
- adjustPests(-rand(1,5))
- adjustWeeds(-rand(1,5))
- if(S.has_reagent(/datum/reagent/medicine/adminordrazine, 5))
- switch(rand(100))
- if(66 to 100)
- mutatespecie()
- if(33 to 65)
- mutateweed()
- if(1 to 32)
- mutatepest(user)
- else
- to_chat(user, "Nothing happens...")
diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm
index d2cc76d9..c7bed07a 100644
--- a/code/modules/hydroponics/hydroponics.dm
+++ b/code/modules/hydroponics/hydroponics.dm
@@ -512,13 +512,14 @@
else if(transfer_amount) // Droppers, cans, beakers, what have you.
visi_msg="[user] uses [reagent_source] on [target]"
irrigate = 1
+ if(reagent_source.is_drainable())
+ playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE)
if(irrigate && transfer_amount > 30 && reagent_source.reagents.total_volume >= 30 && using_irrigation)
trays = FindConnected()
if (trays.len > 1)
visi_msg += ", setting off the irrigation system."
- playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE)
if(visi_msg)
visible_message("[visi_msg]")
@@ -528,15 +529,17 @@
for(var/obj/machinery/hydroponics/H in trays)
//cause I don't want to feel like im juggling 15 tamagotchis and I can get to my real work of ripping flooring apart in hopes of validating my life choices of becoming a space-gardener
- var/datum/reagents/S = new /datum/reagents() //This is a strange way, but I don't know of a better one so I can't fix it at the moment...
- S.my_atom = H
+ var/datum/reagents/S = new /datum/reagents //This is a strange way, but I don't know of a better one so I can't fix it at the moment...
reagent_source.reagents.trans_to(S,split)
if(istype(reagent_source, /obj/item/reagent_containers/food/snacks) || istype(reagent_source, /obj/item/reagent_containers/pill))
qdel(reagent_source)
- lastuser = user
- H.applyFertilizer(S, user)
- H.applyChemicals(S, user)
+ if(myseed)
+ myseed.on_chem_reaction(S)
+ lastuser = user
+ for(var/datum/reagent/R in S.reagent_list)
+ if(R.on_tray(H, R.volume, user) >= 1)
+ lastuser = user
S.clear_reagents()
qdel(S)
@@ -544,6 +547,7 @@
if(reagent_source) // If the source wasn't composted and destroyed
reagent_source.update_icon()
+
else if(istype(O, /obj/item/seeds) && !istype(O, /obj/item/seeds/sample))
if(!myseed)
if(istype(O, /obj/item/seeds/kudzu))
diff --git a/code/modules/integrated_electronics/subtypes/reagents.dm b/code/modules/integrated_electronics/subtypes/reagents.dm
index 0fc9f58d..bfa2532d 100644
--- a/code/modules/integrated_electronics/subtypes/reagents.dm
+++ b/code/modules/integrated_electronics/subtypes/reagents.dm
@@ -36,10 +36,11 @@
for(var/obj/machinery/hydroponics/H in trays)
var/datum/reagents/temp_reagents = new /datum/reagents()
- temp_reagents.my_atom = H
source.reagents.trans_to(temp_reagents, split)
- H.applyChemicals(temp_reagents)
+ for(var/datum/reagent/R in temp_reagents.reagent_list)
+ if(R.on_tray(H, R.volume, src) >= 1)
+ tray.lastuser = src
temp_reagents.clear_reagents()
qdel(temp_reagents)
diff --git a/code/modules/jobs/access.dm b/code/modules/jobs/access.dm
index 29234a2b..61960572 100644
--- a/code/modules/jobs/access.dm
+++ b/code/modules/jobs/access.dm
@@ -356,9 +356,9 @@
/proc/get_all_jobs()
return list("Assistant", "Captain", "Head of Personnel", "Bartender", "Cook", "Botanist", "Quartermaster", "Cargo Technician",
- "Shaft Miner", "Clown", "Mime", "Janitor", "Curator", "Lawyer", "Chaplain", "Chief Engineer", "Station Engineer",
- "Atmospheric Technician", "Chief Medical Officer", "Medical Doctor", "Chemist", "Geneticist", "Virologist",
- "Research Director", "Scientist", "Roboticist", "Head of Security", "Warden", "Detective", "Security Officer")
+ "Shaft Miner", "Clown", "Mime", "Janitor", "Curator", "Lawyer", "Chaplain", "Chief Engineer", "Station Engineer", "Engineering Intern",
+ "Atmospheric Technician", "Chief Medical Officer", "Medical Doctor", "Chemist", "Geneticist", "Virologist", "Medical Resident",
+ "Research Director", "Scientist", "Roboticist", "Research Student", "Head of Security", "Warden", "Detective", "Security Officer", "Rookie")
/proc/get_all_job_icons() //For all existing HUD icons
return get_all_jobs() + list("Prisoner")
diff --git a/code/modules/jobs/job_types/engineering.dm b/code/modules/jobs/job_types/engineering.dm
index 3514e7c8..ce36edcc 100644
--- a/code/modules/jobs/job_types/engineering.dm
+++ b/code/modules/jobs/job_types/engineering.dm
@@ -196,6 +196,7 @@ Junior Engineer
ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_TECH_STORAGE, ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_MAINT_TUNNELS,
ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM)
+ override_roundstart_spawn = /obj/effect/landmark/start/station_engineer
/datum/outfit/job/engineer/junior
name = "Engineering Intern"
@@ -228,9 +229,3 @@ Junior Engineer
suit_store = /obj/item/tank/internals/oxygen
head = null
internals_slot = SLOT_S_STORE
-
-/datum/job/junior_engineer/after_spawn(mob/living/carbon/human/H, mob/M) //Instead of going through the process of adding spawnpoints
- var/turf/T
- var/spawn_point = locate(/obj/effect/landmark/start/station_engineer) in GLOB.start_landmarks_list
- T = get_turf(spawn_point)
- H.Move(T)
\ No newline at end of file
diff --git a/code/modules/jobs/job_types/job.dm b/code/modules/jobs/job_types/job.dm
index c0a2aa00..3a8aa68b 100644
--- a/code/modules/jobs/job_types/job.dm
+++ b/code/modules/jobs/job_types/job.dm
@@ -61,6 +61,8 @@
var/list/alt_titles = list()
+ var/override_roundstart_spawn = null //Where the player spawns at roundstart if defined
+
//Only override this proc
//H is usually a human unless an /equip override transformed it
/datum/job/proc/after_spawn(mob/living/H, mob/M, latejoin = FALSE)
diff --git a/code/modules/jobs/job_types/medical.dm b/code/modules/jobs/job_types/medical.dm
index 0458ce89..9b07a2ad 100644
--- a/code/modules/jobs/job_types/medical.dm
+++ b/code/modules/jobs/job_types/medical.dm
@@ -243,6 +243,7 @@ Junior Doctor
access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM)
+ override_roundstart_spawn = /obj/effect/landmark/start/medical_doctor
/datum/outfit/job/doctor/junior
name = "Medical Resident"
@@ -261,9 +262,3 @@ Junior Doctor
duffelbag = /obj/item/storage/backpack/duffelbag/med
chameleon_extras = /obj/item/gun/syringe
-
-/datum/job/junior_doctor/after_spawn(mob/living/carbon/human/H, mob/M) //Instead of going through the process of adding spawnpoints
- var/turf/T
- var/spawn_point = locate(/obj/effect/landmark/start/medical_doctor) in GLOB.start_landmarks_list
- T = get_turf(spawn_point)
- H.Move(T)
\ No newline at end of file
diff --git a/code/modules/jobs/job_types/science.dm b/code/modules/jobs/job_types/science.dm
index 1cd36504..fd72fbfe 100644
--- a/code/modules/jobs/job_types/science.dm
+++ b/code/modules/jobs/job_types/science.dm
@@ -160,10 +160,11 @@ Junior Scientist
access = list(ACCESS_ROBOTICS, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE, ACCESS_GENETICS)
minimal_access = list(ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM)
+ override_roundstart_spawn = /obj/effect/landmark/start/scientist
/datum/outfit/job/scientist/junior
- name = "Scientist"
- jobtype = /datum/job/scientist
+ name = "Research Student"
+ jobtype = /datum/job/junior_scientist
belt = /obj/item/pda/toxins
ears = /obj/item/radio/headset/headset_sci
@@ -173,9 +174,3 @@ Junior Scientist
backpack = /obj/item/storage/backpack/science
satchel = /obj/item/storage/backpack/satchel/tox
-
-/datum/job/junior_scientist/after_spawn(mob/living/carbon/human/H, mob/M) //Instead of going through the process of adding spawnpoints
- var/turf/T
- var/spawn_point = locate(/obj/effect/landmark/start/scientist) in GLOB.start_landmarks_list
- T = get_turf(spawn_point)
- H.Move(T)
\ No newline at end of file
diff --git a/code/modules/jobs/job_types/security.dm b/code/modules/jobs/job_types/security.dm
index 4600fce9..2f828072 100644
--- a/code/modules/jobs/job_types/security.dm
+++ b/code/modules/jobs/job_types/security.dm
@@ -375,6 +375,7 @@ Junior Security Officer
mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/nonviolent, /datum/quirk/paraplegic)
+ override_roundstart_spawn = /obj/effect/landmark/start/security_officer
/datum/job/junior_officer/get_access()
@@ -461,8 +462,8 @@ Junior Security Officer
/datum/outfit/job/security/junior
- name = "Security Officer"
- jobtype = /datum/job/officer
+ name = "Rookie"
+ jobtype = /datum/job/junior_officer
belt = /obj/item/pda/security
ears = /obj/item/radio/headset/headset_sec/alt
diff --git a/code/modules/mob/dead/dead.dm b/code/modules/mob/dead/dead.dm
index 0c50cb04..ad65bf8e 100644
--- a/code/modules/mob/dead/dead.dm
+++ b/code/modules/mob/dead/dead.dm
@@ -17,7 +17,7 @@ INITIALIZE_IMMEDIATE(/mob/dead)
prepare_huds()
if(length(CONFIG_GET(keyed_list/cross_server)))
- verbs += /mob/dead/proc/server_hop
+ add_verb(src, /mob/dead/proc/server_hop)
set_focus(src)
return INITIALIZE_HINT_NORMAL
@@ -42,27 +42,26 @@ INITIALIZE_IMMEDIATE(/mob/dead)
loc = destination
Moved(oldloc, NONE, TRUE)
-/mob/dead/Stat()
- ..()
- if(!statpanel("Status"))
- return
- //stat(null, "Game Mode: [SSticker.hide_mode ? "Secret" : "[GLOB.master_mode]"]")
+/mob/dead/get_status_tab_items()
+ . = ..()
+ . += ""
+ //. += "Game Mode: [SSticker.hide_mode ? "Secret" : "[GLOB.master_mode]"]"
if(SSticker.HasRoundStarted())
return
var/time_remaining = SSticker.GetTimeLeft()
if(time_remaining > 0)
- stat(null, "Time To Start: [round(time_remaining/10)]s")
+ . += "Time To Start: [round(time_remaining/10)]s"
else if(time_remaining == -10)
- stat(null, "Time To Start: DELAYED")
+ . += "Time To Start: DELAYED"
else
- stat(null, "Time To Start: SOON")
+ . += "Time To Start: SOON"
- stat(null, "Players: [SSticker.totalPlayers]")
+ . += "Players: [SSticker.totalPlayers]"
if(client.holder)
- stat(null, "Players Ready: [SSticker.totalPlayersReady]")
+ . += "Players Ready: [SSticker.totalPlayersReady]"
/mob/dead/proc/server_hop()
set category = "OOC"
@@ -74,7 +73,7 @@ INITIALIZE_IMMEDIATE(/mob/dead)
var/pick
switch(csa.len)
if(0)
- verbs -= /mob/dead/proc/server_hop
+ remove_verb(src, /mob/dead/proc/server_hop)
to_chat(src, "Server Hop has been disabled.")
if(1)
pick = csa[0]
diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm
index ca660860..59347e77 100644
--- a/code/modules/mob/dead/new_player/new_player.dm
+++ b/code/modules/mob/dead/new_player/new_player.dm
@@ -303,6 +303,7 @@
if(observer.client && observer.client.prefs)
observer.real_name = observer.client.prefs.real_name
observer.name = observer.real_name
+ observer.client.init_verbs()
observer.update_icon()
observer.stop_sound_channel(CHANNEL_LOBBYMUSIC)
QDEL_NULL(mind)
@@ -397,6 +398,7 @@
character.update_parallax_teleport()
SSticker.minds += character.mind
+ character.client.init_verbs() // init verbs for the late join
var/mob/living/carbon/human/humanc
if(ishuman(character))
@@ -590,6 +592,7 @@
mind.transfer_to(H) //won't transfer key since the mind is not active
H.name = real_name
+ client.init_verbs()
//h13 assign your characters custom height.
if (H.custom_body_size) //Do they have it set?
H.resize(H.custom_body_size * 0.01)
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 541fb5e1..1c91b733 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -59,10 +59,10 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
/mob/dead/observer/Initialize()
set_invisibility(GLOB.observer_default_invisibility)
- verbs += list(
+ add_verb(src, list(
/mob/dead/observer/proc/dead_tele,
/mob/dead/observer/proc/open_spawners_menu,
- /mob/dead/observer/proc/view_gas)
+ /mob/dead/observer/proc/view_gas))
if(icon_state in GLOB.ghost_forms_with_directions_list)
ghostimage_default = image(src.icon,src,src.icon_state + "_nodir")
@@ -120,8 +120,8 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
real_name = name
if(!fun_verbs)
- verbs -= /mob/dead/observer/verb/boo
- verbs -= /mob/dead/observer/verb/possess
+ remove_verb(src, /mob/dead/observer/verb/boo)
+ remove_verb(src, /mob/dead/observer/verb/possess)
animate(src, pixel_y = 2, time = 10, loop = -1)
@@ -367,6 +367,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
client.change_view(CONFIG_GET(string/default_view))
SStgui.on_transfer(src, mind.current) // Transfer NanoUIs.
mind.current.key = key
+ mind.current.client.init_verbs()
return 1
/mob/dead/observer/proc/notify_cloning(var/message, var/sound, var/atom/source, flashwindow = TRUE)
@@ -777,11 +778,11 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
ghostimage_simple.icon_state = icon_state
if("fun_verbs")
if(fun_verbs)
- verbs += /mob/dead/observer/verb/boo
- verbs += /mob/dead/observer/verb/possess
+ add_verb(src, /mob/dead/observer/verb/boo)
+ add_verb(src, /mob/dead/observer/verb/possess)
else
- verbs -= /mob/dead/observer/verb/boo
- verbs -= /mob/dead/observer/verb/possess
+ remove_verb(src, /mob/dead/observer/verb/boo)
+ remove_verb(src, /mob/dead/observer/verb/possess)
/mob/dead/observer/reset_perspective(atom/A)
if(client)
diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm
index a5e55ea5..2fbf2575 100644
--- a/code/modules/mob/living/blood.dm
+++ b/code/modules/mob/living/blood.dm
@@ -44,7 +44,6 @@
//Blood regeneration if there is some space
if(blood_volume < (BLOOD_VOLUME_NORMAL * blood_ratio) && !HAS_TRAIT(src, TRAIT_NOHUNGER))
var/nutrition_ratio = 0
- //thirst_ratio = 1 //Uncomment if something fancy gets added
switch(nutrition)
if(0 to NUTRITION_LEVEL_STARVING)
nutrition_ratio = 0.2
@@ -61,7 +60,8 @@
if(satiety > 80)
nutrition_ratio *= 1.25
nutrition = max(0, nutrition - nutrition_ratio * HUNGER_FACTOR)
- thirst = max(0, thirst - 0.8 * THIRST_FACTOR)
+ if(!HAS_TRAIT(src, TRAIT_NOTHIRST))
+ thirst = max(0, thirst - THIRST_FACTOR) //After 2 seconds of research, I learned that you get quite thirsty when at low blood levels
blood_volume = min((BLOOD_VOLUME_NORMAL * blood_ratio), blood_volume + 0.5 * nutrition_ratio)
//Effects of bloodloss
diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm
index bd24a4b4..c9a504e2 100644
--- a/code/modules/mob/living/carbon/alien/alien.dm
+++ b/code/modules/mob/living/carbon/alien/alien.dm
@@ -26,8 +26,8 @@
var/static/regex/alien_name_regex = new("alien (larva|sentinel|drone|hunter|praetorian|queen)( \\(\\d+\\))?")
/mob/living/carbon/alien/Initialize()
- verbs += /mob/living/proc/mob_sleep
- verbs += /mob/living/proc/lay_down
+ add_verb(src, /mob/living/proc/mob_sleep)
+ add_verb(src, /mob/living/proc/lay_down)
create_bodyparts() //initialize bodyparts
@@ -86,11 +86,10 @@
/mob/living/carbon/alien/IsAdvancedToolUser()
return has_fine_manipulation
-/mob/living/carbon/alien/Stat()
- ..()
- if(statpanel("Status"))
- stat(null, "Intent: [a_intent]")
+/mob/living/carbon/alien/get_status_tab_items()
+ . = ..()
+ . += "Intent: [a_intent]"
/mob/living/carbon/alien/getTrail()
if(getBruteLoss() < 200)
diff --git a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
index 323bd408..509caf81 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
@@ -143,10 +143,10 @@ Doesn't work on other aliens/AI.*/
action_icon_state = "alien_acid"
/obj/effect/proc_holder/alien/acid/on_gain(mob/living/carbon/user)
- user.verbs.Add(/mob/living/carbon/proc/corrosive_acid)
+ add_verb(user, /mob/living/carbon/proc/corrosive_acid)
/obj/effect/proc_holder/alien/acid/on_lose(mob/living/carbon/user)
- user.verbs.Remove(/mob/living/carbon/proc/corrosive_acid)
+ remove_verb(user, /mob/living/carbon/proc/corrosive_acid)
/obj/effect/proc_holder/alien/acid/proc/corrode(atom/target,mob/living/carbon/user = usr)
if(target in oview(1,user))
diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm
index 3b150a22..9fdf7ab8 100644
--- a/code/modules/mob/living/carbon/alien/larva/larva.dm
+++ b/code/modules/mob/living/carbon/alien/larva/larva.dm
@@ -29,11 +29,9 @@
internal_organs += new /obj/item/organ/alien/plasmavessel/small/tiny
..()
-//This needs to be fixed
-/mob/living/carbon/alien/larva/Stat()
- ..()
- if(statpanel("Status"))
- stat(null, "Progress: [amount_grown]/[max_grown]")
+/mob/living/carbon/alien/larva/get_status_tab_items()
+ . = ..()
+ . += "Progress: [amount_grown]/[max_grown]"
/mob/living/carbon/alien/larva/adjustPlasma(amount)
if(stat != DEAD && amount > 0)
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 33214a0f..38d9b377 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -465,16 +465,18 @@
var/turf/target = get_turf(loc)
I.safe_throw_at(target,I.throw_range,I.throw_speed,src, force = move_force)
-/mob/living/carbon/Stat()
- ..()
- if(statpanel("Status"))
- var/obj/item/organ/alien/plasmavessel/vessel = getorgan(/obj/item/organ/alien/plasmavessel)
- if(vessel)
- stat(null, "Plasma Stored: [vessel.storedPlasma]/[vessel.max_plasma]")
- if(locate(/obj/item/assembly/health) in src)
- stat(null, "Health: [health]")
- add_abilities_to_panel()
+/mob/living/carbon/get_status_tab_items()
+ . = ..()
+ var/obj/item/organ/alien/plasmavessel/vessel = getorgan(/obj/item/organ/alien/plasmavessel)
+ if(vessel)
+ . += "Plasma Stored: [vessel.storedPlasma]/[vessel.max_plasma]"
+ if(locate(/obj/item/assembly/health) in src)
+ . += "Health: [health]"
+
+/mob/living/carbon/get_proc_holders()
+ . = ..()
+ . += add_abilities_to_panel()
/mob/living/carbon/attack_ui(slot)
if(!has_hand_for_held_index(active_hand_index))
@@ -995,4 +997,4 @@
/mob/living/carbon/transfer_ckey(mob/new_mob, send_signal = TRUE)
if(combatmode)
toggle_combat_mode(TRUE, TRUE)
- return ..()
+ return ..()
diff --git a/code/modules/mob/living/carbon/carbon_movement.dm b/code/modules/mob/living/carbon/carbon_movement.dm
index fcf85505..e93e4871 100644
--- a/code/modules/mob/living/carbon/carbon_movement.dm
+++ b/code/modules/mob/living/carbon/carbon_movement.dm
@@ -41,7 +41,12 @@
nutrition = NUTRITION_LEVEL_FED - 1 //just less than feeling vigorous
else if(nutrition && stat != DEAD)
nutrition -= HUNGER_FACTOR/12
- thirst -= THIRST_FACTOR/12
if(m_intent == MOVE_INTENT_RUN)
nutrition -= HUNGER_FACTOR/5
+
+ if(HAS_TRAIT(src, TRAIT_NOTHIRST))
+ thirst = THIRST_LEVEL_QUENCHED - 1
+ else if(thirst && stat != DEAD)
+ thirst -= THIRST_FACTOR/12
+ if(m_intent == MOVE_INTENT_RUN)
thirst -= THIRST_FACTOR/5
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index b8b62a8b..58264160 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -6,9 +6,8 @@
appearance_flags = KEEP_TOGETHER|TILE_BOUND|PIXEL_SCALE|LONG_GLIDE
/mob/living/carbon/human/Initialize()
- verbs += /mob/living/proc/mob_sleep
- verbs += /mob/living/proc/lay_down
- verbs += /mob/living/carbon/human/proc/underwear_toggle //fwee
+ add_verb(src, /mob/living/proc/mob_sleep)
+ add_verb(src, /mob/living/proc/lay_down)
time_initialized = world.time
//initialize limbs first
@@ -62,58 +61,52 @@
add_to_all_human_data_huds()
-/mob/living/carbon/human/Stat()
- ..()
- //Same thing from mob
- if(statpanel("Status"))
- if(tickrefresh == 1)
- sList2 = list()
- sList2 += "Intent: [a_intent]"
- sList2 += "Move Mode: [m_intent]"
- if (internal)
- if (!internal.air_contents)
- qdel(internal)
- else
- sList2 += "Internal Atmosphere Info: "+ "[internal.name]"
- sList2 += "Tank Pressure: "+ "[internal.air_contents.return_pressure()]"
- sList2 += "Distribution Pressure: "+ "[internal.distribute_pressure]"
- if(mind)
- var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
- if(changeling)
- sList2 += "Chemical Storage: " + "[changeling.chem_charges]/[changeling.chem_storage]"
- sList2 += "Absorbed DNA: "+ "[changeling.absorbedcount]"
- if (sList2 != null)
- stat(null, "[sList2.Join("\n\n")]")
+/mob/living/carbon/human/get_status_tab_items()
+ . = ..()
+ . += "Intent: [a_intent]"
+ . += "Move Mode: [m_intent]"
+ if (internal)
+ if (!internal.air_contents)
+ qdel(internal)
+ else
+ . += ""
+ . += "Internal Atmosphere Info: [internal.name]"
+ . += "Tank Pressure: [internal.air_contents.return_pressure()]"
+ . += "Distribution Pressure: [internal.distribute_pressure]"
+ if(mind)
+ var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
+ if(changeling)
+ . += ""
+ . += "Chemical Storage: [changeling.chem_charges]/[changeling.chem_storage]"
+ . += "Absorbed DNA: [changeling.absorbedcount]"
//NINJACODE
if(istype(wear_suit, /obj/item/clothing/suit/space/space_ninja)) //Only display if actually a ninja.
var/obj/item/clothing/suit/space/space_ninja/SN = wear_suit
- if(statpanel("SpiderOS"))
- stat("SpiderOS Status:","[SN.s_initialized ? "Initialized" : "Disabled"]")
- stat("Current Time:", "[STATION_TIME_TIMESTAMP("hh:mm:ss")]")
- if(SN.s_initialized)
- //Suit gear
- stat("Energy Charge:", "[round(SN.cell.charge/100)]%")
- stat("Smoke Bombs:", "\Roman [SN.s_bombs]")
- //Ninja status
- stat("Fingerprints:", "[md5(dna.uni_identity)]")
- stat("Unique Identity:", "[dna.unique_enzymes]")
- stat("Overall Status:", "[stat > 1 ? "dead" : "[health]% healthy"]")
- stat("Nutrition Status:", "[nutrition]")
- stat("Hydration Status:", "[thirst]")
- stat("Oxygen Loss:", "[getOxyLoss()]")
- stat("Toxin Levels:", "[getToxLoss()]")
- stat("Burn Severity:", "[getFireLoss()]")
- stat("Brute Trauma:", "[getBruteLoss()]")
- stat("Radiation Levels:","[radiation] rad")
- stat("Body Temperature:","[bodytemperature-T0C] degrees C ([bodytemperature*1.8-459.67] degrees F)")
+ . += "SpiderOS Status: [SN.s_initialized ? "Initialized" : "Disabled"]"
+ . += "Current Time: [station_time_timestamp()]"
+ if(SN.s_initialized)
+ //Suit gear
+ . += "Energy Charge: [round(SN.cell.charge/100)]%"
+ . += "Smoke Bombs: \Roman [SN.s_bombs]"
+ //Ninja status
+ . += "Fingerprints: [md5(dna.uni_identity)]"
+ . += "Unique Identity: [dna.unique_enzymes]"
+ . += "Overall Status: [stat > 1 ? "dead" : "[health]% healthy"]"
+ . += "Nutrition Status: [nutrition]"
+ . += "Oxygen Loss: [getOxyLoss()]"
+ . += "Toxin Levels: [getToxLoss()]"
+ . += "Burn Severity: [getFireLoss()]"
+ . += "Brute Trauma: [getBruteLoss()]"
+ . += "Radiation Levels: [radiation] rad"
+ . += "Body Temperature: [bodytemperature-T0C] degrees C ([bodytemperature*1.8-459.67] degrees F)"
- //Diseases
- if(diseases.len)
- stat("Viruses:", null)
- for(var/thing in diseases)
- var/datum/disease/D = thing
- stat("*", "[D.name], Type: [D.spread_text], Stage: [D.stage]/[D.max_stages], Possible Cure: [D.cure_text]")
+ //Diseases
+ if(length(diseases))
+ . += "Viruses:"
+ for(var/thing in diseases)
+ var/datum/disease/D = thing
+ . += "* [D.name], Type: [D.spread_text], Stage: [D.stage]/[D.max_stages], Possible Cure: [D.cure_text]"
/mob/living/carbon/human/show_inv(mob/user)
diff --git a/code/modules/mob/living/carbon/human/species_types/abductors.dm b/code/modules/mob/living/carbon/human/species_types/abductors.dm
index ffd129eb..f6e78530 100644
--- a/code/modules/mob/living/carbon/human/species_types/abductors.dm
+++ b/code/modules/mob/living/carbon/human/species_types/abductors.dm
@@ -4,7 +4,7 @@
say_mod = "gibbers"
sexes = FALSE
species_traits = list(NOBLOOD,NOEYES,NOGENITALS,NOAROUSAL)
- inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NOGUNS,TRAIT_NOHUNGER,TRAIT_NOBREATH)
+ inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NOGUNS,TRAIT_NOHUNGER,TRAIT_NOTHIRST,TRAIT_NOBREATH)
mutanttongue = /obj/item/organ/tongue/abductor
/datum/species/abductor/on_species_gain(mob/living/carbon/C, datum/species/old_species)
diff --git a/code/modules/mob/living/carbon/human/species_types/android.dm b/code/modules/mob/living/carbon/human/species_types/android.dm
index 0f522b55..81f2acad 100644
--- a/code/modules/mob/living/carbon/human/species_types/android.dm
+++ b/code/modules/mob/living/carbon/human/species_types/android.dm
@@ -3,7 +3,7 @@
id = "android"
say_mod = "states"
species_traits = list(NOBLOOD,NOGENITALS,NOAROUSAL)
- inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_NOFIRE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_LIMBATTACHMENT)
+ inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_NOFIRE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_NOTHIRST,TRAIT_LIMBATTACHMENT)
inherent_biotypes = list(MOB_ROBOTIC, MOB_HUMANOID)
meat = null
gib_types = /obj/effect/gibspawner/robot
diff --git a/code/modules/mob/living/carbon/human/species_types/corporate.dm b/code/modules/mob/living/carbon/human/species_types/corporate.dm
index 3de530ff..a733c248 100644
--- a/code/modules/mob/living/carbon/human/species_types/corporate.dm
+++ b/code/modules/mob/living/carbon/human/species_types/corporate.dm
@@ -16,6 +16,6 @@
blacklisted = 1
use_skintones = 0
species_traits = list(NOBLOOD,EYECOLOR,NOGENITALS)
- inherent_traits = list(TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOLIMBDISABLE,TRAIT_NOHUNGER)
+ inherent_traits = list(TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOLIMBDISABLE,TRAIT_NOHUNGER,TRAIT_NOTHIRST)
sexes = 0
gib_types = /obj/effect/gibspawner/robot
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/species_types/dullahan.dm b/code/modules/mob/living/carbon/human/species_types/dullahan.dm
index 5b2ad6e5..103f724e 100644
--- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm
+++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm
@@ -3,7 +3,7 @@
id = "dullahan"
default_color = "FFFFFF"
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS)
- inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH)
+ inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOTHIRST,TRAIT_NOBREATH)
default_features = list("mcolor" = "FFF", "tail_human" = "None", "ears" = "None", "wings" = "None")
use_skintones = TRUE
mutant_brain = /obj/item/organ/brain/dullahan
diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index c482b6df..2abbf50b 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -293,9 +293,7 @@
if(isturf(H.loc)) //else, there's considered to be no light
var/turf/T = H.loc
light_amount = min(1,T.get_lumcount()) - 0.5
- H.nutrition += light_amount * 10
- if(H.nutrition > NUTRITION_LEVEL_FULL)
- H.nutrition = NUTRITION_LEVEL_FULL
+ H.nutrition = min(H.nutrition + light_amount * 10, NUTRITION_LEVEL_FULL)
if(light_amount > 0.2) //if there's enough light, heal
H.heal_overall_damage(1,1)
H.adjustToxLoss(-1)
diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
index 6601d55f..aa46399a 100644
--- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
@@ -5,7 +5,7 @@
sexes = 0
meat = /obj/item/stack/sheet/mineral/plasma
species_traits = list(NOBLOOD,NOTRANSSTING)
- inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_RADIMMUNE,TRAIT_NOHUNGER)
+ inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_RADIMMUNE,TRAIT_NOHUNGER,TRAIT_NOTHIRST)
inherent_biotypes = list(MOB_INORGANIC, MOB_HUMANOID)
mutantlungs = /obj/item/organ/lungs/plasmaman
mutanttongue = /obj/item/organ/tongue/bone/plasmaman
diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
index dcf26b70..786357dd 100644
--- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
@@ -35,9 +35,7 @@
if(isturf(H.loc)) //else, there's considered to be no light
var/turf/T = H.loc
light_amount = min(1,T.get_lumcount()) - 0.5
- H.nutrition += light_amount * light_nutrition_gain_factor
- if(H.nutrition > NUTRITION_LEVEL_FULL)
- H.nutrition = NUTRITION_LEVEL_FULL
+ H.nutrition = min(H.nutrition + light_amount * light_nutrition_gain_factor, NUTRITION_LEVEL_FULL)
if(light_amount > 0.2) //if there's enough light, heal
H.heal_overall_damage(light_bruteheal, light_burnheal)
H.adjustToxLoss(-light_toxheal)
diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
index 3c716fa1..0fc134ec 100644
--- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
@@ -39,7 +39,7 @@
blacklisted = TRUE
no_equip = list(SLOT_WEAR_MASK, SLOT_WEAR_SUIT, SLOT_GLOVES, SLOT_SHOES, SLOT_W_UNIFORM, SLOT_S_STORE)
species_traits = list(NOBLOOD,NO_UNDERWEAR,NO_DNA_COPY,NOTRANSSTING,NOEYES,NOGENITALS,NOAROUSAL)
- inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_NOBREATH,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER)
+ inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_NOBREATH,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOTHIRST)
mutanteyes = /obj/item/organ/eyes/night_vision/nightmare
mutant_organs = list(/obj/item/organ/heart/nightmare)
mutant_brain = /obj/item/organ/brain/nightmare
@@ -183,9 +183,14 @@
. = ..()
if(!proximity)
return
- if(isopenturf(AM)) //So you can actually melee with it
+ if(isopenturf(AM) && !istype(AM, /turf/open/space) && !istype(AM, /turf/open/lava))
+ var/turf/T = AM
+ if(T.light_power || T.light_range)
+ to_chat(user, "[src] consumes the lights in [AM].")
+ T.set_light(0,0)
+ else if(isopenturf(AM))
return
- if(isliving(AM))
+ else if(isliving(AM))
var/mob/living/L = AM
if(iscyborg(AM))
var/mob/living/silicon/robot/borg = AM
@@ -194,20 +199,40 @@
to_chat(borg, "Your headlamp is fried! You'll need a human to help replace it.")
else
for(var/obj/item/O in AM)
- if(O.light_range && O.light_power)
- disintegrate(O)
- if(L.pulling && L.pulling.light_range && isitem(L.pulling))
- disintegrate(L.pulling)
+ if(O.light_range && O.light_power && !check_plasmaman(O, AM))
+ disintegrate(O, user)
+ if(L.pulling && L.pulling.light_range && isitem(L.pulling) && !check_plasmaman(L.pulling, L))
+ disintegrate(L.pulling, user)
else if(isitem(AM))
var/obj/item/I = AM
- if(I.light_range && I.light_power)
- disintegrate(I)
+ if(I.light_range && I.light_power && !check_plasmaman(AM))
+ disintegrate(I, user)
else if(istype(AM, /obj/structure/marker_beacon))
var/obj/structure/marker_beacon/I = AM
- disintegrate(I)
+ disintegrate(I, user)
//why the fuck is the marker beacon a structure? who. what. why.
+ else if(istype(AM, /obj/machinery/light))
+ var/obj/machinery/light/L = AM
+ if(L.status == 2) //Assume we just broke the light
+ handle_objectives(user)
+ L.status = 1 //No tube
+ L.update(FALSE)
-/obj/item/light_eater/proc/disintegrate(obj/item/O)
+/obj/item/light_eater/proc/handle_objectives(mob/living/carbon/human/H)
+ if(!H.mind)
+ return
+
+ if(!H.mind.objectives)
+ return
+
+ for(var/O in H.mind.objectives)
+ if(!istype(O, /datum/objective/break_lights))
+ continue
+ var/datum/objective/break_lights/BL = O
+ if(!BL.mode)
+ BL.lightsbroken++
+
+/obj/item/light_eater/proc/disintegrate(obj/item/O, user)
if(istype(O, /obj/item/pda))
var/obj/item/pda/PDA = O
PDA.set_light(0)
@@ -220,5 +245,21 @@
O.burn()
playsound(src, 'sound/items/welder.ogg', 50, 1)
+ if(is_species(user, /datum/species/shadow/nightmare))
+ handle_objectives(user)
+
+/obj/item/light_eater/proc/check_plasmaman(obj/item/O, mob/living/carbon/human/user)
+ if(!istype(O, /obj/item/clothing/head/helmet/space/plasmaman))
+ return FALSE
+ var/obj/item/clothing/head/helmet/space/plasmaman/H = O
+ if(H.on)
+ H.on = FALSE
+ H.icon_state = "[initial(H.icon_state)][H.on ? "-light":""]"
+ H.item_state = H.icon_state
+ if(user)
+ user.update_inv_head()
+ to_chat(user, "Your [H]'s torch extinguishes!")
+ return TRUE
+
#undef HEART_SPECIAL_SHADOWIFY
#undef HEART_RESPAWN_THRESHHOLD
diff --git a/code/modules/mob/living/carbon/human/species_types/skeletons.dm b/code/modules/mob/living/carbon/human/species_types/skeletons.dm
index 7d739990..d8a186fc 100644
--- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm
+++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm
@@ -7,7 +7,7 @@
sexes = 0
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/skeleton
species_traits = list(NOBLOOD,NOGENITALS,NOAROUSAL)
- inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER)
+ inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_NOTHIRST,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER)
inherent_biotypes = list(MOB_UNDEAD, MOB_HUMANOID)
mutanttongue = /obj/item/organ/tongue/bone
damage_overlay_type = ""//let's not show bloody wounds or burns over bones.
@@ -24,7 +24,7 @@
id = "spaceskeleton"
limbs_id = "skeleton"
blacklisted = 1
- inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER)
+ inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_NOTHIRST,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER)
/datum/species/skeleton/pirate/check_roundstart_eligible()
return FALSE
diff --git a/code/modules/mob/living/carbon/human/species_types/synths.dm b/code/modules/mob/living/carbon/human/species_types/synths.dm
index 703fffa4..b379da2e 100644
--- a/code/modules/mob/living/carbon/human/species_types/synths.dm
+++ b/code/modules/mob/living/carbon/human/species_types/synths.dm
@@ -4,7 +4,7 @@
say_mod = "beep boops" //inherited from a user's real species
sexes = 0
species_traits = list(NOTRANSSTING,NOGENITALS,NOAROUSAL) //all of these + whatever we inherit from the real species
- inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOBREATH)
+ inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOTHIRST,TRAIT_NOBREATH)
inherent_biotypes = list(MOB_ROBOTIC, MOB_HUMANOID)
dangerous_existence = 1
blacklisted = 1
@@ -13,7 +13,7 @@
damage_overlay_type = "synth"
limbs_id = "synth"
var/list/initial_species_traits = list(NOTRANSSTING) //for getting these values back for assume_disguise()
- var/list/initial_inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOLIMBDISABLE,TRAIT_NOBREATH)
+ var/list/initial_inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOTHIRST,TRAIT_NOLIMBDISABLE,TRAIT_NOBREATH)
var/disguise_fail_health = 75 //When their health gets to this level their synthflesh partially falls off
var/datum/species/fake_species = null //a species to do most of our work for us, unless we're damaged
diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm
index 43940362..611ba7f4 100644
--- a/code/modules/mob/living/carbon/human/species_types/vampire.dm
+++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm
@@ -3,7 +3,7 @@
id = "vampire"
default_color = "FFFFFF"
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,DRINKSBLOOD)
- inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH)
+ inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOTHIRST,TRAIT_NOBREATH)
inherent_biotypes = list(MOB_UNDEAD, MOB_HUMANOID)
default_features = list("mcolor" = "FFF", "tail_human" = "None", "ears" = "None", "wings" = "None")
exotic_bloodtype = "U"
diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm
index a287c569..7aa89392 100644
--- a/code/modules/mob/living/carbon/monkey/monkey.dm
+++ b/code/modules/mob/living/carbon/monkey/monkey.dm
@@ -17,8 +17,8 @@
hud_type = /datum/hud/monkey
/mob/living/carbon/monkey/Initialize(mapload, cubespawned=FALSE, mob/spawner)
- verbs += /mob/living/proc/mob_sleep
- verbs += /mob/living/proc/lay_down
+ add_verb(src, /mob/living/proc/mob_sleep)
+ add_verb(src, /mob/living/proc/lay_down)
if(unique_name) //used to exclude pun pun
gender = pick(MALE, FEMALE)
@@ -89,16 +89,16 @@
return
add_movespeed_modifier(MOVESPEED_ID_MONKEY_TEMPERATURE_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = amount)
-/mob/living/carbon/monkey/Stat()
- ..()
- if(statpanel("Status"))
- stat(null, "Intent: [a_intent]")
- stat(null, "Move Mode: [m_intent]")
- if(client && mind)
- var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
- if(changeling)
- stat("Chemical Storage", "[changeling.chem_charges]/[changeling.chem_storage]")
- stat("Absorbed DNA", changeling.absorbedcount)
+/mob/living/carbon/monkey/get_status_tab_items()
+ . = ..()
+ . += "Intent: [a_intent]"
+ . += "Move Mode: [m_intent]"
+ if(client && mind)
+ var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
+ if(changeling)
+ . += ""
+ . += "Chemical Storage: [changeling.chem_charges]/[changeling.chem_storage]"
+ . += "Absorbed DNA: [changeling.absorbedcount]"
return
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 9832e3b2..affafe34 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -516,6 +516,7 @@
SetSleeping(0, FALSE)
radiation = 0
nutrition = NUTRITION_LEVEL_FED + 50
+ thirst = THIRST_LEVEL_QUENCHED + 50
bodytemperature = BODYTEMP_NORMAL
set_blindness(0)
set_blurriness(0)
@@ -1104,8 +1105,10 @@
A.action.Remove(src)
/mob/living/proc/add_abilities_to_panel()
+ var/list/L = list()
for(var/obj/effect/proc_holder/A in abilities)
- statpanel("[A.panel]",A.get_panel_text(),A)
+ L[++L.len] = list("[A.panel]",A.get_panel_text(),A.name,"[REF(A)]")
+ return L
/mob/living/lingcheck()
if(mind)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index efc714f2..04d241d2 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -137,7 +137,7 @@
spark_system.set_up(5, 0, src)
spark_system.attach(src)
- verbs += /mob/living/silicon/ai/proc/show_laws_verb
+ add_verb(src, /mob/living/silicon/ai/proc/show_laws_verb)
aiPDA = new/obj/item/pda/ai(src)
aiPDA.owner = name
@@ -151,10 +151,10 @@
deploy_action.Grant(src)
if(isturf(loc))
- verbs.Add(/mob/living/silicon/ai/proc/ai_network_change, \
+ add_verb(src, list(/mob/living/silicon/ai/proc/ai_network_change, \
/mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \
/mob/living/silicon/ai/proc/botcall, /mob/living/silicon/ai/proc/control_integrated_radio, \
- /mob/living/silicon/ai/proc/set_automatic_say_channel)
+ /mob/living/silicon/ai/proc/set_automatic_say_channel))
GLOB.ai_list += src
GLOB.shuttle_caller_list += src
@@ -205,26 +205,26 @@
display_icon_override = ai_core_icon
set_core_display_icon(ai_core_icon)
-/mob/living/silicon/ai/Stat()
- ..()
- if(statpanel("Status"))
- if(!stat)
- stat(null, text("System integrity: [(health+100)/2]%"))
- stat(null, text("Connected cyborgs: [connected_robots.len]"))
- for(var/mob/living/silicon/robot/R in connected_robots)
- var/robot_status = "Nominal"
- if(R.shell)
- robot_status = "AI SHELL"
- else if(R.stat || !R.client)
- robot_status = "OFFLINE"
- else if(!R.cell || R.cell.charge <= 0)
- robot_status = "DEPOWERED"
- //Name, Health, Battery, Module, Area, and Status! Everything an AI wants to know about its borgies!
- stat(null, text("[R.name] | S.Integrity: [R.health]% | Cell: [R.cell ? "[R.cell.charge]/[R.cell.maxcharge]" : "Empty"] | \
- Module: [R.designation] | Loc: [get_area_name(R, TRUE)] | Status: [robot_status]"))
- stat(null, text("AI shell beacons detected: [LAZYLEN(GLOB.available_ai_shells)]")) //Count of total AI shells
- else
- stat(null, text("Systems nonfunctional"))
+/mob/living/silicon/ai/get_status_tab_items()
+ . = ..()
+ if(stat != CONSCIOUS)
+ . += text("Systems nonfunctional")
+ return
+ . += text("System integrity: [(health + 100) * 0.5]%")
+ . += text("Connected cyborgs: [length(connected_robots)]")
+ for(var/r in connected_robots)
+ var/mob/living/silicon/robot/connected_robot = r
+ var/robot_status = "Nominal"
+ if(connected_robot.shell)
+ robot_status = "AI SHELL"
+ else if(connected_robot.stat != CONSCIOUS || !connected_robot.client)
+ robot_status = "OFFLINE"
+ else if(!connected_robot.cell || connected_robot.cell.charge <= 0)
+ robot_status = "DEPOWERED"
+ //Name, Health, Battery, Module, Area, and Status! Everything an AI wants to know about its borgies!
+ . += text("[connected_robot.name] | S.Integrity: [connected_robot.health]% | Cell: [connected_robot.cell ? "[connected_robot.cell.charge]/[connected_robot.cell.maxcharge]" : "Empty"] | \
+ Module: [connected_robot.designation] | Loc: [get_area_name(connected_robot, TRUE)] | Status: [robot_status]")
+ . += text("AI shell beacons detected: [LAZYLEN(GLOB.available_ai_shells)]") //Count of total AI shells
/mob/living/silicon/ai/proc/ai_alerts()
var/dat = "