diff --git a/code/__DEFINES/maths.dm b/code/__DEFINES/maths.dm
index b6d1b771a..cfb90f13f 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 000000000..642ca3eab
--- /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 b9c0544bc..10d586dca 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 f4e0c316e..f2ef56387 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 05c93878c..ec1abadd6 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 000000000..60dcaedaf
--- /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 46ae8e395..c04a98a4c 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 2cd0ddeda..31ea453d4 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 5a3cca967..ba69f4b60 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 06547d120..90f0976f5 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 3ce770b66..a260ed4ec 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 a085b2641..6b5fb294e 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 125da84a3..76a3b1eb5 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 4fe0812c5..d9d818acf 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 e3c415960..21fb43490 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 8395eda70..ccbf8ffc6 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 1b1c7bc3b..53c86004a 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 9be1d8d90..4fe5533e1 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 db6dc6513..6ac42f8c0 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 f8ca1e7ea..328818fd6 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 8992fa7b9..03b7931d8 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 9048d77b1..3d525e055 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 12b467b62..7eff66eb4 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 c4b09d1b8..04b654108 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 aac9f9d3d..1e8efff01 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 7fd351244..5e8fc1f5e 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 20eb2af00..f8f7a16bc 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 c5d6dfa12..637b04993 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 f23f41b79..b6cec58b2 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 000000000..b6fa8c536
--- /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 dacbac409..9fc689ff9 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 908b8944c..b491cc3c2 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 810882ff7..0f4b34f42 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 d0eb0b9ce..90ee4b48a 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 c4ed00313..84a56aced 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 0e4e9319f..8712851a6 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 f68e189ab..ec69fdb90 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 5e0d0d77d..1ab1dd5cc 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 d3c530cb2..04314dd77 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 c5946719d..bcdee7911 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 72655cde3..17dad5256 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 3ff2424d8..5c9d50760 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 bb53f6861..1ea8b361d 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 a4f286bf8..946b3cac9 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 bc32b158c..466caf933 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 5b4a4386a..811d5f241 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 013883fe6..7121aaac0 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 0ab823e20..3a24d7aa7 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 f9bed188f..04c1909c4 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 41496b358..3e83974d6 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 b24ce6d1f..256bdaf01 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 c0445d588..1a5c7d335 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 699b2d50b..8450793f8 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 3a0b1e979..bb005a6b2 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 445de4c40..ee4d12656 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 01882821a..57ae1d4c7 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 5cb4faa86..b3d5d683f 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 7b30d10c5..812f7c4ab 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 e824c5c9c..ff935f32b 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 41a3f181d..847ceeb61 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 000000000..dbcadc5e6
--- /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 f4418a622..2fa4952a9 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 9f663fc55..02ddf315c 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 0d9b2a642..9fd0850f9 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 505b9a1ed..f13341faf 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 fd5c711b8..44eb0ad52 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 531708057..792e40adb 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 23bfebb2c..04b714f11 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 f806e5c96..ad8e5ef0b 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 1465a0c90..087c434b8 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 120e690c4..23d1d6860 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 b941a978d..a32532d12 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 d5366c576..c288953ef 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 473267fcd..f807a4915 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 b0821ae37..000000000
--- 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 d2cc76d99..c7bed07ab 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 0fc9f58db..bfa2532d3 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 29234a2b8..619605725 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 3514e7c87..ce36edcc3 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 c0a2aa00d..3a8aa68ba 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 0458ce89b..9b07a2ad3 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 1cd365046..fd72fbfe2 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 4600fce91..2f8280722 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 0c50cb046..ad65bf8e1 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 ca6608608..59347e772 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 541fb5e17..1c91b733b 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 a5e55ea54..2fbf2575b 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 bd24a4b4c..c9a504e20 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 323bd408c..509caf81a 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 3b150a226..9fdf7ab86 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 33214a0fe..38d9b3772 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 fcf855056..e93e4871b 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 b8b62a8b0..58264160e 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 ffd129ebf..f6e785309 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 0f522b552..81f2acadc 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 3de530ff5..a733c248a 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 5b2ad6e5e..103f724ea 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 c482b6df5..2abbf50b3 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 6601d55f2..aa46399a7 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 dcf26b70b..786357dd5 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 3c716fa12..0fc134ec0 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 7d7399903..d8a186fce 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 703fffa4d..b379da2e5 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 43940362e..611ba7f4c 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 a287c5697..7aa89392a 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 9832e3b28..affafe346 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 efc714f24..04d241d2b 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 = "