diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm
index 65994dda5a..8efb2617bd 100644
--- a/code/__DEFINES/dcs/signals.dm
+++ b/code/__DEFINES/dcs/signals.dm
@@ -32,7 +32,7 @@
#define COMSIG_ELEMENT_DETACH "element_detach"
/// sent to the component itself when unregistered from a parent
-#define COMSIG_COMPONENT_UNREGISTER_PARENT "component_unregister_parent"
+#define COMSIG_COMPONENT_UNREGISTER_PARENT "component_unregister_parent"
/// sent to the component itself when registered to a parent
#define COMSIG_COMPONENT_REGISTER_PARENT "component_register_parent"
@@ -184,6 +184,7 @@
// #define HEARING_SOURCE 8
#define COMSIG_MOVABLE_DISPOSING "movable_disposing" //called when the movable is added to a disposal holder object for disposal movement: (obj/structure/disposalholder/holder, obj/machinery/disposal/source)
#define COMSIG_MOVABLE_TELEPORTED "movable_teleported" //from base of do_teleport(): (channel, turf/origin, turf/destination)
+#define COMSIG_MOVABLE_CHASM_DROP "movable_chasm_drop" //from base of /datum/component/chasm/drop() (/datum/component/chasm)
// /mind signals
#define COMSIG_PRE_MIND_TRANSFER "pre_mind_transfer" //from base of mind/transfer_to() before it's done: (new_character, old_character)
diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm
index 719735392d..0171057286 100644
--- a/code/__HELPERS/_lists.dm
+++ b/code/__HELPERS/_lists.dm
@@ -681,3 +681,11 @@
continue
if(istype(D, path))
return TRUE
+
+/proc/safe_json_encode(list/L, default = "")
+ . = default
+ return json_encode(L)
+
+/proc/safe_json_decode(string, default = list())
+ . = default
+ return json_decode(string)
diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm
index 6dcb5f2534..1d09057617 100644
--- a/code/__HELPERS/roundend.dm
+++ b/code/__HELPERS/roundend.dm
@@ -402,7 +402,7 @@
for (var/i in GLOB.ai_list)
var/mob/living/silicon/ai/aiPlayer = i
if(aiPlayer.mind)
- parts += "[aiPlayer.name] (Played by: [aiPlayer.mind.key])'s laws [aiPlayer.stat != DEAD ? "at the end of the round" : "when it was deactivated"] were:"
+ parts += "[aiPlayer.name][aiPlayer.mind.hide_ckey ? "" : " (Played by: [aiPlayer.mind.key])"]'s laws [aiPlayer.stat != DEAD ? "at the end of the round" : "when it was deactivated"] were:"
parts += aiPlayer.laws.get_law_list(include_zeroth=TRUE)
parts += "Total law changes: [aiPlayer.law_change_counter]"
@@ -413,14 +413,14 @@
for(var/mob/living/silicon/robot/robo in aiPlayer.connected_robots)
borg_num--
if(robo.mind)
- robolist += "[robo.name] (Played by: [robo.mind.key])[robo.stat == DEAD ? " (Deactivated)" : ""][borg_num ?", ":""]
"
+ robolist += "[robo.name][robo.mind.hide_ckey ? "" : " (Played by: [robo.mind.key])"] [robo.stat == DEAD ? " (Deactivated)" : ""][borg_num ?", ":""]
"
parts += "[robolist]"
if(!borg_spacer)
borg_spacer = TRUE
for (var/mob/living/silicon/robot/robo in GLOB.silicon_mobs)
if (!robo.connected_ai && robo.mind)
- parts += "[borg_spacer?"
":""][robo.name] (Played by: [robo.mind.key]) [(robo.stat != DEAD)? "survived as an AI-less borg!" : "was unable to survive the rigors of being a cyborg without an AI."] Its laws were:"
+ parts += "[borg_spacer?"
":""][robo.name][robo.mind.hide_ckey ? "" : " (Played by: [robo.mind.key])"] [(robo.stat != DEAD)? "survived as an AI-less borg!" : "was unable to survive the rigors of being a cyborg without an AI."] Its laws were:"
if(robo) //How the hell do we lose robo between here and the world messages directly above this?
parts += robo.laws.get_law_list(include_zeroth=TRUE)
@@ -529,7 +529,7 @@
var/jobtext = ""
if(ply.assigned_role)
jobtext = " the [ply.assigned_role]"
- var/text = "[ply.key] was [ply.name][jobtext] and"
+ var/text = "[ply.hide_ckey ? "[ply.name][jobtext] " : "[ply.key] was [ply.name][jobtext] and "]"
if(ply.current)
if(ply.current.stat == DEAD)
text += " died"
diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm
index c4d105a3a6..bbbf99c9de 100644
--- a/code/__HELPERS/type2type.dm
+++ b/code/__HELPERS/type2type.dm
@@ -462,16 +462,14 @@
else
. = max(0, min(255, 138.5177312231 * log(temp - 10) - 305.0447927307))
-/proc/fusionpower2text(power) //used when displaying fusion power on analyzers
- switch(power)
- if(0 to 5)
- return "low"
- if(5 to 20)
- return "mid"
- if(20 to 50)
- return "high"
- if(50 to INFINITY)
- return "super"
+/proc/instability2text(instability) //used when displaying fusion power on analyzers
+ switch(instability)
+ if(0 to 2)
+ return "stable, meaning that its heat will always increase."
+ if(2 to 3)
+ return "metastable, meaning that its heat will trend upwards."
+ if (3 to INFINITY)
+ return "unstable, meaning that its heat will trend downwards."
/proc/color2hex(color) //web colors
if(!color)
diff --git a/code/_globalvars/lists/maintenance_loot.dm b/code/_globalvars/lists/maintenance_loot.dm
index 865f405442..14a1924e76 100644
--- a/code/_globalvars/lists/maintenance_loot.dm
+++ b/code/_globalvars/lists/maintenance_loot.dm
@@ -107,13 +107,8 @@ GLOBAL_LIST_INIT(maintenance_loot, list(
/obj/item/toy/eightball = 1,
/obj/item/reagent_containers/pill/floorpill = 1,
/obj/item/reagent_containers/food/snacks/cannedpeaches/maint = 2,
- /obj/item/storage/daki = 3, //VERY IMPORTANT CIT CHANGE - adds bodypillows to maint
- /obj/item/storage/pill_bottle/penis_enlargement = 2,
- /obj/item/storage/pill_bottle/breast_enlargement = 2,
/obj/item/clothing/shoes/wheelys = 1,
/obj/item/clothing/shoes/kindleKicks = 1,
- /obj/item/autosurgeon/penis = 1,
- /obj/item/autosurgeon/testicles = 1,
/obj/item/storage/box/marshmallow = 2,
/obj/item/clothing/gloves/tackler/offbrand = 1,
/obj/item/stack/sticky_tape = 1,
diff --git a/code/datums/accents.dm b/code/datums/accents.dm
index edfdfb9fee..9baba90c32 100644
--- a/code/datums/accents.dm
+++ b/code/datums/accents.dm
@@ -94,6 +94,7 @@
/datum/accent/robot/modify_speech(list/speech_args)
speech_args[SPEECH_SPANS] = SPAN_ROBOT
+ return speech_args
/datum/accent/dullahan/modify_speech(list/speech_args, datum/source, mob/living/carbon/owner)
if(owner)
diff --git a/code/datums/components/chasm.dm b/code/datums/components/chasm.dm
index 0bb6c4a0af..f5a34bfca2 100644
--- a/code/datums/components/chasm.dm
+++ b/code/datums/components/chasm.dm
@@ -76,19 +76,11 @@
return FALSE
if(M.is_flying())
return FALSE
- if(ishuman(AM))
- var/mob/living/carbon/human/H = AM
- if(istype(H.belt, /obj/item/wormhole_jaunter))
- var/obj/item/wormhole_jaunter/J = H.belt
- //To freak out any bystanders
- H.visible_message("[H] falls into [parent]!")
- J.chasm_react(H)
- return FALSE
return TRUE
/datum/component/chasm/proc/drop(atom/movable/AM)
//Make sure the item is still there after our sleep
- if(!AM || QDELETED(AM))
+ if(!AM || QDELETED(AM) || SEND_SIGNAL(AM, COMSIG_MOVABLE_CHASM_DROP, src))
return
falling_atoms[AM] = (falling_atoms[AM] || 0) + 1
var/turf/T = target_turf
diff --git a/code/datums/diseases/advance/symptoms/fire.dm b/code/datums/diseases/advance/symptoms/fire.dm
index ea1897b67d..891d8a286a 100644
--- a/code/datums/diseases/advance/symptoms/fire.dm
+++ b/code/datums/diseases/advance/symptoms/fire.dm
@@ -113,9 +113,9 @@ Bonus
symptom_delay_max = 90
var/chems = FALSE
var/explosion_power = 1
- threshold_desc = "Resistance 9: Doubles the intensity of the effect, but reduces its frequency.
\
- Stage Speed 8: Increases explosion radius when the host is wet.
\
- Transmission 8: Additionally synthesizes chlorine trifluoride and napalm inside the host."
+ threshold_desc = list("Resistance 9" = "Doubles the intensity of the effect, but reduces its frequency.",
+ "Stage Speed 8" = "Increases explosion radius when the host is wet.",
+ "Transmission 8" = "Additionally synthesizes chlorine trifluoride and napalm inside the host.")
/datum/symptom/alkali/Start(datum/disease/advance/A)
if(!..())
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index cb99fdc5a3..0731cf8bf4 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -41,6 +41,8 @@
var/special_role
var/list/restricted_roles = list()
+ var/hide_ckey = FALSE //hide ckey from round-end report
+
var/list/spell_list = list() // Wizard mode & "Give Spell" badmin button.
var/linglink
@@ -69,6 +71,7 @@
///What character we spawned in as- either at roundstart or latejoin, so we know for persistent scars if we ended as the same person or not
var/mob/original_character
+
/datum/mind/New(var/key)
skill_holder = new(src)
src.key = key
@@ -137,6 +140,8 @@
if(L.client?.prefs && L.client.prefs.auto_ooc && L.client.prefs.chat_toggles & CHAT_OOC)
DISABLE_BITFIELD(L.client.prefs.chat_toggles,CHAT_OOC)
+ hide_ckey = current.client?.prefs?.hide_ckey
+
SEND_SIGNAL(src, COMSIG_MIND_TRANSFER, new_character, old_character)
SEND_SIGNAL(new_character, COMSIG_MOB_ON_NEW_MIND)
@@ -780,6 +785,7 @@
if(!mind.name)
mind.name = real_name
mind.current = src
+ mind.hide_ckey = client?.prefs?.hide_ckey
/mob/living/carbon/mind_initialize()
..()
diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm
index 41270bb09e..871fe838d7 100644
--- a/code/game/objects/effects/anomalies.dm
+++ b/code/game/objects/effects/anomalies.dm
@@ -285,7 +285,7 @@
S.rabid = TRUE
S.amount_grown = SLIME_EVOLUTION_THRESHOLD
S.Evolve()
- offer_control(S)
+ offer_control(S,POLL_IGNORE_SENTIENCE_POTION)
/////////////////////
diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm
index 7f8b720509..2a9944f770 100644
--- a/code/game/objects/items/crayons.dm
+++ b/code/game/objects/items/crayons.dm
@@ -735,7 +735,11 @@
if(isobj(target))
if(actually_paints)
var/list/hsl = rgb2hsl(hex2num(copytext(paint_color,2,4)),hex2num(copytext(paint_color,4,6)),hex2num(copytext(paint_color,6,8)))
- if(hsl[3] < 0.25 && !istype(target, /obj/structure/window) && !istype(target, /obj/effect/decal/cleanable/crayon)) //Colors too dark are rejected
+ var/static/whitelisted = typecacheof(list(/obj/structure/window,
+ /obj/effect/decal/cleanable/crayon,
+ /obj/machinery/door/window)
+ )
+ if(hsl[3] < 0.25 && !whitelisted[target]) //Colors too dark are rejected
to_chat(usr, "A color that dark on an object like this? Surely not...")
return FALSE
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index fae2833c8a..8fdeaa0f9f 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -729,10 +729,10 @@ GENETICS SCANNER
to_chat(user, "[target] is empty!")
if(cached_scan_results && cached_scan_results["fusion"]) //notify the user if a fusion reaction was detected
- var/fusion_power = round(cached_scan_results["fusion"], 0.01)
- var/tier = fusionpower2text(fusion_power)
+ var/instability = round(cached_scan_results["fusion"], 0.01)
+ var/tier = instability2text(instability)
to_chat(user, "Large amounts of free neutrons detected in the air indicate that a fusion reaction took place.")
- to_chat(user, "Power of the last fusion reaction: [fusion_power]\n This power indicates it was a [tier]-tier fusion reaction.")
+ to_chat(user, "Instability of the last fusion reaction: [instability]\n This indicates it was [tier].")
return
/obj/item/analyzer/proc/scan_turf(mob/user, turf/location)
@@ -783,10 +783,10 @@ GENETICS SCANNER
to_chat(user, "Temperature: [round(environment.return_temperature()-T0C, 0.01)] °C ([round(environment.return_temperature(), 0.01)] K)")
if(cached_scan_results && cached_scan_results["fusion"]) //notify the user if a fusion reaction was detected
- var/fusion_power = round(cached_scan_results["fusion"], 0.01)
- var/tier = fusionpower2text(fusion_power)
+ var/instability = round(cached_scan_results["fusion"], 0.01)
+ var/tier = instability2text(instability)
to_chat(user, "Large amounts of free neutrons detected in the air indicate that a fusion reaction took place.")
- to_chat(user, "Power of the last fusion reaction: [fusion_power]\n This power indicates it was a [tier]-tier fusion reaction.")
+ to_chat(user, "Instability of the last fusion reaction: [instability]\n This indicates it was [tier].")
/obj/item/analyzer/ranged
desc = "A hand-held scanner which uses advanced spectroscopy and infrared readings to analyze gases as a distance. Alt-Click to use the built in barometer function."
@@ -992,4 +992,4 @@ GENETICS SCANNER
#undef SCANMODE_CHEMICAL
#undef SCANMODE_WOUND
#undef SCANNER_CONDENSED
-#undef SCANNER_VERBOSE
\ No newline at end of file
+#undef SCANNER_VERBOSE
diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm
index 01d2924a90..52ff0f740e 100644
--- a/code/game/objects/items/melee/misc.dm
+++ b/code/game/objects/items/melee/misc.dm
@@ -234,6 +234,9 @@
/obj/item/melee/rapier/attack(mob/living/target, mob/living/user)
. = ..()
if(iscarbon(target))
+ if(HAS_TRAIT(user, TRAIT_PACIFISM))
+ visible_message("[user] gently taps [target] with [src].",null,null,COMBAT_MESSAGE_RANGE)
+ log_combat(user, target, "slept", src)
var/mob/living/carbon/H = target
H.Dizzy(10)
H.adjustStaminaLoss(30)
diff --git a/code/game/world.dm b/code/game/world.dm
index a342200b3d..2d174c86e5 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -20,8 +20,6 @@ GLOBAL_LIST(topic_status_cache)
log_world("World loaded at [TIME_STAMP("hh:mm:ss", FALSE)]!")
- SetupExternalRSC()
-
GLOB.config_error_log = GLOB.world_manifest_log = GLOB.world_pda_log = GLOB.world_job_debug_log = GLOB.sql_error_log = GLOB.world_href_log = GLOB.world_runtime_log = GLOB.world_attack_log = GLOB.world_game_log = "data/logs/config_error.[GUID()].log" //temporary file used to record errors with loading config, moved to log directory once logging is set bl
make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once)
@@ -87,17 +85,6 @@ GLOBAL_LIST(topic_status_cache)
#endif
SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, /proc/addtimer, cb, 10 SECONDS))
-/world/proc/SetupExternalRSC()
-#if (PRELOAD_RSC == 0)
- GLOB.external_rsc_urls = world.file2list("[global.config.directory]/external_rsc_urls.txt","\n")
- var/i=1
- while(i<=GLOB.external_rsc_urls.len)
- if(GLOB.external_rsc_urls[i])
- i++
- else
- GLOB.external_rsc_urls.Cut(i,i+1)
-#endif
-
/world/proc/SetupLogs()
var/override_dir = params[OVERRIDE_LOG_DIRECTORY_PARAMETER]
if(!override_dir)
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index b077a0c8db..51e027522c 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -163,6 +163,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
)
var/custom_speech_verb = "default" //if your say_mod is to be something other than your races
var/custom_tongue = "default" //if your tongue is to be something other than your races
+ var/chosen_limb_id //body sprite selected to load for the users limbs, null means default, is sanitized when loaded
/// Security record note section
var/security_records
@@ -246,7 +247,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
/// Which of the 5 persistent scar slots we randomly roll to load for this round, if enabled. Actually rolled in [/datum/preferences/proc/load_character(slot)]
var/scars_index = 1
- var/chosen_limb_id //body sprite selected to load for the users limbs, null means default, is sanitized when loaded
+ var/hide_ckey = FALSE //pref for hiding if your ckey shows round-end or not
/datum/preferences/New(client/C)
parent = C
@@ -372,6 +373,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "[medical_records]"
else
dat += "[TextPreview(medical_records)]...
"
+ dat += "
Hide ckey: [hide_ckey ? "Enabled" : "Disabled"]
"
dat += ""
//Character Appearance
@@ -1448,6 +1450,11 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(!isnull(msg))
features["ooc_notes"] = msg
+ if("hide_ckey")
+ hide_ckey = !hide_ckey
+ if(user)
+ user.mind?.hide_ckey = hide_ckey
+
if("hair")
var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference","#"+hair_color) as color|null
if(new_hair)
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index 55a594cf21..8591d77e50 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -515,7 +515,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["scars4"] >> scars_list["4"]
S["scars5"] >> scars_list["5"]
S["chosen_limb_id"] >> chosen_limb_id
-
+ S["hide_ckey"] >> hide_ckey //saved per-character
//Custom names
for(var/custom_name_id in GLOB.preferences_custom_names)
@@ -859,6 +859,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["joblessrole"] , joblessrole)
//Write prefs
WRITE_FILE(S["job_preferences"] , job_preferences)
+ WRITE_FILE(S["hide_ckey"] , hide_ckey)
//Quirks
WRITE_FILE(S["all_quirks"] , all_quirks)
@@ -874,6 +875,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["scars4"] , scars_list["4"])
WRITE_FILE(S["scars5"] , scars_list["5"])
+
//gear loadout
if(chosen_gear.len)
var/text_to_save = chosen_gear.Join("|")
diff --git a/code/modules/mining/equipment/wormhole_jaunter.dm b/code/modules/mining/equipment/wormhole_jaunter.dm
index c17b62ba6c..e9f8079400 100644
--- a/code/modules/mining/equipment/wormhole_jaunter.dm
+++ b/code/modules/mining/equipment/wormhole_jaunter.dm
@@ -18,6 +18,15 @@
SSblackbox.record_feedback("tally", "jaunter", 1, "User") // user activated
activate(user, TRUE)
+/obj/item/wormhole_jaunter/equipped(mob/user, slot)
+ . = ..()
+ if(slot == SLOT_BELT)
+ RegisterSignal(user, COMSIG_MOVABLE_CHASM_DROP, .proc/chasm_react)
+
+/obj/item/wormhole_jaunter/dropped(mob/user)
+ . = ..()
+ UnregisterSignal(user, COMSIG_MOVABLE_CHASM_DROP)
+
/obj/item/wormhole_jaunter/proc/turf_check(mob/user)
var/turf/device_turf = get_turf(user)
if(!device_turf || is_centcom_level(device_turf.z) || is_reserved_level(device_turf.z))
@@ -71,13 +80,14 @@
SSblackbox.record_feedback("tally", "jaunter", 1, "EMP") // EMP accidental activation
activate(M)
-/obj/item/wormhole_jaunter/proc/chasm_react(mob/user)
- if(user.get_item_by_slot(SLOT_BELT) == src)
- to_chat(user, "Your [name] activates, saving you from the chasm!")
- SSblackbox.record_feedback("tally", "jaunter", 1, "Chasm") // chasm automatic activation
- activate(user, FALSE, TRUE)
- else
- to_chat(user, "[src] is not attached to your belt, preventing it from saving you from the chasm. RIP.")
+/obj/item/wormhole_jaunter/proc/chasm_react(mob/source, datum/component/chasm/C)
+ to_chat(source, "Your [name] activates, saving you from the chasm!")
+ SSblackbox.record_feedback("tally", "jaunter", 1, "Chasm") // chasm automatic activation
+ activate(source, FALSE, TRUE)
+ if(C)
+ var/atom/A = C.parent
+ A.visible_message("[source] falls into [A]!")
+ return TRUE
//jaunter tunnel
/obj/effect/portal/jaunt_tunnel
diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm
index 1bdd988694..b74dd6fa20 100644
--- a/code/modules/mob/living/simple_animal/slime/slime.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -106,6 +106,7 @@
set_colour(new_colour)
. = ..()
AddComponent(/datum/component/footstep, FOOTSTEP_MOB_SLIME, 7.5)
+ set_nutrition(rand(650, 800))
/mob/living/simple_animal/slime/Destroy()
for (var/A in actions)
diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm
index 31bfb5621f..0d4afd0915 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -50,6 +50,8 @@
var/datum/callback/CB = foo
CB.Invoke()
+ mind?.hide_ckey = client?.prefs?.hide_ckey
+
log_message("Client [key_name(src)] has taken ownership of mob [src]([src.type])", LOG_OWNERSHIP)
SEND_SIGNAL(src, COMSIG_MOB_CLIENT_LOGIN, client)
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 52b755d926..aa6635f73d 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -431,7 +431,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
/mob/living/getImplant(type)
return locate(type) in implants
-/proc/offer_control(mob/M)
+/proc/offer_control(mob/M,ignore_category=null)
to_chat(M, "Control of your mob has been offered to dead players.")
if(usr)
log_admin("[key_name(usr)] has offered control of ([key_name(M)]) to ghosts.")
@@ -445,7 +445,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
var/datum/antagonist/A = M.mind.has_antag_datum(/datum/antagonist/)
if(A)
poll_message = "[poll_message] Status:[A.name]."
- var/list/mob/candidates = pollCandidatesForMob(poll_message, ROLE_PAI, null, FALSE, 100, M)
+ var/list/mob/candidates = pollCandidatesForMob(poll_message, ROLE_PAI, null, FALSE, 100, M, ignore_category)
if(LAZYLEN(candidates))
var/mob/C = pick(candidates)
diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm
index 38029b5d4c..25a9cf0043 100644
--- a/code/modules/paperwork/photocopier.dm
+++ b/code/modules/paperwork/photocopier.dm
@@ -187,12 +187,13 @@
*/
/obj/machinery/photocopier/proc/do_copy_loop(datum/callback/copy_cb, mob/user)
busy = TRUE
- var/i
- for(i in 1 to num_copies)
+ var/num_loops
+ for(var/i in 1 to num_copies)
//if(attempt_charge(src, user) & COMPONENT_OBJ_CANCEL_CHARGE)
// break
addtimer(copy_cb, i SECONDS)
- addtimer(CALLBACK(src, .proc/reset_busy), i SECONDS)
+ num_loops++
+ addtimer(CALLBACK(src, .proc/reset_busy), num_loops SECONDS)
/**
* Sets busy to `FALSE`. Created as a proc so it can be used in callbacks.
diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm
index c739d426c2..e758a43589 100644
--- a/code/modules/unit_tests/_unit_tests.dm
+++ b/code/modules/unit_tests/_unit_tests.dm
@@ -3,6 +3,7 @@
#ifdef UNIT_TESTS
#include "anchored_mobs.dm"
+#include "character_saving.dm"
#include "component_tests.dm"
#include "reagent_id_typos.dm"
#include "reagent_recipe_collisions.dm"
diff --git a/code/modules/unit_tests/character_saving.dm b/code/modules/unit_tests/character_saving.dm
new file mode 100644
index 0000000000..6c83d4142a
--- /dev/null
+++ b/code/modules/unit_tests/character_saving.dm
@@ -0,0 +1,14 @@
+/datum/unit_test/character_saving/Run()
+ try
+ var/datum/preferences/P = new
+ P.load_path("test")
+ P.features["flavor_text"] = "Foo"
+ P.features["ooc_notes"] = "Bar"
+ P.save_character()
+ P.load_character()
+ if(P.features["flavor_text"] != "Foo")
+ Fail("Flavor text is failing to save.")
+ if(P.features["ooc_notes"] != "Bar")
+ Fail("OOC text is failing to save.")
+ catch(var/exception/e)
+ Fail("Failed to save and load character due to exception [e.name]")
diff --git a/code/modules/vending/kinkmate.dm b/code/modules/vending/kinkmate.dm
index a78a4e6ef4..e522583772 100644
--- a/code/modules/vending/kinkmate.dm
+++ b/code/modules/vending/kinkmate.dm
@@ -26,7 +26,12 @@
/obj/item/clothing/under/shorts/polychromic/pantsu = 3,
/obj/item/clothing/under/misc/poly_bottomless = 3,
/obj/item/clothing/under/misc/poly_tanktop = 3,
- /obj/item/clothing/under/misc/poly_tanktop/female = 3
+ /obj/item/clothing/under/misc/poly_tanktop/female = 3,
+ /obj/item/autosurgeon/penis = 3,
+ /obj/item/autosurgeon/testicles = 3,
+ /obj/item/storage/pill_bottle/penis_enlargement = 5,
+ /obj/item/storage/pill_bottle/breast_enlargement = 5,
+ /obj/item/storage/daki = 4
)
contraband = list(
/obj/item/clothing/neck/petcollar/locked = 2,
diff --git a/html/changelog.html b/html/changelog.html
index 3e5ac03804..864b5d19b0 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -50,6 +50,47 @@
-->