Refactors Temporal Scarring, changes how it works, removes longtimer quirk (#52688)

* changes temporal scarring

* hhh why is there no ckey

* note

* oops

* fixed
This commit is contained in:
Ryll Ryll
2020-08-10 15:29:27 -04:00
committed by GitHub
parent 04c7734c31
commit b7ae6fc64d
10 changed files with 156 additions and 119 deletions

View File

@@ -1,20 +1,27 @@
// ~wound damage/rolling defines
/// the cornerstone of the wound threshold system, your base wound roll for any attack is rand(1, damage^this), after armor reduces said damage. See [/obj/item/bodypart/proc/check_wounding]
#define WOUND_DAMAGE_EXPONENT 1.4
/// an attack must do this much damage after armor in order to roll for being a wound (incremental pressure damage need not apply)
/// any damage dealt over this is ignored for damage rolls unless the target has the frail quirk (35^1.4=145, for reference)
#define WOUND_MAX_CONSIDERED_DAMAGE 35
/// an attack must do this much damage after armor in order to roll for being a wound (so pressure damage/being on fire doesn't proc it)
#define WOUND_MINIMUM_DAMAGE 5
/// an attack must do this much damage after armor in order to be eliigible to dismember a suitably mushed bodypart
#define DISMEMBER_MINIMUM_DAMAGE 10
/// any damage dealt over this is ignored for damage rolls unless the target has the frail quirk (35^1.4=145)
#define WOUND_MAX_CONSIDERED_DAMAGE 35
/// set wound_bonus on an item or attack to this to disable checking wounding for the attack
#define CANT_WOUND -100
#define WOUND_SEVERITY_TRIVIAL 0 // for jokey/meme wounds like stubbed toe, no standard messages/sounds or second winds
// ~wound severities
/// for jokey/meme wounds like stubbed toe, no standard messages/sounds or second winds
#define WOUND_SEVERITY_TRIVIAL 0
#define WOUND_SEVERITY_MODERATE 1
#define WOUND_SEVERITY_SEVERE 2
#define WOUND_SEVERITY_CRITICAL 3
#define WOUND_SEVERITY_LOSS 4 // theoretical total limb loss, like dismemberment for cuts
/// outright dismemberment of limb
#define WOUND_SEVERITY_LOSS 4
// ~wound categories
/// any brute weapon/attack that doesn't have sharpness. rolls for blunt bone wounds
#define WOUND_BLUNT 1
/// any brute weapon/attack with sharpness = SHARP_EDGED. rolls for slash wounds
@@ -24,18 +31,18 @@
/// any concentrated burn attack (lasers really). rolls for burning wounds
#define WOUND_BURN 4
// How much determination reagent to add each time someone gains a new wound in [/datum/wound/proc/second_wind()]
// ~determination second wind defines
// How much determination reagent to add each time someone gains a new wound in [/datum/wound/proc/second_wind]
#define WOUND_DETERMINATION_MODERATE 1
#define WOUND_DETERMINATION_SEVERE 2.5
#define WOUND_DETERMINATION_CRITICAL 5
#define WOUND_DETERMINATION_LOSS 7.5
/// the max amount of determination you can have
#define WOUND_DETERMINATION_MAX 10
/// set wound_bonus on an item or attack to this to disable checking wounding for the attack
#define CANT_WOUND -100
// ~wound global lists
// list in order of highest severity to lowest
GLOBAL_LIST_INIT(global_wound_types, list(WOUND_BLUNT = list(/datum/wound/blunt/critical, /datum/wound/blunt/severe, /datum/wound/blunt/moderate),
WOUND_SLASH = list(/datum/wound/slash/critical, /datum/wound/slash/severe, /datum/wound/slash/moderate),
@@ -43,11 +50,14 @@ GLOBAL_LIST_INIT(global_wound_types, list(WOUND_BLUNT = list(/datum/wound/blunt/
WOUND_BURN = list(/datum/wound/burn/critical, /datum/wound/burn/severe, /datum/wound/burn/moderate)
))
// every single type of wound that can be rolled naturally, in case you need to pull a random one
GLOBAL_LIST_INIT(global_all_wound_types, list(/datum/wound/blunt/critical, /datum/wound/blunt/severe, /datum/wound/blunt/moderate,
/datum/wound/slash/critical, /datum/wound/slash/severe, /datum/wound/slash/moderate,
/datum/wound/pierce/critical, /datum/wound/pierce/severe, /datum/wound/pierce/moderate,
/datum/wound/burn/critical, /datum/wound/burn/severe, /datum/wound/burn/moderate))
// ~burn wound infection defines
// Thresholds for infection for burn wounds, once infestation hits each threshold, things get steadily worse
/// below this has no ill effects from infection
#define WOUND_INFECTION_MODERATE 4
@@ -60,6 +70,7 @@ GLOBAL_LIST_INIT(global_all_wound_types, list(/datum/wound/blunt/critical, /datu
// above WOUND_INFECTION_SEPTIC, your limb is completely putrid and you start rolling to lose the entire limb by way of paralyzation. After 3 failed rolls (~4-5% each probably), the limb is paralyzed
// ~random wound balance defines
/// how quickly sanitization removes infestation and decays per tick
#define WOUND_BURN_SANITIZATION_RATE 0.15
/// how much blood you can lose per tick per slash max. 8 is a LOT of blood for one cut so don't worry about hitting it easily
@@ -69,25 +80,9 @@ GLOBAL_LIST_INIT(global_all_wound_types, list(/datum/wound/blunt/critical, /datu
/// if we suffer a bone wound to the head that creates brain traumas, the timer for the trauma cycle is +/- by this percent (0-100)
#define WOUND_BONE_HEAD_TIME_VARIANCE 20
// The following are for persistent scar save formats
/// The version number of the scar we're saving
#define SCAR_SAVE_VERS 1
/// The body_zone we're applying to on granting
#define SCAR_SAVE_ZONE 2
/// The description we're loading
#define SCAR_SAVE_DESC 3
/// The precise location we're loading
#define SCAR_SAVE_PRECISE_LOCATION 4
/// The severity the scar had
#define SCAR_SAVE_SEVERITY 5
///how many fields there are above (NOT INCLUDING THIS OBVIOUSLY)
#define SCAR_SAVE_LENGTH 5
// increment this number when you update the persistent scarring format in a way that invalidates previous saved scars (new fields, reordering, etc)
/// saved scars with a version lower than this will be discarded
#define SCAR_CURRENT_VERSION 1
// ~mangling defines
// With the wounds pt. 2 update, general dismemberment now requires 2 things for a limb to be dismemberable (bone only creatures just need the second):
// 1. Skin is mangled: A critical slash or pierce wound on that limb
// 2. Bone is mangled: At least a severe bone wound on that limb
@@ -97,6 +92,8 @@ GLOBAL_LIST_INIT(global_all_wound_types, list(/datum/wound/blunt/critical, /datu
#define BODYPART_MANGLED_FLESH 2
#define BODYPART_MANGLED_BOTH 3
// ~biology defines
// What kind of biology we have, and what wounds we can suffer, mostly relies on the HAS_FLESH and HAS_BONE species traits on human species
/// golems and androids, cannot suffer any wounds
#define BIO_INORGANIC 0
@@ -104,9 +101,11 @@ GLOBAL_LIST_INIT(global_all_wound_types, list(/datum/wound/blunt/critical, /datu
#define BIO_JUST_BONE 1
/// nothing right now, maybe slimepeople in the future, can only suffer slashing, piercing, and burn wounds
#define BIO_JUST_FLESH 2
/// standard humanoids, can suffer all wounds, needs mangled bone and flesh to dismember
/// standard humanoids, can suffer all wounds, needs mangled bone and flesh to dismember. conveniently, what you get when you combine BIO_JUST_BONE and BIO_JUST_FLESH
#define BIO_FLESH_BONE 3
// ~wound flag defines
/// If this wound requires having the HAS_FLESH flag for humanoids
#define FLESH_WOUND (1<<0)
/// If this wound requires having the HAS_BONE flag for humanaoids
@@ -118,3 +117,25 @@ GLOBAL_LIST_INIT(global_all_wound_types, list(/datum/wound/blunt/critical, /datu
/// If this wound marks the limb as being allowed to have gauze applied
#define ACCEPTS_GAUZE (1<<4)
// ~scar persistence defines
// The following are the order placements for persistent scar save formats
/// The version number of the scar we're saving, any scars being loaded below this number will be discarded, see SCAR_CURRENT_VERSION below
#define SCAR_SAVE_VERS 1
/// The body_zone we're applying to on granting
#define SCAR_SAVE_ZONE 2
/// The description we're loading
#define SCAR_SAVE_DESC 3
/// The precise location we're loading
#define SCAR_SAVE_PRECISE_LOCATION 4
/// The severity the scar had
#define SCAR_SAVE_SEVERITY 5
/// Whether this is a BIO_JUST_BONE scar, a BIO_JUST_FLESH scar, or a BIO_FLESH_BONE scar (so you can't load fleshy human scars on a plasmaman character)
#define SCAR_SAVE_BIOLOGY 6
///how many fields we save for each scar (so the number of above fields)
#define SCAR_SAVE_LENGTH 6
/// saved scars with a version lower than this will be discarded, increment when you update the persistent scarring format in a way that invalidates previous saved scars (new fields, reordering, etc)
#define SCAR_CURRENT_VERSION 2
/// how many scar slots we have to cycle through for persistent scarring, if enabled in character prefs
#define PERSISTENT_SCAR_SLOTS 3

View File

@@ -402,15 +402,6 @@ SUBSYSTEM_DEF(persistence)
var/mob/living/carbon/human/original_human = ending_human.mind.original_character
if(!original_human || original_human.stat == DEAD || !original_human.all_scars || !(original_human == ending_human))
if(ending_human.client) // i was told if i don't check this every step of the way byond might decide a client ceases to exist mid proc so here we go
ending_human.client.prefs.scars_list["[ending_human.client.prefs.scars_index]"] = ""
original_human.save_persistent_scars(TRUE)
else
for(var/k in ending_human.all_wounds)
var/datum/wound/iter_wound = k
iter_wound.remove_wound() // so we can get the scars for open wounds
if(!ending_human.client)
return
ending_human.client.prefs.scars_list["[ending_human.client.prefs.scars_index]"] = ending_human.format_scars()
if(!ending_human.client)
return
ending_human.client.prefs.save_character()
original_human.save_persistent_scars()

View File

@@ -325,15 +325,20 @@ SUBSYSTEM_DEF(ticker)
else
stack_trace("[S] [S.type] found in start landmarks list, which isn't a start landmark!")
// handle persistence stuff that requires ckeys, in this case hardcore mode and temporal scarring
for(var/i in GLOB.player_list)
if(!ishuman(i))
continue
var/mob/living/carbon/human/hardcore_player = i
if(!hardcore_player.hardcore_survival_score)
var/mob/living/carbon/human/iter_human = i
iter_human.increment_scar_slot()
iter_human.load_persistent_scars()
if(!iter_human.hardcore_survival_score)
continue
if(hardcore_player.mind?.special_role)
hardcore_player.hardcore_survival_score *= 2 //Double for antags
to_chat(hardcore_player, "<span class='notice'>You will gain [round(hardcore_player.hardcore_survival_score)] hardcore random points if you survive this round!</span>")
if(iter_human.mind?.special_role)
iter_human.hardcore_survival_score *= 2 //Double for antags
to_chat(iter_human, "<span class='notice'>You will gain [round(iter_human.hardcore_survival_score)] hardcore random points if you survive this round!</span>")
//These callbacks will fire after roundstart key transfer
/datum/controller/subsystem/ticker/proc/OnRoundstart(datum/callback/cb)

View File

@@ -73,6 +73,8 @@
var/list/known_skills = list()
///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
/// What scar slot we have loaded, so we don't have to constantly check the savefile
var/current_scar_slot
///Skill multiplier, adjusts how much xp you get/loose from adjust_xp. Dont override it directly, add your reason to experience_multiplier_reasons and use that as a key to put your value in there.
var/experience_multiplier = 1
///Skill multiplier list, just slap your multiplier change onto this with the type it is coming from as key.

View File

@@ -240,19 +240,3 @@
///Applies a bad moodlet for having an uncovered head
/datum/quirk/bald/proc/unequip_hat(mob/user, obj/item/clothing, force, newloc, no_move, invdrop, silent)
SEND_SIGNAL(quirk_holder, COMSIG_ADD_MOOD_EVENT, "bad_hair_day", /datum/mood_event/bald)
/datum/quirk/longtimer
name = "Longtimer"
desc = "You've been around for a long time and seen more than your fair share of action, suffering some pretty nasty scars along the way. For whatever reason, you've declined to get them removed or augmented."
value = 0
gain_text = "<span class='notice'>Your body has seen better days.</span>"
lose_text = "<span class='notice'>Your sins may wash away, but those scars are here to stay...</span>"
medical_record_text = "Patient has withstood significant physical trauma and declined plastic surgery procedures to heal scarring."
/// the minimum amount of scars we can generate
var/min_scars = 3
/// the maximum amount of scars we can generate
var/max_scars = 7
/datum/quirk/longtimer/on_spawn()
var/mob/living/carbon/C = quirk_holder
C.generate_fake_scars(rand(min_scars, max_scars))

View File

@@ -9,19 +9,21 @@
/datum/scar
var/obj/item/bodypart/limb
var/mob/living/carbon/victim
/// The severity of the scar, derived from the worst severity a wound was at before it was healed (see: slashes), determines how visible/bold the scar description is
var/severity
/// The description of the scar for examining
var/description
/// A string detailing the specific part of the bodypart the scar is on, for fluff purposes. See [/datum/scar/proc/generate]
var/precise_location
/// Scars from the longtimer quirk are "fake" and won't be saved with persistent scarring, since it makes you spawn with a lot by default
/// In case we ever want to make scars that won't be saved for persistent scarring (formerly used by the now-removed longtimer quirk)
var/fake=FALSE
/// How many tiles away someone can see this scar, goes up with severity. Clothes covering this limb will decrease visibility by 1 each, except for the head/face which is a binary "is mask obscuring face" check
var/visibility = 2
/// Whether this scar can actually be covered up by clothing
var/coverable = TRUE
/// What zones this scar can be applied to
var/list/applicable_zones = list(BODY_ZONE_CHEST, BODY_ZONE_HEAD, BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_ARM, BODY_ZONE_R_LEG)
/// Obviously, scars that describe damaged flesh wouldn't apply to a skeleton (in some cases like bone wounds, there can be different descriptions for skeletons and fleshy humanoids)
var/biology = BIO_FLESH_BONE
/datum/scar/Destroy(force, ...)
if(limb)
@@ -41,9 +43,6 @@
* * add_to_scars- Should always be TRUE unless you're just storing a scar for later usage, like how cuts want to store a scar for the highest severity of cut, rather than the severity when the wound is fully healed (probably demoted to moderate)
*/
/datum/scar/proc/generate(obj/item/bodypart/BP, datum/wound/W, add_to_scars=TRUE)
if(!(BP.body_zone in applicable_zones))
qdel(src)
return
limb = BP
severity = W.severity
if(limb.owner)
@@ -53,9 +52,11 @@
if(victim)
LAZYADD(victim.all_scars, src)
if(victim && victim.get_biological_state() == BIO_JUST_BONE)
biology = victim?.get_biological_state() || BIO_FLESH_BONE
if(biology == BIO_JUST_BONE)
description = pick(strings(BONE_SCAR_FILE, W.scar_keyword)) || "general disfigurement"
else
else // no specific support for flesh w/o bone scars since it's not really useful
description = pick(strings(FLESH_SCAR_FILE, W.scar_keyword)) || "general disfigurement"
precise_location = pick(strings(SCAR_LOC_FILE, limb.body_zone))
@@ -78,17 +79,23 @@
LAZYADD(victim.all_scars, src)
/// Used to "load" a persistent scar
/datum/scar/proc/load(obj/item/bodypart/BP, version, description, specific_location, severity=WOUND_SEVERITY_SEVERE)
if(!(BP.body_zone in applicable_zones) || !BP.is_organic_limb())
/datum/scar/proc/load(obj/item/bodypart/BP, version, description, specific_location, severity=WOUND_SEVERITY_SEVERE, biology=BIO_FLESH_BONE)
if(!BP.is_organic_limb())
qdel(src)
return
limb = BP
src.severity = severity
LAZYADD(limb.scars, src)
if(BP.owner)
victim = BP.owner
if(limb.owner)
victim = limb.owner
if(victim.get_biological_state() != biology)
qdel(src)
return
LAZYADD(victim.all_scars, src)
src.severity = severity
src.biology = biology
LAZYADD(limb.scars, src)
src.description = description
precise_location = specific_location
switch(severity)
@@ -143,10 +150,9 @@
/// Used to format a scar to safe in preferences for persistent scars
/datum/scar/proc/format()
if(!fake)
return "[SCAR_CURRENT_VERSION]|[limb.body_zone]|[description]|[precise_location]|[severity]"
return fake ? null : "[SCAR_CURRENT_VERSION]|[limb.body_zone]|[description]|[precise_location]|[severity]|[biology]"
/// Used to format a scar to safe in preferences for persistent scars
/datum/scar/proc/format_amputated(body_zone)
description = pick(list("is several skintone shades paler than the rest of the body", "is a gruesome patchwork of artificial flesh", "has a large series of attachment scars at the articulation points"))
return "[SCAR_CURRENT_VERSION]|[body_zone]|[description]|amputated|[WOUND_SEVERITY_LOSS]"
return "[SCAR_CURRENT_VERSION]|[body_zone]|[description]|amputated|[WOUND_SEVERITY_LOSS]|[BIO_FLESH_BONE]"

View File

@@ -133,13 +133,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/hearted_until
/// Agendered spessmen can choose whether to have a male or female bodytype
var/body_type
/// If we have persistent scars enabled
var/persistent_scars = TRUE
/// We have 5 slots for persistent scars, if enabled we pick a random one to load (empty by default) and scars at the end of the shift if we survived as our original person
var/list/scars_list = list("1" = "", "2" = "", "3" = "", "4" = "", "5" = "")
/// 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
/datum/preferences/New(client/C)
parent = C
@@ -1721,12 +1716,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
persistent_scars = !persistent_scars
if("clear_scars")
to_chat(user, "<span class='notice'>All scar slots cleared. Please save character to confirm.</span>")
scars_list["1"] = ""
scars_list["2"] = ""
scars_list["3"] = ""
scars_list["4"] = ""
scars_list["5"] = ""
var/path = "data/player_saves/[user.ckey[1]]/[user.ckey]/scars.sav"
fdel(path)
to_chat(user, "<span class='notice'>All scar slots cleared.</span>")
if("hear_midis")
toggles ^= SOUND_MIDI

View File

@@ -291,7 +291,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
if(newtype)
pref_species = new newtype
scars_index = rand(1,5)
//Character
READ_FILE(S["real_name"], real_name)
@@ -326,11 +325,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
READ_FILE(S["feature_moth_wings"], features["moth_wings"])
READ_FILE(S["feature_moth_markings"], features["moth_markings"])
READ_FILE(S["persistent_scars"] , persistent_scars)
READ_FILE(S["scars1"], scars_list["1"])
READ_FILE(S["scars2"], scars_list["2"])
READ_FILE(S["scars3"], scars_list["3"])
READ_FILE(S["scars4"], scars_list["4"])
READ_FILE(S["scars5"], scars_list["5"])
if(!CONFIG_GET(flag/join_with_mutant_humans))
features["tail_human"] = "none"
features["ears"] = "none"
@@ -422,11 +416,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
features["moth_markings"] = sanitize_inlist(features["moth_markings"], GLOB.moth_markings_list, "None")
persistent_scars = sanitize_integer(persistent_scars)
scars_list["1"] = sanitize_text(scars_list["1"])
scars_list["2"] = sanitize_text(scars_list["2"])
scars_list["3"] = sanitize_text(scars_list["3"])
scars_list["4"] = sanitize_text(scars_list["4"])
scars_list["5"] = sanitize_text(scars_list["5"])
joblessrole = sanitize_integer(joblessrole, 1, 3, initial(joblessrole))
//Validate job prefs
@@ -484,12 +473,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["feature_moth_wings"] , features["moth_wings"])
WRITE_FILE(S["feature_moth_markings"] , features["moth_markings"])
WRITE_FILE(S["persistent_scars"] , persistent_scars)
WRITE_FILE(S["scars1"] , scars_list["1"])
WRITE_FILE(S["scars2"] , scars_list["2"])
WRITE_FILE(S["scars3"] , scars_list["3"])
WRITE_FILE(S["scars4"] , scars_list["4"])
WRITE_FILE(S["scars5"] , scars_list["5"])
//Custom names
for(var/custom_name_id in GLOB.preferences_custom_names)

View File

@@ -331,6 +331,9 @@
to_chat(humanc, "<span class='userdanger'><i>THERE CAN BE ONLY ONE!!!</i></span>")
humanc.make_scottish()
humanc.increment_scar_slot()
humanc.load_persistent_scars()
if(GLOB.summon_guns_triggered)
give_guns(humanc)
if(GLOB.summon_magic_triggered)
@@ -432,16 +435,6 @@
is_antag = TRUE
client.prefs.copy_to(H, antagonist = is_antag, is_latejoiner = transfer_after)
var/cur_scar_index = client.prefs.scars_index
if(client.prefs.persistent_scars && client.prefs.scars_list["[cur_scar_index]"])
var/scar_string = client.prefs.scars_list["[cur_scar_index]"]
var/valid_scars = ""
for(var/scar_line in splittext(scar_string, ";"))
if(H.load_scar(scar_line))
valid_scars += "[scar_line];"
client.prefs.scars_list["[cur_scar_index]"] = valid_scars
client.prefs.save_character()
client.prefs.copy_to(H, antagonist = is_antag)
H.dna.update_dna_identity()

View File

@@ -176,7 +176,24 @@
if(isclothing(wear_mask) && (wear_mask.clothing_flags & SCAN_REAGENTS))
return TRUE
/// For use formatting all of the scars this human has for saving for persistent scarring
/// When we're joining the game in [/mob/dead/new_player/proc/create_character], we increment our scar slot then store the slot in our mind datum.
/mob/living/carbon/human/proc/increment_scar_slot()
var/check_ckey = ckey || client?.ckey
if(!check_ckey || !mind || !client?.prefs.persistent_scars)
return
var/path = "data/player_saves/[check_ckey[1]]/[check_ckey]/scars.sav"
var/index = mind.current_scar_slot
if (!index)
if(fexists(path))
var/savefile/F = new /savefile(path)
index = F["current_index"] || 1
else
index = 1
mind.current_scar_slot = (index % PERSISTENT_SCAR_SLOTS) + 1 || 1
/// For use formatting all of the scars this human has for saving for persistent scarring, returns a string with all current scars/missing limb amputation scars for saving or loading purposes
/mob/living/carbon/human/proc/format_scars()
var/list/missing_bodyparts = get_missing_limbs()
if(!all_scars && !length(missing_bodyparts))
@@ -200,7 +217,50 @@
return
var/obj/item/bodypart/the_part = get_bodypart("[scar_data[SCAR_SAVE_ZONE]]")
var/datum/scar/scaries = new
return scaries.load(the_part, scar_data[SCAR_SAVE_VERS], scar_data[SCAR_SAVE_DESC], scar_data[SCAR_SAVE_PRECISE_LOCATION], text2num(scar_data[SCAR_SAVE_SEVERITY]))
return scaries.load(the_part, scar_data[SCAR_SAVE_VERS], scar_data[SCAR_SAVE_DESC], scar_data[SCAR_SAVE_PRECISE_LOCATION], text2num(scar_data[SCAR_SAVE_SEVERITY]), text2num(scar_data[SCAR_SAVE_BIOLOGY]))
/// Read all the scars we have at the designated slot, verify they're good (or dump them if they're old/wrong format), create them on the user, and write the scars that passed muster back to the file
/mob/living/carbon/human/proc/load_persistent_scars()
if(!ckey || !mind || !client?.prefs.persistent_scars)
return
var/path = "data/player_saves/[ckey[1]]/[ckey]/scars.sav"
if (!fexists(path))
return FALSE
var/savefile/F = new /savefile(path)
if(!F)
return
var/index = mind.current_scar_slot || F["current_index"] || 1
var/scar_string = F["scar[index]"]
var/valid_scars = ""
for(var/scar_line in splittext(sanitize_text(scar_string), ";"))
if(load_scar(scar_line))
valid_scars += "[scar_line];"
WRITE_FILE(F["scar[index]"], sanitize_text(valid_scars))
/// Save any scars we have to our designated slot, then write our current slot so that the next time we call [/mob/living/carbon/human/proc/increment_scar_slot] (the next round we join), we'll be there
/mob/living/carbon/human/proc/save_persistent_scars(nuke=FALSE)
if(!ckey || !mind || !client?.prefs.persistent_scars)
return
var/path = "data/player_saves/[ckey[1]]/[ckey]/scars.sav"
var/savefile/F = new /savefile(path)
var/index = mind.current_scar_slot || F["current_index"] || 1
if(nuke)
WRITE_FILE(F["scar[index]"], "")
return
for(var/k in all_wounds)
var/datum/wound/iter_wound = k
iter_wound.remove_wound() // so we can get the scars for open wounds
var/valid_scars = format_scars()
WRITE_FILE(F["scar[index]"], sanitize_text(valid_scars))
WRITE_FILE(F["current_index"], sanitize_integer(index))
/mob/living/carbon/human/get_biological_state()
return dna.species.get_biological_state()