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",
diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index 7d2c094bbd92..27f303f2c3fa 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -588,13 +588,11 @@
if((character.mind.assigned_role == "Cyborg") || (character.mind.assigned_role == character.mind.special_role) || (character.mind.assigned_role == "Stowaway"))
return
- //Skyrat changes
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]
+ 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, displayed_rank, list()) //make the list empty to make it announce it in common
- //End of skyrat changes
+ announcer.announce("ARRIVAL", character.real_name, rank, 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/_compile_options.dm b/code/_compile_options.dm
index 832241f47952..04b730c9be8e 100644
--- a/code/_compile_options.dm
+++ b/code/_compile_options.dm
@@ -50,6 +50,10 @@
//#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;
#endif // 1 to use the default behaviour;
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
diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm
index dd0a29bdb220..0efd5b1e1c72 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -477,12 +477,10 @@ SUBSYSTEM_DEF(job)
else
handle_auto_deadmin_roles(M.client, rank)
- //Skyrat changes
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]
- //End of skyrat changes
- to_chat(M, "You are the [display_rank].") //Skyrat change
+ 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 [display_rank] you answer directly to [job.supervisors]. Special circumstances may change this.") //Skyrat change
job.radio_help_message(M)
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
diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm
index b6a6d776be84..63e8f0c68268 100644
--- a/code/datums/datacore.dm
+++ b/code/datums/datacore.dm
@@ -142,16 +142,18 @@
var/static/list/show_directions = list(SOUTH, WEST)
if(H.mind && (H.mind.assigned_role != H.mind.special_role) && (H.mind.assigned_role != "Stowaway"))
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"
- //Skyrat changes
- if(C && C.prefs && C.prefs.alt_titles_preferences[assignment])
- assignment = C.prefs.alt_titles_preferences[assignment]
- //End of skyrat changes
+ 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)
@@ -174,7 +176,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)
@@ -221,7 +223,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/datums/elements/cleaning.dm b/code/datums/elements/cleaning.dm
index fd48f582dd17..21ea954f2122 100644
--- a/code/datums/elements/cleaning.dm
+++ b/code/datums/elements/cleaning.dm
@@ -1,66 +1,73 @@
-/datum/element/cleaning/Attach(datum/target)
+/datum/element/cleaning
+ element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH
+ id_arg_index = 2
+ /// Range of cleaning on moving
+ var/range = 0
+
+/datum/element/cleaning/Attach(atom/movable/cleaner, cleaning_range)
. = ..()
- if(!ismovable(target))
+ if(!istype(cleaner))
return ELEMENT_INCOMPATIBLE
- RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(Clean))
+ if(cleaning_range)
+ range = cleaning_range
+ RegisterSignal(cleaner, COMSIG_MOVABLE_MOVED, PROC_REF(Clean))
-/datum/element/cleaning/Detach(datum/target)
+/datum/element/cleaning/Detach(atom/movable/cleaner)
. = ..()
- UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
+ UnregisterSignal(cleaner, COMSIG_MOVABLE_MOVED)
-/datum/element/cleaning/proc/Clean(datum/source)
- var/atom/movable/AM = source
- var/turf/T = AM.loc
- SEND_SIGNAL(T, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
- for(var/A in T)
- if(is_cleanable(A))
- qdel(A)
- else if(isitem(A))
- var/obj/item/cleaned_item = A
- SEND_SIGNAL(cleaned_item, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
- cleaned_item.clean_blood()
- if(ismob(cleaned_item.loc))
- var/mob/M = cleaned_item.loc
- M.regenerate_icons()
- else if(ishuman(A))
- var/mob/living/carbon/human/cleaned_human = A
- if(cleaned_human.lying)
- if(cleaned_human.head)
- SEND_SIGNAL(cleaned_human.head, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
- cleaned_human.head.clean_blood()
- cleaned_human.update_inv_head()
- if(cleaned_human.wear_suit)
- SEND_SIGNAL(cleaned_human.wear_suit, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
- cleaned_human.wear_suit.clean_blood()
- cleaned_human.update_inv_wear_suit()
- else if(cleaned_human.w_uniform)
- SEND_SIGNAL(cleaned_human.w_uniform, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
- cleaned_human.w_uniform.clean_blood()
- cleaned_human.update_inv_w_uniform()
- //skyrat edit
- else if(cleaned_human.w_underwear)
- SEND_SIGNAL(cleaned_human.w_underwear, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
- cleaned_human.w_underwear.clean_blood()
- cleaned_human.update_inv_w_underwear()
- else if(cleaned_human.w_socks)
- SEND_SIGNAL(cleaned_human.w_socks, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
- cleaned_human.w_socks.clean_blood()
- cleaned_human.update_inv_w_socks()
- else if(cleaned_human.w_shirt)
- SEND_SIGNAL(cleaned_human.w_shirt, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
- cleaned_human.w_shirt.clean_blood()
- cleaned_human.update_inv_w_shirt()
- else if(cleaned_human.wrists)
- SEND_SIGNAL(cleaned_human.wrists, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
- cleaned_human.w_shirt.clean_blood()
- cleaned_human.update_inv_wrists()
- //
- if(cleaned_human.shoes)
- SEND_SIGNAL(cleaned_human.shoes, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
- cleaned_human.shoes.clean_blood()
- cleaned_human.update_inv_shoes()
- SEND_SIGNAL(cleaned_human, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
- cleaned_human.clean_blood()
- cleaned_human.wash_cream()
- cleaned_human.regenerate_icons()
- to_chat(cleaned_human, "[AM] cleans your face!")
+/datum/element/cleaning/proc/Clean(atom/movable/cleaner)
+ for (var/turf/turf in RANGE_TURFS(range, cleaner.loc))
+ SEND_SIGNAL(turf, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ for(var/atom/atom as anything in turf)
+ if(is_cleanable(atom))
+ qdel(atom)
+ else if(isitem(atom))
+ var/obj/item/cleaned_item = atom
+ SEND_SIGNAL(cleaned_item, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_item.clean_blood()
+ if(ismob(cleaned_item.loc))
+ var/mob/mob = cleaned_item.loc
+ mob.regenerate_icons()
+ else if(ishuman(atom))
+ var/mob/living/carbon/human/cleaned_human = atom
+ if(cleaned_human.lying)
+ if(cleaned_human.head)
+ SEND_SIGNAL(cleaned_human.head, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_human.head.clean_blood()
+ cleaned_human.update_inv_head()
+ if(cleaned_human.wear_suit)
+ SEND_SIGNAL(cleaned_human.wear_suit, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_human.wear_suit.clean_blood()
+ cleaned_human.update_inv_wear_suit()
+ else if(cleaned_human.w_uniform)
+ SEND_SIGNAL(cleaned_human.w_uniform, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_human.w_uniform.clean_blood()
+ cleaned_human.update_inv_w_uniform()
+ //skyrat edit
+ else if(cleaned_human.w_underwear)
+ SEND_SIGNAL(cleaned_human.w_underwear, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_human.w_underwear.clean_blood()
+ cleaned_human.update_inv_w_underwear()
+ else if(cleaned_human.w_socks)
+ SEND_SIGNAL(cleaned_human.w_socks, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_human.w_socks.clean_blood()
+ cleaned_human.update_inv_w_socks()
+ else if(cleaned_human.w_shirt)
+ SEND_SIGNAL(cleaned_human.w_shirt, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_human.w_shirt.clean_blood()
+ cleaned_human.update_inv_w_shirt()
+ else if(cleaned_human.wrists)
+ SEND_SIGNAL(cleaned_human.wrists, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_human.w_shirt.clean_blood()
+ cleaned_human.update_inv_wrists()
+ //
+ if(cleaned_human.shoes)
+ SEND_SIGNAL(cleaned_human.shoes, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_human.shoes.clean_blood()
+ cleaned_human.update_inv_shoes()
+ SEND_SIGNAL(cleaned_human, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_human.clean_blood()
+ cleaned_human.wash_cream()
+ cleaned_human.regenerate_icons()
+ to_chat(cleaned_human, span_danger("[cleaner] cleans your face!"))
diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm
index a26e345e957e..08d08a20c0d8 100644
--- a/code/datums/emotes.dm
+++ b/code/datums/emotes.dm
@@ -63,12 +63,13 @@
//msg = "[user] " + msg //SKYRAT CHANGE
var/dchatmsg = "[user] [msg]" //SKYRAT CHANGE
- 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 && (M.client.prefs.chat_toggles & CHAT_GHOSTSIGHT)) && !(M in viewers(T, null)) && (user.client)) //SKYRAT CHANGE - only user controlled mobs show their emotes to all-seeing ghosts, to reduce chat spam
- M.show_message(dchatmsg) //SKYRAT CHANGE
+ 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(dchatmsg)
if(emote_type == EMOTE_AUDIBLE)
user.audible_message(dchatmsg, runechat_popup = chat_popup, rune_msg = msg)
diff --git a/code/game/machinery/announcement_system.dm b/code/game/machinery/announcement_system.dm
index d65e41b3bc83..69cdabe65fff 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
var/cryostorage_tele = "%PERSON, %RANK, has been teleported to CentCom." // you saying it hat man.
@@ -71,12 +71,13 @@ 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
@@ -87,13 +88,13 @@ GLOBAL_LIST_EMPTY(announcement_systems)
rank = "Unknown"
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 == "CRYOSTORAGE_TELE")
- message = CompileText(cryostorage_tele, user, rank)
+ message = CompileText(cryostorage_tele, user, rank, displayed_rank)
else if(message_type == "ARRIVALS_BROKEN")
message = "The arrivals shuttle has been damaged. Docking for repairs..."
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
index d07a5ecd178e..30f7e244aac1 100644
--- a/code/game/machinery/cryopod.dm
+++ b/code/game/machinery/cryopod.dm
@@ -404,7 +404,7 @@ GLOBAL_LIST_EMPTY(cryopod_computers)
// Make an announcement and log the person entering storage.
if(GLOB.announcement_systems.len)
var/obj/machinery/announcement_system/announcer = pick(GLOB.announcement_systems)
- announcer.announce(is_teleporter ? "CRYOSTORAGE_TELE" : "CRYOSTORAGE", mob_occupant.real_name, announce_rank, list())
+ announcer.announce(is_teleporter ? "CRYOSTORAGE_TELE" : "CRYOSTORAGE", mob_occupant.real_name, announce_rank, announce_rank, list())
if (pod)
pod.visible_message(span_notice("\The [pod] hums and hisses as it [is_teleporter ? "teleports" : "moves"] [mob_occupant.real_name] [is_teleporter ? "to centcom" : "into storage"]."))
diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm
index a52bbb75f35f..d2fb3172de9a 100644
--- a/code/game/objects/items/cigs_lighters.dm
+++ b/code/game/objects/items/cigs_lighters.dm
@@ -560,6 +560,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
. += lighter_overlay
/obj/item/lighter/ignition_effect(atom/A, mob/user)
+ playsound(src, 'modular_sand/sound/items/lighter/light.ogg', 50, 0)
if(get_temperature())
. = "With a single flick of [user.p_their()] wrist, [user] smoothly lights [A] with [src]. Damn [user.p_theyre()] cool."
@@ -583,6 +584,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/obj/item/lighter/attack_self(mob/living/user)
if(user.is_holding(src))
if(!lit)
+ // SANDSTORM EDIT
+ playsound(src, 'modular_sand/sound/items/lighter/open.ogg', 50, 0)
+ // End of edit
set_lit(TRUE)
if(fancy)
user.visible_message("Without even breaking stride, [user] flips open and lights [src] in one smooth movement.", "Without even breaking stride, you flip open and light [src] in one smooth movement.")
@@ -606,6 +610,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "burnt_thumb", /datum/mood_event/burnt_thumb)
else
+ // SANDSTORM EDIT
+ playsound(src, 'modular_sand/sound/items/lighter/close.ogg', 50, 0)
+ // Edit end
set_lit(FALSE)
if(fancy)
user.visible_message("You hear a quiet click, as [user] shuts off [src] without even looking at what [user.p_theyre()] doing. Wow.", "You quietly shut off [src] without even looking at what you're doing. Wow.")
diff --git a/code/game/world.dm b/code/game/world.dm
index 430e8d4ada08..cabb344867ff 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -13,6 +13,12 @@ GLOBAL_LIST(topic_status_cache)
if (dll)
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)]!")
@@ -378,19 +384,18 @@ GLOBAL_LIST(topic_status_cache)
/world/proc/on_tickrate_change()
SStimer?.reset_buckets()
-#ifdef TRACY_PROFILING
-/proc/prof_init()
- var/lib
+/world/proc/init_byond_tracy()
+ var/library
- switch(world.system_type)
- if(MS_WINDOWS) lib = "prof.dll"
- if(UNIX) lib = "libprof.so"
- else CRASH("unsupported platform")
+ switch (system_type)
+ if (MS_WINDOWS)
+ library = "prof.dll"
+ if (UNIX)
+ library = "libprof.so"
+ else
+ CRASH("Unsupported platform: [system_type]")
- var/init = LIBCALL(lib, "init")()
- if("0" != init) CRASH("[lib] init error: [init]")
+ var/init_result = call_ext(library, "init")("block")
+ if (init_result != "0")
+ CRASH("Error initializing byond-tracy: [init_result]")
-/world/New()
- prof_init()
- . = ..()
-#endif
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
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index ef2b2b348cca..0c910556df08 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -107,6 +107,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()
// Added by SPLURT (Custom Blood Color)
var/custom_blood_color = FALSE
@@ -132,7 +133,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/view_pixelshift = FALSE
var/enable_personal_chat_color = FALSE
var/personal_chat_color = "#ffffff"
- var/list/alt_titles_preferences = list()
var/lust_tolerance = 100
var/sexual_potency = 15
//Sandstorm CHANGES END
@@ -1810,11 +1810,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
HTML += "
"
var/rank = job.title
- //Skyrat changes
var/displayed_rank = rank
if(job.alt_titles.len && (rank in alt_titles_preferences))
displayed_rank = alt_titles_preferences[rank]
- //End of skyrat changes
lastJob = job
if(jobban_isbanned(user, rank))
HTML += "[rank] | BANNED |
"
@@ -1836,16 +1834,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
- //Skyrat changes
var/rank_title_line = "[displayed_rank]"
if((rank in GLOB.command_positions) || (rank == "AI"))//Bold head jobs
rank_title_line = "[rank_title_line]"
if(job.alt_titles.len)
rank_title_line = "[rank_title_line]"
+
else
rank_title_line = "[rank_title_line]" //Make it dark if we're not adding a button for alt titles
HTML += rank_title_line
- //End of skyrat changes
HTML += ""
@@ -2099,7 +2096,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
SetChoices(user)
if("setJobLevel")
UpdateJobPreference(user, href_list["text"], text2num(href_list["level"]))
- //SKYRAT CHANGES
if("alt_title")
var/job_title = href_list["job_title"]
var/titles_list = list(job_title)
@@ -2115,7 +2111,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
else
alt_titles_preferences[job_title] = chosen_title
SetChoices(user)
- //END OF SKYRAT CHANGES
else
SetChoices(user)
return TRUE
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index bf2fd5654199..8ab8c39df594 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -1121,6 +1121,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"])
@@ -1386,9 +1387,16 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["pregnancy_inflation"] >> pregnancy_inflation
S["pregnancy_breast_growth"] >> pregnancy_breast_growth
//SPLURT EDIT END
-
+
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)
splurt_character_pref_load(S)
@@ -1553,6 +1561,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["feature_neckfire"], features["neckfire"])
WRITE_FILE(S["feature_neckfire_color"], features["neckfire_color"])
+ WRITE_FILE(S["alt_titles_preferences"], alt_titles_preferences)
+
WRITE_FILE(S["feature_ooc_notes"], features["ooc_notes"])
WRITE_FILE(S["feature_color_scheme"], features["color_scheme"])
diff --git a/code/modules/jobs/job_titles.dm b/code/modules/jobs/job_titles.dm
new file mode 100644
index 000000000000..a230fc4d3139
--- /dev/null
+++ b/code/modules/jobs/job_titles.dm
@@ -0,0 +1,99 @@
+//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")
+
+//Service
+/datum/job/assistant
+ alt_titles = list("Civilian", "Morale Officer", "Off-Duty", "Visitor", "Businessman", "Trader", "Entertainer", "Tourist")
+
+/datum/job/cook
+ alt_titles = list("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")
+
+//Medical
+/datum/job/cmo
+ alt_titles = list("Medical Director", "Medical Administrator")
+
+/datum/job/doctor
+ alt_titles = list("Nurse", "Surgeon", "Physician", "Paramedic", "Trophologist", "Nutritionist", "Therapist", "Psychiatrist")
+
+/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")
+
+//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")
+
+
+//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 d81684044c9d..ecc6a553925f 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)
@@ -313,14 +316,13 @@
C.access = J.get_access()
shuffle_inplace(C.access) // Shuffle access list to make NTNet passkeys less predictable
C.registered_name = H.real_name
- //Skyrat change
+ C.assignment = J.title
if(preference_source && preference_source.prefs && preference_source.prefs.alt_titles_preferences[J.title])
- C.assignment = preference_source.prefs.alt_titles_preferences[J.title]
+ C.update_label(C.registered_name, preference_source.prefs.alt_titles_preferences[J.title])
else
- C.assignment = J.title
- //End of skyrat change
- C.update_label()
- if(J.title != "Stowaway")
+ C.update_label()
+
+ if(J.title != "Stowaway") //SPLURT EDIT
for(var/A in SSeconomy.bank_accounts)
var/datum/bank_account/B = A
if(B.account_id == H.account_id)
@@ -332,12 +334,10 @@
var/obj/item/pda/PDA = H.get_item_by_slot(pda_slot)
if(istype(PDA))
PDA.owner = H.real_name
- //Skyrat change
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
- //End of skyrat change
PDA.update_label()
if(preference_source && !PDA.equipped) //PDA's screen color, font style and look depend on client preferences.
PDA.update_style(preference_source)
diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm
index 08bcf38c87b3..cdc188093555 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 b001d08d9c21..41e54ea109de 100644
--- a/code/modules/mob/dead/new_player/new_player.dm
+++ b/code/modules/mob/dead/new_player/new_player.dm
@@ -610,15 +610,14 @@
var/command_bold = ""
if(job in GLOB.command_positions)
command_bold = " command"
- //Sandstorm changes
- var/jobline = "[job_datum.title]"
if(job_datum in SSjob.prioritized_jobs)
- jobline = "[jobline]"
- if(client && client.prefs && client.prefs.alt_titles_preferences[job_datum.title])
- jobline = "[jobline] (as [client.prefs.alt_titles_preferences[job_datum.title]])"
- jobline = "[jobline] ([num_positions_current]/[num_positions_total])"
- dept_dat += jobline
- //End of Sandstorm changes
+ 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]]"
+ dept_dat += ""
+
if(!dept_dat.len)
dept_dat += "No positions open."
dat += jointext(dept_dat, "")
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index d6a35116d4f2..c2505565ac71 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -1650,7 +1650,15 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.Jitter(5)
hunger_rate = 3 * HUNGER_FACTOR
hunger_rate *= H.physiology.hunger_mod
- H.adjust_nutrition(-hunger_rate)
+
+ // SANDSTORM EDIT
+ if (H.client)
+ H.adjust_nutrition(-hunger_rate)
+ else
+ // Do not allow SSD players to get too hungry.
+ if (H.nutrition >= NUTRITION_LEVEL_FED)
+ H.adjust_nutrition(-hunger_rate)
+ // End of sandstorm edit
if (H.nutrition > NUTRITION_LEVEL_FULL)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 3c37003394a5..44f8236aac29 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -1032,7 +1032,7 @@
if(GLOB.announcement_systems.len)
// Sends an announcement the AI has cryoed.
var/obj/machinery/announcement_system/announcer = pick(GLOB.announcement_systems)
- announcer.announce("CRYOSTORAGE", src.real_name, announce_rank, list())
+ announcer.announce("CRYOSTORAGE", src.real_name, announce_rank, announce_rank, list())
new /obj/structure/ai_core/latejoin_inactive(loc)
if(src.mind)
//Handle job slot/tater cleanup.
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 4eff3fab6779..e4b86ff584b0 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -926,7 +926,7 @@
status_flags &= ~CANPUSH
if(module.clean_on_move)
- AddElement(/datum/element/cleaning)
+ AddElement(/datum/element/cleaning, cleaning_range = 1)
else
RemoveElement(/datum/element/cleaning)
@@ -1196,8 +1196,8 @@
var/mob/unbuckle_me_now = i
unbuckle_mob(unbuckle_me_now, FALSE)
-/mob/living/silicon/robot/proc/TryConnectToAI()
- set_connected_ai(select_active_ai_with_fewest_borgs(z))
+/mob/living/silicon/robot/proc/TryConnectToAI(mob/living/silicon/ai/connect_to)
+ set_connected_ai(connect_to || select_active_ai_with_fewest_borgs(z))
if(connected_ai)
lawsync()
lawupdate = TRUE
diff --git a/config/config.txt b/config/config.txt
index f9a588e63ad0..e491231d0730 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -40,9 +40,9 @@ $include entries/urls.txt
$include entries/vote.txt
$include plushies/defines.txt
-# Special Sandstorm configs
-$include sandstorm/config.txt
-$include sandstorm/balance.txt
+
+# Sandstorm configs
+$include sandstorm/includes.txt
# Special SPLURT configs
$include splurt/fetish_content.txt
diff --git a/config/sandstorm/includes.txt b/config/sandstorm/includes.txt
new file mode 100644
index 000000000000..adf290da66dc
--- /dev/null
+++ b/config/sandstorm/includes.txt
@@ -0,0 +1,4 @@
+# This file is mostly so main config file relays to here, and this one relays to the rest
+$include sandstorm/balance.txt
+$include sandstorm/config.txt
+$include sandstorm/qol.txt
diff --git a/config/sandstorm/qol.txt b/config/sandstorm/qol.txt
new file mode 100644
index 000000000000..4f2b082bd25c
--- /dev/null
+++ b/config/sandstorm/qol.txt
@@ -0,0 +1,7 @@
+###
+## AI
+###
+
+## How many shells would an AI gain at roundstart
+## Comment to disable
+ROUNDSTART_AI_SHELLS 1
diff --git a/html/changelogs/archive/2024-11.yml b/html/changelogs/archive/2024-11.yml
index cfcb7124ceb4..98c160e85c7e 100644
--- a/html/changelogs/archive/2024-11.yml
+++ b/html/changelogs/archive/2024-11.yml
@@ -12,3 +12,18 @@
LeDrascol:
- code_imp: Modular quirks are now in separate files
- code_imp: Modularized edits to upstream quirks
+2024-11-20:
+ Arrhythmia_V:
+ - rscadd: Blade tail now available in character creator (Ported from VOREstation)
+2024-11-25:
+ Mosley:
+ - bugfix: Fixes the arrivals announcements
+2024-11-27:
+ Mosley:
+ - bugfix: Fixes the rest of the announcement systems from the update
+2024-11-28:
+ xTheLifex:
+ - rscadd: AIs will now spawn with a AI Shell
+ - tweak: SSD Players will no longer decrease hunger below normal stats.
+ - soundadd: Added sounds to lighters
+ - code_imp: Cleaning element now supports a range variable.
diff --git a/modular_citadel/code/modules/client/preferences_savefile.dm b/modular_citadel/code/modules/client/preferences_savefile.dm
index dc5e559ee18c..191e89eeafd9 100644
--- a/modular_citadel/code/modules/client/preferences_savefile.dm
+++ b/modular_citadel/code/modules/client/preferences_savefile.dm
@@ -20,14 +20,6 @@
S["lust_tolerance"] >> lust_tolerance
S["sexual_potency"] >> sexual_potency
- S["alt_titles_preferences"] >> alt_titles_preferences
- alt_titles_preferences = SANITIZE_LIST(alt_titles_preferences)
- if(SSjob)
- for(var/datum/job/job in sort_list(SSjob.occupations, GLOBAL_PROC_REF(cmp_job_display_asc)))
- if(alt_titles_preferences[job.title])
- if(!(alt_titles_preferences[job.title] in job.alt_titles))
- alt_titles_preferences.Remove(job.title)
-
erppref = sanitize_inlist(S["erp_pref"], GLOB.lewd_prefs_choices, "Ask")
nonconpref = sanitize_inlist(S["noncon_pref"], GLOB.lewd_prefs_choices, "Ask")
vorepref = sanitize_inlist(S["vore_pref"], GLOB.lewd_prefs_choices, "Ask")
@@ -79,7 +71,6 @@
WRITE_FILE(S["extreme_harm"], extremeharm)
WRITE_FILE(S["enable_personal_chat_color"], enable_personal_chat_color)
WRITE_FILE(S["personal_chat_color"], personal_chat_color)
- WRITE_FILE(S["alt_titles_preferences"], alt_titles_preferences)
WRITE_FILE(S["lust_tolerance"], lust_tolerance)
WRITE_FILE(S["sexual_potency"], sexual_potency)
WRITE_FILE(S["silicon_lawset"], silicon_lawset)
diff --git a/modular_sand/code/controllers/configuration/entries/sandstorm.dm b/modular_sand/code/controllers/configuration/entries/sandstorm.dm
index 155cfb32c52b..b8461801e454 100644
--- a/modular_sand/code/controllers/configuration/entries/sandstorm.dm
+++ b/modular_sand/code/controllers/configuration/entries/sandstorm.dm
@@ -28,3 +28,6 @@
value_mode = VALUE_MODE_TYPE
splitter = " | "
lowercase_key = FALSE
+
+/datum/config_entry/number/roundstart_ai_shells // Per AI, if you ever do get a triumvirate!
+ min_val = 0
diff --git a/modular_sand/code/modules/jobs/job_types/_job.dm b/modular_sand/code/modules/jobs/job_types/_job.dm
deleted file mode 100644
index cfb86b707274..000000000000
--- a/modular_sand/code/modules/jobs/job_types/_job.dm
+++ /dev/null
@@ -1,2 +0,0 @@
-/datum/job
- var/list/alt_titles = list()
diff --git a/modular_sand/code/modules/jobs/job_types/_job_alt_titles.dm b/modular_sand/code/modules/jobs/job_types/_job_alt_titles.dm
index 3b2e238e8325..e22152175bd6 100644
--- a/modular_sand/code/modules/jobs/job_types/_job_alt_titles.dm
+++ b/modular_sand/code/modules/jobs/job_types/_job_alt_titles.dm
@@ -1,207 +1,204 @@
+// Great, since upstream got titles, we gotta do this differently.
+// If you downstream, got conflicts from this, good, it means
+// you'll know that you need to make changes as well
+// Although, why are you modifying it here, go be doing shit modularly
+
//Command
-/datum/job/captain
- alt_titles = list(
+/datum/job/captain/New()
+ alt_titles += list(
"Colony Overseer",
"Senator",
"Consul"
- )
+ )
+ return ..()
-/datum/job/chief_engineer
- alt_titles = list(
+/datum/job/chief_engineer/New()
+ alt_titles += list(
"Senior Engineer"
- )
+ )
+ return ..()
-/datum/job/hop
- alt_titles = list(
+/datum/job/hop/New()
+ alt_titles += list(
"Crew Resource Officer",
"Executive Officer"
- )
+ )
+ return ..()
-/datum/job/hos
- alt_titles = list(
- "Chief of Security",
- "Sheriff",
+/datum/job/hos/New()
+ alt_titles += list(
"Praetor",
- "Tarkhan" //If this reference is an issue I will remove it
- )
+ "Tarkhan"
+ )
+ return ..()
-/datum/job/qm
- alt_titles = list(
+/datum/job/qm/New()
+ alt_titles += list(
"Resource Manager",
"Logistics Supervisor"
- )
+ )
+ return ..()
-/datum/job/rd
- alt_titles = list(
+/datum/job/rd/New()
+ alt_titles += list(
"Chief Science Officer",
"Research Overseer"
- )
-
-//Engineering
-/datum/job/atmos
- alt_titles = list(
- "Firefighter",
- "Life Support Specialist"
- )
-
-/datum/job/engineer
- alt_titles = list(
- "Maintenance Technician",
- "Engine Technician",
- "Electrician"
- )
-
-//Service
-/datum/job/assistant
- alt_titles = list(
- "Civilian",
- "Visitor",
- "Businessman",
- "Trader",
- "Entertainer",
+ )
+ return ..()
+
+// Re-enable once we have our unique again
+/*
+/datum/job/atmos/New()
+ alt_titles += list(
+ )
+ return ..()
+
+/datum/job/engineer/New()
+ alt_titles += list(
+ )
+ return ..()
+*/
+
+/datum/job/assistant/New()
+ alt_titles += list(
"Intern",
- "Off-Duty Civilian"
- )
+ )
+ return ..()
-/datum/job/bartender
- alt_titles = list(
+/datum/job/bartender/New()
+ alt_titles += list(
"Barista"
- )
+ )
+ return ..()
-/datum/job/chaplain
- alt_titles = list(
- "Priest",
+/datum/job/chaplain/New()
+ alt_titles += list(
"Cult Leader",
"Pope",
- "Bishop", // How about you actually say something about it instead of crying on a downstream's comments i won't read.
+ "Bishop",
"Pontiff"
- )
+ )
+ return ..()
-/datum/job/clown //The most useless role in the game, delet this
- alt_titles = list(
+/datum/job/clown/New()
+ alt_titles += list(
"Entertainer"
- )
+ )
+ return ..()
-/datum/job/cook
- alt_titles = list(
- "Culinary Artist",
- "Butcher",
+/datum/job/cook/New()
+ alt_titles += list(
"Chef",
"Nutritionist"
- )
-
-/datum/job/curator
- alt_titles = list(
- "Journalist",
- "Librarian"
- )
-
-/datum/job/hydro
- alt_titles = list(
- "Gardener",
- "Herbalist",
- "Botanical Researcher",
+ )
+ return ..()
+
+/*
+/datum/job/curator/New()
+ alt_titles += list(
+ )
+ return ..()
+*/
+
+/datum/job/hydro/New()
+ alt_titles += list(
"Florist"
- )
-
-/datum/job/janitor
- alt_titles = list(
- "Custodian",
- "Sanitation Technician",
- "Maid"
- )
-
-/datum/job/lawyer
- alt_titles = list(
- "Human Resources Agent",
- "Internal Affairs Agent"
- )
-
-/datum/job/mime
- alt_titles = list(
- "Performer"
- )
-
-//Science
-/datum/job/roboticist
- alt_titles = list(
- "Biomechanical Engineer",
- "Mechatronic Engineer",
- "Mechanic",
+ )
+ return ..()
+
+/*
+/datum/job/janitor/New()
+ alt_titles += list(
+ )
+ return ..()
+
+/datum/job/lawyer/New()
+ alt_titles += list(
+ )
+ return ..()
+
+/datum/job/mime/New()
+ alt_titles += list(
+ )
+ return ..()
+*/
+
+/datum/job/roboticist/New()
+ alt_titles += list(
"Robotics Operator",
"MODsuit Engineer"
- )
-
-/datum/job/scientist
- alt_titles = list(
- "Circuitry Designer",
- "Xenobiologist",
- "Xenobotanist",
- "Chemical Researcher"
- )
-
-//Medical
-/datum/job/chemist
- alt_titles = list(
- "Pharmacist",
- "Pharmacologist"
- )
-
-/datum/job/doctor
- alt_titles = list(
- "Nurse",
- "Surgeon",
+ )
+ return ..()
+
+/*
+/datum/job/scientist/New()
+ alt_titles += list(
+ )
+ return ..()
+
+/datum/job/chemist/New()
+ alt_titles += list(
+ )
+ return ..()
+*/
+
+/datum/job/doctor/New()
+ alt_titles += list(
"Medical Secretary",
"Emergency Physician",
- "Field Surgeon"
- )
+ "Field Surgeon"
+ )
+ return ..()
-/datum/job/geneticist
- alt_titles = list(
- "Genetic Therapist",
+/datum/job/geneticist/New()
+ alt_titles += list(
"Bioengineer"
- )
+ )
+ return ..()
-/datum/job/paramedic
- alt_titles = list(
+/datum/job/paramedic/New()
+ alt_titles += list(
"Emergency Medical Technician",
"Advanced Emergency Medical Technician"
- )
-
-/datum/job/virologist
- alt_titles = list(
- "Pathologist"
- )
-
-//Security
-/datum/job/detective
- alt_titles = list(
- "Forensics Technician",
- "Private Investigator"
- )
-
-/datum/job/officer
- alt_titles = list(
- "Security Cadet",
- "Security Guard",
+ )
+ return ..()
+
+/*
+/datum/job/virologist/New()
+ alt_titles += list(
+ )
+ return ..()
+
+/datum/job/detective/New()
+ alt_titles += list(
+ )
+ return ..()
+*/
+
+/datum/job/officer/New()
+ alt_titles += list(
"Peacekeeper",
"Enforcer"
- )
+ )
+ return ..()
-/datum/job/warden
- alt_titles = list(
+/datum/job/warden/New()
+ alt_titles += list(
"Brig Chief"
- )
-
-//Cargo
+ )
+ return ..()
-/datum/job/cargo_tech
- alt_titles = list(
+/datum/job/cargo_tech/New()
+ alt_titles += list(
"Shipping Specialist",
"Delivery Manager"
- )
+ )
+ return ..()
-/datum/job/mining
- alt_titles = list(
+/*
+/datum/job/mining/New()
+ alt_titles += list(
"Explorer"
- )
+ )
+ return ..()
+*/
diff --git a/modular_sand/code/modules/jobs/job_types/ai.dm b/modular_sand/code/modules/jobs/job_types/ai.dm
index 5f80699ea7fe..df0f3ff8429a 100644
--- a/modular_sand/code/modules/jobs/job_types/ai.dm
+++ b/modular_sand/code/modules/jobs/job_types/ai.dm
@@ -1,6 +1,21 @@
/datum/job/ai/after_spawn(mob/living/silicon/ai/AI, client/player_client, latejoin)
. = ..()
- if(!istype(AI))
+ setup_silicon_law_prefs(AI, player_client)
+
+ if(latejoin)
return
- setup_silicon_law_prefs(AI, player_client)
+ var/free_shells = CONFIG_GET(number/roundstart_ai_shells)
+ if(!free_shells)
+ return
+
+ var/turf/open/turf = locate() in RANGE_TURFS(1, AI)
+
+ // Why the fuck is the station AI completely blocked
+ var/turf/where = turf || get_turf(AI)
+
+ // Creating AI shells for the AI.
+ for(var/iteration in 1 to free_shells)
+ var/mob/living/silicon/robot/free_borg = new(where)
+ free_borg.shell = TRUE
+ free_borg.TryConnectToAI(AI)
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 8f50ffc97b8c..758d6bfcdf82 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
@@ -51,3 +51,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
diff --git a/modular_sand/code/modules/mob/living/carbon/human/species.dm b/modular_sand/code/modules/mob/living/carbon/human/species.dm
index e40880f1285f..6f3ba0c8a5c8 100644
--- a/modular_sand/code/modules/mob/living/carbon/human/species.dm
+++ b/modular_sand/code/modules/mob/living/carbon/human/species.dm
@@ -3,7 +3,12 @@
return
//Put more things here if you plan on adding more things. I know this proc is a bit empty at the moment
- H.adjust_thirst(-THIRST_FACTOR)
+ if (H.client)
+ H.adjust_thirst(-THIRST_FACTOR)
+ else
+ // Do not allow SSD players to too thirsty.
+ if (H.thirst >= THIRST_LEVEL_QUENCHED)
+ H.adjust_thirst(-THIRST_FACTOR)
/* switch(get_thirst(src))
if(THIRST_LEVEL_THIRSTY to INFINITY)
diff --git a/modular_sand/icons/mob/mam_tails.dmi b/modular_sand/icons/mob/mam_tails.dmi
index 121df70b4f79..98abc12b7978 100644
Binary files a/modular_sand/icons/mob/mam_tails.dmi and b/modular_sand/icons/mob/mam_tails.dmi differ
diff --git a/modular_sand/sound/items/lighter/close.ogg b/modular_sand/sound/items/lighter/close.ogg
new file mode 100644
index 000000000000..2435711fa75f
Binary files /dev/null and b/modular_sand/sound/items/lighter/close.ogg differ
diff --git a/modular_sand/sound/items/lighter/light.ogg b/modular_sand/sound/items/lighter/light.ogg
new file mode 100644
index 000000000000..9ca5270bc794
Binary files /dev/null and b/modular_sand/sound/items/lighter/light.ogg differ
diff --git a/modular_sand/sound/items/lighter/open.ogg b/modular_sand/sound/items/lighter/open.ogg
new file mode 100644
index 000000000000..79b2c00a6150
Binary files /dev/null and b/modular_sand/sound/items/lighter/open.ogg differ
diff --git a/prof.dll b/prof.dll
new file mode 100644
index 000000000000..3182f4dfc736
Binary files /dev/null and b/prof.dll differ
diff --git a/tgstation.dme b/tgstation.dme
index 5c173c5b341e..fb5bb8baed38 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -2562,6 +2562,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"
@@ -4302,7 +4303,6 @@
#include "modular_sand\code\modules\integrated_electronics\subtypes\input.dm"
#include "modular_sand\code\modules\integrated_electronics\subtypes\manipulation.dm"
#include "modular_sand\code\modules\integrated_electronics\subtypes\output.dm"
-#include "modular_sand\code\modules\jobs\job_types\_job.dm"
#include "modular_sand\code\modules\jobs\job_types\_job_alt_titles.dm"
#include "modular_sand\code\modules\jobs\job_types\ai.dm"
#include "modular_sand\code\modules\jobs\job_types\cyborg.dm"
|