From b478367fd913b9760985761a914e8c9c97acb861 Mon Sep 17 00:00:00 2001 From: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Date: Thu, 15 Dec 2022 22:55:32 -0800 Subject: [PATCH 01/19] Saves on average 10 seconds from roundstart times (#71730) ## About The Pull Request When runlevels change mid work, subsystems running behind have their next_fire updated. It's offset by a sum of random numbers, so things don't bunch up, especially KEEPTIME SSs The trouble is we have so many subsystems that get added at roundstart that this offset gets LARGE, like 10 seconds on average. So instead of randomly offsetting, why not "fill" a set of time slots? Only 1 keeptime subsystem a tick, and 4 others. Then we just fill up those buckets and get to it (also don't offset things that are already processing) I've talked to mso a bit about this. What he reccomended was sampling a random time withing a 2 second window. I'm not totally sure why, kinda waiting for him to tell me off, if he does I'll fix things up. This pattern takes the max possible delay from 16 (76 * 5 / 20)) seconds to 0.7 (56 / 4 / 20) It obviously scales with subsystem count, but I like this scaling a bit better I've applied the same pattern to the offsetting we do at the start of Loop(), for ticker subsystems. I am less confident in this, it does take last fire times from at worst 3.75 seconds (15 * 5 / 20) to a static 0.75 (15 / 20) As stated I'm less sure of this, hoping to get mso'd so I can clean things up ## Why It's Good For The Game Makes roundstart snappier ## Changelog :cl: code: Roundstart "starting" should be much snappier now /:cl: Co-authored-by: Kyle Spier-Swenson --- code/controllers/master.dm | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/code/controllers/master.dm b/code/controllers/master.dm index b6fb14a69592..e695b0fd0bb8 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -292,7 +292,8 @@ GLOBAL_REAL(Master, /datum/controller/master) = new SS.state = SS_IDLE if (SS.flags & SS_TICKER) tickersubsystems += SS - timer += world.tick_lag * rand(1, 5) + // Timer subsystems aren't allowed to bunch up, so we offset them a bit + timer += world.tick_lag * rand(0, 1) SS.next_fire = timer continue @@ -371,14 +372,16 @@ GLOBAL_REAL(Master, /datum/controller/master) = new var/checking_runlevel = current_runlevel if(cached_runlevel != checking_runlevel) //resechedule subsystems + var/list/old_subsystems = current_runlevel_subsystems cached_runlevel = checking_runlevel current_runlevel_subsystems = runlevel_sorted_subsystems[cached_runlevel] - var/stagger = world.time - for(var/I in current_runlevel_subsystems) - var/datum/controller/subsystem/SS = I - if(SS.next_fire <= world.time) - stagger += world.tick_lag * rand(1, 5) - SS.next_fire = stagger + + //now we'll go through all the subsystems we want to offset and give them a next_fire + for(var/datum/controller/subsystem/SS as anything in current_runlevel_subsystems) + //we only want to offset it if it's new and also behind + if(SS.next_fire > world.time || (SS in old_subsystems)) + continue + SS.next_fire = world.time + world.tick_lag * rand(0, DS2TICKS(min(SS.wait, 2 SECONDS))) subsystems_to_check = current_runlevel_subsystems else From 3a044ef627780b041161851c52e1d86e1090a248 Mon Sep 17 00:00:00 2001 From: Mothblocks <35135081+Mothblocks@users.noreply.github.com> Date: Mon, 31 Oct 2022 23:03:55 -0700 Subject: [PATCH 02/19] Add defines for byond-tracy support (#70931) Adds `USE_BYOND_TRACY`, which automatically loads a given prof.dll/libprof.so using https://github.com/mafemergency/byond-tracy/. Not intended for use in production, and we do not ship a copy of byond-tracy. It is extremely easy to compile yourself, but if you're someone interesting enough to play around with this then let me know and I can just give you a build. I'm going to be using this for init profiling. --- .gitignore | 18 ++++++++++++++++++ code/_compile_options.dm | 4 +++- code/game/world.dm | 21 +++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ef738bcf3887..b365634c32b4 100644 --- a/.gitignore +++ b/.gitignore @@ -196,5 +196,23 @@ Temporary Items /tools/LinuxOneShot/TGS_Config /tools/LinuxOneShot/TGS_Instances /tools/LinuxOneShot/TGS_Logs + + +# Built auxtools libraries and intermediate files +aux*.dll +libaux*.so +aux*.pdb + +# byond-tracy, we intentionally do not ship this and do not want to maintain it +prof.dll +libprof.so + +# JavaScript tools +**/node_modules + +# Screenshot tests +/artifacts + +#byond-tracy tools/UnstandardnessTestForDM/UnstandardnessTestForDM/obj/x86/Debug/UnstandardnessTestForDM.csproj.AssemblyReference.cache tools/UnstandardnessTestForDM/UnstandardnessTestForDM/obj/x86/Debug/.NETFramework,Version=v4.0,Profile=Client.AssemblyAttributes.cs diff --git a/code/_compile_options.dm b/code/_compile_options.dm index 1ed2075537e3..9e5227df9619 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -43,7 +43,9 @@ // #define TRACK_MAX_SHARE //Allows max share tracking, for use in the atmos debugging ui #endif //ifdef TESTING -//#define UNIT_TESTS //If this is uncommented, we do a single run though of the game setup and tear down process with unit tests in between +// If this is uncommented, will attempt to load and initialize prof.dll/libprof.so. +// We do not ship byond-tracy. Build it yourself here: https://github.com/mafemergency/byond-tracy/ +// #define USE_BYOND_TRACY #ifndef PRELOAD_RSC //set to: #define PRELOAD_RSC 2 // 0 to allow using external resources or on-demand behaviour; diff --git a/code/game/world.dm b/code/game/world.dm index c6a5a2ef957a..df92c7c8faac 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -14,6 +14,11 @@ GLOBAL_LIST(topic_status_cache) LIBCALL(dll, "auxtools_init")() enable_debugging() +#ifdef USE_BYOND_TRACY + #warn USE_BYOND_TRACY is enabled + init_byond_tracy() +#endif + world.Profile(PROFILE_START) log_world("World loaded at [TIME_STAMP("hh:mm:ss", FALSE)]!") @@ -369,3 +374,19 @@ GLOBAL_LIST(topic_status_cache) /world/proc/on_tickrate_change() SStimer?.reset_buckets() + +/world/proc/init_byond_tracy() + var/library + + switch (system_type) + if (MS_WINDOWS) + library = "prof.dll" + if (UNIX) + library = "libprof.so" + else + CRASH("Unsupported platform: [system_type]") + + var/init_result = call(library, "init")() + if (init_result != "0") + CRASH("Error initializing byond-tracy: [init_result]") + From b59523ae89080daf5952428e64eaf21da226b8c9 Mon Sep 17 00:00:00 2001 From: Metis <100518708+sheepishgoat@users.noreply.github.com> Date: Wed, 23 Oct 2024 14:00:51 -0400 Subject: [PATCH 03/19] enable byond-tracy --- code/_compile_options.dm | 2 +- code/game/world.dm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/_compile_options.dm b/code/_compile_options.dm index 9e5227df9619..b022f3a2bd2f 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -45,7 +45,7 @@ // If this is uncommented, will attempt to load and initialize prof.dll/libprof.so. // We do not ship byond-tracy. Build it yourself here: https://github.com/mafemergency/byond-tracy/ -// #define USE_BYOND_TRACY +#define USE_BYOND_TRACY #ifndef PRELOAD_RSC //set to: #define PRELOAD_RSC 2 // 0 to allow using external resources or on-demand behaviour; diff --git a/code/game/world.dm b/code/game/world.dm index df92c7c8faac..4ca2259e50b6 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -386,7 +386,7 @@ GLOBAL_LIST(topic_status_cache) else CRASH("Unsupported platform: [system_type]") - var/init_result = call(library, "init")() + var/init_result = call_ext(library, "init")("block") if (init_result != "0") CRASH("Error initializing byond-tracy: [init_result]") From bad81276881b5d2a367014591edd12362863316f Mon Sep 17 00:00:00 2001 From: Metis <100518708+sheepishgoat@users.noreply.github.com> Date: Thu, 24 Oct 2024 01:17:27 -0400 Subject: [PATCH 04/19] some updates --- .gitignore | 4 ---- code/_compile_options.dm | 2 +- prof.dll | Bin 0 -> 104960 bytes 3 files changed, 1 insertion(+), 5 deletions(-) create mode 100644 prof.dll diff --git a/.gitignore b/.gitignore index b365634c32b4..2124f04aca5c 100644 --- a/.gitignore +++ b/.gitignore @@ -203,10 +203,6 @@ aux*.dll libaux*.so aux*.pdb -# byond-tracy, we intentionally do not ship this and do not want to maintain it -prof.dll -libprof.so - # JavaScript tools **/node_modules diff --git a/code/_compile_options.dm b/code/_compile_options.dm index b022f3a2bd2f..5c97a814952d 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -45,7 +45,7 @@ // If this is uncommented, will attempt to load and initialize prof.dll/libprof.so. // We do not ship byond-tracy. Build it yourself here: https://github.com/mafemergency/byond-tracy/ -#define USE_BYOND_TRACY +//#define USE_BYOND_TRACY #ifndef PRELOAD_RSC //set to: #define PRELOAD_RSC 2 // 0 to allow using external resources or on-demand behaviour; diff --git a/prof.dll b/prof.dll new file mode 100644 index 0000000000000000000000000000000000000000..3182f4dfc7363d30e3815adf2b2d78f893826488 GIT binary patch literal 104960 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 Date: Thu, 24 Oct 2024 15:58:04 -0300 Subject: [PATCH 05/19] push --- .vscode/launch.json | 14 +++++++++++++ .vscode/tasks.json | 51 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/.vscode/launch.json b/.vscode/launch.json index e01beb71714e..39f599fd9c67 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -7,6 +7,13 @@ "name": "Launch DreamSeeker", "preLaunchTask": "Build All", "dmb": "${workspaceFolder}/${command:CurrentDMB}" + }, + { + "type": "byond", + "request": "launch", + "name": "Launch DreamSeeker (TRACY)", + "preLaunchTask": "Build All (TRACY)", + "dmb": "${workspaceFolder}/${command:CurrentDMB}" }, { "type": "byond", @@ -45,6 +52,13 @@ "preLaunchTask": "Build All (LOWMEMORYMODE)", "dmb": "${workspaceFolder}/${command:CurrentDMB}", "dreamDaemon": true + }, + { + "type": "byond", + "request": "launch", + "name": "Launch DreamSeeker (LOWMEMORYMODE + TRACY)", + "preLaunchTask": "Build All (LOWMEMORYMODE TRACY)", + "dmb": "${workspaceFolder}/${command:CurrentDMB}" } ] } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 155c69ee991a..5c8886b0c9d9 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -24,6 +24,31 @@ "dependsOn": "dm: reparse", "label": "Build All" }, + { + "type": "process", + "command": "tools/build/build", + "windows": { + "command": ".\\tools\\build\\build.bat" + }, + "options": { + "env": { + "DM_EXE": "${config:dreammaker.byondPath}" + } + }, + "problemMatcher": [ + "$dreammaker", + "$tsc", + "$eslint-stylish" + ], + "group": { + "kind": "build" + }, + "dependsOn": "dm: reparse", + "args": [ + "-DUSE_BYOND_TRACY" + ], + "label": "Build All (TRACY)" + }, { "type": "process", "command": "tools/build/build", @@ -74,6 +99,32 @@ ], "label": "Build All (LOWMEMORYMODE)" }, + { + "type": "process", + "command": "tools/build/build", + "windows": { + "command": ".\\tools\\build\\build.bat" + }, + "options": { + "env": { + "DM_EXE": "${config:dreammaker.byondPath}" + } + }, + "problemMatcher": [ + "$dreammaker", + "$tsc", + "$eslint-stylish" + ], + "group": { + "kind": "build" + }, + "dependsOn": "dm: reparse", + "args": [ + "-DLOWMEMORYMODE", + "-DUSE_BYOND_TRACY" + ], + "label": "Build All (LOWMEMORYMODE TRACY)" + }, { "type": "dreammaker", "dme": "tgstation.dme", From feacce1bb81bc03f787888351f936aa6f91ac517 Mon Sep 17 00:00:00 2001 From: Kylerace Date: Wed, 28 Apr 2021 15:21:24 -0700 Subject: [PATCH 06/19] turns one of the vis_contents in openspace turfs to overlays (#58500) one of the appearances that open space tiles add as vis_contents was an unchanging grey cover. its useless to keep it as vis_contents since its not supposed to change so its better to have it as an overlay. its possible that i can make openspace tiles not add the turf below as vis_contents and instead listen to objects entering and leaving it with connect_loc and add those objects as vis_contents then but that sounds like more trouble than its worth edit: probably not the last part overlays < vis_contents in maptick cost also tramstation has the most open space tiles in high traffic areas compared to other maps. openspace tiles have 2 vis_contents each, equivalent to 2 objects that sendmaps processes every tick this pr only makes it 1 appearance in vis_contents. its also the map with the current highest maptick per player according to lemons graphs --- code/game/turfs/simulated/openspace.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/turfs/simulated/openspace.dm b/code/game/turfs/simulated/openspace.dm index 935bfdc1a7ab..4ee865983efc 100644 --- a/code/game/turfs/simulated/openspace.dm +++ b/code/game/turfs/simulated/openspace.dm @@ -38,7 +38,7 @@ GLOBAL_DATUM_INIT(openspace_backdrop_one_for_all, /atom/movable/openspace_backdr /turf/open/openspace/Initialize(mapload) // handle plane and layer here so that they don't cover other obs/turfs in Dream Maker . = ..() - vis_contents += GLOB.openspace_backdrop_one_for_all //Special grey square for projecting backdrop darkness filter on it. + overlays += GLOB.openspace_backdrop_one_for_all //Special grey square for projecting backdrop darkness filter on it. return INITIALIZE_HINT_LATELOAD /turf/open/openspace/LateInitialize() From bae37cd45c72238d47a2adfd23895051ecd3571e Mon Sep 17 00:00:00 2001 From: Metis <100518708+sheepishgoat@users.noreply.github.com> Date: Thu, 24 Oct 2024 23:33:41 -0400 Subject: [PATCH 07/19] Update slaughterevent.dm --- code/modules/antagonists/slaughter/slaughterevent.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/modules/antagonists/slaughter/slaughterevent.dm b/code/modules/antagonists/slaughter/slaughterevent.dm index 9b62de57bfd0..8d1f92faac4f 100644 --- a/code/modules/antagonists/slaughter/slaughterevent.dm +++ b/code/modules/antagonists/slaughter/slaughterevent.dm @@ -8,6 +8,7 @@ category = EVENT_CATEGORY_ENTITIES description = "Spawns a slaughter demon, to hunt by travelling through pools of blood." +/* /datum/round_event_control/slaughter/canSpawnEvent() weight = initial(src.weight) var/list/allowed_turf_typecache = typecacheof(/turf/open) - typecacheof(/turf/open/space) @@ -24,6 +25,7 @@ weight += 0.03 CHECK_TICK return ..() +*/ /datum/round_event/ghost_role/slaughter minimum_required = 1 From 1bbe63c33bbd5a0cd0ede3f10dcac9612c9aa102 Mon Sep 17 00:00:00 2001 From: Metis <100518708+sheepishgoat@users.noreply.github.com> Date: Fri, 25 Oct 2024 00:44:31 -0400 Subject: [PATCH 08/19] sweet relief --- code/datums/emotes.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm index 5683367c5518..f9c7b5bfe851 100644 --- a/code/datums/emotes.dm +++ b/code/datums/emotes.dm @@ -58,7 +58,7 @@ msg = "[user] [msg]" for(var/mob/M in GLOB.dead_mob_list) - if(!M.client || isnewplayer(M)) + if(!M.client || isnewplayer(M) || !user.client) continue var/T = get_turf(user) if(M.stat == DEAD && M.client && (M.client.prefs.chat_toggles & CHAT_GHOSTSIGHT) && !(M in viewers(T, null))) From b072a63cea727b9a1903296e2a3df1c1744209c1 Mon Sep 17 00:00:00 2001 From: Metis <100518708+sheepishgoat@users.noreply.github.com> Date: Sat, 26 Oct 2024 18:48:16 -0400 Subject: [PATCH 09/19] Update emotes.dm --- code/datums/emotes.dm | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm index f9c7b5bfe851..8d9f6170bd23 100644 --- a/code/datums/emotes.dm +++ b/code/datums/emotes.dm @@ -57,12 +57,13 @@ user.log_message(msg, LOG_EMOTE) msg = "[user] [msg]" - for(var/mob/M in GLOB.dead_mob_list) - if(!M.client || isnewplayer(M) || !user.client) - continue - var/T = get_turf(user) - if(M.stat == DEAD && M.client && (M.client.prefs.chat_toggles & CHAT_GHOSTSIGHT) && !(M in viewers(T, null))) - M.show_message(msg) + if(user.client) + for(var/mob/M in GLOB.dead_mob_list) + if(!M.client || isnewplayer(M)) + continue + var/T = get_turf(user) + if(M.stat == DEAD && M.client && (M.client.prefs.chat_toggles & CHAT_GHOSTSIGHT) && !(M in viewers(T, null))) + M.show_message(msg) if(emote_type == EMOTE_AUDIBLE) user.audible_message(msg) From e1eaa7f6b3953bb2ee90ce05d9bc30d653cd86d8 Mon Sep 17 00:00:00 2001 From: Metis <100518708+sheepishgoat@users.noreply.github.com> Date: Sat, 26 Oct 2024 19:01:00 -0400 Subject: [PATCH 10/19] Update _compile_options.dm --- code/_compile_options.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/_compile_options.dm b/code/_compile_options.dm index 5c97a814952d..ef9692d2a3df 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -43,6 +43,8 @@ // #define TRACK_MAX_SHARE //Allows max share tracking, for use in the atmos debugging ui #endif //ifdef TESTING +//#define UNIT_TESTS //If this is uncommented, we do a single run though of the game setup and tear down process with unit tests in between + // If this is uncommented, will attempt to load and initialize prof.dll/libprof.so. // We do not ship byond-tracy. Build it yourself here: https://github.com/mafemergency/byond-tracy/ //#define USE_BYOND_TRACY From 9e31990e7ad1406a1572a79d0b5daadaeb0f5719 Mon Sep 17 00:00:00 2001 From: Metis <100518708+sheepishgoat@users.noreply.github.com> Date: Mon, 28 Oct 2024 17:26:06 -0400 Subject: [PATCH 11/19] Update .gitignore --- .gitignore | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/.gitignore b/.gitignore index 2124f04aca5c..ef738bcf3887 100644 --- a/.gitignore +++ b/.gitignore @@ -196,19 +196,5 @@ Temporary Items /tools/LinuxOneShot/TGS_Config /tools/LinuxOneShot/TGS_Instances /tools/LinuxOneShot/TGS_Logs - - -# Built auxtools libraries and intermediate files -aux*.dll -libaux*.so -aux*.pdb - -# JavaScript tools -**/node_modules - -# Screenshot tests -/artifacts - -#byond-tracy tools/UnstandardnessTestForDM/UnstandardnessTestForDM/obj/x86/Debug/UnstandardnessTestForDM.csproj.AssemblyReference.cache tools/UnstandardnessTestForDM/UnstandardnessTestForDM/obj/x86/Debug/.NETFramework,Version=v4.0,Profile=Client.AssemblyAttributes.cs From 9ef1d52f34219d058ec84c644d2aa2a71a975935 Mon Sep 17 00:00:00 2001 From: Arrhythmia_V <78709808+Fennec82@users.noreply.github.com> Date: Sat, 2 Nov 2024 00:49:56 -0400 Subject: [PATCH 12/19] Add sprites --- modular_sand/icons/mob/mam_tails.dmi | Bin 1105 -> 1382 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/modular_sand/icons/mob/mam_tails.dmi b/modular_sand/icons/mob/mam_tails.dmi index faa2b13ffad751c595b1cce40aba1c9d060f7fec..68c81e2ce5e817f4ea28b3653ccb3665a09ffcf0 100644 GIT binary patch delta 1358 zcmV-U1+n_k2<8eUiBL{Q4GJ0x0000DNk~Le0002s0002s2m=5B04?*H(*OVfGm#}L zf25?Ohlht^Vq$J?ZZnW4umAu60d!JMQvg8b*k%9#0Ka-vSad{Xb7OL8aCB*JZU6vy zoSl+A3&JoEhUes0gmxFdR+rMM9gHCEA)2!dw236afWO|>4nl|Gb$j38xd-kpWm$13 zIm=HaeS!1Z8n$EG#gdY!Rj9kNSyNJjf3E5<6dz=OE+(xAQa3_DYmI+O1!8|W^J_wh z($4o|D0w*9LZ4StTvi-Qp8p9(S&7l=#-5 z&p06H3*t>bYFd`Eg6H3d{s3HT-S=F7RKKRTUZvpGo`wRc)ogb+dqA%qY@2q7eUPDKyzKpk`nr`o65t5|uI z5QEnrD|lMu3h)ySf134*@RKz-Dc%d23Thdi%pDr`7M)upL~pH9HF!IL;u{b`2qA~MUJYXfB&G?w(S>a zXdeGEW#X1Nb?5O(v}ueXCTRSy3SYbg=LtjgHMk(Y)W*;6ZwcT6d9Ejj(ew4oT5#6$ z+&?=8+|#RN%wARx-I2K@j^cjt%~VAL2<9qT6&X80_@u4%OA)X(-LJyH>^4BM727nC z%H`QehVxmm*UbD4?pSYrf5;AQhFCktr~f>*x~-Z*K|6$dQMVOgcdx79vtcc>s~#tO z*?y#EEpn?t|NrhOKde_=2iT9*ZQCEN2>$=O=loFqQeWeKaFHy~(27C8^SKsv$dxUM zY!q`I$>|pUMi4>>A>_kgzE?K>`Ck6`<$DF-mG2dSXTDbgUin@Tf5eSz67b=I{`p?k zXyki2qmb`q&4+KFLcRyldz3oY{(jOo--GDgXZcil9bBIsuKPBg`5s2!2?dSb;J$-{ zQQUs=%=a+*tIW_$c|Yg3U55Q~_~m;TR#0N-CFqy$fyfO1&iL)~f7in!-vcp%9ezr& z4ScyEv0mzDL3k4te*~kk7h4sS)6B+i`>w2Tz3{E9CJKZZLIG4B$ugzxI8XTr@ zyS0N%aA+M@P??9Jqn~*U^?Mk)bHP=H01eSA&B!mCGKP32GV>_e~J6}9k_!u-_s$yUt+`i zI0f$^%lDKRr+e@ovV2bmbHjwbV=7s`r^G${0j)&&o)+U2*U&NFQ)CK%iCVCHPn9@= zV7^x(SiV;zAOEJC5JCtcgb+dqA*3LJ=XZ(wALUy}?@<`CgwEHF{ea%zGQ;5c;X!@} z_Ldn2&kqmse><@EBofrf506GT%J0D5_epSDsN{!72kjugLwk>sdqyQcJR0L5zr%YA zPMb=8c(@P$=XY@LNpeOt^26hK{@(!Y{Vm#zNco{g@03#|gb+dqA%qY@2q7dZQs;-E zNu3{tCUt%ooYeVYa8l=o8swZGs*rPjs6x*9p$b{&Acq>{ogb!z`5}4D4?098eQwll Q?f?J)07*qoM6N<$f)po?p#T5? delta 1062 zcmV+>1ljxM3egB9iBL{Q4GJ0x0000DNk~Le0002M0002M1Oos70HE@5GynhqCy^y9 z6|?U9H~;_u0d!JMQvg8b*k%9#0I-p96n~LD3&JoIMd##KgmxFdR+rLNGZ;bK!^6C` z0h>q?4EXD9b?Z<}w|j?k54@MNqB?TH$}^`gbY5G-4s5?#Qxdfb-B5O0N;=eS7kqXo$N|bhfoS~#~(Bqglb6ioKxG4VwBeYAM6EsOH-+$J% zR>MLn?KC!;2u?L<4Bius6L?mfvr3fT=YIfKAD@5pHOGGd00SIJL_t(|ob8ygZrd;r zh8?;NBEW;=Ct$c#V*v@B3n<--0(MpdMbx303M6yjp`f>pwfq8(wHK(hWXj}+D&?e& zE8bB$Aq?F1{=ox}cOOYn#{KGaSbr=Qi^XE?wFb252V}qrZTgT55VYxX{{X}c;(A&n z$UOrboDlEbU`V{z$JF=Wm^PpO;t&_aVzF2(7K`;+e^&z` z!P!zsM}J2E3?;l+!*!ekm;%euw&Ed5dyhBLj+UA1ABZCR2ePRCfh^w}V1KcmRM8v1 z^}A8r^9qQP=jlBXo>FCNYpp(A$3=q@593VpFx&Bmo1%y-28_<61 z8-Of-L(c%U{q+PWpRule(5>4L5$dVZI;;cKeE$d1e>IOP)Y>rW0PeWUKL|rm^*6}@ zsPhj(soM2ByX9K{AR4_1_<7A0a)`wyab(k}ejtwH*YDs^??aL#_9)d4bdxa#IFF&@qxylv^zs~zjL*^uG*0yc zqmLsba0Lg*?fU35JpK{^lL1%)(oE6)01ZI*1119jfR)I8z%-Z0ihl&u($f7vh-WBm z?~UvSL|Nn-iX4@22?GdzpsazlhWB)9L9&S-cm$Xd>Kck1srzUJ(9jR;0)&PEW^cd+ zYv>0a0or7M_jJ2d;3+rr13P7mz~zWC0-&4ufj`P%FB*bw<_CUDAsg7TpTuP22TD0= z7K_DVu~@9b)+?IKw9zBvFv{sS6btQ|R4y=;b0UKBUba8`g^ zq+T||m(vbVsTVBK6AkhLga?J=jI4UWQe(5RLKqmXX9loCY73~;%e0=sr?kKUu7^;q zmo1H-*=+2Y{k&MgfK{=+#R1iN!O9Gzsg=>cD{w$@ffDR`C0{bVuqNK6#TvY&CL=F^ z1hk$(e%S>+sGoj Date: Sat, 2 Nov 2024 00:50:32 -0400 Subject: [PATCH 13/19] Add code for Blade tail --- .../mob/dead/new_player/sprite_accessories/tails.dm | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modular_sand/code/modules/mob/dead/new_player/sprite_accessories/tails.dm b/modular_sand/code/modules/mob/dead/new_player/sprite_accessories/tails.dm index 9b04a8d6314f..791c0bfa418c 100644 --- a/modular_sand/code/modules/mob/dead/new_player/sprite_accessories/tails.dm +++ b/modular_sand/code/modules/mob/dead/new_player/sprite_accessories/tails.dm @@ -30,3 +30,15 @@ icon = 'modular_sand/icons/mob/mam_tails.dmi' color_src = MATRIXED matrixed_sections = MATRIX_RED_GREEN + +/datum/sprite_accessory/tails/mam_tails/blade //Ported from Vorestation + name = "Blade" + icon_state = "blade" + icon = 'modular_sand/icons/mob/mam_tails.dmi' + color_src = MUTCOLORS + +/datum/sprite_accessory/tails_animated/mam_tails_animated/blade //Ported from Vorestation + name = "Blade" + icon_state = "blade" + icon = 'modular_sand/icons/mob/mam_tails.dmi' + color_src = MUTCOLORS From f6af059a0619a22fa5d1a660a70a97e57e382b65 Mon Sep 17 00:00:00 2001 From: Metis <100518708+sheepishgoat@users.noreply.github.com> Date: Sat, 2 Nov 2024 03:16:16 -0400 Subject: [PATCH 14/19] job titles --- code/__HELPERS/game.dm | 5 +- code/controllers/subsystem/job.dm | 5 +- code/datums/datacore.dm | 10 +- code/game/machinery/announcement_system.dm | 15 +-- code/modules/client/preferences.dm | 28 ++++- code/modules/client/preferences_savefile.dm | 9 ++ code/modules/jobs/job_titles.dm | 109 ++++++++++++++++++ code/modules/jobs/job_types/_job.dm | 15 ++- code/modules/jobs/job_types/captain.dm | 5 +- .../modules/mob/dead/new_player/new_player.dm | 3 + tgstation.dme | 1 + 11 files changed, 189 insertions(+), 16 deletions(-) create mode 100644 code/modules/jobs/job_titles.dm diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index e177fa286013..cb68fe61fd4a 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -581,8 +581,11 @@ if((character.mind.assigned_role == "Cyborg") || (character.mind.assigned_role == character.mind.special_role)) return + var/displayed_rank = rank + if(character.client && character.client.prefs && character.client?.prefs?.alt_titles_preferences[rank]) + displayed_rank = character.client?.prefs?.alt_titles_preferences[rank] var/obj/machinery/announcement_system/announcer = pick(GLOB.announcement_systems) - announcer.announce("ARRIVAL", character.real_name, rank, list()) //make the list empty to make it announce it in common + announcer.announce("ARRIVAL", character.real_name, displayed_rank, list()) //make the list empty to make it announce it in common /proc/lavaland_equipment_pressure_check(turf/T) . = FALSE diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index b8f5c68deeea..af28f2edf37e 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -464,7 +464,10 @@ SUBSYSTEM_DEF(job) else handle_auto_deadmin_roles(M.client, rank) - to_chat(M, "You are the [rank].") + var/display_rank = rank + if(M.client && M.client.prefs && M.client?.prefs?.alt_titles_preferences[rank]) + display_rank = M.client?.prefs?.alt_titles_preferences[rank] + to_chat(M, "You are the [display_rank].") if(job) to_chat(M, "As the [rank] you answer directly to [job.supervisors]. Special circumstances may change this.") job.radio_help_message(M) diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index 81956667833a..bb0f786fc570 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -138,12 +138,18 @@ var/static/list/show_directions = list(SOUTH, WEST) if(H.mind && (H.mind.assigned_role != H.mind.special_role)) var/assignment + var/displayed_rank if(H.mind.assigned_role) assignment = H.mind.assigned_role else if(H.job) assignment = H.job else assignment = "Unassigned" + if(C && C.prefs && C.prefs.alt_titles_preferences[assignment]) + assignment = C.prefs.alt_titles_preferences[assignment] + + if(assignment) + displayed_rank = C.prefs.alt_titles_preferences[assignment] var/static/record_id_num = 1001 var/id = num2hex(record_id_num++,6) @@ -166,7 +172,7 @@ var/datum/data/record/G = new() G.fields["id"] = id G.fields["name"] = H.real_name - G.fields["rank"] = assignment + G.fields["rank"] = displayed_rank G.fields["age"] = H.age G.fields["species"] = H.dna.species.name G.fields["fingerprint"] = md5(H.dna.uni_identity) @@ -213,7 +219,7 @@ var/datum/data/record/L = new() L.fields["id"] = md5("[H.real_name][H.mind.assigned_role]") //surely this should just be id, like the others? L.fields["name"] = H.real_name - L.fields["rank"] = H.mind.assigned_role + L.fields["rank"] = displayed_rank L.fields["age"] = H.age if(H.gender == MALE) G.fields["gender"] = "Male" diff --git a/code/game/machinery/announcement_system.dm b/code/game/machinery/announcement_system.dm index d06366c02142..1919d424eeac 100644 --- a/code/game/machinery/announcement_system.dm +++ b/code/game/machinery/announcement_system.dm @@ -17,9 +17,9 @@ GLOBAL_LIST_EMPTY(announcement_systems) circuit = /obj/item/circuitboard/machine/announcement_system var/obj/item/radio/headset/radio - var/arrival = "%PERSON has signed up as %RANK" + var/arrival = "%PERSON has signed up as %DISP_RANK (%RANK)" var/arrivalToggle = TRUE - var/newhead = "%PERSON, %RANK, is the department head." + var/newhead = "%PERSON, %DISP_RANK (%RANK), is the department head." var/newheadToggle = TRUE var/cryostorage = "%PERSON, %RANK, has been moved into cryogenic storage." // this shouldnt be changed @@ -70,23 +70,24 @@ GLOBAL_LIST_EMPTY(announcement_systems) else return ..() -/obj/machinery/announcement_system/proc/CompileText(str, user, rank) //replaces user-given variables with actual thingies. +/obj/machinery/announcement_system/proc/CompileText(str, user, rank, displayed_rank) //replaces user-given variables with actual thingies. str = replacetext(str, "%PERSON", "[user]") str = replacetext(str, "%RANK", "[rank]") + str = replacetext(str, "%DISP_RANK", "[displayed_rank]") return str -/obj/machinery/announcement_system/proc/announce(message_type, user, rank, list/channels) +/obj/machinery/announcement_system/proc/announce(message_type, user, rank, displayed_rank, list/channels) if(!is_operational()) return var/message if(message_type == "ARRIVAL" && arrivalToggle) - message = CompileText(arrival, user, rank) + message = CompileText(arrival, user, rank, displayed_rank) else if(message_type == "NEWHEAD" && newheadToggle) - message = CompileText(newhead, user, rank) + message = CompileText(newhead, user, rank, displayed_rank) else if(message_type == "CRYOSTORAGE") - message = CompileText(cryostorage, user, rank) + message = CompileText(cryostorage, user, rank, displayed_rank) else if(message_type == "ARRIVALS_BROKEN") message = "The arrivals shuttle has been damaged. Docking for repairs..." diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index ddf2d71cec16..2f1234f46db7 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -101,6 +101,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/pda_style = MONO var/pda_color = "#808000" var/pda_skin = PDA_SKIN_ALT + var/list/alt_titles_preferences = list() var/uses_glasses_colour = 0 @@ -1449,6 +1450,9 @@ GLOBAL_LIST_EMPTY(preferences_datums) HTML += "" var/rank = job.title + var/displayed_rank = rank + if(job.alt_titles.len && (rank in alt_titles_preferences)) + displayed_rank = alt_titles_preferences[rank] lastJob = job if(jobban_isbanned(user, rank)) HTML += "[rank] BANNED" @@ -1470,10 +1474,15 @@ GLOBAL_LIST_EMPTY(preferences_datums) if((job_preferences["[SSjob.overflow_role]"] == JP_LOW) && (rank != SSjob.overflow_role) && !jobban_isbanned(user, SSjob.overflow_role)) HTML += "[rank]" continue + var/rank_title_line = "[displayed_rank]" if((rank in GLOB.command_positions) || (rank == "AI"))//Bold head jobs - HTML += "[rank]" + rank_title_line = "[rank_title_line]" + if(job.alt_titles.len) + rank_title_line = "[rank_title_line]" + else - HTML += "[rank]" + rank_title_line = "[rank_title_line]" //Make it dark if we're not adding a button for alt titles + HTML += rank_title_line HTML += "" @@ -1727,6 +1736,21 @@ GLOBAL_LIST_EMPTY(preferences_datums) SetChoices(user) if("setJobLevel") UpdateJobPreference(user, href_list["text"], text2num(href_list["level"])) + if("alt_title") + var/job_title = href_list["job_title"] + var/titles_list = list(job_title) + var/datum/job/J = SSjob.GetJob(job_title) + for(var/i in J.alt_titles) + titles_list += i + var/chosen_title + chosen_title = input(user, "Choose your job's title:", "Job Preference") as null|anything in titles_list + if(chosen_title) + if(chosen_title == job_title) + if(alt_titles_preferences[job_title]) + alt_titles_preferences.Remove(job_title) + else + alt_titles_preferences[job_title] = chosen_title + SetChoices(user) else SetChoices(user) return TRUE diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 1f74ca9031cd..5ff539497d4f 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -910,6 +910,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car if(json_from_file) belly_prefs = json_from_file["belly_prefs"] + S["alt_titles_preferences"] >> alt_titles_preferences //gear loadout if(istext(S["loadout"])) loadout_data = safe_json_decode(S["loadout"]) @@ -1098,6 +1099,13 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car loadout_slot = sanitize_num_clamp(loadout_slot, 1, MAXIMUM_LOADOUT_SAVES, 1, TRUE) + alt_titles_preferences = SANITIZE_LIST(alt_titles_preferences) + if(SSjob) + for(var/datum/job/job in SSjob.occupations) + if(alt_titles_preferences[job.title]) + if(!(alt_titles_preferences[job.title] in job.alt_titles)) + alt_titles_preferences.Remove(job.title) + cit_character_pref_load(S) return TRUE @@ -1214,6 +1222,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["feature_butt_color"], features["butt_color"]) WRITE_FILE(S["feature_butt_size"], features["butt_size"]) WRITE_FILE(S["feature_butt_visibility"], features["butt_visibility"]) + WRITE_FILE(S["alt_titles_preferences"], alt_titles_preferences) WRITE_FILE(S["feature_ooc_notes"], features["ooc_notes"]) diff --git a/code/modules/jobs/job_titles.dm b/code/modules/jobs/job_titles.dm new file mode 100644 index 000000000000..9f516940aef8 --- /dev/null +++ b/code/modules/jobs/job_titles.dm @@ -0,0 +1,109 @@ +//This file also determines the order for the choose your occupation chances screen. + +//Engineering +/datum/job/chief_engineer + alt_titles = list("Head Engineer", "Construction Coordinator", "Project Manager", "Power Plant Director") + +/datum/job/engineer + alt_titles = list("Maintenance Technician", "Engine Technician", "Electrician", "Structural Engineer", "Mechanic", "Station Architect", "Nuclear Plant Operator") + +/datum/job/atmos + alt_titles = list("Firefighter", "Life Support Specialist", "Disposals Technician") + +/datum/job/junior_engineer + +//Service +/datum/job/assistant + alt_titles = list("Civilian", "Morale Officer", "Stripper", "Off-Duty", "Escort", "Visitor", "Businessman", "Trader", "Entertainer", "Tourist") + +/datum/job/cook + alt_titles = list("Cook", "Culinary Artist", "Butcher", "Chef de partie", "Poissonier", "Baker", "Taste Tester") + +/datum/job/hydro + alt_titles = list("Gardener", "Herbalist", "Botanical Researcher", "Hydroponicist", "Farmer", "Beekeeper", "Vintner") + +/datum/job/curator + alt_titles = list("Journalist", "Librarian", "Keeper") + +/datum/job/chaplain + alt_titles = list("Priest", "Priestess", "Prior", "Monk", "Nun", "Counselor") + +/datum/job/janitor + alt_titles = list("Custodian", "Sanitation Technician", "Maid", "Trash Can", "Disposal Unit") + +/datum/job/lawyer + alt_titles = list("Human Resources Agent", "Internal Affairs Agent", "Attorney") + +/datum/job/clown + alt_titles = list("Jester", "Comedian") + +/datum/job/mime + alt_titles = list("Performer", "Pantomime", "Mimic") + +/datum/job/bartender + alt_titles = list("Mixologist", "Sommelier", "Bar Owner", "Barmaid", "Expediter") + +//Science +/datum/job/rd + alt_titles = list("Research Manager", "Science Administrator") + +/datum/job/scientist + alt_titles = list("Circuitry Designer", "Xenobiologist", "Xenobotanist", "Xenoarcheologist", "Chemical Researcher", "Researcher", "Pyrotechnician") + +/datum/job/roboticist + alt_titles = list("Biomechanical Engineer", "Mechatronic Engineer", "Mechanic") + +/datum/job/junior_scientist + +//Medical +/datum/job/cmo + alt_titles = list("Medical Director", "Medical Administrator") + +/datum/job/doctor + alt_titles = list("Nurse", "Surgeon", "Physician", "Paramedic", "Trophologist", "Nutritionist") + +/datum/job/chemist + alt_titles = list("Pharmacist", "Pharmacologist") + +/datum/job/virologist + alt_titles = list("Microbiologist", "Biochemist", "Pathologist") + +/datum/job/geneticist + alt_titles = list("Gene Therapist", "Genetics Researcher") + +/datum/job/psychologist + alt_titles = list("Therapist", "Psychiatrist") + +/datum/job/junior_doctor + +//Security +/datum/job/hos + alt_titles = list("Chief of Security", "Security Commander", "Sheriff") + +/datum/job/warden + alt_titles = list("Prison Chief", "Armory Manager", "Prison Administrator", "Brig Superintendent") + +/datum/job/officer + alt_titles = list("Security Agent", "Probation Officer", "Security Peacekeeper", "Security Guard", "Guardsman", "Security Cadet") + +/datum/job/detective + alt_titles = list("Forensics Technician", "Private Investigator", "Gumshoe") + +/datum/job/junior_officer + +//Supply +/datum/job/qm + alt_titles = list("Supply Chief") + +/datum/job/cargo_tech + alt_titles = list("Mail Man", "Mail Woman", "Mailroom Technician", "Deliveries Officer", "Logistics Technician") + +/datum/job/mining + alt_titles = list("Exotic Ore Miner", "Fauna Hunter", "Explorer", "Digger") //Just because you're a hunter does not excuse you from rock collecting!!!!!!!!!!!! + +//Command +/datum/job/captain + alt_titles = list("Station Director", "Station Commander", "Station Overseer", "Stationmaster", "Commissar") + +/datum/job/hop + alt_titles = list("Personnel Manager", "Staff Administrator", "Records Administrator") diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index 969a39b560d3..f9140cfc439c 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -63,6 +63,9 @@ var/list/mind_traits // Traits added to the mind of the mob assigned this job var/list/blacklisted_quirks //list of quirk typepaths blacklisted. + /// What alternate titles does this job currently have? + var/list/alt_titles = list() + /// Should this job be allowed to be picked for the bureaucratic error event? var/allow_bureaucratic_error = TRUE @@ -211,7 +214,7 @@ /datum/job/proc/announce_head(var/mob/living/carbon/human/H, var/channels) //tells the given channel that the given mob is the new department head. See communications.dm for valid channels. if(H && GLOB.announcement_systems.len) //timer because these should come after the captain announcement - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_addtimer), CALLBACK(pick(GLOB.announcement_systems), TYPE_PROC_REF(/obj/machinery/announcement_system, announce), "NEWHEAD", H.real_name, H.job, channels), 1)) + SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_addtimer), CALLBACK(pick(GLOB.announcement_systems), TYPE_PROC_REF(/obj/machinery/announcement_system, announce), "NEWHEAD", H.real_name, H.job, H.client?.prefs.alt_titles_preferences[H.job], channels), 1)) //If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1 /datum/job/proc/player_old_enough(client/C) @@ -314,7 +317,11 @@ shuffle_inplace(C.access) // Shuffle access list to make NTNet passkeys less predictable C.registered_name = H.real_name C.assignment = J.title - C.update_label() + if(preference_source && preference_source.prefs && preference_source.prefs.alt_titles_preferences[J.title]) + C.update_label(C.registered_name, preference_source.prefs.alt_titles_preferences[J.title]) + else + C.update_label() + for(var/A in SSeconomy.bank_accounts) var/datum/bank_account/B = A if(B.account_id == H.account_id) @@ -326,6 +333,10 @@ var/obj/item/pda/PDA = H.get_item_by_slot(pda_slot) if(istype(PDA)) PDA.owner = H.real_name + if(preference_source && preference_source.prefs && preference_source.prefs.alt_titles_preferences[J.title]) + PDA.ownjob = preference_source.prefs.alt_titles_preferences[J.title] + else + PDA.ownjob = J.title PDA.ownjob = J.title PDA.update_label() if(preference_source && !PDA.equipped) //PDA's screen color, font style and look depend on client preferences. diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm index fe594e4660fe..e217b3c0d258 100644 --- a/code/modules/jobs/job_types/captain.dm +++ b/code/modules/jobs/job_types/captain.dm @@ -50,7 +50,10 @@ /datum/job/captain/announce(mob/living/carbon/human/H) ..() - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(minor_announce), "Captain [H.nameless ? "" : "[H.real_name] "]on deck!")) + var/displayed_rank = H.client?.prefs?.alt_titles_preferences[title] + if(!displayed_rank) //Default to Captain + displayed_rank = "Captain" + SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(minor_announce), "[displayed_rank] [H.nameless ? "" : "[H.real_name] "]on deck!")) /datum/outfit/job/captain name = "Captain" diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index b3811b8fef9a..330d9b36db19 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -606,6 +606,9 @@ dept_dat += "[job_datum.title] ([num_positions_current]/[num_positions_total])" else dept_dat += "[job_datum.title] ([num_positions_current]/[num_positions_total])" + if(client && client.prefs && client?.prefs?.alt_titles_preferences[job_datum.title]) + dept_dat += "
(as [client?.prefs?.alt_titles_preferences[job_datum.title]])" + if(!dept_dat.len) dept_dat += "No positions open." dat += jointext(dept_dat, "") diff --git a/tgstation.dme b/tgstation.dme index 4a116ff9fd52..0d49f689c2ed 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -2472,6 +2472,7 @@ #include "code\modules\jobs\access.dm" #include "code\modules\jobs\job_exp.dm" #include "code\modules\jobs\job_report.dm" +#include "code\modules\jobs\job_titles.dm" #include "code\modules\jobs\jobs.dm" #include "code\modules\jobs\job_types\_job.dm" #include "code\modules\jobs\job_types\ai.dm" From 88dbbd0d3b8075f25d501e61f7cf6322077c9aa6 Mon Sep 17 00:00:00 2001 From: Metis <100518708+sheepishgoat@users.noreply.github.com> Date: Sun, 3 Nov 2024 13:28:02 -0500 Subject: [PATCH 15/19] Update job_titles.dm --- code/modules/jobs/job_titles.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/jobs/job_titles.dm b/code/modules/jobs/job_titles.dm index 9f516940aef8..3a68e7af5254 100644 --- a/code/modules/jobs/job_titles.dm +++ b/code/modules/jobs/job_titles.dm @@ -14,7 +14,7 @@ //Service /datum/job/assistant - alt_titles = list("Civilian", "Morale Officer", "Stripper", "Off-Duty", "Escort", "Visitor", "Businessman", "Trader", "Entertainer", "Tourist") + alt_titles = list("Civilian", "Morale Officer", "Off-Duty", "Visitor", "Businessman", "Trader", "Entertainer", "Tourist") /datum/job/cook alt_titles = list("Cook", "Culinary Artist", "Butcher", "Chef de partie", "Poissonier", "Baker", "Taste Tester") From 128714345dec17efb15897ca9f568d82295e455c Mon Sep 17 00:00:00 2001 From: Metis <100518708+sheepishgoat@users.noreply.github.com> Date: Sun, 17 Nov 2024 16:43:09 -0500 Subject: [PATCH 16/19] whoops --- code/modules/jobs/job_titles.dm | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/code/modules/jobs/job_titles.dm b/code/modules/jobs/job_titles.dm index 3a68e7af5254..8518d4950c3c 100644 --- a/code/modules/jobs/job_titles.dm +++ b/code/modules/jobs/job_titles.dm @@ -10,8 +10,6 @@ /datum/job/atmos alt_titles = list("Firefighter", "Life Support Specialist", "Disposals Technician") -/datum/job/junior_engineer - //Service /datum/job/assistant alt_titles = list("Civilian", "Morale Officer", "Off-Duty", "Visitor", "Businessman", "Trader", "Entertainer", "Tourist") @@ -53,14 +51,12 @@ /datum/job/roboticist alt_titles = list("Biomechanical Engineer", "Mechatronic Engineer", "Mechanic") -/datum/job/junior_scientist - //Medical /datum/job/cmo alt_titles = list("Medical Director", "Medical Administrator") /datum/job/doctor - alt_titles = list("Nurse", "Surgeon", "Physician", "Paramedic", "Trophologist", "Nutritionist") + alt_titles = list("Nurse", "Surgeon", "Physician", "Paramedic", "Trophologist", "Nutritionist", "Therapist", "Psychiatrist") /datum/job/chemist alt_titles = list("Pharmacist", "Pharmacologist") @@ -71,11 +67,6 @@ /datum/job/geneticist alt_titles = list("Gene Therapist", "Genetics Researcher") -/datum/job/psychologist - alt_titles = list("Therapist", "Psychiatrist") - -/datum/job/junior_doctor - //Security /datum/job/hos alt_titles = list("Chief of Security", "Security Commander", "Sheriff") @@ -89,7 +80,6 @@ /datum/job/detective alt_titles = list("Forensics Technician", "Private Investigator", "Gumshoe") -/datum/job/junior_officer //Supply /datum/job/qm From d6561e523692d4b2d1e2f15d1cd91da273f71a05 Mon Sep 17 00:00:00 2001 From: Metis <100518708+sheepishgoat@users.noreply.github.com> Date: Sun, 17 Nov 2024 18:00:26 -0500 Subject: [PATCH 17/19] Update rped.dm --- .../components/storage/concrete/rped.dm | 111 +++++++++++++++++- 1 file changed, 105 insertions(+), 6 deletions(-) diff --git a/code/datums/components/storage/concrete/rped.dm b/code/datums/components/storage/concrete/rped.dm index 47549be56511..70298d4e25f7 100644 --- a/code/datums/components/storage/concrete/rped.dm +++ b/code/datums/components/storage/concrete/rped.dm @@ -1,3 +1,5 @@ +#define MAX_STACK_PICKUP 30 + /datum/component/storage/concrete/rped collection_mode = COLLECT_EVERYTHING allow_quick_gather = TRUE @@ -9,13 +11,61 @@ max_items = 100 display_numerical_stacking = TRUE + var/static/list/allowed_material_types = list( + /obj/item/stack/sheet/glass, + /obj/item/stack/sheet/plasteel, + /obj/item/stack/cable_coil, + ) + + var/static/list/allowed_bluespace_types = list( + /obj/item/stack/ore/bluespace_crystal, + /obj/item/stack/sheet/bluespace_crystal, + ) + /datum/component/storage/concrete/rped/can_be_inserted(obj/item/I, stop_messages, mob/M) . = ..() - if(!I.get_part_rating()) - if (!stop_messages) - to_chat(M, "[parent] only accepts machine parts!") + if(!.) + return . + + //we check how much of glass,plasteel & cable the user can insert + if(isstack(I)) + //user tried to insert invalid stacktype + if(!is_type_in_list(I, allowed_material_types) && !is_type_in_list(I, allowed_bluespace_types)) + return FALSE + + var/obj/item/stack/the_stack = I + var/present_amount = 0 + + //we try to count & limit how much the user can insert of each type to prevent them from using it as an normal storage medium + for(var/obj/item/stack/stack_content in parent) + //is user trying to insert any of these listed bluespace stuff + if(is_type_in_list(I, allowed_bluespace_types)) + //if yes count total bluespace stuff is the RPED and then compare the total amount to the value the user is trying to insert + if(is_type_in_list(stack_content, allowed_bluespace_types)) + present_amount += stack_content.amount + //count other normal stack stuff + else if(istype(I,stack_content.type)) + present_amount = stack_content.amount + break + + //no more storage for this specific stack type + if(MAX_STACK_PICKUP - present_amount == 0) + return FALSE + + //we want the user to insert the exact stack amount which is available so we dont have to bother subtracting & leaving left overs for the user + var/available = MAX_STACK_PICKUP-present_amount + if(available - the_stack.amount < 0) + return FALSE + + else if(istype(I, /obj/item/circuitboard/machine) || istype(I, /obj/item/circuitboard/computer)) + return TRUE + + //check normal insertion of other stock parts + else if(!I.get_part_rating()) return FALSE + return . + /datum/component/storage/concrete/rped/quick_empty(mob/M) var/atom/A = parent if(!M.canUseStorage() || !A.Adjacent(M) || M.incapacitated()) @@ -52,13 +102,60 @@ max_items = 350 display_numerical_stacking = TRUE + var/static/list/allowed_material_types = list( + /obj/item/stack/sheet/glass, + /obj/item/stack/sheet/plasteel, + /obj/item/stack/cable_coil, + ) + + var/static/list/allowed_bluespace_types = list( + /obj/item/stack/ore/bluespace_crystal, + /obj/item/stack/sheet/bluespace_crystal, + ) + /datum/component/storage/concrete/bluespace/rped/can_be_inserted(obj/item/I, stop_messages, mob/M) . = ..() - if(!I.get_part_rating()) - if (!stop_messages) - to_chat(M, "[parent] only accepts machine parts!") + if(!.) + return . + + //we check how much of glass,plasteel & cable the user can insert + if(isstack(I)) + //user tried to insert invalid stacktype + if(!is_type_in_list(I, allowed_material_types) && !is_type_in_list(I, allowed_bluespace_types)) + return FALSE + + var/obj/item/stack/the_stack = I + var/present_amount = 0 + + //we try to count & limit how much the user can insert of each type to prevent them from using it as an normal storage medium + for(var/obj/item/stack/stack_content in parent) + //is user trying to insert any of these listed bluespace stuff + if(is_type_in_list(I, allowed_bluespace_types)) + //if yes count total bluespace stuff is the RPED and then compare the total amount to the value the user is trying to insert + if(is_type_in_list(stack_content, allowed_bluespace_types)) + present_amount += stack_content.amount + //count other normal stack stuff + else if(istype(I,stack_content.type)) + present_amount = stack_content.amount + break + + //no more storage for this specific stack type + if(MAX_STACK_PICKUP - present_amount == 0) + return FALSE + + //we want the user to insert the exact stack amount which is available so we dont have to bother subtracting & leaving left overs for the user + var/available = MAX_STACK_PICKUP-present_amount + if(available - the_stack.amount < 0) + return FALSE + + else if(istype(I, /obj/item/circuitboard/machine) || istype(I, /obj/item/circuitboard/computer)) + return TRUE + + //check normal insertion of other stock parts + else if(!I.get_part_rating()) return FALSE + return . /datum/component/storage/concrete/bluespace/rped/quick_empty(mob/M) var/atom/A = parent @@ -85,3 +182,5 @@ stoplag(1) progress.end_progress() A.do_squish(0.8, 1.2) + +#undef MAX_STACK_PICKUP From 59aa14e5d49c8492a4c82e73eeefaab39d23fde6 Mon Sep 17 00:00:00 2001 From: Sandstorm Bot <85452301+Sandstorm-Bot@users.noreply.github.com> Date: Wed, 20 Nov 2024 02:24:18 +0000 Subject: [PATCH 18/19] Automatic changelog generation for PR #389 [ci skip] --- html/changelogs/AutoChangeLog-pr-389.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-389.yml diff --git a/html/changelogs/AutoChangeLog-pr-389.yml b/html/changelogs/AutoChangeLog-pr-389.yml new file mode 100644 index 000000000000..479b224b3a36 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-389.yml @@ -0,0 +1,4 @@ +author: Arrhythmia_V +delete-after: true +changes: + - rscadd: Blade tail now available in character creator (Ported from VOREstation) From 0fb1e8836de6837f0476d8a492ea86dda9b1e80c Mon Sep 17 00:00:00 2001 From: Sandstorm Bot <85452301+Sandstorm-Bot@users.noreply.github.com> Date: Wed, 20 Nov 2024 02:25:14 +0000 Subject: [PATCH 19/19] Automatic changelog compile [ci skip] --- .../{AutoChangeLog-pr-389.yml => archive/2024-11.yml} | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) rename html/changelogs/{AutoChangeLog-pr-389.yml => archive/2024-11.yml} (63%) diff --git a/html/changelogs/AutoChangeLog-pr-389.yml b/html/changelogs/archive/2024-11.yml similarity index 63% rename from html/changelogs/AutoChangeLog-pr-389.yml rename to html/changelogs/archive/2024-11.yml index 479b224b3a36..789c74bf8223 100644 --- a/html/changelogs/AutoChangeLog-pr-389.yml +++ b/html/changelogs/archive/2024-11.yml @@ -1,4 +1,3 @@ -author: Arrhythmia_V -delete-after: true -changes: +2024-11-20: + Arrhythmia_V: - rscadd: Blade tail now available in character creator (Ported from VOREstation)