diff --git a/code/__DEFINES/maths.dm b/code/__DEFINES/maths.dm index b6d1b771..cfb90f13 100644 --- a/code/__DEFINES/maths.dm +++ b/code/__DEFINES/maths.dm @@ -217,3 +217,12 @@ #define RULE_OF_THREE(a, b, x) ((a*x)/b) // ) + +#define MANHATTAN_DISTANCE(a, b) (abs(a.x - b.x) + abs(a.y - b.y)) + +#define LOGISTIC_FUNCTION(L,k,x,x_0) (L/(1+(NUM_E**(-k*(x-x_0))))) + +/// Make sure something is a boolean TRUE/FALSE 1/0 value, since things like bitfield & bitflag doesn't always give 1s and 0s. +#define FORCE_BOOLEAN(x) ((x)? TRUE : FALSE) + +#define TILES_TO_PIXELS(tiles) (tiles * PIXELS) diff --git a/code/__DEFINES/procpath.dm b/code/__DEFINES/procpath.dm new file mode 100644 index 00000000..642ca3ea --- /dev/null +++ b/code/__DEFINES/procpath.dm @@ -0,0 +1,26 @@ +/// Represents a proc or verb path. +/// +/// Despite having no DM-defined static type, proc paths have some variables, +/// listed below. These are not modifiable, but for a given procpath P, +/// `new P(null, "Name", "Desc")` can be used to create a new procpath with the +/// same code but new `name` and `desc` values. The other variables cannot be +/// changed in this way. +/// +/// This type exists only to act as an annotation, providing reasonable static +/// typing for procpaths. Previously, types like `/atom/verb` were used, with +/// the `name` and `desc` vars of `/atom` thus being accessible. Proc and verb +/// paths will fail `istype` and `ispath` checks against `/procpath`. +/procpath + // Although these variables are effectively const, if they are marked const + // below, their accesses are optimized away. + + /// A text string of the verb's name. + var/name as text + /// The verb's help text or description. + var/desc as text + /// The category or tab the verb will appear in. + var/category as text + /// Only clients/mobs with `see_invisibility` higher can use the verb. + var/invisibility as num + /// Whether or not the verb appears in statpanel and commandbar when you press space + var/hidden as num diff --git a/code/__DEFINES/spaceman_dmm.dm b/code/__DEFINES/spaceman_dmm.dm index b9c0544b..10d586dc 100644 --- a/code/__DEFINES/spaceman_dmm.dm +++ b/code/__DEFINES/spaceman_dmm.dm @@ -6,10 +6,14 @@ #define RETURN_TYPE(X) set SpacemanDMM_return_type = X #define SHOULD_CALL_PARENT(X) set SpacemanDMM_should_call_parent = X #define UNLINT(X) SpacemanDMM_unlint(X) + #define SHOULD_NOT_OVERRIDE(X) set SpacemanDMM_should_not_override = X + #define SHOULD_NOT_SLEEP(X) set SpacemanDMM_should_not_sleep = X #else #define RETURN_TYPE(X) #define SHOULD_CALL_PARENT(X) #define UNLINT(X) X + #define SHOULD_NOT_OVERRIDE(X) + #define SHOULD_NOT_SLEEP(X) #endif /world/proc/enable_debugger() diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index f4e0c316..f2ef5638 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -84,6 +84,7 @@ #define INIT_ORDER_MINOR_MAPPING -40 #define INIT_ORDER_PATH -50 #define INIT_ORDER_PERSISTENCE -95 +#define INIT_ORDER_STATPANELS -98 #define INIT_ORDER_CHAT -100 //Should be last to ensure chat remains smooth during init. // Subsystem fire priority, from lowest to highest priority diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index 05c93878..ec1abadd 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -337,7 +337,7 @@ if(!previous) var/list/report_parts = list(personal_report(C), GLOB.common_report) content = report_parts.Join() - C.verbs -= /client/proc/show_previous_roundend_report + remove_verb(C, /client/proc/show_previous_roundend_report) fdel(filename) text2file(content, filename) else diff --git a/code/__HELPERS/verbs.dm b/code/__HELPERS/verbs.dm new file mode 100644 index 00000000..60dcaeda --- /dev/null +++ b/code/__HELPERS/verbs.dm @@ -0,0 +1,96 @@ +/** + * handles adding verbs and updating the stat panel browser + * + * pass the verb type path to this instead of adding it directly to verbs so the statpanel can update + * Arguments: + * * target - Who the verb is being added to, client or mob typepath + * * verb - typepath to a verb, or a list of verbs, supports lists of lists + */ +/proc/add_verb(client/target, verb_or_list_to_add) + if(!target) + CRASH("add_verb called without a target") + if(IsAdminAdvancedProcCall()) + return + var/mob/mob_target = null + + if(ismob(target)) + mob_target = target + target = mob_target.client + else if(!istype(target, /client)) + CRASH("add_verb called on a non-mob and non-client") + var/list/verbs_list = list() + if(!islist(verb_or_list_to_add)) + verbs_list += verb_or_list_to_add + else + var/list/verb_listref = verb_or_list_to_add + var/list/elements_to_process = verb_listref.Copy() + while(length(elements_to_process)) + var/element_or_list = elements_to_process[length(elements_to_process)] //Last element + elements_to_process.len-- + if(islist(element_or_list)) + elements_to_process += element_or_list //list/a += list/b adds the contents of b into a, not the reference to the list itself + else + verbs_list += element_or_list + + if(mob_target) + mob_target.verbs += verbs_list + if(!target) + return //Our work is done. + else + target.verbs += verbs_list + + var/list/output_list = list() + for(var/thing in verbs_list) + var/procpath/verb_to_add = thing + output_list[++output_list.len] = list(verb_to_add.category, verb_to_add.name) + output_list = url_encode(json_encode(output_list)) + + target << output("[output_list];", "statbrowser:add_verb_list") + +/** + * handles removing verb and sending it to browser to update, use this for removing verbs + * + * pass the verb type path to this instead of removing it from verbs so the statpanel can update + * Arguments: + * * target - Who the verb is being removed from, client or mob typepath + * * verb - typepath to a verb, or a list of verbs, supports lists of lists + */ +/proc/remove_verb(client/target, verb_or_list_to_remove) + if(IsAdminAdvancedProcCall()) + return + + var/mob/mob_target = null + if(ismob(target)) + mob_target = target + target = mob_target.client + else if(!istype(target, /client)) + CRASH("remove_verb called on a non-mob and non-client") + + var/list/verbs_list = list() + if(!islist(verb_or_list_to_remove)) + verbs_list += verb_or_list_to_remove + else + var/list/verb_listref = verb_or_list_to_remove + var/list/elements_to_process = verb_listref.Copy() + while(length(elements_to_process)) + var/element_or_list = elements_to_process[length(elements_to_process)] //Last element + elements_to_process.len-- + if(islist(element_or_list)) + elements_to_process += element_or_list //list/a += list/b adds the contents of b into a, not the reference to the list itself + else + verbs_list += element_or_list + + if(mob_target) + mob_target.verbs -= verbs_list + if(!target) + return //Our work is done. + else + target.verbs -= verbs_list + + var/list/output_list = list() + for(var/thing in verbs_list) + var/procpath/verb_to_remove = thing + output_list[++output_list.len] = list(verb_to_remove.category, verb_to_remove.name) + output_list = url_encode(json_encode(output_list)) + + target << output("[output_list];", "statbrowser:remove_verb_list") \ No newline at end of file diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 46ae8e39..c04a98a4 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -75,6 +75,9 @@ if(notransform) return + if(SEND_SIGNAL(src, COMSIG_MOB_CLICKON, A, params) & COMSIG_MOB_CANCEL_CLICKON) + return + var/list/modifiers = params2list(params) if(modifiers["shift"] && modifiers["middle"]) ShiftMiddleClickOn(A) @@ -351,8 +354,10 @@ Unused except for AI */ /mob/proc/AltClickOn(atom/A) - if(!A.AltClick(src)) - altclick_listed_turf(A) + . = SEND_SIGNAL(src, COMSIG_MOB_ALTCLICKON, A) + if(. & COMSIG_MOB_CANCEL_CLICKON) + return + A.AltClick(src) /mob/proc/altclick_listed_turf(atom/A) var/turf/T = get_turf(A) @@ -361,7 +366,9 @@ listed_turf = null else if(TurfAdjacent(T)) listed_turf = T - client.statpanel = T.name + client << output("[url_encode(json_encode(T.name))];", "statbrowser:create_listedturf") + + /mob/living/carbon/AltClickOn(atom/A) if(!stat && mind && iscarbon(A) && A != src) @@ -373,7 +380,18 @@ ..() /atom/proc/AltClick(mob/user) - . = SEND_SIGNAL(src, COMSIG_CLICK_ALT, user) + SEND_SIGNAL(src, COMSIG_CLICK_ALT, user) + var/turf/T = get_turf(src) + if(T && (isturf(loc) || isturf(src)) && user.TurfAdjacent(T)) + user.listed_turf = T + user.client << output("[url_encode(json_encode(T.name))];", "statbrowser:create_listedturf") + +/atom/proc/AltClickNoInteract(mob/user, atom/A) + var/turf/T = get_turf(A) + if(T && user.TurfAdjacent(T)) + user.listed_turf = T + user.client << output("[url_encode(json_encode(T.name))];", "statbrowser:create_listedturf") + /mob/proc/TurfAdjacent(turf/T) return T.Adjacent(src) diff --git a/code/_onclick/hud/credits.dm b/code/_onclick/hud/credits.dm index 2cd0dded..31ea453d 100644 --- a/code/_onclick/hud/credits.dm +++ b/code/_onclick/hud/credits.dm @@ -11,7 +11,7 @@ var/icon/credits_icon = new(CREDITS_PATH) LAZYINITLIST(credits) var/list/_credits = credits - verbs += /client/proc/ClearCredits + add_verb(src, /client/proc/ClearCredits) var/static/list/credit_order_for_this_round if(isnull(credit_order_for_this_round)) credit_order_for_this_round = list("Thanks for playing!") + (shuffle(icon_states(credits_icon)) - "Thanks for playing!") @@ -21,13 +21,13 @@ _credits += new /obj/screen/credit(null, I, src, credits_icon) sleep(CREDIT_SPAWN_SPEED) sleep(CREDIT_ROLL_SPEED - CREDIT_SPAWN_SPEED) - verbs -= /client/proc/ClearCredits + remove_verb(src, /client/proc/ClearCredits) qdel(credits_icon) /client/proc/ClearCredits() set name = "Hide Credits" set category = "OOC" - verbs -= /client/proc/ClearCredits + remove_verb(src, /client/proc/ClearCredits) QDEL_LIST(credits) credits = null diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm index 5a3cca96..ba69f4b6 100644 --- a/code/controllers/configuration/configuration.dm +++ b/code/controllers/configuration/configuration.dm @@ -178,10 +178,10 @@ var/list/banned_edits = list(NAMEOF(src, entries_by_type), NAMEOF(src, entries), NAMEOF(src, directory)) return !(var_name in banned_edits) && ..() -/datum/controller/configuration/stat_entry() - if(!statclick) - statclick = new/obj/effect/statclick/debug(null, "Edit", src) - stat("[name]:", statclick) + +/datum/controller/configuration/stat_entry(msg) + msg = "Edit" + return msg /datum/controller/configuration/proc/Get(entry_type) var/datum/config_entry/E = entry_type diff --git a/code/controllers/controller.dm b/code/controllers/controller.dm index 06547d12..90f0976f 100644 --- a/code/controllers/controller.dm +++ b/code/controllers/controller.dm @@ -16,4 +16,4 @@ /datum/controller/proc/Recover() -/datum/controller/proc/stat_entry() \ No newline at end of file +/datum/controller/proc/stat_entry(msg) \ No newline at end of file diff --git a/code/controllers/failsafe.dm b/code/controllers/failsafe.dm index 3ce770b6..a260ed4e 100644 --- a/code/controllers/failsafe.dm +++ b/code/controllers/failsafe.dm @@ -95,8 +95,6 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe) /datum/controller/failsafe/proc/defcon_pretty() return defcon -/datum/controller/failsafe/stat_entry() - if(!statclick) - statclick = new/obj/effect/statclick/debug(null, "Initializing...", src) - - stat("Failsafe Controller:", statclick.update("Defcon: [defcon_pretty()] (Interval: [Failsafe.processing_interval] | Iteration: [Failsafe.master_iteration])")) +/datum/controller/failsafe/stat_entry(msg) + msg = "Defcon: [defcon_pretty()] (Interval: [Failsafe.processing_interval] | Iteration: [Failsafe.master_iteration])" + return msg \ No newline at end of file diff --git a/code/controllers/globals.dm b/code/controllers/globals.dm index a085b264..6b5fb294 100644 --- a/code/controllers/globals.dm +++ b/code/controllers/globals.dm @@ -24,11 +24,9 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars) //fuck off kevinz return QDEL_HINT_IWILLGC -/datum/controller/global_vars/stat_entry() - if(!statclick) - statclick = new/obj/effect/statclick/debug(null, "Initializing...", src) - - stat("Globals:", statclick.update("Edit")) +/datum/controller/global_vars/stat_entry(msg) + msg = "Edit" + return msg /datum/controller/global_vars/vv_edit_var(var_name, var_value) if(gvars_datum_protected_varlist[var_name]) diff --git a/code/controllers/master.dm b/code/controllers/master.dm index 125da84a..76a3b1eb 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -54,7 +54,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new var/static/restart_clear = 0 var/static/restart_timeout = 0 var/static/restart_count = 0 - + var/static/random_seed //current tick limit, assigned before running a subsystem. @@ -69,7 +69,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new if(!random_seed) random_seed = (TEST_RUN_PARAMETER in world.params) ? 29051994 : rand(1, 1e9) rand_seed(random_seed) - + var/list/_subsystems = list() subsystems = _subsystems if (Master != src) @@ -584,12 +584,9 @@ GLOBAL_REAL(Master, /datum/controller/master) = new -/datum/controller/master/stat_entry() - if(!statclick) - statclick = new/obj/effect/statclick/debug(null, "Initializing...", src) - - stat("Byond:", "(FPS:[world.fps]) (TickCount:[world.time/world.tick_lag]) (TickDrift:[round(Master.tickdrift,1)]([round((Master.tickdrift/(world.time/world.tick_lag))*100,0.1)]%))") - stat("Master Controller:", statclick.update("(TickRate:[Master.processing]) (Iteration:[Master.iteration])")) +/datum/controller/master/stat_entry(msg) + msg = "(TickRate:[Master.processing]) (Iteration:[Master.iteration]) (TickLimit: [round(Master.current_ticklimit, 0.1)])" + return msg /datum/controller/master/StartLoadingMap() //disallow more than one map to load at once, multithreading it will just cause race conditions diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm index 4fe0812c..d9d818ac 100644 --- a/code/controllers/subsystem.dm +++ b/code/controllers/subsystem.dm @@ -165,10 +165,9 @@ log_world(msg) return time -//hook for printing stats to the "MC" statuspanel for admins to see performance and related stats etc. + /datum/controller/subsystem/stat_entry(msg) - if(!statclick) - statclick = new/obj/effect/statclick/debug(null, "Initializing...", src) + @@ -177,11 +176,7 @@ else msg = "OFFLINE\t[msg]" - var/title = name - if (can_fire) - title = "\[[state_letter()]][title]" - - stat(title, statclick.update(msg)) + return msg /datum/controller/subsystem/proc/state_letter() switch (state) diff --git a/code/controllers/subsystem/acid.dm b/code/controllers/subsystem/acid.dm index e3c41596..21fb4349 100644 --- a/code/controllers/subsystem/acid.dm +++ b/code/controllers/subsystem/acid.dm @@ -7,9 +7,9 @@ SUBSYSTEM_DEF(acid) var/list/currentrun = list() var/list/processing = list() -/datum/controller/subsystem/acid/stat_entry() - ..("P:[processing.len]") - +/datum/controller/subsystem/acid/stat_entry(msg) + msg = "P:[length(processing)]" + return ..() /datum/controller/subsystem/acid/fire(resumed = 0) if (!resumed) diff --git a/code/controllers/subsystem/adjacent_air.dm b/code/controllers/subsystem/adjacent_air.dm index 8395eda7..ccbf8ffc 100644 --- a/code/controllers/subsystem/adjacent_air.dm +++ b/code/controllers/subsystem/adjacent_air.dm @@ -6,12 +6,13 @@ SUBSYSTEM_DEF(adjacent_air) priority = FIRE_PRIORITY_ATMOS_ADJACENCY var/list/queue = list() -/datum/controller/subsystem/adjacent_air/stat_entry() +/datum/controller/subsystem/adjacent_air/stat_entry(msg) #ifdef TESTING - ..("P:[length(queue)], S:[GLOB.atmos_adjacent_savings[1]], T:[GLOB.atmos_adjacent_savings[2]]") + msg = "P:[length(queue)], S:[GLOB.atmos_adjacent_savings[1]], T:[GLOB.atmos_adjacent_savings[2]]" #else - ..("P:[length(queue)]") + msg = "P:[length(queue)]" #endif + return ..() /datum/controller/subsystem/adjacent_air/Initialize() while(length(queue)) diff --git a/code/controllers/subsystem/augury.dm b/code/controllers/subsystem/augury.dm index 1b1c7bc3..53c86004 100644 --- a/code/controllers/subsystem/augury.dm +++ b/code/controllers/subsystem/augury.dm @@ -9,7 +9,8 @@ SUBSYSTEM_DEF(augury) var/list/observers_given_action = list() /datum/controller/subsystem/augury/stat_entry(msg) - ..("W:[watchers.len]|D:[doombringers.len]") + msg = "W:[watchers.len]|D:[length(doombringers)]" + return ..() /datum/controller/subsystem/augury/proc/register_doom(atom/A, severity) doombringers[A] = severity diff --git a/code/controllers/subsystem/disease.dm b/code/controllers/subsystem/disease.dm index 9be1d8d9..4fe5533e 100644 --- a/code/controllers/subsystem/disease.dm +++ b/code/controllers/subsystem/disease.dm @@ -20,7 +20,8 @@ SUBSYSTEM_DEF(disease) return ..() /datum/controller/subsystem/disease/stat_entry(msg) - ..("P:[active_diseases.len]") + msg = "P:[length(active_diseases)]" + return ..() /datum/controller/subsystem/disease/proc/get_disease_name(id) var/datum/disease/advance/A = archive_diseases[id] diff --git a/code/controllers/subsystem/fire_burning.dm b/code/controllers/subsystem/fire_burning.dm index db6dc651..6ac42f8c 100644 --- a/code/controllers/subsystem/fire_burning.dm +++ b/code/controllers/subsystem/fire_burning.dm @@ -7,9 +7,9 @@ SUBSYSTEM_DEF(fire_burning) var/list/currentrun = list() var/list/processing = list() -/datum/controller/subsystem/fire_burning/stat_entry() - ..("P:[processing.len]") - +/datum/controller/subsystem/fire_burning/stat_entry(msg) + msg = "P:[length(processing)]" + return ..() /datum/controller/subsystem/fire_burning/fire(resumed = 0) if (!resumed) diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index f8ca1e7e..328818fd 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -57,7 +57,7 @@ SUBSYSTEM_DEF(garbage) msg += "TGR:[round((totalgcs/(totaldels+totalgcs))*100, 0.01)]%" msg += " P:[pass_counts.Join(",")]" msg += "|F:[fail_counts.Join(",")]" - ..(msg) + return ..() /datum/controller/subsystem/garbage/Shutdown() //Adds the del() log to the qdel log file diff --git a/code/controllers/subsystem/idlenpcpool.dm b/code/controllers/subsystem/idlenpcpool.dm index 8992fa7b..03b7931d 100644 --- a/code/controllers/subsystem/idlenpcpool.dm +++ b/code/controllers/subsystem/idlenpcpool.dm @@ -8,10 +8,11 @@ SUBSYSTEM_DEF(idlenpcpool) var/list/currentrun = list() var/static/list/idle_mobs_by_zlevel[][] -/datum/controller/subsystem/idlenpcpool/stat_entry() +/datum/controller/subsystem/idlenpcpool/stat_entry(msg) var/list/idlelist = GLOB.simple_animals[AI_IDLE] var/list/zlist = GLOB.simple_animals[AI_Z_OFF] - ..("IdleNPCS:[idlelist.len]|Z:[zlist.len]") + msg = "IdleNPCS:[length(idlelist)]|Z:[length(zlist)]" + return ..() /datum/controller/subsystem/idlenpcpool/proc/MaxZChanged() if (!islist(idle_mobs_by_zlevel)) diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index 9048d77b..3d525e05 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -395,7 +395,7 @@ SUBSYSTEM_DEF(job) if(!joined_late) var/obj/S = null for(var/obj/effect/landmark/start/sloc in GLOB.start_landmarks_list) - if(sloc.name != rank) + if(sloc.name != rank && sloc.type != job.override_roundstart_spawn) S = sloc //so we can revert to spawning them on top of eachother if something goes wrong continue if(locate(/mob/living) in sloc.loc) diff --git a/code/controllers/subsystem/lighting.dm b/code/controllers/subsystem/lighting.dm index 12b467b6..7eff66eb 100644 --- a/code/controllers/subsystem/lighting.dm +++ b/code/controllers/subsystem/lighting.dm @@ -7,10 +7,13 @@ SUBSYSTEM_DEF(lighting) wait = 2 init_order = INIT_ORDER_LIGHTING flags = SS_TICKER + var/static/list/sources_queue = list() // List of lighting sources queued for update. + var/static/list/corners_queue = list() // List of lighting corners queued for update. + var/static/list/objects_queue = list() // List of lighting objects queued for update. -/datum/controller/subsystem/lighting/stat_entry() - ..("L:[GLOB.lighting_update_lights.len]|C:[GLOB.lighting_update_corners.len]|O:[GLOB.lighting_update_objects.len]") - +/datum/controller/subsystem/lighting/stat_entry(msg) + msg = "L:[length(sources_queue)]|C:[length(corners_queue)]|O:[length(objects_queue)]" + return ..() /datum/controller/subsystem/lighting/Initialize(timeofday) if(!initialized) diff --git a/code/controllers/subsystem/machines.dm b/code/controllers/subsystem/machines.dm index c4b09d1b..04b65410 100644 --- a/code/controllers/subsystem/machines.dm +++ b/code/controllers/subsystem/machines.dm @@ -22,9 +22,10 @@ SUBSYSTEM_DEF(machines) NewPN.add_cable(PC) propagate_network(PC,PC.powernet) -/datum/controller/subsystem/machines/stat_entry() - ..("M:[processing.len]|PN:[powernets.len]") +/datum/controller/subsystem/machines/stat_entry(msg) + msg = "M:[length(processing)]|PN:[length(powernets)]" + return ..() /datum/controller/subsystem/machines/fire(resumed = 0) if (!resumed) diff --git a/code/controllers/subsystem/mobs.dm b/code/controllers/subsystem/mobs.dm index aac9f9d3..1e8efff0 100644 --- a/code/controllers/subsystem/mobs.dm +++ b/code/controllers/subsystem/mobs.dm @@ -10,8 +10,9 @@ SUBSYSTEM_DEF(mobs) var/static/list/cubemonkeys = list() var/static/list/cheeserats = list() -/datum/controller/subsystem/mobs/stat_entry() - ..("P:[GLOB.mob_living_list.len]") +/datum/controller/subsystem/mobs/stat_entry(msg) + msg = "P:[length(GLOB.mob_living_list)]" + return ..() /datum/controller/subsystem/mobs/proc/MaxZChanged() if (!islist(clients_by_zlevel)) diff --git a/code/controllers/subsystem/npcpool.dm b/code/controllers/subsystem/npcpool.dm index 7fd35124..5e8fc1f5 100644 --- a/code/controllers/subsystem/npcpool.dm +++ b/code/controllers/subsystem/npcpool.dm @@ -6,9 +6,10 @@ SUBSYSTEM_DEF(npcpool) var/list/currentrun = list() -/datum/controller/subsystem/npcpool/stat_entry() +/datum/controller/subsystem/npcpool/stat_entry(msg) var/list/activelist = GLOB.simple_animals[AI_ON] - ..("NPCS:[activelist.len]") + msg = "NPCS:[length(activelist)]" + return ..() /datum/controller/subsystem/npcpool/fire(resumed = FALSE) diff --git a/code/controllers/subsystem/overlays.dm b/code/controllers/subsystem/overlays.dm index 20eb2af0..f8f7a16b 100644 --- a/code/controllers/subsystem/overlays.dm +++ b/code/controllers/subsystem/overlays.dm @@ -21,10 +21,9 @@ SUBSYSTEM_DEF(overlays) fire(mc_check = FALSE) return ..() - -/datum/controller/subsystem/overlays/stat_entry() - ..("Ov:[length(queue)]") - +/datum/controller/subsystem/overlays/stat_entry(msg) + msg = "Ov:[length(queue)]" + return ..() /datum/controller/subsystem/overlays/Shutdown() text2file(render_stats(stats), "[GLOB.log_directory]/overlay.log") diff --git a/code/controllers/subsystem/processing/processing.dm b/code/controllers/subsystem/processing/processing.dm index c5d6dfa1..637b0499 100644 --- a/code/controllers/subsystem/processing/processing.dm +++ b/code/controllers/subsystem/processing/processing.dm @@ -10,8 +10,9 @@ SUBSYSTEM_DEF(processing) var/list/processing = list() var/list/currentrun = list() -/datum/controller/subsystem/processing/stat_entry() - ..("[stat_tag]:[processing.len]") +/datum/controller/subsystem/processing/stat_entry(msg) + msg = "[stat_tag]:[length(processing)]" + return ..() /datum/controller/subsystem/processing/fire(resumed = 0) if (!resumed) diff --git a/code/controllers/subsystem/spacedrift.dm b/code/controllers/subsystem/spacedrift.dm index f23f41b7..b6cec58b 100644 --- a/code/controllers/subsystem/spacedrift.dm +++ b/code/controllers/subsystem/spacedrift.dm @@ -8,9 +8,9 @@ SUBSYSTEM_DEF(spacedrift) var/list/currentrun = list() var/list/processing = list() -/datum/controller/subsystem/spacedrift/stat_entry() - ..("P:[processing.len]") - +/datum/controller/subsystem/spacedrift/stat_entry(msg) + msg = "P:[length(processing)]" + return ..() /datum/controller/subsystem/spacedrift/fire(resumed = 0) if (!resumed) diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm new file mode 100644 index 00000000..b6fa8c53 --- /dev/null +++ b/code/controllers/subsystem/statpanel.dm @@ -0,0 +1,118 @@ +SUBSYSTEM_DEF(statpanels) + name = "Stat Panels" + wait = 4 + init_order = INIT_ORDER_STATPANELS + runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY + var/list/currentrun = list() + var/encoded_global_data + var/mc_data_encoded + var/list/cached_images = list() + +/datum/controller/subsystem/statpanels/fire(resumed = FALSE) + if (!resumed) + var/datum/map_config/cached = SSmapping.next_map_config + var/round_time = world.time - SSticker.round_start_time + var/list/global_data = list( + "Map: [SSmapping.config?.map_name || "Loading..."]", + cached ? "Next Map: [cached.map_name]" : null, + "Round ID: [GLOB.round_id ? GLOB.round_id : "NULL"]", + "Server Time: [time2text(world.timeofday, "YYYY-MM-DD hh:mm:ss")]", + "Round Time: [round_time > MIDNIGHT_ROLLOVER ? "[round(round_time/MIDNIGHT_ROLLOVER)]:[worldtime2text()]" : worldtime2text()]", + "Station Time: [station_time_timestamp()]", + "Time Dilation: [round(SStime_track.time_dilation_current,1)]% AVG:([round(SStime_track.time_dilation_avg_fast,1)]%, [round(SStime_track.time_dilation_avg,1)]%, [round(SStime_track.time_dilation_avg_slow,1)]%)" + ) + + if(SSshuttle.emergency) + var/ETA = SSshuttle.emergency.getModeStr() + if(ETA) + global_data += "[ETA] [SSshuttle.emergency.getTimerStr()]" + encoded_global_data = url_encode(json_encode(global_data)) + + var/list/mc_data = list( + list("CPU:", world.cpu), + list("Instances:", "[num2text(world.contents.len, 10)]"), + list("World Time:", "[world.time]"), + list("Globals:", GLOB.stat_entry(), "\ref[GLOB]"), + list("[config]:", config.stat_entry(), "\ref[config]"), + list("Byond:", "(FPS:[world.fps]) (TickCount:[world.time/world.tick_lag]) (TickDrift:[round(Master.tickdrift,1)]([round((Master.tickdrift/(world.time/world.tick_lag))*100,0.1)]%))"), + list("Master Controller:", Master.stat_entry(), "\ref[Master]"), + list("Failsafe Controller:", Failsafe.stat_entry(), "\ref[Failsafe]"), + list("","") + ) + for(var/ss in Master.subsystems) + var/datum/controller/subsystem/sub_system = ss + mc_data[++mc_data.len] = list("\[[sub_system.state_letter()]][sub_system.name]", sub_system.stat_entry(), "\ref[sub_system]") + mc_data[++mc_data.len] = list("Camera Net", "Cameras: [GLOB.cameranet.cameras.len] | Chunks: [GLOB.cameranet.chunks.len]", "\ref[GLOB.cameranet]") + mc_data_encoded = url_encode(json_encode(mc_data)) + src.currentrun = GLOB.clients.Copy() + + var/list/currentrun = src.currentrun + while(length(currentrun)) + var/client/target = currentrun[length(currentrun)] + currentrun.len-- + var/ping_str = url_encode("Ping: [round(target.lastping, 1)]ms (Average: [round(target.avgping, 1)]ms)") + var/other_str = url_encode(json_encode(target.mob.get_status_tab_items())) + target << output("[encoded_global_data];[ping_str];[other_str]", "statbrowser:update") + if(!target.holder) + target << output("", "statbrowser:remove_admin_tabs") + else + var/turf/eye_turf = get_turf(target.eye) + var/coord_entry = url_encode(COORD(eye_turf)) + target << output("[mc_data_encoded];[coord_entry];[url_encode(target.holder.href_token)]", "statbrowser:update_mc") + var/list/ahelp_tickets = GLOB.ahelp_tickets.stat_entry() + target << output("[url_encode(json_encode(ahelp_tickets))];", "statbrowser:update_tickets") + if(!length(GLOB.sdql2_queries)) + target << output("", "statbrowser:remove_sqdl2") + else + var/list/sqdl2A = list() + sqdl2A[++sqdl2A.len] = list("", "Access Global SDQL2 List", REF(GLOB.sdql2_vv_statobj)) + var/list/sqdl2B = list() + sqdl2A += sqdl2B + target << output(url_encode(json_encode(sqdl2A)), "statbrowser:update_sqdl2") + var/list/proc_holders = target.mob.get_proc_holders() + target.spell_tabs.Cut() + for(var/phl in proc_holders) + var/list/proc_holder_list = phl + target.spell_tabs |= proc_holder_list[1] + var/proc_holders_encoded = "" + if(length(proc_holders)) + proc_holders_encoded = url_encode(json_encode(proc_holders)) + target << output("[url_encode(json_encode(target.spell_tabs))];[proc_holders_encoded]", "statbrowser:update_spells") + if(target.mob?.listed_turf) + var/mob/target_mob = target.mob + if(!target_mob.TurfAdjacent(target_mob.listed_turf)) + target << output("", "statbrowser:remove_listedturf") + target_mob.listed_turf = null + else + var/list/overrides = list() + var/list/turfitems = list() + for(var/img in target.images) + var/image/target_image = img + if(!target_image.loc || target_image.loc.loc != target_mob.listed_turf || !target_image.override) + continue + overrides += target_image.loc + if(!(REF(target_mob.listed_turf) in cached_images)) + target << browse_rsc(getFlatIcon(target_mob.listed_turf, no_anim = TRUE), "[REF(target_mob.listed_turf)].png") + cached_images += REF(target_mob.listed_turf) + turfitems[++turfitems.len] = list("[target_mob.listed_turf]", REF(target_mob.listed_turf), "[REF(target_mob.listed_turf)].png") + for(var/tc in target_mob.listed_turf) + var/atom/movable/turf_content = tc + if(turf_content.mouse_opacity == MOUSE_OPACITY_TRANSPARENT) + continue + if(turf_content.invisibility > target_mob.see_invisible) + continue + if(turf_content in overrides) + continue + if(turf_content.IsObscured()) + continue + if(length(turfitems) < 30) // only create images for the first 30 items on the turf, for performance reasons + if(!(REF(turf_content) in cached_images)) + target << browse_rsc(getFlatIcon(turf_content, no_anim = TRUE), "[REF(turf_content)].png") + cached_images += REF(turf_content) + turfitems[++turfitems.len] = list("[turf_content.name]", REF(turf_content), "[REF(turf_content)].png") + else + turfitems[++turfitems.len] = list("[turf_content.name]", REF(turf_content)) + turfitems = url_encode(json_encode(turfitems)) + target << output("[turfitems];", "statbrowser:update_listedturf") + if(MC_TICK_CHECK) + return \ No newline at end of file diff --git a/code/controllers/subsystem/tgui.dm b/code/controllers/subsystem/tgui.dm index dacbac40..9fc689ff 100644 --- a/code/controllers/subsystem/tgui.dm +++ b/code/controllers/subsystem/tgui.dm @@ -16,8 +16,9 @@ SUBSYSTEM_DEF(tgui) /datum/controller/subsystem/tgui/Shutdown() close_all_uis() -/datum/controller/subsystem/tgui/stat_entry() - ..("P:[processing_uis.len]") +/datum/controller/subsystem/tgui/stat_entry(msg) + msg = "P:[length(open_uis)]" + return ..() /datum/controller/subsystem/tgui/fire(resumed = 0) if (!resumed) diff --git a/code/controllers/subsystem/throwing.dm b/code/controllers/subsystem/throwing.dm index 908b8944..b491cc3c 100644 --- a/code/controllers/subsystem/throwing.dm +++ b/code/controllers/subsystem/throwing.dm @@ -11,9 +11,9 @@ SUBSYSTEM_DEF(throwing) var/list/currentrun var/list/processing = list() -/datum/controller/subsystem/throwing/stat_entry() - ..("P:[processing.len]") - +/datum/controller/subsystem/throwing/stat_entry(msg) + msg = "P:[length(processing)]" + return ..() /datum/controller/subsystem/throwing/fire(resumed = 0) if (!resumed) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 810882ff..0f4b34f4 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -402,6 +402,7 @@ SUBSYSTEM_DEF(ticker) if(living.client) var/obj/screen/splash/S = new(living.client, TRUE) S.Fade(TRUE) + living.client.init_verbs() livings += living if(livings.len) addtimer(CALLBACK(src, .proc/release_characters, livings), 30, TIMER_CLIENT_TIME) @@ -677,7 +678,7 @@ SUBSYSTEM_DEF(ticker) if(!round_end_sound) round_end_sound = pick(\ 'sound/roundend/iwishtherewassomethingmore.ogg', - 'sound/roundend/likeisaid.ogg', + 'sound/roundend/likeisaid.ogg', 'sound/roundend/whatarottenwaytodie.ogg', 'sound/roundend/whatashame.ogg', 'sound/roundend/newroundsexy.ogg', diff --git a/code/controllers/subsystem/timer.dm b/code/controllers/subsystem/timer.dm index d0eb0b9c..90ee4b48 100644 --- a/code/controllers/subsystem/timer.dm +++ b/code/controllers/subsystem/timer.dm @@ -34,7 +34,8 @@ SUBSYSTEM_DEF(timer) bucket_resolution = world.tick_lag /datum/controller/subsystem/timer/stat_entry(msg) - ..("B:[bucket_count] P:[length(second_queue)] H:[length(hashes)] C:[length(clienttime_timers)] S:[length(timer_id_dict)]") + msg = "B:[bucket_count] P:[length(second_queue)] H:[length(hashes)] C:[length(clienttime_timers)] S:[length(timer_id_dict)]" + return ..() /datum/controller/subsystem/timer/fire(resumed = FALSE) var/lit = last_invoke_tick diff --git a/code/datums/components/rotation.dm b/code/datums/components/rotation.dm index c4ed0031..84a56ace 100644 --- a/code/datums/components/rotation.dm +++ b/code/datums/components/rotation.dm @@ -12,6 +12,48 @@ var/rotation_flags = NONE var/default_rotation_direction = ROTATION_CLOCKWISE +/* +/proc/add_verb(client/target, verb_or_list_to_add) + if(!target) + CRASH("add_verb called without a target") + if(IsAdminAdvancedProcCall()) + return + var/mob/mob_target = null + + if(ismob(target)) + mob_target = target + target = mob_target.client + else if(!istype(target, /client)) + CRASH("add_verb called on a non-mob and non-client") + var/list/verbs_list = list() + if(!islist(verb_or_list_to_add)) + verbs_list += verb_or_list_to_add + else + var/list/verb_listref = verb_or_list_to_add + var/list/elements_to_process = verb_listref.Copy() + while(length(elements_to_process)) + var/element_or_list = elements_to_process[length(elements_to_process)] //Last element + elements_to_process.len-- + if(islist(element_or_list)) + elements_to_process += element_or_list //list/a += list/b adds the contents of b into a, not the reference to the list itself + else + verbs_list += element_or_list + + if(mob_target) + mob_target.verbs += verbs_list + if(!target) + return //Our work is done. + else + target.verbs += verbs_list + + var/list/output_list = list() + for(var/thing in verbs_list) + var/procpath/verb_to_add = thing + //output_list[++output_list.len] = list(verb_to_add.category, verb_to_add.name) + output_list = url_encode(json_encode(output_list)) + + target << output("[output_list];", "statbrowser:add_verb_list") +*/ /datum/component/simple_rotation/Initialize(rotation_flags = NONE ,can_user_rotate,can_be_rotated,after_rotation) if(!ismovableatom(parent)) diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 0e4e9319..8712851a 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -128,6 +128,9 @@ transfer_martial_arts(new_character) if(active || force_key_move) new_character.key = key //now transfer the key to link the client to our new body + if(new_character.client) + //LAZYCLEARLIST(new_character.client.recent_examines) + new_character.client.init_verbs() // re-initialize character specific verbs //CIT CHANGE - makes arousal update when transfering bodies if(isliving(new_character)) //New humans and such are by default enabled arousal. Let's always use the new mind's prefs. @@ -771,6 +774,7 @@ if(istype(S, spell)) spell_list -= S qdel(S) + current?.client << output(null, "statbrowser:check_spells") /datum/mind/proc/RemoveAllSpells() for(var/obj/effect/proc_holder/S in spell_list) diff --git a/code/datums/ruins/lavaland.dm b/code/datums/ruins/lavaland.dm index f68e189a..ec69fdb9 100644 --- a/code/datums/ruins/lavaland.dm +++ b/code/datums/ruins/lavaland.dm @@ -239,5 +239,5 @@ id = "lunaraltar" description = "Millenia ago, the humanoids of this strange land used to offer sacrifices here..." suffix = "lavaland_surface_lunaraltar.dmm" - allow_duplicates = FALSE + allow_duplicates = TRUE cost = 10 diff --git a/code/datums/wires/robot.dm b/code/datums/wires/robot.dm index 5e0d0d77..1ab1dd5c 100644 --- a/code/datums/wires/robot.dm +++ b/code/datums/wires/robot.dm @@ -38,7 +38,7 @@ new_ai = select_active_ai(R) R.notify_ai(DISCONNECT) if(new_ai && (new_ai != R.connected_ai)) - R.connected_ai = new_ai + R.set_connected_ai(new_ai) if(R.shell) R.undeploy() //If this borg is an AI shell, disconnect the controlling AI and assign ti to a new AI R.notify_ai(AI_SHELL) @@ -67,7 +67,7 @@ R.notify_ai(DISCONNECT) if(R.shell) R.undeploy() - R.connected_ai = null + R.set_connected_ai(null) if(WIRE_LAWSYNC) // Cut the law wire, and the borg will no longer receive law updates from its AI. Repair and it will re-sync. if(mend) if(!R.emagged) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index d3c530cb..04314dd7 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -873,3 +873,20 @@ Proc for attack log creation, because really why not /atom/proc/intercept_zImpact(atom/movable/AM, levels = 1) . |= SEND_SIGNAL(src, COMSIG_ATOM_INTERCEPT_Z_FALL, AM, levels) +///Passes Stat Browser Panel clicks to the game and calls client click on an atom +/atom/Topic(href, list/href_list) + . = ..() + if(!usr?.client) + return + var/client/usr_client = usr.client + var/list/paramslist = list() + if(href_list["statpanel_item_shiftclick"]) + paramslist["shift"] = "1" + if(href_list["statpanel_item_ctrlclick"]) + paramslist["ctrl"] = "1" + if(href_list["statpanel_item_altclick"]) + paramslist["alt"] = "1" + if(href_list["statpanel_item_click"]) + // first of all make sure we valid + var/mouseparams = list2params(paramslist) + usr_client.Click(src, loc, null, mouseparams) \ No newline at end of file diff --git a/code/game/gamemodes/sandbox/h_sandbox.dm b/code/game/gamemodes/sandbox/h_sandbox.dm index c5946719..bcdee791 100644 --- a/code/game/gamemodes/sandbox/h_sandbox.dm +++ b/code/game/gamemodes/sandbox/h_sandbox.dm @@ -9,7 +9,8 @@ GLOBAL_VAR_INIT(hsboxspawn, TRUE) sandbox.owner = src.ckey if(src.client.holder) sandbox.admin = 1 - verbs += new/mob/proc/sandbox_panel + add_verb(src, /mob/proc/sandbox_panel) + /mob/proc/sandbox_panel() set name = "Sandbox Panel" if(sandbox) diff --git a/code/game/machinery/aug_manipulator.dm b/code/game/machinery/aug_manipulator.dm index 72655cde..17dad525 100644 --- a/code/game/machinery/aug_manipulator.dm +++ b/code/game/machinery/aug_manipulator.dm @@ -8,7 +8,7 @@ max_integrity = 200 var/obj/item/bodypart/storedpart var/initial_icon_state - var/static/list/style_list_icons = list("standard" = 'icons/mob/augmentation/augments.dmi', "engineer" = 'icons/mob/augmentation/augments_engineer.dmi', "security" = 'icons/mob/augmentation/augments_security.dmi', "mining" = 'icons/mob/augmentation/augments_mining.dmi') + var/static/list/style_list_icons = list("standard" = 'icons/mob/augmentation/augments.dmi', "engineer" = 'icons/mob/augmentation/augments_engineer.dmi', "security" = 'icons/mob/augmentation/augments_security.dmi', "mining" = 'icons/mob/augmentation/augments_mining.dmi', "bootypeace female" = 'icons/mob/augmentation/augments_lewdf.dmi', "bootypeace male" = 'icons/mob/augmentation/augments_lewdm.dmi', "bootypeace intersex" = 'icons/mob/augmentation/augments_lewds.dmi', "bootypeace bob hair (HEAD ONLY)" = 'icons/mob/augmentation/augments_lewdbobhair.dmi', "bootybimbo ponytail (HEAD ONLY)" = 'icons/mob/augmentation/augments_bimbohair.dmi', "bootybimbo female" = 'icons/mob/augmentation/augments_lewdbimbof.dmi', "bootybimbo male" = 'icons/mob/augmentation/augments_lewdbimbom.dmi', "bootybimbo intersex" = 'icons/mob/augmentation/augments_lewdbimbos.dmi') /obj/machinery/aug_manipulator/examine(mob/user) . = ..() diff --git a/code/game/machinery/transformer.dm b/code/game/machinery/transformer.dm index 3ff2424d..5c9d5076 100644 --- a/code/game/machinery/transformer.dm +++ b/code/game/machinery/transformer.dm @@ -101,7 +101,7 @@ // So he can't jump out the gate right away. R.SetLockdown() if(masterAI) - R.connected_ai = masterAI + R.set_connected_ai(masterAI) R.lawsync() R.lawupdate = 1 addtimer(CALLBACK(src, .proc/unlock_new_robot, R), 50) diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index bb53f686..1ea8b361 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -50,6 +50,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM attack_verb = list("burnt","singed") START_PROCESSING(SSobj, src) update_icon() + playsound(src, 'sound/items/match.ogg', 50, 1, -1) /obj/item/match/proc/matchburnout() if(lit) diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index a4f286bf..946b3cac 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -628,11 +628,12 @@ H.adjustOxyLoss(H.health - HALFWAYCRITDEATH, 0) else var/overall_damage = total_brute + total_burn + H.getToxLoss() + H.getOxyLoss() - var/mobhealth = H.health - H.adjustOxyLoss((mobhealth - HALFWAYCRITDEATH) * (H.getOxyLoss() / overall_damage), 0) - H.adjustToxLoss((mobhealth - HALFWAYCRITDEATH) * (H.getToxLoss() / overall_damage), 0) - H.adjustFireLoss((mobhealth - HALFWAYCRITDEATH) * (total_burn / overall_damage), 0) - H.adjustBruteLoss((mobhealth - HALFWAYCRITDEATH) * (total_brute / overall_damage), 0) + if(overall_damage) + var/mobhealth = H.health + H.adjustOxyLoss((mobhealth - HALFWAYCRITDEATH) * (H.getOxyLoss() / overall_damage), 0) + H.adjustToxLoss((mobhealth - HALFWAYCRITDEATH) * (H.getToxLoss() / overall_damage), 0) + H.adjustFireLoss((mobhealth - HALFWAYCRITDEATH) * (total_burn / overall_damage), 0) + H.adjustBruteLoss((mobhealth - HALFWAYCRITDEATH) * (total_brute / overall_damage), 0) H.updatehealth() // Previous "adjust" procs don't update health, so we do it manually. user.visible_message("[req_defib ? "[defib]" : "[src]"] pings: Resuscitation successful.") playsound(src, 'sound/machines/defib_success.ogg', 50, 0) diff --git a/code/game/objects/items/grenades/spawnergrenade.dm b/code/game/objects/items/grenades/spawnergrenade.dm index bc32b158..466caf93 100644 --- a/code/game/objects/items/grenades/spawnergrenade.dm +++ b/code/game/objects/items/grenades/spawnergrenade.dm @@ -47,5 +47,5 @@ name = "clustaur grenade" icon_state = "clustaur" item_state = "clustaur" - deliveryamt = 10 + deliveryamt = 5 spawner_type = /obj/item/reagent_containers/glass/beaker/waterbottle/wataur \ No newline at end of file diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index 5b4a4386..811d5f24 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -282,11 +282,11 @@ O.locked = panel_locked if(!aisync) lawsync = 0 - O.connected_ai = null + O.set_connected_ai(null) else O.notify_ai(NEW_BORG) if(forced_ai) - O.connected_ai = forced_ai + O.set_connected_ai(forced_ai) if(!lawsync) O.lawupdate = 0 if(M.laws.id == DEFAULT_AI_LAWID) @@ -338,10 +338,10 @@ if(!aisync) lawsync = FALSE - O.connected_ai = null + O.set_connected_ai(null) else if(forced_ai) - O.connected_ai = forced_ai + O.set_connected_ai(forced_ai) O.notify_ai(AI_SHELL) if(!lawsync) O.lawupdate = FALSE diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 013883fe..7121aaac 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -426,7 +426,7 @@ "} if(GLOB.master_mode == "secret") dat += "(Force Secret Mode)
" - + if(GLOB.master_mode == "dynamic") if(SSticker.current_state <= GAME_STATE_PREGAME) dat += "(Force Roundstart Rulesets)
" @@ -987,6 +987,7 @@ SSblackbox.record_feedback("tally", "admin_verb", 1, "Ghost Drag Control") tomob.ckey = frommob.ckey + tomob.client?.init_verbs() qdel(frommob) return 1 diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 0ab823e2..3a24d7aa 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -74,6 +74,7 @@ GLOBAL_LIST_INIT(admin_verbs_admin, world.AVerbsAdmin()) /client/proc/addbunkerbypass, /client/proc/revokebunkerbypass, /client/proc/stop_sounds, + /client/proc/debugstatpanel, /client/proc/hide_verbs, /*hides all our adminverbs*/ /client/proc/hide_most_verbs, /*hides all our hideable adminverbs*/ /datum/admins/proc/open_borgopanel @@ -256,36 +257,36 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list( control_freak = CONTROL_FREAK_SKIN | CONTROL_FREAK_MACROS var/rights = holder.rank.rights - verbs += GLOB.admin_verbs_default + add_verb(src, GLOB.admin_verbs_default) if(rights & R_BUILDMODE) - verbs += /client/proc/togglebuildmodeself + add_verb(src, /client/proc/togglebuildmodeself) if(rights & R_ADMIN) - verbs += GLOB.admin_verbs_admin + add_verb(src, GLOB.admin_verbs_admin) if(rights & R_BAN) - verbs += GLOB.admin_verbs_ban + add_verb(src, GLOB.admin_verbs_ban) if(rights & R_FUN) - verbs += GLOB.admin_verbs_fun + add_verb(src, GLOB.admin_verbs_fun) if(rights & R_SERVER) - verbs += GLOB.admin_verbs_server + add_verb(src, GLOB.admin_verbs_server) if(rights & R_DEBUG) - verbs += GLOB.admin_verbs_debug + add_verb(src, GLOB.admin_verbs_debug) if(rights & R_POSSESS) - verbs += GLOB.admin_verbs_possess + add_verb(src, GLOB.admin_verbs_possess) if(rights & R_PERMISSIONS) - verbs += GLOB.admin_verbs_permissions + add_verb(src, GLOB.admin_verbs_permissions) if(rights & R_STEALTH) - verbs += /client/proc/stealth + add_verb(src, /client/proc/stealth) if(rights & R_ADMIN) - verbs += GLOB.admin_verbs_poll + add_verb(src, GLOB.admin_verbs_poll) if(rights & R_SOUNDS) - verbs += GLOB.admin_verbs_sounds + add_verb(src, GLOB.admin_verbs_sounds) if(CONFIG_GET(string/invoke_youtubedl)) - verbs += /client/proc/play_web_sound + add_verb(src, /client/proc/play_web_sound) if(rights & R_SPAWN) - verbs += GLOB.admin_verbs_spawn + add_verb(src, GLOB.admin_verbs_spawn) /client/proc/remove_admin_verbs() - verbs.Remove( + remove_verb(src, list( GLOB.admin_verbs_default, /client/proc/togglebuildmodeself, GLOB.admin_verbs_admin, @@ -304,14 +305,14 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list( GLOB.admin_verbs_debug_mapping, /client/proc/disable_debug_verbs, /client/proc/readmin - ) + )) /client/proc/hide_most_verbs()//Allows you to keep some functionality while hiding some verbs set name = "Adminverbs - Hide Most" set category = "Admin" verbs.Remove(/client/proc/hide_most_verbs, GLOB.admin_verbs_hideable) - verbs += /client/proc/show_verbs + add_verb(src, /client/proc/show_verbs) to_chat(src, "Most of your adminverbs have been hidden.") SSblackbox.record_feedback("tally", "admin_verb", 1, "Hide Most Adminverbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -322,7 +323,7 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list( set category = "Admin" remove_admin_verbs() - verbs += /client/proc/show_verbs + add_verb(src, /client/proc/show_verbs) to_chat(src, "Almost all of your adminverbs have been hidden.") SSblackbox.record_feedback("tally", "admin_verb", 1, "Hide All Adminverbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -332,7 +333,7 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list( set name = "Adminverbs - Show" set category = "Admin" - verbs -= /client/proc/show_verbs + remove_verb(src, /client/proc/show_verbs) add_admin_verbs() to_chat(src, "All of your adminverbs are now visible.") @@ -365,6 +366,7 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list( message_admins("[key_name_admin(usr)] admin ghosted.") var/mob/body = mob body.ghostize(1) + init_verbs() if(body && !body.key) body.key = "@[key]" //Haaaaaaaack. But the people have spoken. If it breaks; blame adminbus SSblackbox.record_feedback("tally", "admin_verb", 1, "Admin Ghost") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -717,3 +719,10 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list( log_admin("[key_name(usr)] has [AI_Interact ? "activated" : "deactivated"] Admin AI Interact") message_admins("[key_name_admin(usr)] has [AI_Interact ? "activated" : "deactivated"] their AI interaction") + + +/client/proc/debugstatpanel() + set name = "Debug Stat Panel" + set category = "Debug" + + src << output("", "statbrowser:create_debug") \ No newline at end of file diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm index f9bed188..04c1909c 100644 --- a/code/modules/admin/holder2.dm +++ b/code/modules/admin/holder2.dm @@ -93,7 +93,7 @@ GLOBAL_PROTECT(href_token) var/client/C if ((C = owner) || (C = GLOB.directory[target])) disassociate() - C.verbs += /client/proc/readmin + add_verb(C, /client/proc/readmin) /datum/admins/proc/associate(client/C) if(IsAdminAdvancedProcCall()) @@ -113,7 +113,8 @@ GLOBAL_PROTECT(href_token) owner = C owner.holder = src owner.add_admin_verbs() //TODO <--- todo what? the proc clearly exists and works since its the backbone to our entire admin system - owner.verbs -= /client/proc/readmin + remove_verb(owner, /client/proc/readmin) + owner.init_verbs() //re-initialize the verb list GLOB.admins |= C /datum/admins/proc/disassociate() @@ -125,6 +126,7 @@ GLOBAL_PROTECT(href_token) if(owner) GLOB.admins -= owner owner.remove_admin_verbs() + owner.init_verbs() owner.holder = null owner = null diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm index 41496b35..3e83974d 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm @@ -393,11 +393,14 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null delete_click = new(null, "INITIALIZING", src) if(!action_click) action_click = new(null, "INITIALIZNG", src) - stat("[id] ", delete_click.update("DELETE QUERY | STATE : [text_state()] | ALL/ELIG/FIN \ + + var/list/L = list() + L[++L.len] = list("[id] ", "[delete_click.update("DELETE QUERY | STATE : [text_state()] | ALL/ELIG/FIN \ [islist(obj_count_all)? length(obj_count_all) : (isnull(obj_count_all)? "0" : obj_count_all)]/\ [islist(obj_count_eligible)? length(obj_count_eligible) : (isnull(obj_count_eligible)? "0" : obj_count_eligible)]/\ - [islist(obj_count_finished)? length(obj_count_finished) : (isnull(obj_count_finished)? "0" : obj_count_finished)] - [get_query_text()]")) - stat(" ", action_click.update("[SDQL2_IS_RUNNING? "HALT" : "RUN"]")) + [islist(obj_count_finished)? length(obj_count_finished) : (isnull(obj_count_finished)? "0" : obj_count_finished)] - [get_query_text()]")]", REF(delete_click)) + L[++L.len] = list(" ", "[action_click.update("[SDQL2_IS_RUNNING? "HALT" : "RUN"]")]", REF(action_click)) + return L /datum/SDQL2_query/proc/delete_click() admin_del(usr) @@ -1161,10 +1164,18 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null return istype(thing, /datum) || istype(thing, /client) /obj/effect/statclick/SDQL2_delete/Click() + if(!usr.client?.holder) + message_admins("[key_name_admin(usr)] non-holder clicked on a statclick! ([src])") + log_game("[key_name(usr)] non-holder clicked on a statclick! ([src])") + return var/datum/SDQL2_query/Q = target Q.delete_click() /obj/effect/statclick/SDQL2_action/Click() + if(!usr.client?.holder) + message_admins("[key_name_admin(usr)] non-holder clicked on a statclick! ([src])") + log_game("[key_name(usr)] non-holder clicked on a statclick! ([src])") + return var/datum/SDQL2_query/Q = target Q.action_click() @@ -1172,4 +1183,13 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null name = "VIEW VARIABLES" /obj/effect/statclick/SDQL2_VV_all/Click() + if(!usr.client?.holder) + message_admins("[key_name_admin(usr)] non-holder clicked on a statclick! ([src])") + log_game("[key_name(usr)] non-holder clicked on a statclick! ([src])") + return usr.client.debug_variables(GLOB.sdql2_queries) + + if(!usr.client?.holder) + message_admins("[key_name_admin(usr)] non-holder clicked on a statclick! ([src])") + log_game("[key_name(usr)] non-holder clicked on a statclick! ([src])") + return \ No newline at end of file diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index b24ce6d1..256bdaf0 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -89,18 +89,23 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) //Tickets statpanel /datum/admin_help_tickets/proc/stat_entry() + SHOULD_CALL_PARENT(TRUE) + SHOULD_NOT_SLEEP(TRUE) + var/list/L = list() var/num_disconnected = 0 - stat("Active Tickets:", astatclick.update("[active_tickets.len]")) + L[++L.len] = list("Active Tickets:", "[astatclick.update("[active_tickets.len]")]", null, REF(astatclick)) + astatclick.update("[active_tickets.len]") for(var/I in active_tickets) var/datum/admin_help/AH = I if(AH.initiator) - stat("#[AH.id]. [AH.initiator_key_name]:", AH.statclick.update()) + L[++L.len] = list("#[AH.id]. [AH.initiator_key_name]:", "[AH.statclick.update()]", REF(AH)) else ++num_disconnected if(num_disconnected) - stat("Disconnected:", astatclick.update("[num_disconnected]")) - stat("Closed Tickets:", cstatclick.update("[closed_tickets.len]")) - stat("Resolved Tickets:", rstatclick.update("[resolved_tickets.len]")) + L[++L.len] = list("Disconnected:", "[astatclick.update("[num_disconnected]")]", null, REF(astatclick)) + L[++L.len] = list("Closed Tickets:", "[cstatclick.update("[closed_tickets.len]")]", null, REF(cstatclick)) + L[++L.len] = list("Resolved Tickets:", "[rstatclick.update("[resolved_tickets.len]")]", null, REF(rstatclick)) + return L //Reassociate still open ticket if one exists /datum/admin_help_tickets/proc/ClientLogin(client/C) @@ -137,6 +142,13 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) /obj/effect/statclick/ticket_list/Click() GLOB.ahelp_tickets.BrowseTickets(current_state) + +//called by admin topic +/obj/effect/statclick/ticket_list/proc/Action() + Click() + + + // //TICKET DATUM // @@ -221,7 +233,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) //Removes the ahelp verb and returns it after 30 seconds /datum/admin_help/proc/TimeoutVerb() - initiator.verbs -= /client/verb/adminhelp + remove_verb(initiator, /client/verb/adminhelp) initiator.adminhelptimerid = addtimer(CALLBACK(initiator, /client/proc/giveadminhelpverb), 300, TIMER_STOPPABLE) //30 seconds cooldown of admin helps //private @@ -492,7 +504,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) // /client/proc/giveadminhelpverb() - src.verbs |= /client/verb/adminhelp + add_verb(src, /client/verb/adminhelp) deltimer(adminhelptimerid) adminhelptimerid = 0 diff --git a/code/modules/admin/verbs/borgpanel.dm b/code/modules/admin/verbs/borgpanel.dm index c0445d58..1a5c7d33 100644 --- a/code/modules/admin/verbs/borgpanel.dm +++ b/code/modules/admin/verbs/borgpanel.dm @@ -199,7 +199,7 @@ borg.notify_ai(DISCONNECT) if(borg.shell) borg.undeploy() - borg.connected_ai = newai + borg.set_connected_ai(newai) borg.notify_ai(TRUE) message_admins("[key_name_admin(user)] slaved [ADMIN_LOOKUPFLW(borg)] to the AI [ADMIN_LOOKUPFLW(newai)].") log_admin("[key_name(user)] slaved [key_name(borg)] to the AI [key_name(newai)].") @@ -207,7 +207,7 @@ borg.notify_ai(DISCONNECT) if(borg.shell) borg.undeploy() - borg.connected_ai = null + borg.set_connected_ai(null) message_admins("[key_name_admin(user)] freed [ADMIN_LOOKUPFLW(borg)] from being slaved to an AI.") log_admin("[key_name(user)] freed [key_name(borg)] from being slaved to an AI.") if (borg.lawupdate) diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 699b2d50..8450793f 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -493,6 +493,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention) log_admin("[key_name(usr)] assumed direct control of [M].") var/mob/adminmob = src.mob M.ckey = src.ckey + init_verbs() if( isobserver(adminmob) ) qdel(adminmob) SSblackbox.record_feedback("tally", "admin_verb", 1, "Assume Direct Control") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index 3a0b1e97..bb005a6b 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -205,15 +205,15 @@ GLOBAL_LIST_EMPTY(dirty_vars) set name = "Debug verbs - Enable" if(!check_rights(R_DEBUG)) return - verbs -= /client/proc/enable_debug_verbs - verbs.Add(/client/proc/disable_debug_verbs, GLOB.admin_verbs_debug_mapping) + remove_verb(src, /client/proc/enable_debug_verbs) + add_verb(src, list(/client/proc/disable_debug_verbs, GLOB.admin_verbs_debug_mapping)) SSblackbox.record_feedback("tally", "admin_verb", 1, "Enable Debug Verbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/disable_debug_verbs() set category = "Debug" set name = "Debug verbs - Disable" - verbs.Remove(/client/proc/disable_debug_verbs, GLOB.admin_verbs_debug_mapping) - verbs += /client/proc/enable_debug_verbs + remove_verb(src, list(/client/proc/disable_debug_verbs, GLOB.admin_verbs_debug_mapping)) + add_verb(src, /client/proc/enable_debug_verbs) SSblackbox.record_feedback("tally", "admin_verb", 1, "Disable Debug Verbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/count_objects_on_z_level() diff --git a/code/modules/admin/verbs/possess.dm b/code/modules/admin/verbs/possess.dm index 445de4c4..ee4d1265 100644 --- a/code/modules/admin/verbs/possess.dm +++ b/code/modules/admin/verbs/possess.dm @@ -48,6 +48,6 @@ set desc = "Give this guy possess/release verbs" set category = "Debug" set name = "Give Possessing Verbs" - M.verbs += /proc/possess - M.verbs += /proc/release + add_verb(M, /proc/possess) + add_verb(M, /proc/release) SSblackbox.record_feedback("tally", "admin_verb", 1, "Give Possessing Verbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/antagonists/blob/blob/overmind.dm b/code/modules/antagonists/blob/blob/overmind.dm index 01882821..57ae1d4c 100644 --- a/code/modules/antagonists/blob/blob/overmind.dm +++ b/code/modules/antagonists/blob/blob/overmind.dm @@ -223,19 +223,16 @@ GLOBAL_LIST_EMPTY(blob_nodes) /mob/camera/blob/blob_act(obj/structure/blob/B) return -/mob/camera/blob/Stat() - ..() - if(statpanel("Status")) - if(blob_core) - stat(null, "Core Health: [blob_core.obj_integrity]") - stat(null, "Power Stored: [blob_points]/[max_blob_points]") - stat(null, "Blobs to Win: [blobs_legit.len]/[blobwincount]") - if(free_chem_rerolls) - stat(null, "You have [free_chem_rerolls] Free Chemical Reroll\s Remaining") - if(!placed) - if(manualplace_min_time) - stat(null, "Time Before Manual Placement: [max(round((manualplace_min_time - world.time)*0.1, 0.1), 0)]") - stat(null, "Time Before Automatic Placement: [max(round((autoplace_max_time - world.time)*0.1, 0.1), 0)]") +/mob/camera/blob/get_status_tab_items() + . = ..() + if(blob_core) + . += "Core Health: [blob_core.obj_integrity]" + . += "Power Stored: [blob_points]/[max_blob_points]" + . += "Blobs to Win: [blobs_legit.len]/[blobwincount]" + if(!placed) + if(manualplace_min_time) + . += "Time Before Manual Placement: [max(round((manualplace_min_time - world.time)*0.1, 0.1), 0)]" + . += "Time Before Automatic Placement: [max(round((autoplace_max_time - world.time)*0.1, 0.1), 0)]" /mob/camera/blob/Move(NewLoc, Dir = 0) if(placed) diff --git a/code/modules/antagonists/changeling/powers/absorb.dm b/code/modules/antagonists/changeling/powers/absorb.dm index 5cb4faa8..b3d5d683 100644 --- a/code/modules/antagonists/changeling/powers/absorb.dm +++ b/code/modules/antagonists/changeling/powers/absorb.dm @@ -60,6 +60,8 @@ if(user.nutrition < NUTRITION_LEVEL_WELL_FED) user.nutrition = min((user.nutrition + target.nutrition), NUTRITION_LEVEL_WELL_FED) + if(user.thirst < THIRST_LEVEL_QUENCHED) + user.thirst = min((user.thirst + target.thirst), THIRST_LEVEL_QUENCHED) if(target.mind)//if the victim has got a mind // Absorb a lizard, speak Draconic. diff --git a/code/modules/antagonists/disease/disease_abilities.dm b/code/modules/antagonists/disease/disease_abilities.dm index 7b30d10c..812f7c4a 100644 --- a/code/modules/antagonists/disease/disease_abilities.dm +++ b/code/modules/antagonists/disease/disease_abilities.dm @@ -76,7 +76,7 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list( resistance += initial(S.resistance) stage_speed += initial(S.stage_speed) transmittable += initial(S.transmittable) - threshold_block += initial(S.threshold_desc) + threshold_block += initial(S.threshold_desc) stat_block = "Resistance: [resistance]
Stealth: [stealth]
Stage Speed: [stage_speed]
Transmissibility: [transmittable]

" if(symptoms.len == 1) //lazy boy's dream name = initial(S.name) @@ -194,8 +194,6 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list( /datum/disease_ability/action/sneeze name = "Voluntary Sneezing" actions = list(/datum/action/cooldown/disease_sneeze) - cost = 2 - required_total_points = 3 short_desc = "Force the host you are following to sneeze, spreading your infection to those in front of them." long_desc = "Force the host you are following to sneeze with extra force, spreading your infection to any victims in a 4 meter cone in front of your host.
Cooldown: 20 seconds" @@ -232,8 +230,6 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list( /datum/disease_ability/action/infect name = "Secrete Infection" actions = list(/datum/action/cooldown/disease_infect) - cost = 2 - required_total_points = 3 short_desc = "Cause all objects your host is touching to become infectious for a limited time, spreading your infection to anyone who touches them." long_desc = "Cause the host you are following to excrete an infective substance from their pores, causing all objects touching their skin to transmit your infection to anyone who touches them for the next 30 seconds. This includes the floor, if they are not wearing shoes, and any items they are holding, if they are not wearing gloves.
Cooldown: 40 seconds" @@ -274,22 +270,19 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list( //healing costs more so you have to techswitch from naughty disease otherwise we'd have friendly disease for easy greentext (no fun!) /datum/disease_ability/symptom/mild - cost = 2 - required_total_points = 4 category = "Symptom (Weak)" /datum/disease_ability/symptom/medium - cost = 4 - required_total_points = 8 category = "Symptom" /datum/disease_ability/symptom/medium/heal cost = 5 + required_total_points = 5 category = "Symptom (+)" /datum/disease_ability/symptom/powerful cost = 4 - required_total_points = 16 + required_total_points = 10 category = "Symptom (Strong)" /datum/disease_ability/symptom/powerful/heal diff --git a/code/modules/antagonists/disease/disease_mob.dm b/code/modules/antagonists/disease/disease_mob.dm index e824c5c9..ff935f32 100644 --- a/code/modules/antagonists/disease/disease_mob.dm +++ b/code/modules/antagonists/disease/disease_mob.dm @@ -84,17 +84,16 @@ the new instance inside the host to be updated to the template's stats. to_chat(src, "You have [DisplayTimeText(freemove_end - world.time)] to select your first host. Click on a human to select your host.") -/mob/camera/disease/Stat() - ..() - if(statpanel("Status")) - if(freemove) - stat("Host Selection Time: [round((freemove_end - world.time)/10)]s") - else - stat("Adaptation Points: [points]/[total_points]") - stat("Hosts: [disease_instances.len]") - var/adapt_ready = next_adaptation_time - world.time - if(adapt_ready > 0) - stat("Adaptation Ready: [round(adapt_ready/10, 0.1)]s") +/mob/camera/disease/get_status_tab_items() + + if(freemove) + . += "Host Selection Time: [round((freemove_end - world.time)/10)]s" + else + . += "Adaptation Points: [points]/[total_points]" + . += "Hosts: [disease_instances.len]" + var/adapt_ready = next_adaptation_time - world.time + if(adapt_ready > 0) + . += "Adaptation Ready: [round(adapt_ready/10, 0.1)]s" /mob/camera/disease/examine(mob/user) diff --git a/code/modules/antagonists/nightmare/nightmare.dm b/code/modules/antagonists/nightmare/nightmare.dm index 41a3f181..847ceeb6 100644 --- a/code/modules/antagonists/nightmare/nightmare.dm +++ b/code/modules/antagonists/nightmare/nightmare.dm @@ -1,4 +1,21 @@ +#define LIGHTSTOBREAK_MINIMUM 25 +#define LIGHTSTOBREAK_MAXIMUM 75 +#define LIGHTSTOBREAK_THRESHOLD 50 +#define LIGHTSTOBREAK_MAX_CHANCE 50 +#define LIGHTSTOBREAK_AREA_MIN 1 +#define LIGHTSTOBREAK_AREA_MAX 2 + /datum/antagonist/nightmare name = "Nightmare" show_in_antagpanel = FALSE - show_name_in_check_antagonists = TRUE \ No newline at end of file + show_name_in_check_antagonists = TRUE + +/datum/antagonist/nightmare/on_gain() + owner.objectives += forge_objective() + owner.objectives += new /datum/objective/survive + +/datum/antagonist/nightmare/proc/forge_objective() + var/datum/objective/break_lights/O = new + O.mode = prob(50) ? TRUE : FALSE + antag_memory = "Objectives:
1.
[O.apply_rules()]
2. Stay alive until the end." + return O diff --git a/code/modules/antagonists/nightmare/nightmare_objectives.dm b/code/modules/antagonists/nightmare/nightmare_objectives.dm new file mode 100644 index 00000000..dbcadc5e --- /dev/null +++ b/code/modules/antagonists/nightmare/nightmare_objectives.dm @@ -0,0 +1,105 @@ +/datum/objective/break_lights + var/mode = FALSE //If true, break all lights in determined area + var/list/area_targets = list() //Which areas we have to keep lights broken + target_amount = LIGHTSTOBREAK_AREA_MIN + var/lightsbroken = 0 + + var/safe_areas = list( + /area/space, + /area/maintenance/solars, + /area/maintenance/central, //HOP/Conference room APC + /area/ai_monitored, + /area/shuttle, + /area/engine/engine_smes, + /area/security/prison, //If you get unlucky, you'll have to break the lights in armory + /area/security/execution) + +/datum/objective/break_lights/proc/apply_rules() + if(mode) + var/list/valid_areas = list() + for(var/obj/machinery/power/apc/C in GLOB.apcs_list) + if(C.cell && is_station_level(C.z)) + var/is_safearea = 1 + for(var/A in safe_areas) + if(istype(C.area, A)) + is_safearea = 0 + break + if(is_safearea) + valid_areas += C.area + var/I = rand(LIGHTSTOBREAK_AREA_MIN, LIGHTSTOBREAK_AREA_MAX) + for(var/N in 1 to I) + var/area2add = pick(valid_areas) + if(!locate(area2add) in area_targets) + area_targets += area2add + else + target_amount = rand(LIGHTSTOBREAK_MINIMUM, LIGHTSTOBREAK_MAXIMUM) + if(prob(LIGHTSTOBREAK_MAX_CHANCE)) + if(target_amount > LIGHTSTOBREAK_THRESHOLD) + target_amount = LIGHTSTOBREAK_MAXIMUM + else if(target_amount > LIGHTSTOBREAK_THRESHOLD) + target_amount = LIGHTSTOBREAK_THRESHOLD + explanation_text = update_explanation_text() + return explanation_text + +/datum/objective/break_lights/update_explanation_text() + ..() + if(mode) + if(!area_targets.len) + return "Uh oh! Something broke! Report this." + . += "There must not be any light sources in the " + if(area_targets.len == 1) + var/area/A = area_targets[1] + . += "[A.name]" + else if(area_targets.len == 2) + var/area/A = area_targets[1] + var/area/B = area_targets[2] + . += "[A.name] and [B.name]" + else //Won't get here because of define values, but during development you can get here. leaving this here for future purposes + var/i = 1 + for(var/area/A in area_targets) + if(i != area_targets.len) . += "[A.name], " + else . += "and [A.name]" + + . += " before the end." + else + . += "Break at least [target_amount] lights with your light eater." + +/datum/objective/break_lights/check_completion() + if(completed) + return TRUE //An attempt to stop this from being called twice + if(!mode) + if(lightsbroken >= target_amount) + completed = TRUE + else + var/list/valid_turfs = list() + for(var/area/target in area_targets) + var/list/cached_area = get_area_turfs(target.type) + for(var/turf/A in cached_area) + if(!is_station_level(A.z)) + continue + valid_turfs += A + for(var/turf/T in valid_turfs) + for(var/atom/C in T.contents) + /*if(!C?.visibility) //Doesn't compile, add this another time + continue*/ + if(C.light_range > 0) + if(C.light_power <= SHADOW_SPECIES_LIGHT_THRESHOLD*2) //Give some leniency for not destroying that unbreakable requests console + completed = TRUE + else + completed = FALSE + break + if(!completed) + break + + return completed + +/datum/objective/break_lights/area + mode = TRUE + + +#undef LIGHTSTOBREAK_MINIMUM +#undef LIGHTSTOBREAK_MAXIMUM +#undef LIGHTSTOBREAK_THRESHOLD +#undef LIGHTSTOBREAK_MAX_CHANCE +#undef LIGHTSTOBREAK_AREA_MIN +#undef LIGHTSTOBREAK_AREA_MAX diff --git a/code/modules/antagonists/revenant/revenant.dm b/code/modules/antagonists/revenant/revenant.dm index f4418a62..2fa4952a 100644 --- a/code/modules/antagonists/revenant/revenant.dm +++ b/code/modules/antagonists/revenant/revenant.dm @@ -124,12 +124,12 @@ update_health_hud() ..() -/mob/living/simple_animal/revenant/Stat() - ..() - if(statpanel("Status")) - stat(null, "Current essence: [essence]/[essence_regen_cap]E") - stat(null, "Stolen essence: [essence_accumulated]E") - stat(null, "Stolen perfect souls: [perfectsouls]") + +/mob/living/simple_animal/revenant/get_status_tab_items() + . = ..() + . += "Current essence: [essence]/[essence_regen_cap]E" + . += "Stolen essence: [essence_accumulated]E" + . += "Stolen perfect souls: [perfectsouls]" /mob/living/simple_animal/revenant/update_health_hud() if(hud_used) diff --git a/code/modules/antagonists/swarmer/swarmer.dm b/code/modules/antagonists/swarmer/swarmer.dm index 9f663fc5..02ddf315 100644 --- a/code/modules/antagonists/swarmer/swarmer.dm +++ b/code/modules/antagonists/swarmer/swarmer.dm @@ -107,7 +107,7 @@ /mob/living/simple_animal/hostile/swarmer/Initialize() . = ..() - verbs -= /mob/living/verb/pulled + remove_verb(src, /mob/living/verb/pulled) for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds) diag_hud.add_to_hud(src) @@ -123,10 +123,9 @@ holder.pixel_y = I.Height() - world.icon_size holder.icon_state = "hudstat" -/mob/living/simple_animal/hostile/swarmer/Stat() - ..() - if(statpanel("Status")) - stat("Resources:",resources) +/mob/living/simple_animal/hostile/swarmer/get_status_tab_items() + . = ..() + . += "Resources: [resources]" /mob/living/simple_animal/hostile/swarmer/emp_act() . = ..() diff --git a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm index 0d9b2a64..9fd0850f 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm @@ -89,6 +89,7 @@ if(!panel_open) return anchored = !anchored + move_resist = anchored? INFINITY : 100 I.play_tool_sound(src) if(generator) disconnectFromGenerator() diff --git a/code/modules/awaymissions/mission_code/wildwest.dm b/code/modules/awaymissions/mission_code/wildwest.dm index 505b9a1e..f13341fa 100644 --- a/code/modules/awaymissions/mission_code/wildwest.dm +++ b/code/modules/awaymissions/mission_code/wildwest.dm @@ -105,7 +105,7 @@ if("Immortality") to_chat(user, "Your wish is granted, but at a terrible cost...") to_chat(user, "The Wish Granter punishes you for your selfishness, claiming your soul and warping your body to match the darkness in your heart.") - user.verbs += /mob/living/carbon/proc/immortality + add_verb(user, /mob/living/carbon/proc/immortality) user.set_species(/datum/species/shadow) if("To Kill") to_chat(user, "Your wish is granted, but at a terrible cost...") diff --git a/code/modules/cargo/packs/engine.dm b/code/modules/cargo/packs/engine.dm index fd5c711b..44eb0ad5 100644 --- a/code/modules/cargo/packs/engine.dm +++ b/code/modules/cargo/packs/engine.dm @@ -169,12 +169,22 @@ crate_name = "tesla generator crate" /datum/supply_pack/engine/teg - name = "Thermoelectric Generator" - desc = "Contains your very own Thermoelectric Generator. Time to turn cargo into a blazing hellfire, perhaps?" - cost = 4000 - contains = list(/obj/machinery/power/generator) + name = "Thermoelectric Generator Assembly" + desc = "Contains your very own Thermoelectric Generator Assembly. Time to turn cargo into a blazing hellfire, perhaps?" + cost = 3000 + contains = list(/obj/item/paper/teg, + /obj/item/circuitboard/machine/generator, + /obj/item/circuitboard/machine/circulator, + /obj/item/circuitboard/machine/circulator, + /obj/item/stack/cable_coil, + /obj/item/stack/sheet/metal/twenty) crate_name = "thermoelectric generator crate" +/obj/item/paper/teg + info = "*The seemingly useful notes have been scribbled over with red and black crayon. Hmm.*" + name = "TEG Instructions" + color = "red" + /datum/supply_pack/engine/energy_harvester name = "Energy Harvesting Module" desc = "A Device which upon connection to a node, will harvest the energy and send it to engineerless stations in return for credits, derived from a syndicate powersink model." diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index 53170805..792e40ad 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -4,6 +4,10 @@ //BLACK MAGIC THINGS// ////////////////////// parent_type = /datum + + + /// hides the byond verb panel as we use our own custom version + show_verb_panel = FALSE //////////////// //ADMIN THINGS// //////////////// @@ -24,6 +28,12 @@ var/move_delay = 0 var/area = null + + + /// list of tabs containing spells and abilities + var/list/spell_tabs = list() + /// list of tabs containing verbs + var/list/verb_tabs = list() /////////////// //SOUND STUFF// /////////////// diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 23bfebb2..04b714f1 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -197,7 +197,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) debug_tools_allowed = TRUE //END CITADEL EDIT else if(GLOB.deadmins[ckey]) - verbs += /client/proc/readmin + add_verb(src, /client/proc/readmin) connecting_admin = TRUE if(CONFIG_GET(flag/autoadmin)) if(!GLOB.admin_datums[ckey]) @@ -243,7 +243,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) fps = 40 if(fexists(roundend_report_file())) - verbs += /client/proc/show_previous_roundend_report + add_verb(src, /client/proc/show_previous_roundend_report) var/full_version = "[byond_version].[byond_build ? byond_build : "xxx"]" log_access("Login: [key_name(src)] from [address ? address : "localhost"]-[computer_id] || BYOND v[full_version]") @@ -304,6 +304,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) set_macros() chatOutput.start() // Starts the chat + src << browse(file('html/statbrowser.html'), "window=statbrowser") //starts stats tab if(alert_mob_dupe_login) spawn() @@ -798,9 +799,9 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) /client/proc/add_verbs_from_config() if(CONFIG_GET(flag/see_own_notes)) - verbs += /client/proc/self_notes + add_verb(src, /client/proc/self_notes) if(CONFIG_GET(flag/use_exp_tracking)) - verbs += /client/proc/self_playtime + add_verb(src, /client/proc/self_playtime) #undef UPLOAD_LIMIT @@ -865,6 +866,31 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) y = CLAMP(y+change, min,max) change_view("[x]x[y]") +/// compiles a full list of verbs and sends it to the browser +/client/proc/init_verbs() + if(IsAdminAdvancedProcCall()) + return + var/list/verblist = list() + + var/list/verbstoprocess = verbs.Copy() + if(mob) + verbstoprocess += mob.verbs + for(var/AM in mob.contents) + var/atom/movable/thing = AM + verbstoprocess += thing.verbs + verb_tabs.Cut() + for(var/thing in verbstoprocess) + var/procpath/verb_to_init = thing + if(!verb_to_init) + continue + if(verb_to_init.hidden) + continue + if(!istext(verb_to_init.category)) + continue + verb_tabs |= verb_to_init.category + verblist[++verblist.len] = list(verb_to_init.category, verb_to_init.name) + src << output("[url_encode(json_encode(verb_tabs))];[url_encode(json_encode(verblist))]", "statbrowser:init_verbs") + /client/proc/change_view(new_size) if (isnull(new_size)) CRASH("change_view called without argument.") diff --git a/code/modules/client/darkmode.dm b/code/modules/client/darkmode.dm index f806e5c9..ad8e5ef0 100644 --- a/code/modules/client/darkmode.dm +++ b/code/modules/client/darkmode.dm @@ -37,6 +37,7 @@ Thanks to spacemaniac and mcdonald for help with the JS side of this. winset(src, "say", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") winset(src, "asset_cache_browser", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") winset(src, "tooltip", "background-color = [COLOR_WHITEMODE_BACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") + src << output(null, "statbrowser:set_light_theme") /client/proc/force_dark_theme() //Inversely, if theyre using white theme and want to swap to the superior dark theme, let's get WINSET() ing //Main windows @@ -62,4 +63,5 @@ Thanks to spacemaniac and mcdonald for help with the JS side of this. //Etc. winset(src, "say", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") winset(src, "asset_cache_browser", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "tooltip", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") \ No newline at end of file + winset(src, "tooltip", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") + src << output(null, "statbrowser:set_dark_theme") \ No newline at end of file diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm index 1465a0c9..087c434b 100644 --- a/code/modules/client/verbs/ooc.dm +++ b/code/modules/client/verbs/ooc.dm @@ -366,3 +366,10 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8") pct += delta winset(src, "mainwindow.split", "splitter=[pct]") + + +/client/verb/fix_stat_panel() + set name = "Fix Stat Panel" + set hidden = TRUE + + init_verbs() \ No newline at end of file diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm index 120e690c..23d1d686 100644 --- a/code/modules/clothing/glasses/hud.dm +++ b/code/modules/clothing/glasses/hud.dm @@ -47,17 +47,13 @@ name = "prescription health scanner HUD" desc = "A heads-up display, made with a prescription lens, that scans the humans in view and provides accurate data about their health status." icon_state = "healthhud" - hud_type = DATA_HUD_MEDICAL_ADVANCED vision_correction = 1 - glass_colour_type = /datum/client_colour/glass_colour/lightblue /obj/item/clothing/glasses/hud/health/gar name = "gar health scanner HUD" desc = "When you're scared, that's all the more reason to move forward!" icon_state = "garh" item_state = "garh" - hud_type = DATA_HUD_MEDICAL_ADVANCED - glass_colour_type = /datum/client_colour/glass_colour/lightblue force = 10 throwforce = 10 throw_speed = 4 @@ -100,9 +96,7 @@ name = "prescription diagnostic HUD" desc = "A heads-up display capable of analyzing the integrity and status of robotics and exosuits. This one has a prescription lens." icon_state = "diagnostichud" - hud_type = DATA_HUD_DIAGNOSTIC_BASIC vision_correction = 1 - glass_colour_type = /datum/client_colour/glass_colour/lightorange /obj/item/clothing/glasses/hud/diagnostic/night name = "night vision diagnostic HUD" @@ -124,9 +118,7 @@ name = "prescription security HUD" desc = "A heads-up display that scans the humans in view and provides accurate data about their ID status and security records. This one has a prescription lens so you can see the banana peal that slipped you." icon_state = "securityhud" - hud_type = DATA_HUD_SECURITY_ADVANCED vision_correction = 1 - glass_colour_type = /datum/client_colour/glass_colour/red /obj/item/clothing/glasses/hud/security/chameleon name = "chameleon security HUD" diff --git a/code/modules/events/aurora_caelus.dm b/code/modules/events/aurora_caelus.dm index b941a978..a32532d1 100644 --- a/code/modules/events/aurora_caelus.dm +++ b/code/modules/events/aurora_caelus.dm @@ -12,10 +12,11 @@ /datum/round_event/aurora_caelus announceWhen = 1 - startWhen = 9 + startWhen = 8 //Delayed with sleep() endWhen = 50 var/list/aurora_colors = list("#ffd980", "#eaff80", "#eaff80", "#ffd980", "#eaff80", "#A2FFC7", "#9400D3", "#FFC0CB") var/aurora_progress = 0 //this cycles from 1 to 8, slowly changing colors from gentle green to gentle blue + var/list/applicable_areas = list() /datum/round_event/aurora_caelus/announce() priority_announce("[station_name()]: A harmless cloud of ions is approaching your station, and will exhaust their energy battering the hull. Kinaris Command has approved a short break for all employees to relax and observe this very rare event. During this time, starlight will be bright but gentle, shifting between quiet green and blue colors. We will also play quiet music for you to enjoy and relax. Any staff who would like to view these lights for themselves may proceed to the area nearest to them with viewing ports to open space. We hope you enjoy the lights.", @@ -25,38 +26,67 @@ var/mob/M = V if((M.client.prefs.toggles & SOUND_MIDI) && is_station_level(M.z)) M.playsound_local(M, 'sound/ambience/aurora_caelus_new.ogg', 40, FALSE, pressure_affected = FALSE) //ogg is "The Fire is Gone" by Heaven Pierce Her, used in the videogame ULTRAKILL. All respects and credits to the equivalent artists who worked on it. + start_checking() + +/datum/round_event/aurora_caelus/proc/start_checking() + var/list/turfs_to_check = list() + var/x = 1 + var/y = 1 + while(TRUE) + turfs_to_check += locate(x,y,2) //If the station z-level ever gets changed, change this too. I couldn't find if there's an easy way to get it + x++ + if(x > 255) + x = 0 + y++ + if(y > 255) + break + if(!turfs_to_check) + CRASH("Aurora Caelus called, but there's no space!") + var/tlen = turfs_to_check.len + var/i = 0 + while(i < tlen) + i++ + var/turf/T = turfs_to_check[i] + if(!istype(T, /turf/open/space)) + continue + if(i%2500 == 0) + sleep(1) //try to spread the lag around a bit + var/sure = (!istype(get_step(T, NORTH)?.loc, /area/space)||\ + !istype(get_step(T, NORTHEAST)?.loc, /area/space)||\ + !istype(get_step(T, EAST)?.loc, /area/space)||\ + !istype(get_step(T, SOUTHEAST)?.loc, /area/space)||\ + !istype(get_step(T, SOUTH)?.loc, /area/space)||\ + !istype(get_step(T, SOUTHWEST)?.loc, /area/space)||\ + !istype(get_step(T, WEST)?.loc, /area/space)||\ + !istype(get_step(T, NORTHWEST)?.loc, /area/space)) //Better than using range() + if(sure) + applicable_areas += T /datum/round_event/aurora_caelus/start() - for(var/area in GLOB.sortedAreas) - var/area/A = area - if(initial(A.dynamic_lighting) == DYNAMIC_LIGHTING_IFSTARLIGHT) - for(var/turf/open/space/S in A) - S.set_light(S.light_range * 6, S.light_power * 1) + for(var/turf/S in applicable_areas) + S.set_light(6, 0.8, l_color = aurora_colors[1]) /datum/round_event/aurora_caelus/tick() if(activeFor % 5 == 0) aurora_progress++ + if(aurora_progress > LAZYLEN(aurora_colors)) + aurora_progress = 1 var/aurora_color = aurora_colors[aurora_progress] - for(var/area in GLOB.sortedAreas) - var/area/A = area - if(initial(A.dynamic_lighting) == DYNAMIC_LIGHTING_IFSTARLIGHT) - for(var/turf/open/space/S in A) - S.set_light(l_color = aurora_color) + for(var/turf/S in applicable_areas) + S.set_light(l_color = aurora_color) /datum/round_event/aurora_caelus/end() - for(var/area in GLOB.sortedAreas) - var/area/A = area - if(initial(A.dynamic_lighting) == DYNAMIC_LIGHTING_IFSTARLIGHT) - for(var/turf/open/space/S in A) - fade_to_black(S) priority_announce("The aurora caelus event is now ending. Starlight conditions will slowly return to normal. When this has concluded, please return to your workplace and continue work as normal. Have a pleasant shift, [station_name()], and thank you for watching with us.", - sound = 'sound/misc/notice2.ogg', - sender_override = "Kinaris Meteorology Division") + sound = 'sound/misc/notice2.ogg', + sender_override = "Kinaris Meteorology Division") + for(var/S in applicable_areas) + fade_to_black(S) /datum/round_event/aurora_caelus/proc/fade_to_black(turf/open/space/S) set waitfor = FALSE - var/new_light = initial(S.light_range) - while(S.light_range > new_light) - S.set_light(S.light_range - 0.2) - sleep(30) - S.set_light(new_light, initial(S.light_power), initial(S.light_color)) + var/i = 0.8 + while(i>0) + S.set_light(l_power=i) + sleep(10) + i -= 0.05 //16 seconds + S.set_light(initial(S.light_range), initial(S.light_power), initial(S.light_color)) diff --git a/code/modules/events/wizard/ghost.dm b/code/modules/events/wizard/ghost.dm index d5366c57..c288953e 100644 --- a/code/modules/events/wizard/ghost.dm +++ b/code/modules/events/wizard/ghost.dm @@ -21,6 +21,6 @@ /datum/round_event/wizard/possession/start() for(var/mob/dead/observer/G in GLOB.player_list) - G.verbs += /mob/dead/observer/verb/boo - G.verbs += /mob/dead/observer/verb/possess + add_verb(G, /mob/dead/observer/verb/boo) + add_verb(G, /mob/dead/observer/verb/possess) to_chat(G, "You suddenly feel a welling of new spooky powers...") diff --git a/code/modules/food_and_drinks/recipes/drinks_recipes.dm b/code/modules/food_and_drinks/recipes/drinks_recipes.dm index 473267fc..f807a491 100644 --- a/code/modules/food_and_drinks/recipes/drinks_recipes.dm +++ b/code/modules/food_and_drinks/recipes/drinks_recipes.dm @@ -885,7 +885,7 @@ id = /datum/reagent/consumable/ethanol/hotlime_miami results = list(/datum/reagent/consumable/ethanol/hotlime_miami = 2) required_reagents = list(/datum/reagent/medicine/ephedrine = 1, /datum/reagent/consumable/ethanol/pina_colada = 1) - + /datum/chemical_reaction/commander_and_chief name = "Commander and Chief" id = /datum/reagent/consumable/ethanol/commander_and_chief @@ -899,3 +899,15 @@ results = list(/datum/reagent/consumable/wockyslush = 5) required_reagents = list(/datum/reagent/toxin/fentanyl = 1, /datum/reagent/consumable/ice = 1, /datum/reagent/consumable/lemon_lime = 1) mix_message = "That thang bleedin’ P!" + +/datum/chemical_reaction/cum_in_a_hot_tub + name = "Cum in a Hot Tub" + id = /datum/reagent/consumable/ethanol/cum_in_a_hot_tub + results = list(/datum/reagent/consumable/ethanol/cum_in_a_hot_tub = 3) + required_reagents = list(/datum/reagent/consumable/ethanol/vodka = 2, /datum/reagent/consumable/ethanol/white_russian = 1, /datum/reagent/consumable/ethanol/irish_cream = 0.1) + +/datum/chemical_reaction/cum_in_a_hot_tub/semen + name = "Cum in a Hot Tub" + id = /datum/reagent/consumable/ethanol/cum_in_a_hot_tub/semen + results = list(/datum/reagent/consumable/ethanol/cum_in_a_hot_tub/semen = 3) + required_reagents = list(/datum/reagent/consumable/ethanol/vodka = 2, /datum/reagent/consumable/semen = 1, /datum/reagent/consumable/ethanol/irish_cream = 0.1) diff --git a/code/modules/hydroponics/hydro_chemreact.dm b/code/modules/hydroponics/hydro_chemreact.dm deleted file mode 100644 index b0821ae3..00000000 --- a/code/modules/hydroponics/hydro_chemreact.dm +++ /dev/null @@ -1,264 +0,0 @@ -/obj/machinery/hydroponics/proc/applyFertilizer(datum/reagents/S, mob/user) - // Ambrosia Gaia produces earthsblood. - if(S.has_reagent(/datum/reagent/medicine/earthsblood)) - self_sufficiency_progress += S.get_reagent_amount(/datum/reagent/medicine/earthsblood) - if(self_sufficiency_progress >= self_sufficiency_req) - become_self_sufficient() - else if(!self_sustaining) - to_chat(user, "[src] warms as it might on a spring day under a genuine Sun.") - - // Requires 5 mutagen to possibly change species.// Poor man's mutagen. - if(S.has_reagent(/datum/reagent/toxin/mutagen, 5) || S.has_reagent(/datum/reagent/radium, 10) || S.has_reagent(/datum/reagent/uranium, 10)) - switch(rand(100)) - if(91 to 100) - adjustHealth(-10) - to_chat(user, "The plant shrivels and burns.") - if(81 to 90) - mutatespecie() - if(66 to 80) - hardmutate() - if(41 to 65) - mutate() - if(21 to 41) - to_chat(user, "The plants don't seem to react...") - if(11 to 20) - mutateweed() - if(1 to 10) - mutatepest(user) - else - to_chat(user, "Nothing happens...") - - // 2 or 1 units is enough to change the yield and other stats.// Can change the yield and other stats, but requires more than mutagen - else if(S.has_reagent(/datum/reagent/toxin/mutagen, 2) || S.has_reagent(/datum/reagent/radium, 5) || S.has_reagent(/datum/reagent/uranium, 5)) - hardmutate() - else if(S.has_reagent(/datum/reagent/toxin/mutagen, 1) || S.has_reagent(/datum/reagent/radium, 2) || S.has_reagent(/datum/reagent/uranium, 2)) - mutate() - - // Nutriments - if(S.has_reagent(/datum/reagent/plantnutriment/eznutriment, 1)) - yieldmod = 1 - mutmod = 1 - adjustNutri(round(S.get_reagent_amount(/datum/reagent/plantnutriment/eznutriment) * 1)) - if(S.has_reagent(/datum/reagent/plantnutriment/left4zednutriment, 1)) - yieldmod = 0 - mutmod = 2 - adjustNutri(round(S.get_reagent_amount(/datum/reagent/plantnutriment/left4zednutriment) * 1)) - if(S.has_reagent(/datum/reagent/plantnutriment/robustharvestnutriment, 1)) - yieldmod = 1.3 - mutmod = 0 - adjustNutri(round(S.get_reagent_amount(/datum/reagent/plantnutriment/robustharvestnutriment) * 1)) - - - - -/obj/machinery/hydroponics/proc/applyChemicals(datum/reagents/S, mob/user) - if(!myseed) - return - myseed.on_chem_reaction(S) //In case seeds have some special interactions with special chems, currently only used by vines - - // After handling the mutating, we now handle the damage from adding crude radioactives... - if(S.has_reagent(/datum/reagent/uranium, 1)) - adjustHealth(-round(S.get_reagent_amount(/datum/reagent/uranium) * 1)) - adjustToxic(round(S.get_reagent_amount(/datum/reagent/uranium) * 2)) - if(S.has_reagent(/datum/reagent/radium, 1)) - adjustHealth(-round(S.get_reagent_amount(/datum/reagent/radium) * 1)) - adjustToxic(round(S.get_reagent_amount(/datum/reagent/radium) * 3)) // Radium is harsher (OOC: also easier to produce) - - if(S.has_reagent(/datum/reagent/plantnutriment/endurogrow, 1)) - var/total_transferred = S.get_reagent_amount(/datum/reagent/plantnutriment/endurogrow) - if(total_transferred >= 20) - myseed.adjust_potency(-round(total_transferred / 10)) - myseed.adjust_yield(-round(total_transferred / 20)) - myseed.adjust_endurance(round(total_transferred / 60)) - else - to_chat(user, "The plants don't seem to react...") - - if(S.has_reagent(/datum/reagent/plantnutriment/liquidearthquake, 1)) - var/total_transferred = S.get_reagent_amount(/datum/reagent/plantnutriment/liquidearthquake) - if(total_transferred >= 20) - myseed.adjust_weed_chance(round(total_transferred / 10)) - myseed.adjust_weed_rate(round(total_transferred / 60)) - myseed.adjust_production(round(total_transferred / 60)) - else - to_chat(user, "The plants don't seem to react...") - - // Antitoxin binds shit pretty well. So the tox goes significantly down - if(S.has_reagent(/datum/reagent/medicine/charcoal, 1)) - adjustToxic(-round(S.get_reagent_amount(/datum/reagent/medicine/charcoal) * 2)) - - // Toxins, not good for anything - if(S.has_reagent(/datum/reagent/toxin, 1)) - adjustToxic(round(S.get_reagent_amount(/datum/reagent/toxin) * 2)) - - // Milk is good for humans, but bad for plants. The sugars canot be used by plants, and the milk fat fucks up growth. Not shrooms though. I can't deal with this now... - if(S.has_reagent(/datum/reagent/consumable/milk, 1)) - adjustNutri(round(S.get_reagent_amount(/datum/reagent/consumable/milk) * 0.1)) - adjustWater(round(S.get_reagent_amount(/datum/reagent/consumable/milk) * 0.9)) - - // Beer is a chemical composition of alcohol and various other things. It's a shitty nutrient but hey, it's still one. Also alcohol is bad, mmmkay? - if(S.has_reagent(/datum/reagent/consumable/ethanol/beer, 1)) - adjustHealth(-round(S.get_reagent_amount(/datum/reagent/consumable/ethanol/beer) * 0.05)) - adjustNutri(round(S.get_reagent_amount(/datum/reagent/consumable/ethanol/beer) * 0.25)) - adjustWater(round(S.get_reagent_amount(/datum/reagent/consumable/ethanol/beer) * 0.7)) - - // Fluorine one of the most corrosive and deadly gasses - if(S.has_reagent(/datum/reagent/fluorine, 1)) - adjustHealth(-round(S.get_reagent_amount(/datum/reagent/fluorine) * 2)) - adjustToxic(round(S.get_reagent_amount(/datum/reagent/fluorine) * 2.5)) - adjustWater(-round(S.get_reagent_amount(/datum/reagent/fluorine) * 0.5)) - adjustWeeds(-rand(1,4)) - - // Chlorine one of the most corrosive and deadly gasses - if(S.has_reagent(/datum/reagent/chlorine, 1)) - adjustHealth(-round(S.get_reagent_amount(/datum/reagent/chlorine) * 1)) - adjustToxic(round(S.get_reagent_amount(/datum/reagent/chlorine) * 1.5)) - adjustWater(-round(S.get_reagent_amount(/datum/reagent/chlorine) * 0.5)) - adjustWeeds(-rand(1,3)) - - // White Phosphorous + water -> phosphoric acid. That's not a good thing really. - // Phosphoric salts are beneficial though. And even if the plant suffers, in the long run the tray gets some nutrients. The benefit isn't worth that much. - if(S.has_reagent(/datum/reagent/phosphorus, 1)) - adjustHealth(-round(S.get_reagent_amount(/datum/reagent/phosphorus) * 0.75)) - adjustNutri(round(S.get_reagent_amount(/datum/reagent/phosphorus) * 0.1)) - adjustWater(-round(S.get_reagent_amount(/datum/reagent/phosphorus) * 0.5)) - adjustWeeds(-rand(1,2)) - - // Plants should not have sugar, they can't use it and it prevents them getting water/nutients, it is good for mold though... - if(S.has_reagent(/datum/reagent/consumable/sugar, 1)) - adjustWeeds(rand(1,2)) - adjustPests(rand(1,2)) - adjustNutri(round(S.get_reagent_amount(/datum/reagent/consumable/sugar) * 0.1)) - - // It is water! - if(S.has_reagent(/datum/reagent/water, 1)) - adjustWater(round(S.get_reagent_amount(/datum/reagent/water) * 1)) - - // Holy water. Mostly the same as water, it also heals the plant a little with the power of the spirits~ - if(S.has_reagent(/datum/reagent/water/holywater, 1)) - adjustWater(round(S.get_reagent_amount(/datum/reagent/water/holywater) * 1)) - adjustHealth(round(S.get_reagent_amount(/datum/reagent/water/holywater) * 0.1)) - - // A variety of nutrients are dissolved in club soda, without sugar. - // These nutrients include carbon, oxygen, hydrogen, phosphorous, potassium, sulfur and sodium, all of which are needed for healthy plant growth. - if(S.has_reagent(/datum/reagent/consumable/sodawater, 1)) - adjustWater(round(S.get_reagent_amount(/datum/reagent/consumable/sodawater) * 1)) - adjustHealth(round(S.get_reagent_amount(/datum/reagent/consumable/sodawater) * 0.1)) - adjustNutri(round(S.get_reagent_amount(/datum/reagent/consumable/sodawater) * 0.1)) - - // Sulphuric Acid - if(S.has_reagent(/datum/reagent/toxin/acid, 1)) - adjustHealth(-round(S.get_reagent_amount(/datum/reagent/toxin/acid) * 1)) - adjustToxic(round(S.get_reagent_amount(/datum/reagent/toxin/acid) * 1.5)) - adjustWeeds(-rand(1,2)) - - // Acid - if(S.has_reagent(/datum/reagent/toxin/acid/fluacid, 1)) - adjustHealth(-round(S.get_reagent_amount(/datum/reagent/toxin/acid/fluacid) * 2)) - adjustToxic(round(S.get_reagent_amount(/datum/reagent/toxin/acid/fluacid) * 3)) - adjustWeeds(-rand(1,4)) - - // Plant-B-Gone is just as bad - if(S.has_reagent(/datum/reagent/toxin/plantbgone, 1)) - adjustHealth(-round(S.get_reagent_amount(/datum/reagent/toxin/plantbgone) * 5)) - adjustToxic(round(S.get_reagent_amount(/datum/reagent/toxin/plantbgone) * 6)) - adjustWeeds(-rand(4,8)) - - // Napalm, not known for being good for anything organic - if(S.has_reagent(/datum/reagent/napalm, 1)) - if(!(myseed.resistance_flags & FIRE_PROOF)) - adjustHealth(-round(S.get_reagent_amount(/datum/reagent/napalm) * 6)) - adjustToxic(round(S.get_reagent_amount(/datum/reagent/napalm) * 7)) - adjustWeeds(-rand(5,9)) - - //Weed Spray - if(S.has_reagent(/datum/reagent/toxin/plantbgone/weedkiller, 1)) - adjustToxic(round(S.get_reagent_amount(/datum/reagent/toxin/plantbgone/weedkiller) * 0.5)) - //old toxicity was 4, each spray is default 10 (minimal of 5) so 5 and 2.5 are the new ammounts - adjustWeeds(-rand(1,2)) - - //Pest Spray - if(S.has_reagent(/datum/reagent/toxin/pestkiller, 1)) - adjustToxic(round(S.get_reagent_amount(/datum/reagent/toxin/pestkiller) * 0.5)) - adjustPests(-rand(1,2)) - - // Healing - if(S.has_reagent(/datum/reagent/medicine/cryoxadone, 1)) - adjustHealth(round(S.get_reagent_amount(/datum/reagent/medicine/cryoxadone) * 3)) - adjustToxic(-round(S.get_reagent_amount(/datum/reagent/medicine/cryoxadone) * 3)) - - // Ammonia is bad ass. - if(S.has_reagent(/datum/reagent/ammonia, 1)) - adjustHealth(round(S.get_reagent_amount(/datum/reagent/ammonia) * 0.5)) - adjustNutri(round(S.get_reagent_amount(/datum/reagent/ammonia) * 1)) - if(myseed) - myseed.adjust_yield(round(S.get_reagent_amount(/datum/reagent/ammonia) * 0.01)) - - // Saltpetre is used for gardening IRL, to simplify highly, it speeds up growth and strengthens plants - if(S.has_reagent(/datum/reagent/saltpetre, 1)) - var/salt = S.get_reagent_amount(/datum/reagent/saltpetre) - adjustHealth(round(salt * 0.25)) - if (myseed) - myseed.adjust_production(-round(salt/100)-prob(salt%100)) - myseed.adjust_potency(round(salt*0.5)) - // Ash is also used IRL in gardening, as a fertilizer enhancer and weed killer - if(S.has_reagent(/datum/reagent/ash, 1)) - adjustHealth(round(S.get_reagent_amount(/datum/reagent/ash) * 0.25)) - adjustNutri(round(S.get_reagent_amount(/datum/reagent/ash) * 0.5)) - adjustWeeds(-1) - - // Diethylamine is more bad ass, and pests get hurt by the corrosive nature of it, not the plant. - if(S.has_reagent(/datum/reagent/diethylamine, 1)) - adjustHealth(round(S.get_reagent_amount(/datum/reagent/diethylamine) * 1)) - adjustNutri(round(S.get_reagent_amount(/datum/reagent/diethylamine) * 2)) - if(myseed) - myseed.adjust_yield(round(S.get_reagent_amount(/datum/reagent/diethylamine) * 0.02)) - adjustPests(-rand(1,2)) - - // Enduro Grow sacrifices potency + yield for endurance - if(S.has_reagent(/datum/reagent/plantnutriment/endurogrow, 1)) - myseed.adjust_potency(-round(S.get_reagent_amount(/datum/reagent/plantnutriment/endurogrow) * 0.1)) - myseed.adjust_yield(-round(S.get_reagent_amount(/datum/reagent/plantnutriment/endurogrow) * 0.075)) - myseed.adjust_endurance(round(S.get_reagent_amount(/datum/reagent/plantnutriment/endurogrow) * 0.35)) - - // Liquid Earthquake increases production speed but increases weeds - if(S.has_reagent(/datum/reagent/plantnutriment/liquidearthquake, 1)) - myseed.adjust_weed_rate(round(S.get_reagent_amount(/datum/reagent/plantnutriment/liquidearthquake) * 0.1)) - myseed.adjust_weed_chance(round(S.get_reagent_amount(/datum/reagent/plantnutriment/liquidearthquake) * 0.3)) - myseed.adjust_production(round(S.get_reagent_amount(/datum/reagent/plantnutriment/liquidearthquake) * 0.075)) - - // Nutriment Compost, effectively - if(S.has_reagent(/datum/reagent/consumable/nutriment, 1)) - adjustHealth(round(S.get_reagent_amount(/datum/reagent/consumable/nutriment) * 0.5)) - adjustNutri(round(S.get_reagent_amount(/datum/reagent/consumable/nutriment) * 1)) - - // Virusfood Compost for EVERYTHING - if(S.has_reagent(/datum/reagent/toxin/mutagen/mutagenvirusfood, 1)) - adjustNutri(round(S.get_reagent_amount(/datum/reagent/toxin/mutagen/mutagenvirusfood) * 0.5)) - adjustHealth(-round(S.get_reagent_amount(/datum/reagent/toxin/mutagen/mutagenvirusfood) * 0.5)) - - // Blood - if(S.has_reagent(/datum/reagent/blood, 1)) - adjustNutri(round(S.get_reagent_amount(/datum/reagent/blood) * 1)) - adjustPests(rand(2,4)) - - // Strange reagent - if(S.has_reagent(/datum/reagent/medicine/strange_reagent, 1)) - spawnplant() - - // Adminordrazine the best stuff there is. For testing/debugging. - if(S.has_reagent(/datum/reagent/medicine/adminordrazine, 1)) - adjustWater(round(S.get_reagent_amount(/datum/reagent/medicine/adminordrazine) * 1)) - adjustHealth(round(S.get_reagent_amount(/datum/reagent/medicine/adminordrazine) * 1)) - adjustNutri(round(S.get_reagent_amount(/datum/reagent/medicine/adminordrazine) * 1)) - adjustPests(-rand(1,5)) - adjustWeeds(-rand(1,5)) - if(S.has_reagent(/datum/reagent/medicine/adminordrazine, 5)) - switch(rand(100)) - if(66 to 100) - mutatespecie() - if(33 to 65) - mutateweed() - if(1 to 32) - mutatepest(user) - else - to_chat(user, "Nothing happens...") diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index d2cc76d9..c7bed07a 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -512,13 +512,14 @@ else if(transfer_amount) // Droppers, cans, beakers, what have you. visi_msg="[user] uses [reagent_source] on [target]" irrigate = 1 + if(reagent_source.is_drainable()) + playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE) if(irrigate && transfer_amount > 30 && reagent_source.reagents.total_volume >= 30 && using_irrigation) trays = FindConnected() if (trays.len > 1) visi_msg += ", setting off the irrigation system." - playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE) if(visi_msg) visible_message("[visi_msg]") @@ -528,15 +529,17 @@ for(var/obj/machinery/hydroponics/H in trays) //cause I don't want to feel like im juggling 15 tamagotchis and I can get to my real work of ripping flooring apart in hopes of validating my life choices of becoming a space-gardener - var/datum/reagents/S = new /datum/reagents() //This is a strange way, but I don't know of a better one so I can't fix it at the moment... - S.my_atom = H + var/datum/reagents/S = new /datum/reagents //This is a strange way, but I don't know of a better one so I can't fix it at the moment... reagent_source.reagents.trans_to(S,split) if(istype(reagent_source, /obj/item/reagent_containers/food/snacks) || istype(reagent_source, /obj/item/reagent_containers/pill)) qdel(reagent_source) - lastuser = user - H.applyFertilizer(S, user) - H.applyChemicals(S, user) + if(myseed) + myseed.on_chem_reaction(S) + lastuser = user + for(var/datum/reagent/R in S.reagent_list) + if(R.on_tray(H, R.volume, user) >= 1) + lastuser = user S.clear_reagents() qdel(S) @@ -544,6 +547,7 @@ if(reagent_source) // If the source wasn't composted and destroyed reagent_source.update_icon() + else if(istype(O, /obj/item/seeds) && !istype(O, /obj/item/seeds/sample)) if(!myseed) if(istype(O, /obj/item/seeds/kudzu)) diff --git a/code/modules/integrated_electronics/subtypes/reagents.dm b/code/modules/integrated_electronics/subtypes/reagents.dm index 0fc9f58d..bfa2532d 100644 --- a/code/modules/integrated_electronics/subtypes/reagents.dm +++ b/code/modules/integrated_electronics/subtypes/reagents.dm @@ -36,10 +36,11 @@ for(var/obj/machinery/hydroponics/H in trays) var/datum/reagents/temp_reagents = new /datum/reagents() - temp_reagents.my_atom = H source.reagents.trans_to(temp_reagents, split) - H.applyChemicals(temp_reagents) + for(var/datum/reagent/R in temp_reagents.reagent_list) + if(R.on_tray(H, R.volume, src) >= 1) + tray.lastuser = src temp_reagents.clear_reagents() qdel(temp_reagents) diff --git a/code/modules/jobs/access.dm b/code/modules/jobs/access.dm index 29234a2b..61960572 100644 --- a/code/modules/jobs/access.dm +++ b/code/modules/jobs/access.dm @@ -356,9 +356,9 @@ /proc/get_all_jobs() return list("Assistant", "Captain", "Head of Personnel", "Bartender", "Cook", "Botanist", "Quartermaster", "Cargo Technician", - "Shaft Miner", "Clown", "Mime", "Janitor", "Curator", "Lawyer", "Chaplain", "Chief Engineer", "Station Engineer", - "Atmospheric Technician", "Chief Medical Officer", "Medical Doctor", "Chemist", "Geneticist", "Virologist", - "Research Director", "Scientist", "Roboticist", "Head of Security", "Warden", "Detective", "Security Officer") + "Shaft Miner", "Clown", "Mime", "Janitor", "Curator", "Lawyer", "Chaplain", "Chief Engineer", "Station Engineer", "Engineering Intern", + "Atmospheric Technician", "Chief Medical Officer", "Medical Doctor", "Chemist", "Geneticist", "Virologist", "Medical Resident", + "Research Director", "Scientist", "Roboticist", "Research Student", "Head of Security", "Warden", "Detective", "Security Officer", "Rookie") /proc/get_all_job_icons() //For all existing HUD icons return get_all_jobs() + list("Prisoner") diff --git a/code/modules/jobs/job_types/engineering.dm b/code/modules/jobs/job_types/engineering.dm index 3514e7c8..ce36edcc 100644 --- a/code/modules/jobs/job_types/engineering.dm +++ b/code/modules/jobs/job_types/engineering.dm @@ -196,6 +196,7 @@ Junior Engineer ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) minimal_access = list(ACCESS_TECH_STORAGE, ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_MAINT_TUNNELS, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) + override_roundstart_spawn = /obj/effect/landmark/start/station_engineer /datum/outfit/job/engineer/junior name = "Engineering Intern" @@ -228,9 +229,3 @@ Junior Engineer suit_store = /obj/item/tank/internals/oxygen head = null internals_slot = SLOT_S_STORE - -/datum/job/junior_engineer/after_spawn(mob/living/carbon/human/H, mob/M) //Instead of going through the process of adding spawnpoints - var/turf/T - var/spawn_point = locate(/obj/effect/landmark/start/station_engineer) in GLOB.start_landmarks_list - T = get_turf(spawn_point) - H.Move(T) \ No newline at end of file diff --git a/code/modules/jobs/job_types/job.dm b/code/modules/jobs/job_types/job.dm index c0a2aa00..3a8aa68b 100644 --- a/code/modules/jobs/job_types/job.dm +++ b/code/modules/jobs/job_types/job.dm @@ -61,6 +61,8 @@ var/list/alt_titles = list() + var/override_roundstart_spawn = null //Where the player spawns at roundstart if defined + //Only override this proc //H is usually a human unless an /equip override transformed it /datum/job/proc/after_spawn(mob/living/H, mob/M, latejoin = FALSE) diff --git a/code/modules/jobs/job_types/medical.dm b/code/modules/jobs/job_types/medical.dm index 0458ce89..9b07a2ad 100644 --- a/code/modules/jobs/job_types/medical.dm +++ b/code/modules/jobs/job_types/medical.dm @@ -243,6 +243,7 @@ Junior Doctor access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM) minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM) + override_roundstart_spawn = /obj/effect/landmark/start/medical_doctor /datum/outfit/job/doctor/junior name = "Medical Resident" @@ -261,9 +262,3 @@ Junior Doctor duffelbag = /obj/item/storage/backpack/duffelbag/med chameleon_extras = /obj/item/gun/syringe - -/datum/job/junior_doctor/after_spawn(mob/living/carbon/human/H, mob/M) //Instead of going through the process of adding spawnpoints - var/turf/T - var/spawn_point = locate(/obj/effect/landmark/start/medical_doctor) in GLOB.start_landmarks_list - T = get_turf(spawn_point) - H.Move(T) \ No newline at end of file diff --git a/code/modules/jobs/job_types/science.dm b/code/modules/jobs/job_types/science.dm index 1cd36504..fd72fbfe 100644 --- a/code/modules/jobs/job_types/science.dm +++ b/code/modules/jobs/job_types/science.dm @@ -160,10 +160,11 @@ Junior Scientist access = list(ACCESS_ROBOTICS, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE, ACCESS_GENETICS) minimal_access = list(ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM) + override_roundstart_spawn = /obj/effect/landmark/start/scientist /datum/outfit/job/scientist/junior - name = "Scientist" - jobtype = /datum/job/scientist + name = "Research Student" + jobtype = /datum/job/junior_scientist belt = /obj/item/pda/toxins ears = /obj/item/radio/headset/headset_sci @@ -173,9 +174,3 @@ Junior Scientist backpack = /obj/item/storage/backpack/science satchel = /obj/item/storage/backpack/satchel/tox - -/datum/job/junior_scientist/after_spawn(mob/living/carbon/human/H, mob/M) //Instead of going through the process of adding spawnpoints - var/turf/T - var/spawn_point = locate(/obj/effect/landmark/start/scientist) in GLOB.start_landmarks_list - T = get_turf(spawn_point) - H.Move(T) \ No newline at end of file diff --git a/code/modules/jobs/job_types/security.dm b/code/modules/jobs/job_types/security.dm index 4600fce9..2f828072 100644 --- a/code/modules/jobs/job_types/security.dm +++ b/code/modules/jobs/job_types/security.dm @@ -375,6 +375,7 @@ Junior Security Officer mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/nonviolent, /datum/quirk/paraplegic) + override_roundstart_spawn = /obj/effect/landmark/start/security_officer /datum/job/junior_officer/get_access() @@ -461,8 +462,8 @@ Junior Security Officer /datum/outfit/job/security/junior - name = "Security Officer" - jobtype = /datum/job/officer + name = "Rookie" + jobtype = /datum/job/junior_officer belt = /obj/item/pda/security ears = /obj/item/radio/headset/headset_sec/alt diff --git a/code/modules/mob/dead/dead.dm b/code/modules/mob/dead/dead.dm index 0c50cb04..ad65bf8e 100644 --- a/code/modules/mob/dead/dead.dm +++ b/code/modules/mob/dead/dead.dm @@ -17,7 +17,7 @@ INITIALIZE_IMMEDIATE(/mob/dead) prepare_huds() if(length(CONFIG_GET(keyed_list/cross_server))) - verbs += /mob/dead/proc/server_hop + add_verb(src, /mob/dead/proc/server_hop) set_focus(src) return INITIALIZE_HINT_NORMAL @@ -42,27 +42,26 @@ INITIALIZE_IMMEDIATE(/mob/dead) loc = destination Moved(oldloc, NONE, TRUE) -/mob/dead/Stat() - ..() - if(!statpanel("Status")) - return - //stat(null, "Game Mode: [SSticker.hide_mode ? "Secret" : "[GLOB.master_mode]"]") +/mob/dead/get_status_tab_items() + . = ..() + . += "" + //. += "Game Mode: [SSticker.hide_mode ? "Secret" : "[GLOB.master_mode]"]" if(SSticker.HasRoundStarted()) return var/time_remaining = SSticker.GetTimeLeft() if(time_remaining > 0) - stat(null, "Time To Start: [round(time_remaining/10)]s") + . += "Time To Start: [round(time_remaining/10)]s" else if(time_remaining == -10) - stat(null, "Time To Start: DELAYED") + . += "Time To Start: DELAYED" else - stat(null, "Time To Start: SOON") + . += "Time To Start: SOON" - stat(null, "Players: [SSticker.totalPlayers]") + . += "Players: [SSticker.totalPlayers]" if(client.holder) - stat(null, "Players Ready: [SSticker.totalPlayersReady]") + . += "Players Ready: [SSticker.totalPlayersReady]" /mob/dead/proc/server_hop() set category = "OOC" @@ -74,7 +73,7 @@ INITIALIZE_IMMEDIATE(/mob/dead) var/pick switch(csa.len) if(0) - verbs -= /mob/dead/proc/server_hop + remove_verb(src, /mob/dead/proc/server_hop) to_chat(src, "Server Hop has been disabled.") if(1) pick = csa[0] diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index ca660860..59347e77 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -303,6 +303,7 @@ if(observer.client && observer.client.prefs) observer.real_name = observer.client.prefs.real_name observer.name = observer.real_name + observer.client.init_verbs() observer.update_icon() observer.stop_sound_channel(CHANNEL_LOBBYMUSIC) QDEL_NULL(mind) @@ -397,6 +398,7 @@ character.update_parallax_teleport() SSticker.minds += character.mind + character.client.init_verbs() // init verbs for the late join var/mob/living/carbon/human/humanc if(ishuman(character)) @@ -590,6 +592,7 @@ mind.transfer_to(H) //won't transfer key since the mind is not active H.name = real_name + client.init_verbs() //h13 assign your characters custom height. if (H.custom_body_size) //Do they have it set? H.resize(H.custom_body_size * 0.01) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 541fb5e1..1c91b733 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -59,10 +59,10 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) /mob/dead/observer/Initialize() set_invisibility(GLOB.observer_default_invisibility) - verbs += list( + add_verb(src, list( /mob/dead/observer/proc/dead_tele, /mob/dead/observer/proc/open_spawners_menu, - /mob/dead/observer/proc/view_gas) + /mob/dead/observer/proc/view_gas)) if(icon_state in GLOB.ghost_forms_with_directions_list) ghostimage_default = image(src.icon,src,src.icon_state + "_nodir") @@ -120,8 +120,8 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) real_name = name if(!fun_verbs) - verbs -= /mob/dead/observer/verb/boo - verbs -= /mob/dead/observer/verb/possess + remove_verb(src, /mob/dead/observer/verb/boo) + remove_verb(src, /mob/dead/observer/verb/possess) animate(src, pixel_y = 2, time = 10, loop = -1) @@ -367,6 +367,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp client.change_view(CONFIG_GET(string/default_view)) SStgui.on_transfer(src, mind.current) // Transfer NanoUIs. mind.current.key = key + mind.current.client.init_verbs() return 1 /mob/dead/observer/proc/notify_cloning(var/message, var/sound, var/atom/source, flashwindow = TRUE) @@ -777,11 +778,11 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp ghostimage_simple.icon_state = icon_state if("fun_verbs") if(fun_verbs) - verbs += /mob/dead/observer/verb/boo - verbs += /mob/dead/observer/verb/possess + add_verb(src, /mob/dead/observer/verb/boo) + add_verb(src, /mob/dead/observer/verb/possess) else - verbs -= /mob/dead/observer/verb/boo - verbs -= /mob/dead/observer/verb/possess + remove_verb(src, /mob/dead/observer/verb/boo) + remove_verb(src, /mob/dead/observer/verb/possess) /mob/dead/observer/reset_perspective(atom/A) if(client) diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index a5e55ea5..2fbf2575 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -44,7 +44,6 @@ //Blood regeneration if there is some space if(blood_volume < (BLOOD_VOLUME_NORMAL * blood_ratio) && !HAS_TRAIT(src, TRAIT_NOHUNGER)) var/nutrition_ratio = 0 - //thirst_ratio = 1 //Uncomment if something fancy gets added switch(nutrition) if(0 to NUTRITION_LEVEL_STARVING) nutrition_ratio = 0.2 @@ -61,7 +60,8 @@ if(satiety > 80) nutrition_ratio *= 1.25 nutrition = max(0, nutrition - nutrition_ratio * HUNGER_FACTOR) - thirst = max(0, thirst - 0.8 * THIRST_FACTOR) + if(!HAS_TRAIT(src, TRAIT_NOTHIRST)) + thirst = max(0, thirst - THIRST_FACTOR) //After 2 seconds of research, I learned that you get quite thirsty when at low blood levels blood_volume = min((BLOOD_VOLUME_NORMAL * blood_ratio), blood_volume + 0.5 * nutrition_ratio) //Effects of bloodloss diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index bd24a4b4..c9a504e2 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -26,8 +26,8 @@ var/static/regex/alien_name_regex = new("alien (larva|sentinel|drone|hunter|praetorian|queen)( \\(\\d+\\))?") /mob/living/carbon/alien/Initialize() - verbs += /mob/living/proc/mob_sleep - verbs += /mob/living/proc/lay_down + add_verb(src, /mob/living/proc/mob_sleep) + add_verb(src, /mob/living/proc/lay_down) create_bodyparts() //initialize bodyparts @@ -86,11 +86,10 @@ /mob/living/carbon/alien/IsAdvancedToolUser() return has_fine_manipulation -/mob/living/carbon/alien/Stat() - ..() - if(statpanel("Status")) - stat(null, "Intent: [a_intent]") +/mob/living/carbon/alien/get_status_tab_items() + . = ..() + . += "Intent: [a_intent]" /mob/living/carbon/alien/getTrail() if(getBruteLoss() < 200) diff --git a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm index 323bd408..509caf81 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm @@ -143,10 +143,10 @@ Doesn't work on other aliens/AI.*/ action_icon_state = "alien_acid" /obj/effect/proc_holder/alien/acid/on_gain(mob/living/carbon/user) - user.verbs.Add(/mob/living/carbon/proc/corrosive_acid) + add_verb(user, /mob/living/carbon/proc/corrosive_acid) /obj/effect/proc_holder/alien/acid/on_lose(mob/living/carbon/user) - user.verbs.Remove(/mob/living/carbon/proc/corrosive_acid) + remove_verb(user, /mob/living/carbon/proc/corrosive_acid) /obj/effect/proc_holder/alien/acid/proc/corrode(atom/target,mob/living/carbon/user = usr) if(target in oview(1,user)) diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm index 3b150a22..9fdf7ab8 100644 --- a/code/modules/mob/living/carbon/alien/larva/larva.dm +++ b/code/modules/mob/living/carbon/alien/larva/larva.dm @@ -29,11 +29,9 @@ internal_organs += new /obj/item/organ/alien/plasmavessel/small/tiny ..() -//This needs to be fixed -/mob/living/carbon/alien/larva/Stat() - ..() - if(statpanel("Status")) - stat(null, "Progress: [amount_grown]/[max_grown]") +/mob/living/carbon/alien/larva/get_status_tab_items() + . = ..() + . += "Progress: [amount_grown]/[max_grown]" /mob/living/carbon/alien/larva/adjustPlasma(amount) if(stat != DEAD && amount > 0) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 33214a0f..38d9b377 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -465,16 +465,18 @@ var/turf/target = get_turf(loc) I.safe_throw_at(target,I.throw_range,I.throw_speed,src, force = move_force) -/mob/living/carbon/Stat() - ..() - if(statpanel("Status")) - var/obj/item/organ/alien/plasmavessel/vessel = getorgan(/obj/item/organ/alien/plasmavessel) - if(vessel) - stat(null, "Plasma Stored: [vessel.storedPlasma]/[vessel.max_plasma]") - if(locate(/obj/item/assembly/health) in src) - stat(null, "Health: [health]") - add_abilities_to_panel() +/mob/living/carbon/get_status_tab_items() + . = ..() + var/obj/item/organ/alien/plasmavessel/vessel = getorgan(/obj/item/organ/alien/plasmavessel) + if(vessel) + . += "Plasma Stored: [vessel.storedPlasma]/[vessel.max_plasma]" + if(locate(/obj/item/assembly/health) in src) + . += "Health: [health]" + +/mob/living/carbon/get_proc_holders() + . = ..() + . += add_abilities_to_panel() /mob/living/carbon/attack_ui(slot) if(!has_hand_for_held_index(active_hand_index)) @@ -995,4 +997,4 @@ /mob/living/carbon/transfer_ckey(mob/new_mob, send_signal = TRUE) if(combatmode) toggle_combat_mode(TRUE, TRUE) - return ..() + return ..() diff --git a/code/modules/mob/living/carbon/carbon_movement.dm b/code/modules/mob/living/carbon/carbon_movement.dm index fcf85505..e93e4871 100644 --- a/code/modules/mob/living/carbon/carbon_movement.dm +++ b/code/modules/mob/living/carbon/carbon_movement.dm @@ -41,7 +41,12 @@ nutrition = NUTRITION_LEVEL_FED - 1 //just less than feeling vigorous else if(nutrition && stat != DEAD) nutrition -= HUNGER_FACTOR/12 - thirst -= THIRST_FACTOR/12 if(m_intent == MOVE_INTENT_RUN) nutrition -= HUNGER_FACTOR/5 + + if(HAS_TRAIT(src, TRAIT_NOTHIRST)) + thirst = THIRST_LEVEL_QUENCHED - 1 + else if(thirst && stat != DEAD) + thirst -= THIRST_FACTOR/12 + if(m_intent == MOVE_INTENT_RUN) thirst -= THIRST_FACTOR/5 diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index b8b62a8b..58264160 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -6,9 +6,8 @@ appearance_flags = KEEP_TOGETHER|TILE_BOUND|PIXEL_SCALE|LONG_GLIDE /mob/living/carbon/human/Initialize() - verbs += /mob/living/proc/mob_sleep - verbs += /mob/living/proc/lay_down - verbs += /mob/living/carbon/human/proc/underwear_toggle //fwee + add_verb(src, /mob/living/proc/mob_sleep) + add_verb(src, /mob/living/proc/lay_down) time_initialized = world.time //initialize limbs first @@ -62,58 +61,52 @@ add_to_all_human_data_huds() -/mob/living/carbon/human/Stat() - ..() - //Same thing from mob - if(statpanel("Status")) - if(tickrefresh == 1) - sList2 = list() - sList2 += "Intent: [a_intent]" - sList2 += "Move Mode: [m_intent]" - if (internal) - if (!internal.air_contents) - qdel(internal) - else - sList2 += "Internal Atmosphere Info: "+ "[internal.name]" - sList2 += "Tank Pressure: "+ "[internal.air_contents.return_pressure()]" - sList2 += "Distribution Pressure: "+ "[internal.distribute_pressure]" - if(mind) - var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling) - if(changeling) - sList2 += "Chemical Storage: " + "[changeling.chem_charges]/[changeling.chem_storage]" - sList2 += "Absorbed DNA: "+ "[changeling.absorbedcount]" - if (sList2 != null) - stat(null, "[sList2.Join("\n\n")]") +/mob/living/carbon/human/get_status_tab_items() + . = ..() + . += "Intent: [a_intent]" + . += "Move Mode: [m_intent]" + if (internal) + if (!internal.air_contents) + qdel(internal) + else + . += "" + . += "Internal Atmosphere Info: [internal.name]" + . += "Tank Pressure: [internal.air_contents.return_pressure()]" + . += "Distribution Pressure: [internal.distribute_pressure]" + if(mind) + var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling) + if(changeling) + . += "" + . += "Chemical Storage: [changeling.chem_charges]/[changeling.chem_storage]" + . += "Absorbed DNA: [changeling.absorbedcount]" //NINJACODE if(istype(wear_suit, /obj/item/clothing/suit/space/space_ninja)) //Only display if actually a ninja. var/obj/item/clothing/suit/space/space_ninja/SN = wear_suit - if(statpanel("SpiderOS")) - stat("SpiderOS Status:","[SN.s_initialized ? "Initialized" : "Disabled"]") - stat("Current Time:", "[STATION_TIME_TIMESTAMP("hh:mm:ss")]") - if(SN.s_initialized) - //Suit gear - stat("Energy Charge:", "[round(SN.cell.charge/100)]%") - stat("Smoke Bombs:", "\Roman [SN.s_bombs]") - //Ninja status - stat("Fingerprints:", "[md5(dna.uni_identity)]") - stat("Unique Identity:", "[dna.unique_enzymes]") - stat("Overall Status:", "[stat > 1 ? "dead" : "[health]% healthy"]") - stat("Nutrition Status:", "[nutrition]") - stat("Hydration Status:", "[thirst]") - stat("Oxygen Loss:", "[getOxyLoss()]") - stat("Toxin Levels:", "[getToxLoss()]") - stat("Burn Severity:", "[getFireLoss()]") - stat("Brute Trauma:", "[getBruteLoss()]") - stat("Radiation Levels:","[radiation] rad") - stat("Body Temperature:","[bodytemperature-T0C] degrees C ([bodytemperature*1.8-459.67] degrees F)") + . += "SpiderOS Status: [SN.s_initialized ? "Initialized" : "Disabled"]" + . += "Current Time: [station_time_timestamp()]" + if(SN.s_initialized) + //Suit gear + . += "Energy Charge: [round(SN.cell.charge/100)]%" + . += "Smoke Bombs: \Roman [SN.s_bombs]" + //Ninja status + . += "Fingerprints: [md5(dna.uni_identity)]" + . += "Unique Identity: [dna.unique_enzymes]" + . += "Overall Status: [stat > 1 ? "dead" : "[health]% healthy"]" + . += "Nutrition Status: [nutrition]" + . += "Oxygen Loss: [getOxyLoss()]" + . += "Toxin Levels: [getToxLoss()]" + . += "Burn Severity: [getFireLoss()]" + . += "Brute Trauma: [getBruteLoss()]" + . += "Radiation Levels: [radiation] rad" + . += "Body Temperature: [bodytemperature-T0C] degrees C ([bodytemperature*1.8-459.67] degrees F)" - //Diseases - if(diseases.len) - stat("Viruses:", null) - for(var/thing in diseases) - var/datum/disease/D = thing - stat("*", "[D.name], Type: [D.spread_text], Stage: [D.stage]/[D.max_stages], Possible Cure: [D.cure_text]") + //Diseases + if(length(diseases)) + . += "Viruses:" + for(var/thing in diseases) + var/datum/disease/D = thing + . += "* [D.name], Type: [D.spread_text], Stage: [D.stage]/[D.max_stages], Possible Cure: [D.cure_text]" /mob/living/carbon/human/show_inv(mob/user) diff --git a/code/modules/mob/living/carbon/human/species_types/abductors.dm b/code/modules/mob/living/carbon/human/species_types/abductors.dm index ffd129eb..f6e78530 100644 --- a/code/modules/mob/living/carbon/human/species_types/abductors.dm +++ b/code/modules/mob/living/carbon/human/species_types/abductors.dm @@ -4,7 +4,7 @@ say_mod = "gibbers" sexes = FALSE species_traits = list(NOBLOOD,NOEYES,NOGENITALS,NOAROUSAL) - inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NOGUNS,TRAIT_NOHUNGER,TRAIT_NOBREATH) + inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NOGUNS,TRAIT_NOHUNGER,TRAIT_NOTHIRST,TRAIT_NOBREATH) mutanttongue = /obj/item/organ/tongue/abductor /datum/species/abductor/on_species_gain(mob/living/carbon/C, datum/species/old_species) diff --git a/code/modules/mob/living/carbon/human/species_types/android.dm b/code/modules/mob/living/carbon/human/species_types/android.dm index 0f522b55..81f2acad 100644 --- a/code/modules/mob/living/carbon/human/species_types/android.dm +++ b/code/modules/mob/living/carbon/human/species_types/android.dm @@ -3,7 +3,7 @@ id = "android" say_mod = "states" species_traits = list(NOBLOOD,NOGENITALS,NOAROUSAL) - inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_NOFIRE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_LIMBATTACHMENT) + inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_NOFIRE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_NOTHIRST,TRAIT_LIMBATTACHMENT) inherent_biotypes = list(MOB_ROBOTIC, MOB_HUMANOID) meat = null gib_types = /obj/effect/gibspawner/robot diff --git a/code/modules/mob/living/carbon/human/species_types/corporate.dm b/code/modules/mob/living/carbon/human/species_types/corporate.dm index 3de530ff..a733c248 100644 --- a/code/modules/mob/living/carbon/human/species_types/corporate.dm +++ b/code/modules/mob/living/carbon/human/species_types/corporate.dm @@ -16,6 +16,6 @@ blacklisted = 1 use_skintones = 0 species_traits = list(NOBLOOD,EYECOLOR,NOGENITALS) - inherent_traits = list(TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOLIMBDISABLE,TRAIT_NOHUNGER) + inherent_traits = list(TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOLIMBDISABLE,TRAIT_NOHUNGER,TRAIT_NOTHIRST) sexes = 0 gib_types = /obj/effect/gibspawner/robot \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/species_types/dullahan.dm b/code/modules/mob/living/carbon/human/species_types/dullahan.dm index 5b2ad6e5..103f724e 100644 --- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm +++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm @@ -3,7 +3,7 @@ id = "dullahan" default_color = "FFFFFF" species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS) - inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH) + inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOTHIRST,TRAIT_NOBREATH) default_features = list("mcolor" = "FFF", "tail_human" = "None", "ears" = "None", "wings" = "None") use_skintones = TRUE mutant_brain = /obj/item/organ/brain/dullahan diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index c482b6df..2abbf50b 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -293,9 +293,7 @@ if(isturf(H.loc)) //else, there's considered to be no light var/turf/T = H.loc light_amount = min(1,T.get_lumcount()) - 0.5 - H.nutrition += light_amount * 10 - if(H.nutrition > NUTRITION_LEVEL_FULL) - H.nutrition = NUTRITION_LEVEL_FULL + H.nutrition = min(H.nutrition + light_amount * 10, NUTRITION_LEVEL_FULL) if(light_amount > 0.2) //if there's enough light, heal H.heal_overall_damage(1,1) H.adjustToxLoss(-1) diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm index 6601d55f..aa46399a 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -5,7 +5,7 @@ sexes = 0 meat = /obj/item/stack/sheet/mineral/plasma species_traits = list(NOBLOOD,NOTRANSSTING) - inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_RADIMMUNE,TRAIT_NOHUNGER) + inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_RADIMMUNE,TRAIT_NOHUNGER,TRAIT_NOTHIRST) inherent_biotypes = list(MOB_INORGANIC, MOB_HUMANOID) mutantlungs = /obj/item/organ/lungs/plasmaman mutanttongue = /obj/item/organ/tongue/bone/plasmaman diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm index dcf26b70..786357dd 100644 --- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm @@ -35,9 +35,7 @@ if(isturf(H.loc)) //else, there's considered to be no light var/turf/T = H.loc light_amount = min(1,T.get_lumcount()) - 0.5 - H.nutrition += light_amount * light_nutrition_gain_factor - if(H.nutrition > NUTRITION_LEVEL_FULL) - H.nutrition = NUTRITION_LEVEL_FULL + H.nutrition = min(H.nutrition + light_amount * light_nutrition_gain_factor, NUTRITION_LEVEL_FULL) if(light_amount > 0.2) //if there's enough light, heal H.heal_overall_damage(light_bruteheal, light_burnheal) H.adjustToxLoss(-light_toxheal) diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm index 3c716fa1..0fc134ec 100644 --- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm @@ -39,7 +39,7 @@ blacklisted = TRUE no_equip = list(SLOT_WEAR_MASK, SLOT_WEAR_SUIT, SLOT_GLOVES, SLOT_SHOES, SLOT_W_UNIFORM, SLOT_S_STORE) species_traits = list(NOBLOOD,NO_UNDERWEAR,NO_DNA_COPY,NOTRANSSTING,NOEYES,NOGENITALS,NOAROUSAL) - inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_NOBREATH,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER) + inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_NOBREATH,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOTHIRST) mutanteyes = /obj/item/organ/eyes/night_vision/nightmare mutant_organs = list(/obj/item/organ/heart/nightmare) mutant_brain = /obj/item/organ/brain/nightmare @@ -183,9 +183,14 @@ . = ..() if(!proximity) return - if(isopenturf(AM)) //So you can actually melee with it + if(isopenturf(AM) && !istype(AM, /turf/open/space) && !istype(AM, /turf/open/lava)) + var/turf/T = AM + if(T.light_power || T.light_range) + to_chat(user, "[src] consumes the lights in [AM].") + T.set_light(0,0) + else if(isopenturf(AM)) return - if(isliving(AM)) + else if(isliving(AM)) var/mob/living/L = AM if(iscyborg(AM)) var/mob/living/silicon/robot/borg = AM @@ -194,20 +199,40 @@ to_chat(borg, "Your headlamp is fried! You'll need a human to help replace it.") else for(var/obj/item/O in AM) - if(O.light_range && O.light_power) - disintegrate(O) - if(L.pulling && L.pulling.light_range && isitem(L.pulling)) - disintegrate(L.pulling) + if(O.light_range && O.light_power && !check_plasmaman(O, AM)) + disintegrate(O, user) + if(L.pulling && L.pulling.light_range && isitem(L.pulling) && !check_plasmaman(L.pulling, L)) + disintegrate(L.pulling, user) else if(isitem(AM)) var/obj/item/I = AM - if(I.light_range && I.light_power) - disintegrate(I) + if(I.light_range && I.light_power && !check_plasmaman(AM)) + disintegrate(I, user) else if(istype(AM, /obj/structure/marker_beacon)) var/obj/structure/marker_beacon/I = AM - disintegrate(I) + disintegrate(I, user) //why the fuck is the marker beacon a structure? who. what. why. + else if(istype(AM, /obj/machinery/light)) + var/obj/machinery/light/L = AM + if(L.status == 2) //Assume we just broke the light + handle_objectives(user) + L.status = 1 //No tube + L.update(FALSE) -/obj/item/light_eater/proc/disintegrate(obj/item/O) +/obj/item/light_eater/proc/handle_objectives(mob/living/carbon/human/H) + if(!H.mind) + return + + if(!H.mind.objectives) + return + + for(var/O in H.mind.objectives) + if(!istype(O, /datum/objective/break_lights)) + continue + var/datum/objective/break_lights/BL = O + if(!BL.mode) + BL.lightsbroken++ + +/obj/item/light_eater/proc/disintegrate(obj/item/O, user) if(istype(O, /obj/item/pda)) var/obj/item/pda/PDA = O PDA.set_light(0) @@ -220,5 +245,21 @@ O.burn() playsound(src, 'sound/items/welder.ogg', 50, 1) + if(is_species(user, /datum/species/shadow/nightmare)) + handle_objectives(user) + +/obj/item/light_eater/proc/check_plasmaman(obj/item/O, mob/living/carbon/human/user) + if(!istype(O, /obj/item/clothing/head/helmet/space/plasmaman)) + return FALSE + var/obj/item/clothing/head/helmet/space/plasmaman/H = O + if(H.on) + H.on = FALSE + H.icon_state = "[initial(H.icon_state)][H.on ? "-light":""]" + H.item_state = H.icon_state + if(user) + user.update_inv_head() + to_chat(user, "Your [H]'s torch extinguishes!") + return TRUE + #undef HEART_SPECIAL_SHADOWIFY #undef HEART_RESPAWN_THRESHHOLD diff --git a/code/modules/mob/living/carbon/human/species_types/skeletons.dm b/code/modules/mob/living/carbon/human/species_types/skeletons.dm index 7d739990..d8a186fc 100644 --- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm +++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm @@ -7,7 +7,7 @@ sexes = 0 meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/skeleton species_traits = list(NOBLOOD,NOGENITALS,NOAROUSAL) - inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER) + inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_NOTHIRST,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER) inherent_biotypes = list(MOB_UNDEAD, MOB_HUMANOID) mutanttongue = /obj/item/organ/tongue/bone damage_overlay_type = ""//let's not show bloody wounds or burns over bones. @@ -24,7 +24,7 @@ id = "spaceskeleton" limbs_id = "skeleton" blacklisted = 1 - inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER) + inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_NOTHIRST,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER) /datum/species/skeleton/pirate/check_roundstart_eligible() return FALSE diff --git a/code/modules/mob/living/carbon/human/species_types/synths.dm b/code/modules/mob/living/carbon/human/species_types/synths.dm index 703fffa4..b379da2e 100644 --- a/code/modules/mob/living/carbon/human/species_types/synths.dm +++ b/code/modules/mob/living/carbon/human/species_types/synths.dm @@ -4,7 +4,7 @@ say_mod = "beep boops" //inherited from a user's real species sexes = 0 species_traits = list(NOTRANSSTING,NOGENITALS,NOAROUSAL) //all of these + whatever we inherit from the real species - inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOBREATH) + inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOTHIRST,TRAIT_NOBREATH) inherent_biotypes = list(MOB_ROBOTIC, MOB_HUMANOID) dangerous_existence = 1 blacklisted = 1 @@ -13,7 +13,7 @@ damage_overlay_type = "synth" limbs_id = "synth" var/list/initial_species_traits = list(NOTRANSSTING) //for getting these values back for assume_disguise() - var/list/initial_inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOLIMBDISABLE,TRAIT_NOBREATH) + var/list/initial_inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOTHIRST,TRAIT_NOLIMBDISABLE,TRAIT_NOBREATH) var/disguise_fail_health = 75 //When their health gets to this level their synthflesh partially falls off var/datum/species/fake_species = null //a species to do most of our work for us, unless we're damaged diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm index 43940362..611ba7f4 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -3,7 +3,7 @@ id = "vampire" default_color = "FFFFFF" species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,DRINKSBLOOD) - inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH) + inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOTHIRST,TRAIT_NOBREATH) inherent_biotypes = list(MOB_UNDEAD, MOB_HUMANOID) default_features = list("mcolor" = "FFF", "tail_human" = "None", "ears" = "None", "wings" = "None") exotic_bloodtype = "U" diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index a287c569..7aa89392 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -17,8 +17,8 @@ hud_type = /datum/hud/monkey /mob/living/carbon/monkey/Initialize(mapload, cubespawned=FALSE, mob/spawner) - verbs += /mob/living/proc/mob_sleep - verbs += /mob/living/proc/lay_down + add_verb(src, /mob/living/proc/mob_sleep) + add_verb(src, /mob/living/proc/lay_down) if(unique_name) //used to exclude pun pun gender = pick(MALE, FEMALE) @@ -89,16 +89,16 @@ return add_movespeed_modifier(MOVESPEED_ID_MONKEY_TEMPERATURE_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = amount) -/mob/living/carbon/monkey/Stat() - ..() - if(statpanel("Status")) - stat(null, "Intent: [a_intent]") - stat(null, "Move Mode: [m_intent]") - if(client && mind) - var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling) - if(changeling) - stat("Chemical Storage", "[changeling.chem_charges]/[changeling.chem_storage]") - stat("Absorbed DNA", changeling.absorbedcount) +/mob/living/carbon/monkey/get_status_tab_items() + . = ..() + . += "Intent: [a_intent]" + . += "Move Mode: [m_intent]" + if(client && mind) + var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling) + if(changeling) + . += "" + . += "Chemical Storage: [changeling.chem_charges]/[changeling.chem_storage]" + . += "Absorbed DNA: [changeling.absorbedcount]" return diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 9832e3b2..affafe34 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -516,6 +516,7 @@ SetSleeping(0, FALSE) radiation = 0 nutrition = NUTRITION_LEVEL_FED + 50 + thirst = THIRST_LEVEL_QUENCHED + 50 bodytemperature = BODYTEMP_NORMAL set_blindness(0) set_blurriness(0) @@ -1104,8 +1105,10 @@ A.action.Remove(src) /mob/living/proc/add_abilities_to_panel() + var/list/L = list() for(var/obj/effect/proc_holder/A in abilities) - statpanel("[A.panel]",A.get_panel_text(),A) + L[++L.len] = list("[A.panel]",A.get_panel_text(),A.name,"[REF(A)]") + return L /mob/living/lingcheck() if(mind) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index efc714f2..04d241d2 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -137,7 +137,7 @@ spark_system.set_up(5, 0, src) spark_system.attach(src) - verbs += /mob/living/silicon/ai/proc/show_laws_verb + add_verb(src, /mob/living/silicon/ai/proc/show_laws_verb) aiPDA = new/obj/item/pda/ai(src) aiPDA.owner = name @@ -151,10 +151,10 @@ deploy_action.Grant(src) if(isturf(loc)) - verbs.Add(/mob/living/silicon/ai/proc/ai_network_change, \ + add_verb(src, list(/mob/living/silicon/ai/proc/ai_network_change, \ /mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \ /mob/living/silicon/ai/proc/botcall, /mob/living/silicon/ai/proc/control_integrated_radio, \ - /mob/living/silicon/ai/proc/set_automatic_say_channel) + /mob/living/silicon/ai/proc/set_automatic_say_channel)) GLOB.ai_list += src GLOB.shuttle_caller_list += src @@ -205,26 +205,26 @@ display_icon_override = ai_core_icon set_core_display_icon(ai_core_icon) -/mob/living/silicon/ai/Stat() - ..() - if(statpanel("Status")) - if(!stat) - stat(null, text("System integrity: [(health+100)/2]%")) - stat(null, text("Connected cyborgs: [connected_robots.len]")) - for(var/mob/living/silicon/robot/R in connected_robots) - var/robot_status = "Nominal" - if(R.shell) - robot_status = "AI SHELL" - else if(R.stat || !R.client) - robot_status = "OFFLINE" - else if(!R.cell || R.cell.charge <= 0) - robot_status = "DEPOWERED" - //Name, Health, Battery, Module, Area, and Status! Everything an AI wants to know about its borgies! - stat(null, text("[R.name] | S.Integrity: [R.health]% | Cell: [R.cell ? "[R.cell.charge]/[R.cell.maxcharge]" : "Empty"] | \ - Module: [R.designation] | Loc: [get_area_name(R, TRUE)] | Status: [robot_status]")) - stat(null, text("AI shell beacons detected: [LAZYLEN(GLOB.available_ai_shells)]")) //Count of total AI shells - else - stat(null, text("Systems nonfunctional")) +/mob/living/silicon/ai/get_status_tab_items() + . = ..() + if(stat != CONSCIOUS) + . += text("Systems nonfunctional") + return + . += text("System integrity: [(health + 100) * 0.5]%") + . += text("Connected cyborgs: [length(connected_robots)]") + for(var/r in connected_robots) + var/mob/living/silicon/robot/connected_robot = r + var/robot_status = "Nominal" + if(connected_robot.shell) + robot_status = "AI SHELL" + else if(connected_robot.stat != CONSCIOUS || !connected_robot.client) + robot_status = "OFFLINE" + else if(!connected_robot.cell || connected_robot.cell.charge <= 0) + robot_status = "DEPOWERED" + //Name, Health, Battery, Module, Area, and Status! Everything an AI wants to know about its borgies! + . += text("[connected_robot.name] | S.Integrity: [connected_robot.health]% | Cell: [connected_robot.cell ? "[connected_robot.cell.charge]/[connected_robot.cell.maxcharge]" : "Empty"] | \ + Module: [connected_robot.designation] | Loc: [get_area_name(connected_robot, TRUE)] | Status: [robot_status]") + . += text("AI shell beacons detected: [LAZYLEN(GLOB.available_ai_shells)]") //Count of total AI shells /mob/living/silicon/ai/proc/ai_alerts() var/dat = "Current Station Alerts\n" diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index f4859ab2..05b0fc5e 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -172,13 +172,12 @@ else client.eye = card -/mob/living/silicon/pai/Stat() - ..() - if(statpanel("Status")) - if(!stat) - stat(null, text("Emitter Integrity: [emitterhealth * (100/emittermaxhealth)]")) - else - stat(null, text("Systems nonfunctional")) +/mob/living/silicon/pai/get_status_tab_items() + . += ..() + if(!stat) + . += text("Emitter Integrity: [emitterhealth * (100/emittermaxhealth)]") + else + . += text("Systems nonfunctional") /mob/living/silicon/pai/restrained(ignore_grab) . = FALSE diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 8d8444a6..7435cc60 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -198,7 +198,7 @@ radio.keyslot = null //END CITADEL EDIT if(connected_ai) - connected_ai.connected_robots -= src + set_connected_ai(null) if(shell) GLOB.available_ai_shells -= src else @@ -321,19 +321,20 @@ if(thruster_button) thruster_button.icon_state = "ionpulse[ionpulse_on]" -/mob/living/silicon/robot/Stat() - ..() - if(statpanel("Status")) - if(cell) - stat("Charge Left:", "[cell.charge]/[cell.maxcharge]") - else - stat(null, text("No Cell Inserted!")) - if(module) - for(var/datum/robot_energy_storage/st in module.storages) - stat("[st.name]:", "[st.energy]/[st.max_energy]") - if(connected_ai) - stat("Master AI:", connected_ai.name) +/mob/living/silicon/robot/get_status_tab_items() + . = ..() + . += "" + if(cell) + . += "Charge Left: [cell.charge]/[cell.maxcharge]" + else + . += text("No Cell Inserted!") + + if(module) + for(var/datum/robot_energy_storage/st in module.storages) + . += "[st.name]: [st.energy]/[st.max_energy]" + if(connected_ai) + . += "Master AI: [connected_ai.name]" /mob/living/silicon/robot/restrained(ignore_grab) . = 0 @@ -707,9 +708,7 @@ gib() /mob/living/silicon/robot/proc/UnlinkSelf() - if(src.connected_ai) - connected_ai.connected_robots -= src - src.connected_ai = null + set_connected_ai(null) lawupdate = 0 lockcharge = 0 canmove = 1 @@ -1133,7 +1132,7 @@ builtInCamera.c_tag = real_name //update the camera name too mainframe = AI deployed = TRUE - connected_ai = mainframe + set_connected_ai(mainframe) mainframe.connected_robots |= src lawupdate = TRUE lawsync() @@ -1230,7 +1229,7 @@ . = ..(user) /mob/living/silicon/robot/proc/TryConnectToAI() - connected_ai = select_active_ai_with_fewest_borgs() + set_connected_ai(select_active_ai_with_fewest_borgs(z)) if(connected_ai) connected_ai.connected_robots += src lawsync() @@ -1260,3 +1259,14 @@ update_transform() return TRUE + +/mob/living/silicon/robot/proc/set_connected_ai(new_ai) + if(connected_ai == new_ai) + return + . = connected_ai + connected_ai = new_ai + if(.) + var/mob/living/silicon/ai/old_ai = . + old_ai.connected_robots -= src + if(connected_ai) + connected_ai.connected_robots |= src \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm index a85b8648..a81b5ab8 100644 --- a/code/modules/mob/living/silicon/robot/robot_defense.dm +++ b/code/modules/mob/living/silicon/robot/robot_defense.dm @@ -133,7 +133,7 @@ SetEmagged(1) SetStun(60) //Borgs were getting into trouble because they would attack the emagger before the new laws were shown lawupdate = 0 - connected_ai = null + set_connected_ai(null) message_admins("[ADMIN_LOOKUPFLW(user)] emagged cyborg [ADMIN_LOOKUPFLW(src)]. Laws overridden.") log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.") var/time = time2text(world.realtime,"hh:mm:ss") diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm index 2380db56..c204508a 100644 --- a/code/modules/mob/living/simple_animal/friendly/cat.dm +++ b/code/modules/mob/living/simple_animal/friendly/cat.dm @@ -38,7 +38,7 @@ /mob/living/simple_animal/pet/cat/Initialize() . = ..() - verbs += /mob/living/proc/lay_down + add_verb(src, /mob/living/proc/lay_down) /mob/living/simple_animal/pet/cat/ComponentInitialize() . = ..() diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm index 903c3ea3..50fbc9d1 100644 --- a/code/modules/mob/living/simple_animal/guardian/guardian.dm +++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm @@ -154,18 +154,17 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians REMOVE_TRAIT(summoner, TRAIT_NODEATH, "memento_mori") to_chat(summoner,"You feel incredibly vulnerable as the memento mori pulls your life force in one too many directions!") -/mob/living/simple_animal/hostile/guardian/Stat() - ..() - if(statpanel("Status")) - if(summoner) - var/resulthealth - if(iscarbon(summoner)) - resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - summoner.health) / abs(HEALTH_THRESHOLD_DEAD - summoner.maxHealth)) * 100) - else - resulthealth = round((summoner.health / summoner.maxHealth) * 100, 0.5) - stat(null, "Summoner Health: [resulthealth]%") - if(cooldown >= world.time) - stat(null, "Manifest/Recall Cooldown Remaining: [DisplayTimeText(cooldown - world.time)]") +/mob/living/simple_animal/hostile/guardian/get_status_tab_items() + . += ..() + if(summoner) + var/resulthealth + if(iscarbon(summoner)) + resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - summoner.health) / abs(HEALTH_THRESHOLD_DEAD - summoner.maxHealth)) * 100) + else + resulthealth = round((summoner.health / summoner.maxHealth) * 100, 0.5) + . += "Summoner Health: [resulthealth]%" + if(cooldown >= world.time) + . += "Manifest/Recall Cooldown Remaining: [DisplayTimeText(cooldown - world.time)]" /mob/living/simple_animal/hostile/guardian/Move() //Returns to summoner if they move out of range . = ..() @@ -441,13 +440,13 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians to_chat(src, "[G.real_name] has been summoned!") guardians -= G if(!guardians.len) - verbs -= /mob/living/proc/guardian_reset + remove_verb(src, /mob/living/proc/guardian_reset) else to_chat(src, "There were no ghosts willing to take control of [G.real_name]. Looks like you're stuck with it for now.") else to_chat(src, "You decide not to reset [guardians.len > 1 ? "any of your guardians":"your guardian"].") else - verbs -= /mob/living/proc/guardian_reset + remove_verb(src, /mob/living/proc/guardian_reset) ////////parasite tracking/finding procs @@ -571,9 +570,9 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians if("carp") to_chat(user, "[G.carp_fluff_string]") to_chat(user, "[G.real_name] has been caught!") - user.verbs += /mob/living/proc/guardian_comm - user.verbs += /mob/living/proc/guardian_recall - user.verbs += /mob/living/proc/guardian_reset + add_verb(user, list(/mob/living/proc/guardian_comm, \ + /mob/living/proc/guardian_recall, \ + /mob/living/proc/guardian_reset)) /obj/item/guardiancreator/choose random = FALSE diff --git a/code/modules/mob/living/simple_animal/guardian/types/assassin.dm b/code/modules/mob/living/simple_animal/guardian/types/assassin.dm index e507a4c8..1b4758b9 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/assassin.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/assassin.dm @@ -24,11 +24,10 @@ if(loc == summoner && toggle) ToggleMode(0) -/mob/living/simple_animal/hostile/guardian/assassin/Stat() - ..() - if(statpanel("Status")) - if(stealthcooldown >= world.time) - stat(null, "Stealth Cooldown Remaining: [DisplayTimeText(stealthcooldown - world.time)]") +/mob/living/simple_animal/hostile/guardian/assassin/get_status_tab_items() + . = ..() + if(stealthcooldown >= world.time) + . += "Stealth Cooldown Remaining: [DisplayTimeText(stealthcooldown - world.time)]" /mob/living/simple_animal/hostile/guardian/assassin/AttackingTarget() . = ..() diff --git a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm b/code/modules/mob/living/simple_animal/guardian/types/explosive.dm index e9f76737..a480ce0f 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/explosive.dm @@ -7,11 +7,10 @@ carp_fluff_string = "CARP CARP CARP! Caught one! It's an explosive carp! Boom goes the fishy." var/bomb_cooldown = 0 -/mob/living/simple_animal/hostile/guardian/bomb/Stat() - ..() - if(statpanel("Status")) - if(bomb_cooldown >= world.time) - stat(null, "Bomb Cooldown Remaining: [DisplayTimeText(bomb_cooldown - world.time)]") +/mob/living/simple_animal/hostile/guardian/bomb/get_status_tab_items() + . = ..() + if(bomb_cooldown >= world.time) + . += "Bomb Cooldown Remaining: [DisplayTimeText(bomb_cooldown - world.time)]" /mob/living/simple_animal/hostile/guardian/bomb/AttackingTarget() . = ..() diff --git a/code/modules/mob/living/simple_animal/guardian/types/support.dm b/code/modules/mob/living/simple_animal/guardian/types/support.dm index 2b1b330d..78ad55be 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/support.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/support.dm @@ -17,11 +17,11 @@ var/datum/atom_hud/medsensor = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] medsensor.add_hud_to(src) -/mob/living/simple_animal/hostile/guardian/healer/Stat() - ..() - if(statpanel("Status")) - if(beacon_cooldown >= world.time) - stat(null, "Beacon Cooldown Remaining: [DisplayTimeText(beacon_cooldown - world.time)]") + +/mob/living/simple_animal/hostile/guardian/healer/get_status_tab_items() + . = ..() + if(beacon_cooldown >= world.time) + . += "Beacon Cooldown Remaining: [DisplayTimeText(beacon_cooldown - world.time)]" /mob/living/simple_animal/hostile/guardian/healer/AttackingTarget() . = ..() diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm b/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm index deb88d67..9634c7fe 100644 --- a/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm +++ b/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm @@ -128,7 +128,7 @@ /mob/living/simple_animal/hostile/jungle/leaper/Initialize() . = ..() - verbs -= /mob/living/verb/pulled + remove_verb(src, /mob/living/verb/pulled) /mob/living/simple_animal/hostile/jungle/leaper/CtrlClickOn(atom/A) face_atom(A) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index 0308443d..573a9ef8 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -638,8 +638,8 @@ Difficulty: Very Hard /mob/living/simple_animal/hostile/lightgeist/Initialize() . = ..() - verbs -= /mob/living/verb/pulled - verbs -= /mob/verb/me_verb + remove_verb(src, /mob/living/verb/pulled) + remove_verb(src, /mob/verb/me_verb) var/datum/atom_hud/medsensor = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] medsensor.add_hud_to(src) @@ -728,7 +728,7 @@ Difficulty: Very Hard L.mind.transfer_to(holder_animal) var/obj/effect/proc_holder/spell/targeted/exit_possession/P = new /obj/effect/proc_holder/spell/targeted/exit_possession holder_animal.mind.AddSpell(P) - holder_animal.verbs -= /mob/living/verb/pulled + remove_verb(holder_animal, /mob/living/verb/pulled) /obj/structure/closet/stasis/dump_contents(var/kill = 1) STOP_PROCESSING(SSobj, src) diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm index acf695a7..286831aa 100644 --- a/code/modules/mob/living/simple_animal/parrot.dm +++ b/code/modules/mob/living/simple_animal/parrot.dm @@ -110,12 +110,12 @@ parrot_sleep_dur = parrot_sleep_max //In case someone decides to change the max without changing the duration var - verbs.Add(/mob/living/simple_animal/parrot/proc/steal_from_ground, \ + add_verb(src, list(/mob/living/simple_animal/parrot/proc/steal_from_ground, \ /mob/living/simple_animal/parrot/proc/steal_from_mob, \ /mob/living/simple_animal/parrot/verb/drop_held_item_player, \ /mob/living/simple_animal/parrot/proc/perch_player, \ /mob/living/simple_animal/parrot/proc/toggle_mode, - /mob/living/simple_animal/parrot/proc/perch_mob_player) + /mob/living/simple_animal/parrot/proc/perch_mob_player)) /mob/living/simple_animal/parrot/examine(mob/user) @@ -137,11 +137,12 @@ ..(gibbed) -/mob/living/simple_animal/parrot/Stat() - ..() - if(statpanel("Status")) - stat("Held Item", held_item) - stat("Mode",a_intent) + +/mob/living/simple_animal/parrot/get_status_tab_items() + . = ..() + . += "" + . += "Held Item: [held_item]" + . += "Mode: [a_intent]" /mob/living/simple_animal/parrot/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans, message_mode, atom/movable/source) . = ..() diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index f8e799e5..e482f72a 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -5,7 +5,7 @@ maxHealth = 20 gender = PLURAL //placeholder blood_volume = 550 //How much blud it has for bloodsucking - + status_flags = CANPUSH var/icon_living = "" @@ -294,11 +294,11 @@ remove_movespeed_modifier(MOVESPEED_ID_SIMPLEMOB_VARSPEED, TRUE) add_movespeed_modifier(MOVESPEED_ID_SIMPLEMOB_VARSPEED, TRUE, 100, multiplicative_slowdown = speed, override = TRUE) -/mob/living/simple_animal/Stat() - ..() - if(statpanel("Status")) - stat(null, "Health: [round((health / maxHealth) * 100)]%") - return 1 + +/mob/living/simple_animal/get_status_tab_items() + . = ..() + . += "" + . += "Health: [round((health / maxHealth) * 100)]%" /mob/living/simple_animal/proc/drop_loot() if(loot.len) diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index 67b3cb53..593ea1fa 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -197,21 +197,21 @@ /mob/living/simple_animal/slime/Process_Spacemove(movement_dir = 0) return 2 -/mob/living/simple_animal/slime/Stat() +/mob/living/simple_animal/slime/get_status_tab_items() if(..()) if(!docile) - stat(null, "Nutrition: [nutrition]/[get_max_nutrition()]") + . += "Nutrition: [nutrition]/[get_max_nutrition()]" if(amount_grown >= SLIME_EVOLUTION_THRESHOLD) if(is_adult) - stat(null, "You can reproduce!") + . += "You can reproduce!" else - stat(null, "You can evolve!") + . += "You can evolve!" if(stat == UNCONSCIOUS) - stat(null,"You are knocked out by high levels of BZ!") + . += "You are knocked out by high levels of BZ!" else - stat(null,"Power Level: [powerlevel]") + . += "Power Level: [powerlevel]" /mob/living/simple_animal/slime/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 4f1afd3d..98209303 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -572,7 +572,7 @@ mob/visible_message(message, self_message, blind_message, vision_distance = DEFA /mob/proc/is_muzzled() return 0 - +/* /mob/Stat() ..() //This is where I try and add a temporary solution to the issue of the status tab. This solution is bad and I should feel bad, but it should mitigate some of the client lag. @@ -646,25 +646,31 @@ mob/visible_message(message, self_message, blind_message, vision_distance = DEFA if(A.IsObscured()) continue statpanel(listed_turf.name, null, A) +*/ +/// Adds this list to the output to the stat browser +/mob/proc/get_status_tab_items() + . = list() +/// Gets all relevant proc holders for the browser statpenl +/mob/proc/get_proc_holders() + . = list() if(mind) - add_spells_to_statpanel(mind.spell_list) - var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling) - if(changeling) - add_stings_to_statpanel(changeling.purchasedpowers) - add_spells_to_statpanel(mob_spell_list) + . += get_spells_for_statpanel(mind.spell_list) + . += get_spells_for_statpanel(mob_spell_list) -/mob/proc/add_spells_to_statpanel(list/spells) +/mob/proc/get_spells_for_statpanel(list/spells) + var/list/L = list() for(var/obj/effect/proc_holder/spell/S in spells) if(S.can_be_cast_by(src)) switch(S.charge_type) if("recharge") - statpanel("[S.panel]","[S.charge_counter/10.0]/[S.charge_max/10]",S) + L[++L.len] = list("[S.panel]", "[S.charge_counter/10.0]/[S.charge_max/10]", S.name, REF(S)) if("charges") - statpanel("[S.panel]","[S.charge_counter]/[S.charge_max]",S) + L[++L.len] = list("[S.panel]", "[S.charge_counter]/[S.charge_max]", S.name, REF(S)) if("holdervar") - statpanel("[S.panel]","[S.holder_var_type] [S.holder_var_amount]",S) + L[++L.len] = list("[S.panel]", "[S.holder_var_type] [S.holder_var_amount]", S.name, REF(S)) + return L /mob/proc/add_stings_to_statpanel(list/stings) for(var/obj/effect/proc_holder/changeling/S in stings) @@ -794,6 +800,8 @@ mob/visible_message(message, self_message, blind_message, vision_distance = DEFA if(istype(S, spell)) mob_spell_list -= S qdel(S) + if(client) + client << output(null, "statbrowser:check_spells") /mob/proc/anti_magic_check(magic = TRUE, holy = FALSE) if(!magic && !holy) diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 7bd7e76f..41c1ba3b 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -57,7 +57,7 @@ var/dizziness = 0//Carbon var/jitteriness = 0//Carbon var/nutrition = NUTRITION_LEVEL_START_MIN // randomised in Initialize - var/thirst = 300 + var/thirst = THIRST_LEVEL_START_MIN //same for this var/satiety = 0//Carbon var/overeatduration = 0 // How long this guy is overeating //Carbon diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 540c9431..42048e65 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -424,6 +424,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(M)])") M.ghostize(0) M.key = C.key + M.client?.init_verbs() return TRUE else to_chat(M, "There were no ghosts willing to take control.") diff --git a/code/modules/power/generator.dm b/code/modules/power/generator.dm index 14d2dbaa..c2a67735 100644 --- a/code/modules/power/generator.dm +++ b/code/modules/power/generator.dm @@ -89,7 +89,7 @@ var/energy_transfer = delta_temperature*hot_air_heat_capacity*cold_air_heat_capacity/(hot_air_heat_capacity+cold_air_heat_capacity) var/heat = energy_transfer*(1-efficiency) - lastgen += energy_transfer*efficiency + lastgen += LOGISTIC_FUNCTION(500000,0.0009,delta_temperature,10000) hot_air.temperature = hot_air.temperature - energy_transfer/hot_air_heat_capacity cold_air.temperature = cold_air.temperature + heat/cold_air_heat_capacity diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index cc70253d..30658b98 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -78,6 +78,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) icon_state = "darkmatter" density = TRUE anchored = TRUE + layer = MOB_LAYER flags_1 = PREVENT_CONTENTS_EXPLOSION_1 var/uid = 1 var/static/gl_uid = 1 diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm index 5ddbbc42..c2e7e32e 100644 --- a/code/modules/power/tesla/energy_ball.dm +++ b/code/modules/power/tesla/energy_ball.dm @@ -18,62 +18,43 @@ dissipate_delay = 5 dissipate_strength = 1 var/list/orbiting_balls = list() - var/miniball = FALSE var/produced_power var/energy_to_raise = 32 var/energy_to_lower = -20 -/obj/singularity/energy_ball/Initialize(mapload, starting_energy = 50, is_miniball = FALSE) - miniball = is_miniball +/obj/singularity/energy_ball/Initialize(mapload) . = ..() - if(!is_miniball) - set_light(10, 7, "#EEEEFF") + set_light(10, 7, "#EEEEFF") /obj/singularity/energy_ball/ex_act(severity, target) return /obj/singularity/energy_ball/Destroy() - if(orbiting && istype(orbiting.parent, /obj/singularity/energy_ball)) - var/obj/singularity/energy_ball/EB = orbiting.parent - EB.orbiting_balls -= src - for(var/ball in orbiting_balls) - var/obj/singularity/energy_ball/EB = ball + var/obj/effect/energy_ball/EB = ball qdel(EB) . = ..() -/obj/singularity/energy_ball/admin_investigate_setup() - if(miniball) - return //don't annnounce miniballs - ..() - - /obj/singularity/energy_ball/process() - if(!orbiting) - handle_energy() + handle_energy() + move_the_basket_ball(4 + orbiting_balls.len * 1.5) + playsound(src.loc, 'sound/magic/lightningbolt.ogg', 100, 1, extrarange = 30) - move_the_basket_ball(4 + orbiting_balls.len * 1.5) + pixel_x = 0 + pixel_y = 0 + tesla_zap(src, 7, TESLA_DEFAULT_POWER, TRUE) + pixel_x = -32 + pixel_y = -32 - playsound(src.loc, 'sound/magic/lightningbolt.ogg', 100, 1, extrarange = 30) - - pixel_x = 0 - pixel_y = 0 - - tesla_zap(src, 7, TESLA_DEFAULT_POWER, TRUE) - - pixel_x = -32 - pixel_y = -32 - for (var/ball in orbiting_balls) - var/range = rand(1, CLAMP(orbiting_balls.len, 3, 7)) - tesla_zap(ball, range, TESLA_MINI_POWER/7*range) - else - energy = 0 // ensure we dont have miniballs of miniballs + for (var/ball in orbiting_balls) + var/range = rand(1, CLAMP(orbiting_balls.len, 3, 7)) + tesla_zap(ball, range, TESLA_MINI_POWER/7*range) /obj/singularity/energy_ball/examine(mob/user) . = ..() if(orbiting_balls.len) - . += "The amount of orbiting mini-balls is [orbiting_balls.len]." + . += "There are [orbiting_balls.len] orbiting energy balls around it." /obj/singularity/energy_ball/proc/move_the_basket_ball(var/move_amount) @@ -110,11 +91,9 @@ dissipate() //sing code has a much better system. /obj/singularity/energy_ball/proc/new_mini_ball() - if(!loc) - return - var/obj/singularity/energy_ball/EB = new(loc, 0, TRUE) + var/obj/effect/energy_ball/EB = new(loc, src) - EB.transform *= pick(0.3, 0.4, 0.5, 0.6, 0.7) + EB.transform *= pick(0.45, 0.5, 0.6, 0.7, 0.75) var/icon/I = icon(icon,icon_state,dir) var/orbitsize = (I.Width() + I.Height()) * pick(0.4, 0.5, 0.6, 0.7, 0.8) @@ -138,23 +117,6 @@ qdel(rip_u) C.death() -/obj/singularity/energy_ball/orbit(obj/singularity/energy_ball/target) - if (istype(target)) - target.orbiting_balls += src - GLOB.poi_list -= src - target.dissipate_strength = target.orbiting_balls.len - - . = ..() -/obj/singularity/energy_ball/stop_orbit() - if (orbiting && istype(orbiting.parent, /obj/singularity/energy_ball)) - var/obj/singularity/energy_ball/orbitingball = orbiting.parent - orbitingball.orbiting_balls -= src - orbitingball.dissipate_strength = orbitingball.orbiting_balls.len - . = ..() - if (!QDELETED(src)) - qdel(src) - - /obj/singularity/energy_ball/proc/dust_mobs(atom/A) if(isliving(A)) var/mob/living/L = A @@ -311,3 +273,37 @@ else if(closest_structure) closest_structure.tesla_act(power, tesla_flags, shocked_targets) + +/obj/effect/energy_ball + name = "energy ball" + icon = 'icons/obj/tesla_engine/energy_ball.dmi' + icon_state = "energy_ball" + pixel_x = -32 + pixel_y = -32 + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + var/obj/singularity/energy_ball/parent + +/obj/effect/energy_ball/New(loc, atom/A) + if(istype(A, /obj/singularity/energy_ball)) + parent = A + ..() + +/obj/effect/energy_ball/orbit(atom/A, radius = 10, clockwise = FALSE, rotation_speed = 20, rotation_segments = 36, pre_rotation = TRUE) + if(parent) + parent.orbiting_balls += src + parent.dissipate_strength = parent.orbiting_balls.len + return A == src ? null : A.AddComponent(/datum/component/orbiter, src, radius, clockwise, rotation_speed, rotation_segments, pre_rotation) + +/obj/effect/energy_ball/Destroy() + if(parent) + parent.orbiting_balls -= src + parent.dissipate_strength = parent.orbiting_balls.len + ..() + +/obj/effect/energy_ball/stop_orbit() + if (parent) + parent.orbiting_balls -= src + parent.dissipate_strength = parent.orbiting_balls.len + . = ..() + if (!QDELETED(src)) + QDEL_NULL(src) diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index 89bd36a4..6c518c8e 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -77,6 +77,12 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) /datum/reagent/proc/reaction_turf(turf/T, volume) return +//Hyperstation Edit: Hydroponics trays reactions, idea stolen from citadel but not directly referenced +/datum/reagent/proc/on_tray(obj/machinery/hydroponics/T, volume, mob/user) //See hyperstation's reagent module + if(!T.myseed) + return 0 + return -1 + /datum/reagent/proc/on_mob_life(mob/living/carbon/M) current_cycle++ if(holder) diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index 32e97f0a..18f2c761 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -2422,3 +2422,19 @@ datum/reagent/consumable/ethanol/creme_de_coconut M.set_drugginess(50) M.adjustStaminaLoss(-2) return ..() + +/datum/reagent/consumable/ethanol/cum_in_a_hot_tub + name = "Cum in the Hot Tub" + boozepwr = 80 + color = "#D2D7D9" + quality = DRINK_VERYGOOD + taste_description = "smooth cream" + glass_icon_state = "cum_glass" + shot_glass_icon_state = "cum_shot" //I'm funny, I know + glass_name = "Cum in the Hot Tub" + glass_desc = "Doesn't really leave it to the imagination, eh?" + +/datum/reagent/consumable/ethanol/cum_in_a_hot_tub/semen + boozepwr = 65 + taste_description = "viscous cream" + glass_desc = "The name is probably exactly what it is." diff --git a/code/modules/research/xenobiology/crossbreeding/regenerative.dm b/code/modules/research/xenobiology/crossbreeding/regenerative.dm index 55865d1a..d3f2461c 100644 --- a/code/modules/research/xenobiology/crossbreeding/regenerative.dm +++ b/code/modules/research/xenobiology/crossbreeding/regenerative.dm @@ -129,6 +129,7 @@ Regenerative extracts: /obj/item/slimecross/regenerative/silver/core_effect(mob/living/target, mob/user) target.nutrition = NUTRITION_LEVEL_FULL - 1 + target.nutrition = THIRST_LEVEL_THRESHOLD to_chat(target, "You feel satiated.") /obj/item/slimecross/regenerative/bluespace diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm index fe0595de..fdf2ee60 100644 --- a/code/modules/surgery/organs/eyes.dm +++ b/code/modules/surgery/organs/eyes.dm @@ -362,6 +362,7 @@ on_mob.set_light(1, 1, current_color_string) /obj/effect/abstract/eye_lighting + mouse_opacity = MOUSE_OPACITY_TRANSPARENT var/obj/item/organ/eyes/robotic/glow/parent /obj/effect/abstract/eye_lighting/Initialize() diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm index 558b8459..18cc83a1 100644 --- a/code/modules/surgery/organs/tongue.dm +++ b/code/modules/surgery/organs/tongue.dm @@ -99,8 +99,9 @@ var/static/regex/lizard_hiSS = new("S+", "g") var/message = speech_args[SPEECH_MESSAGE] if(message[1] != "*") - message = lizard_hiss.Replace(message, "sss") - message = lizard_hiSS.Replace(message, "Sss") + var/asterisk_loc = findtext(message, "*")+1 //Don't calculate this every time + message = lizard_hiss.Replace(message, "sss", asterisk_loc) + message = lizard_hiSS.Replace(message, "Sss", asterisk_loc) speech_args[SPEECH_MESSAGE] = message /obj/item/organ/tongue/kitty @@ -117,8 +118,9 @@ var/static/regex/taja_puRR = new("R+", "g") var/message = speech_args[SPEECH_MESSAGE] if(message[1] != "*") - message = taja_purr.Replace(message, "rrr") - message = taja_puRR.Replace(message, "Rrr") + var/asterisk_loc = findtext(message, "*")+1 //Don't calculate this every time + message = taja_purr.Replace(message, "rrr", asterisk_loc) + message = taja_puRR.Replace(message, "Rrr", asterisk_loc) speech_args[SPEECH_MESSAGE] = message /obj/item/organ/tongue/fly @@ -135,8 +137,9 @@ var/static/regex/fly_buZZ = new("Z+", "g") var/message = speech_args[SPEECH_MESSAGE] if(message[1] != "*") - message = fly_buzz.Replace(message, "zzz") - message = fly_buZZ.Replace(message, "ZZZ") + var/asterisk_loc = findtext(message, "*")+1 //Don't calculate this every time + message = fly_buzz.Replace(message, "zzz", asterisk_loc) + message = fly_buZZ.Replace(message, "ZZZ", asterisk_loc) speech_args[SPEECH_MESSAGE] = message /obj/item/organ/tongue/abductor @@ -294,13 +297,14 @@ /obj/item/organ/tongue/fluffy/handle_speech(datum/source, list/speech_args) var/message = speech_args[SPEECH_MESSAGE] if(message[1] != "*") - message = replacetext(message, "ne", "nye") - message = replacetext(message, "nu", "nyu") - message = replacetext(message, "na", "nya") - message = replacetext(message, "no", "nyo") - message = replacetext(message, "ove", "uv") - message = replacetext(message, "l", "w") - message = replacetext(message, "r", "w") + var/asterisk_loc = findtext(message, "*")+1 //Don't calculate this every time + message = replacetext(message, "ne", "nye", asterisk_loc) + message = replacetext(message, "nu", "nyu", asterisk_loc) + message = replacetext(message, "na", "nya", asterisk_loc) + message = replacetext(message, "no", "nyo", asterisk_loc) + message = replacetext(message, "ove", "uv", asterisk_loc) + message = replacetext(message, "l", "w", asterisk_loc) + message = replacetext(message, "r", "w", asterisk_loc) message = lowertext(message) speech_args[SPEECH_MESSAGE] = message diff --git a/config/config.txt b/config/config.txt index f548b087..7f572db4 100644 --- a/config/config.txt +++ b/config/config.txt @@ -480,4 +480,4 @@ DISABLE_HIGH_POP_MC_MODE_AMOUNT 60 DEFAULT_VIEW 21x15 ## Enable Dynamic mode -DYNAMIC_MODE \ No newline at end of file +DYNAMIC_MODE diff --git a/html/statbrowser.html b/html/statbrowser.html new file mode 100644 index 00000000..b55cfd49 --- /dev/null +++ b/html/statbrowser.html @@ -0,0 +1,987 @@ + + + +Stat Browser + + + + + + + + +
+
+ + + diff --git a/hyperstation/code/modules/reagents/chemistry/reagents/hydroponics_reactions.dm b/hyperstation/code/modules/reagents/chemistry/reagents/hydroponics_reactions.dm new file mode 100644 index 00000000..da1d8983 --- /dev/null +++ b/hyperstation/code/modules/reagents/chemistry/reagents/hydroponics_reactions.dm @@ -0,0 +1,294 @@ +/* + * If you ever decide to add more reactions, please remember to keep these + * in alphabetical order, according to reagent names and not their datums. + * It could be hard to find reactions when code diving. + * Due note, unlike before this change, that subtypes will apply to the tray the same as their parents + * -DT + */ + +#define DEFAULT_ACT_MUTAGEN switch(rand(100)){\ + if(91 to 100){\ + T.adjustHealth(-10);\ + to_chat(user, "The plant shrivels and burns.");}\ + if(81 to 90)\ + T.mutatespecie();\ + if(66 to 80)\ + T.hardmutate();\ + if(41 to 65)\ + T.mutate();\ + if(21 to 41)\ + to_chat(user, "The plants don't seem to react...");\ + if(11 to 20)\ + T.mutateweed();\ + if(1 to 10)\ + T.mutatepest(user);\ + else\ + to_chat(user, "Nothing happens...");} + +//Ammonia +/datum/reagent/ammonia/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + T.adjustHealth(round(volume * 0.5)) + T.adjustNutri(round(volume * 1)) + if(..()) + T.myseed.adjust_yield(round(volume * 0.01)) + return 1 + +//Ash +/datum/reagent/ash/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + // Ash is used IRL in gardening, as a fertilizer enhancer and weed killer + T.adjustHealth(round(volume * 0.25)) + T.adjustNutri(round(volume * 0.5)) + T.adjustWeeds(-round(volume / 10)) + return 1 + +//Beer +/datum/reagent/consumable/ethanol/beer/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + // 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? + T.adjustHealth(-round(volume * 0.05)) + T.adjustNutri(round(volume * 0.25)) + T.adjustWater(round(volume * 0.7)) + return 1 + +//Blood +/datum/reagent/blood/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + T.adjustNutri(round(volume * 0.6)) + T.adjustHealth(-round(volume)) + T.adjustPests(rand(2,4)) //they HUNGER + return 1 + +//Charcoal +/datum/reagent/medicine/charcoal/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + T.adjustToxic(-round(volume * 2)) //Antitoxin binds shit pretty well. So the tox goes significantly down + return 1 + +//Chlorine +/datum/reagent/chlorine/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + T.adjustHealth(-round(volume * 1)) + T.adjustToxic(round(volume * 1.5)) + T.adjustWater(-round(volume * 0.5)) + T.adjustWeeds(-rand(1,volume * 0.125)) + return 1 + +//Diethylamine +/datum/reagent/diethylamine/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + //Corrosive to pests, but not to plants + if(..()) + T.myseed.adjust_yield(round(volume * 0.02)) + T.adjustHealth(round(volume)) + T.adjustNutri(round(volume * 2)) + T.adjustPests(-rand(1,round(volume / 30))) + return 1 + +//Earthsblood +/datum/reagent/medicine/earthsblood/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + T.self_sufficiency_progress += volume + if(T.self_sufficiency_progress >= T.self_sufficiency_req) + T.become_self_sufficient() + else + to_chat(user, "[T] warms as it might on a spring day under a genuine Sun.") + return 1 + +//Enduro-Grow +/datum/reagent/plantnutriment/endurogrow/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + if(!..()) + return -1 + T.myseed.adjust_potency(-round(volume / 10)) + T.myseed.adjust_yield(-round(volume / 30)) + T.myseed.adjust_endurance(round(volume / 30)) + return 1 + +//E-Z Nutrient +/datum/reagent/plantnutriment/eznutriment/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + T.yieldmod = 1 + T.mutmod = 1 + return ..() + +//Flourine +/datum/reagent/fluorine/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + // Fluorine one of the most corrosive and deadly gasses + T.adjustHealth(-round(volume * 2)) + T.adjustToxic(round(volume * 2.5)) + T.adjustWater(-round(volume * 0.5)) + T.adjustWeeds(-rand(1, volume * 0.25)) + return 1 + +//Fluorosulfuric acid +/datum/reagent/toxin/acid/fluacid/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + T.adjustHealth(-round(volume * 2)) + T.adjustToxic(round(volume * 3)) + T.adjustWeeds(-rand(1,volume * 0.5)) + return 1 + +//Holy Water +/datum/reagent/water/holywater/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + //Mostly the same as water, it also heals the plant a little with the power of the spirits~ + T.adjustWater(round(volume)) + T.adjustHealth(round(volume * 0.1)) + return 1 + +//Left-4-Zed +/datum/reagent/plantnutriment/left4zednutriment/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + T.yieldmod = 0 + T.mutmod = 2 + return ..() + +//Liquid Earthquake +/datum/reagent/plantnutriment/liquidearthquake/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + if(!..()) + return -1 + T.myseed.adjust_weed_chance(round(volume / 10)) + T.myseed.adjust_weed_rate(round(volume / 30)) + T.myseed.adjust_production(-round(volume / 30)) + return 1 + +//Milk +/datum/reagent/consumable/milk/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + T.adjustNutri(round(volume * 0.2)) + T.adjustWater(round(volume * 0.5)) + if(..()) // Milk is good for humans, but bad for plants. The sugars canot be used by plants, and the milk fat fucks up growth. + if(!T.myseed.get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism)) //Not shrooms though + T.adjustHealth(-round(volume / 2)) + return 1 + +//Napalm +/datum/reagent/napalm/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + if(..()) + if(T.myseed.resistance_flags & FIRE_PROOF) + return 1 + T.adjustHealth(-round(volume * 6)) + T.adjustToxic(round(volume * 7)) + T.adjustWeeds(-rand(5,9)) + return 1 + +//Nutriment +/datum/reagent/consumable/nutriment/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + //Compost, effectively + T.adjustHealth(round(volume * 0.5)) + T.adjustNutri(round(volume)) + return 1 + +//Pest Killer +/datum/reagent/toxin/pestkiller/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + T.adjustToxic(round(volume * 0.5)) + T.adjustPests(-rand(1,volume / 5)) + return 1 + +//Phosphorus +/datum/reagent/phosphorus/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + // 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. + T.adjustHealth(-round(volume * 0.75)) + T.adjustNutri(round(volume * 0.1)) + T.adjustWater(-round(volume * 0.5)) + T.adjustWeeds(-rand(1, volume * 0.1)) + return 1 + +//Plant-B-Gone +/datum/reagent/toxin/plantbgone/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + T.adjustHealth(-round(volume * 5)) + T.adjustToxic(round(volume * 6)) + T.adjustWeeds(-rand(4,8)) + return 1 + +//Plant Base +//For subtypes of /datum/reagent/plantnutriment/ +/datum/reagent/plantnutriment/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + T.adjustNutri(round(volume)) + return ..() + +//Radium +/datum/reagent/radium/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + if(volume >= 10) + DEFAULT_ACT_MUTAGEN + else if(volume >= 5) + T.hardmutate() + else if(volume >= 2) + T.mutate() + + T.adjustHealth(-round(volume)) + T.adjustToxic(round(volume * 3)) // Radium is harsher (OOC: also easier to produce) + return 1 + +//Robust Harvest +/datum/reagent/plantnutriment/robustharvestnutriment/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + T.yieldmod = 1.3 + T.mutmod = 0 + return ..() + +//Saltpetre +/datum/reagent/saltpetre/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + // Saltpetre is used for gardening IRL. To simplify highly, it speeds up growth and strengthens plants + T.adjustHealth(round(volume * 0.25)) + if (..()) + T.myseed.adjust_production(-round(volume/100)-prob(volume%100)) + T.myseed.adjust_potency(round(volume*0.5)) + return 1 + +//Soda Water +/datum/reagent/consumable/sodawater/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + // 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. + T.adjustWater(round(volume) * 0.9) + T.adjustHealth(round(volume * 0.1)) + T.adjustNutri(round(volume * 0.1)) + return 1 + +//Sugar +/datum/reagent/consumable/sugar/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + T.adjustWeeds(round(rand(1, volume / 5))) + T.adjustPests(round(rand(1, volume / 5))) + return 1 + +//Sulphuric Acid +/datum/reagent/toxin/acid/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + T.adjustHealth(-round(volume * 1)) + T.adjustToxic(round(volume * 1.5)) + T.adjustWeeds(-rand(1,volume * 0.25)) + return 1 + +//Toxin +/datum/reagent/toxin/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + T.adjustToxic(round(volume * 2)) + return 1 + +//Unstable Mutagen +/datum/reagent/toxin/mutagen/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + if(volume >= 5) + DEFAULT_ACT_MUTAGEN + else if(volume >= 2) + T.hardmutate() + else if(volume >= 1) + T.mutate() + return 1 + +//Uranium +/datum/reagent/uranium/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + if(volume >= 10) + DEFAULT_ACT_MUTAGEN + else if(volume >= 5) + T.hardmutate() + else if(volume >= 2) + T.mutate() + + T.adjustHealth(-round(volume)) + T.adjustToxic(round(volume * 2)) + return 1 + +//Virus Food +/datum/reagent/toxin/mutagen/mutagenvirusfood/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + T.adjustNutri(round(volume * 0.5)) + T.adjustHealth(-round(volume * 0.5)) + return 1 + +//Water +/datum/reagent/water/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + T.adjustWater(round(volume)) + return 1 + +//Weed Killer +/datum/reagent/toxin/plantbgone/weedkiller/on_tray(obj/machinery/hydroponics/T, volume, mob/user) + T.adjustToxic(round(volume / 2)) + T.adjustWeeds(-rand(1,volume / 5)) + return 1 + +#undef DEFAULT_ACT_MUTAGEN diff --git a/hyperstation/code/modules/resize/sizechems.dm b/hyperstation/code/modules/resize/sizechems.dm index 5d0031d8..67fe8472 100644 --- a/hyperstation/code/modules/resize/sizechems.dm +++ b/hyperstation/code/modules/resize/sizechems.dm @@ -99,7 +99,7 @@ name = "Diminicillin" id = /datum/reagent/shrinkchem mix_message = "the reaction appears to shrink!" - required_reagents = list(/datum/reagent/sizechem = 0.15, /datum/reagent/consumable/frostoil = 0.15, /datum/reagent/drug = 0.30) + required_reagents = list(/datum/reagent/sizechem = 0.15, /datum/reagent/consumable/frostoil = 0.15, /datum/reagent/drug/aphrodisiac = 0.30) results = list(/datum/reagent/shrinkchem = 0.25) required_temp = 1 OptimalTempMin = 100 // Lower area of bell curve for determining heat based rate reactions diff --git a/hyperstation/code/obj/lunaritems.dm b/hyperstation/code/obj/lunaritems.dm index 27d82cfe..db45e6bf 100644 --- a/hyperstation/code/obj/lunaritems.dm +++ b/hyperstation/code/obj/lunaritems.dm @@ -53,7 +53,9 @@ H.update_disabled_bodyparts() H.bleed_rate += 5 H.emote("scream") - new /obj/item/helfiretincture(src.loc) //Eventually a pick, with different items. + var/obj/item/lunar = pick(/obj/item/helfiretincture, + /obj/item/instrument/guitar/biggerukulele) + new lunar(src.loc) visible_message("As you blink, cracks appear on the altar and a flash of lunar light reaches its surface. A gift?") message_admins("[ADMIN_LOOKUPFLW(user)] has sacrificed their [bodypart] on the lunar altar at [AREACOORD(src)].") icon_state = "sacrificealtar-blue" @@ -90,3 +92,63 @@ icon_state = "helfire_tincture" update_icon() to_chat(user, "The tincture vibrates with power once again.") + + +/obj/item/instrument/guitar/biggerukulele + name = "bigger ukulele" + desc = "...and his music was electric." + icon_state = "biggerukulele" + item_state = "guitar" + instrumentExt = "ogg" + attack_verb = list("played a sick solo on", "electrified", "crashed", "smashed") + hitsound = 'sound/weapons/stringsmash.ogg' + instrumentId = "guitar" + siemens_coefficient = -1 + hit_reaction_chance = 100 + var/tesla_power = 25000 + var/tesla_range = 20 + var/tesla_flags = TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE + var/legacy = FALSE + var/legacy_dmg = 30 + var/reactive_cooldown_duration = 20 + var/reactive_cooldown = 0 + var/firstpickup = TRUE + +/obj/item/instrument/guitar/biggerukulele/dropped(mob/user) + ..() + if(istype(user)) + user.flags_1 &= ~TESLA_IGNORE_1 + +/obj/item/instrument/guitar/biggerukulele/pickup(mob/user) + ..() + if(istype(user)) + user.flags_1 |= TESLA_IGNORE_1 + if(firstpickup) + SEND_SOUND(user, sound('hyperstation/sound/misc/biggerukulelepickup.ogg', volume = 100)) + firstpickup = FALSE + +/obj/item/instrument/guitar/biggerukulele/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + if(owner.flags_1 & TESLA_IGNORE_1) + //Do literally nothing. Checking for absence of flags doesn't work for whatever reason, so if !TESLA_IGNORE_1 is not an option. + else if (owner.flags_1) + owner.flags_1 |= TESLA_IGNORE_1 //Sometimes picking up the item doesn't grant the user the flag. This is a way to go around that. Thank you, DM Code. + if(prob(hit_reaction_chance)) + if(world.time < reactive_cooldown) + var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread + sparks.set_up(1, 1, src) + sparks.start() + owner.visible_message("The electric strings of [owner]'s bigger ukulele! The instrument merely emits some sparks.") + return + owner.visible_message("[src] blocks [attack_text], sending out arcs of lightning!") + if(!legacy) + tesla_zap(owner, tesla_range, tesla_power, tesla_flags) + playsound(src.loc, 'sound/weapons/emitter2.ogg', 100, 1, extrarange = 10) + else + for(var/mob/living/M in view(7, owner)) + if(M == owner) + continue + owner.Beam(M,icon_state="purple_lightning",icon='icons/effects/effects.dmi',time=5) + M.adjustFireLoss(legacy_dmg) + playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1) + reactive_cooldown = world.time + reactive_cooldown_duration + return TRUE diff --git a/hyperstation/icons/chat/reward.dmi b/hyperstation/icons/chat/reward.dmi index 1fe18a20..eedb443c 100644 Binary files a/hyperstation/icons/chat/reward.dmi and b/hyperstation/icons/chat/reward.dmi differ diff --git a/hyperstation/sound/misc/biggerukulelepickup.ogg b/hyperstation/sound/misc/biggerukulelepickup.ogg new file mode 100644 index 00000000..43eeca19 Binary files /dev/null and b/hyperstation/sound/misc/biggerukulelepickup.ogg differ diff --git a/icons/mob/augmentation/augments_bimbohair.dmi b/icons/mob/augmentation/augments_bimbohair.dmi new file mode 100644 index 00000000..6b852ad2 Binary files /dev/null and b/icons/mob/augmentation/augments_bimbohair.dmi differ diff --git a/icons/mob/augmentation/augments_lewdbimbof.dmi b/icons/mob/augmentation/augments_lewdbimbof.dmi new file mode 100644 index 00000000..c64d0027 Binary files /dev/null and b/icons/mob/augmentation/augments_lewdbimbof.dmi differ diff --git a/icons/mob/augmentation/augments_lewdbimbom.dmi b/icons/mob/augmentation/augments_lewdbimbom.dmi new file mode 100644 index 00000000..364d1488 Binary files /dev/null and b/icons/mob/augmentation/augments_lewdbimbom.dmi differ diff --git a/icons/mob/augmentation/augments_lewdbimbos.dmi b/icons/mob/augmentation/augments_lewdbimbos.dmi new file mode 100644 index 00000000..ee0cdadd Binary files /dev/null and b/icons/mob/augmentation/augments_lewdbimbos.dmi differ diff --git a/icons/mob/augmentation/augments_lewdbobhair.dmi b/icons/mob/augmentation/augments_lewdbobhair.dmi new file mode 100644 index 00000000..3a3191a8 Binary files /dev/null and b/icons/mob/augmentation/augments_lewdbobhair.dmi differ diff --git a/icons/mob/augmentation/augments_lewdf.dmi b/icons/mob/augmentation/augments_lewdf.dmi new file mode 100644 index 00000000..da0f4b32 Binary files /dev/null and b/icons/mob/augmentation/augments_lewdf.dmi differ diff --git a/icons/mob/augmentation/augments_lewdm.dmi b/icons/mob/augmentation/augments_lewdm.dmi new file mode 100644 index 00000000..38eb30c5 Binary files /dev/null and b/icons/mob/augmentation/augments_lewdm.dmi differ diff --git a/icons/mob/augmentation/augments_lewds.dmi b/icons/mob/augmentation/augments_lewds.dmi new file mode 100644 index 00000000..2b36dabd Binary files /dev/null and b/icons/mob/augmentation/augments_lewds.dmi differ diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi index 5c619c90..2df16ff0 100644 Binary files a/icons/mob/hud.dmi and b/icons/mob/hud.dmi differ diff --git a/icons/mob/mutant_bodyparts.dmi b/icons/mob/mutant_bodyparts.dmi index 19ebe0a4..9a29212f 100644 Binary files a/icons/mob/mutant_bodyparts.dmi and b/icons/mob/mutant_bodyparts.dmi differ diff --git a/icons/obj/clothing/belts.dmi b/icons/obj/clothing/belts.dmi index 9c23efc4..65d2d1e1 100644 Binary files a/icons/obj/clothing/belts.dmi and b/icons/obj/clothing/belts.dmi differ diff --git a/icons/obj/drinks.dmi b/icons/obj/drinks.dmi index 82acf139..b5cfd1f0 100644 Binary files a/icons/obj/drinks.dmi and b/icons/obj/drinks.dmi differ diff --git a/icons/obj/hydroponics/harvest.dmi b/icons/obj/hydroponics/harvest.dmi index 93c96823..e4d1c931 100644 Binary files a/icons/obj/hydroponics/harvest.dmi and b/icons/obj/hydroponics/harvest.dmi differ diff --git a/icons/obj/hydroponics/seeds.dmi b/icons/obj/hydroponics/seeds.dmi index 35ecba68..43ceca57 100644 Binary files a/icons/obj/hydroponics/seeds.dmi and b/icons/obj/hydroponics/seeds.dmi differ diff --git a/icons/obj/musician.dmi b/icons/obj/musician.dmi index 8375b38e..46705002 100644 Binary files a/icons/obj/musician.dmi and b/icons/obj/musician.dmi differ diff --git a/icons/obj/supermatter.dmi b/icons/obj/supermatter.dmi index 92a9dfe2..0da6e964 100644 Binary files a/icons/obj/supermatter.dmi and b/icons/obj/supermatter.dmi differ diff --git a/modular_citadel/code/game/machinery/cryopod.dm b/modular_citadel/code/game/machinery/cryopod.dm index 0c82a210..f8e8665e 100644 --- a/modular_citadel/code/game/machinery/cryopod.dm +++ b/modular_citadel/code/game/machinery/cryopod.dm @@ -306,23 +306,6 @@ announcer.announce("CRYOSTORAGE", mob_occupant.real_name, announce_rank, announce_job_title, list()) visible_message("\The [src] hums and hisses as it moves [mob_occupant.real_name] into storage.") - - for(var/obj/item/W in mob_occupant.GetAllContents()) - if(W.loc.loc && (( W.loc.loc == loc ) || (W.loc.loc == control_computer))) - continue//means we already moved whatever this thing was in - //I'm a professional, okay - for(var/T in preserve_items) - if(istype(W, T)) - if(control_computer && control_computer.allow_items) - control_computer.frozen_items += W - mob_occupant.transferItemToLoc(W, control_computer, TRUE) - else - mob_occupant.transferItemToLoc(W, loc, TRUE) - - for(var/obj/item/W in mob_occupant.GetAllContents()) - qdel(W)//because we moved all items to preserve away - //and yes, this totally deletes their bodyparts one by one, I just couldn't bother - if(iscyborg(mob_occupant)) var/mob/living/silicon/robot/R = occupant if(!istype(R)) return ..() @@ -330,6 +313,24 @@ R.contents -= R.mmi qdel(R.mmi) + QDEL_NULL_LIST(R.contents) + else + for(var/obj/item/W in mob_occupant.GetAllContents()) + if(W.loc.loc && (( W.loc.loc == loc ) || (W.loc.loc == control_computer))) + continue//means we already moved whatever this thing was in + //I'm a professional, okay + for(var/T in preserve_items) + if(istype(W, T)) + if(control_computer && control_computer.allow_items) + control_computer.frozen_items += W + mob_occupant.transferItemToLoc(W, control_computer, TRUE) + else + mob_occupant.transferItemToLoc(W, loc, TRUE) + + for(var/obj/item/W in mob_occupant.GetAllContents()) + qdel(W)//because we moved all items to preserve away + //and yes, this totally deletes their bodyparts one by one, I just couldn't bother + // Ghost and delete the mob. if(!mob_occupant.get_ghost(1)) mob_occupant.ghostize(0) // Players who cryo out may not re-enter the round @@ -387,7 +388,7 @@ if(target.mind.special_role == ROLE_TRAITOR) alert("You're a Traitor![generic_plsnoleave_message]") caught = TRUE - + if(caught) target.client.cryo_warned = world.time return diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/eigentstasium.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/eigentstasium.dm index 6262dc1a..b3e42844 100644 --- a/modular_citadel/code/modules/reagents/chemistry/reagents/eigentstasium.dm +++ b/modular_citadel/code/modules/reagents/chemistry/reagents/eigentstasium.dm @@ -93,7 +93,7 @@ to_chat(M, "Your wavefunction feels like it's been ripped in half. You feel empty inside.") log_game("FERMICHEM: [M] ckey: [M.key] has become addicted to eigenstasium") M.Jitter(10) - M.nutrition = M.nutrition - (M.nutrition/15) + M.nutrition = max(M.nutrition - (M.nutrition/15), 0) ..() /datum/reagent/fermi/eigenstate/addiction_act_stage2(mob/living/M) diff --git a/modular_citadel/interface/skin.dmf b/modular_citadel/interface/skin.dmf index dc2da9a2..9fa01387 100644 --- a/modular_citadel/interface/skin.dmf +++ b/modular_citadel/interface/skin.dmf @@ -110,10 +110,9 @@ window "mapwindow" font-size = 7 is-default = true saved-params = "icon-size" - zoom-mode = distort - style = ".center { text-align: center; } .maptext { font-family: 'Small Fonts'; font-size: 7px; -dm-text-outline: 1px black; color: white; line-height: 1.1; } .command_headset { font-weight: bold;\tfont-size: 8px; } .small { font-size: 6px; } .big { font-size: 8px; } .reallybig { font-size: 8px; } .extremelybig { font-size: 8px; } .greentext { color: #00FF00; font-size: 7px; } .redtext { color: #FF0000; font-size: 7px; } .clown { color: #FF69Bf; font-size: 7px; font-weight: bold; } .his_grace { color: #15D512; } .hypnophrase { color: #0d0d0d; font-weight: bold; } .yell { font-weight: bold; } .italics { font-size: 6px; }" - -window "infowindow" + saved-params = "zoom;letterbox;zoom-mode" + style = ".center { text-align: center; } .maptext { font-family: 'Small Fonts'; font-size: 7px; -dm-text-outline: 1px black; color: white; line-height: 1.1; } .command_headset { font-weight: bold;\tfont-size: 8px; } .small { font-size: 6px; } .big { font-size: 8px; } .reallybig { font-size: 8px; } .extremelybig { font-size: 8px; } .greentext { color: #00FF00; font-size: 7px; } .redtext { color: #FF0000; font-size: 7px; } .clown { color: #FF69Bf; font-size: 7px; font-weight: bold; } .his_grace { color: #15D512; } .hypnophrase { color: #0d0d0d; font-weight: bold; } .yell { font-weight: bold; } .italics { font-size: 6px; }" + window "infowindow" elem "infowindow" type = MAIN pos = 281,0 @@ -264,15 +263,15 @@ window "outputwindow" window "statwindow" elem "statwindow" type = MAIN - pos = 281,0 + pos = 372,0 size = 640x480 anchor1 = none anchor2 = none background-color = #242424 saved-params = "pos;size;is-minimized;is-maximized" is-pane = true - elem "stat" - type = INFO + elem "statbrowser" + type = BROWSER pos = 0,0 size = 640x480 anchor1 = 0,0 @@ -285,7 +284,9 @@ window "statwindow" tab-background-color = #242424 prefix-color = #e0e0e0 suffix-color = #e0e0e0 - + is-visible = false + on-tab = ".output statbrowser:tab_change [[*]]" + window "preferences_window" elem "preferences_window" type = MAIN diff --git a/sound/items/match.ogg b/sound/items/match.ogg new file mode 100644 index 00000000..e38e0274 Binary files /dev/null and b/sound/items/match.ogg differ diff --git a/tgstation.dme b/tgstation.dme index fd4992bd..9aef6ce2 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -79,6 +79,7 @@ #include "code\__DEFINES\pipe_construction.dm" #include "code\__DEFINES\pool.dm" #include "code\__DEFINES\preferences.dm" +#include "code\__DEFINES\procpath.dm" #include "code\__DEFINES\profile.dm" #include "code\__DEFINES\qdel.dm" #include "code\__DEFINES\radiation.dm" @@ -151,6 +152,7 @@ #include "code\__HELPERS\type2type_vr.dm" #include "code\__HELPERS\typelists.dm" #include "code\__HELPERS\unsorted.dm" +#include "code\__HELPERS\verbs.dm" #include "code\__HELPERS\view.dm" #include "code\__HELPERS\sorts\__main.dm" #include "code\__HELPERS\sorts\InsertSort.dm" @@ -275,6 +277,7 @@ #include "code\controllers\subsystem\server_maint.dm" #include "code\controllers\subsystem\shuttle.dm" #include "code\controllers\subsystem\spacedrift.dm" +#include "code\controllers\subsystem\statpanel.dm" #include "code\controllers\subsystem\stickyban.dm" #include "code\controllers\subsystem\sun.dm" #include "code\controllers\subsystem\tgui.dm" @@ -1375,6 +1378,7 @@ #include "code\modules\antagonists\morph\morph.dm" #include "code\modules\antagonists\morph\morph_antag.dm" #include "code\modules\antagonists\nightmare\nightmare.dm" +#include "code\modules\antagonists\nightmare\nightmare_objectives.dm" #include "code\modules\antagonists\ninja\ninja.dm" #include "code\modules\antagonists\nukeop\clownop.dm" #include "code\modules\antagonists\nukeop\nukeop.dm" @@ -1823,7 +1827,6 @@ #include "code\modules\hydroponics\gene_modder.dm" #include "code\modules\hydroponics\grown.dm" #include "code\modules\hydroponics\growninedible.dm" -#include "code\modules\hydroponics\hydro_chemreact.dm" #include "code\modules\hydroponics\hydroitemdefines.dm" #include "code\modules\hydroponics\hydroponics.dm" #include "code\modules\hydroponics\plant_genes.dm" @@ -3062,6 +3065,7 @@ #include "hyperstation\code\modules\mob\mob_helpers.dm" #include "hyperstation\code\modules\patreon\patreon.dm" #include "hyperstation\code\modules\reagents\chemistry\reagents\food_reagents.dm" +#include "hyperstation\code\modules\reagents\chemistry\reagents\hydroponics_reactions.dm" #include "hyperstation\code\modules\resize\resizing.dm" #include "hyperstation\code\modules\resize\sizechems.dm" #include "hyperstation\code\modules\resize\sizegun.dm" @@ -3087,7 +3091,6 @@ #include "interface\interface.dm" #include "interface\menu.dm" #include "interface\stylesheet.dm" -#include "interface\skin.dmf" #include "modular_citadel\code\init.dm" #include "modular_citadel\code\__HELPERS\list2list.dm" #include "modular_citadel\code\__HELPERS\lists.dm"