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 #define WOUND_DAMAGE_EXPONENT 1.4
/// any damage dealt over this is ignored for damage rolls unless the target has the frail quirk (35^1.4=145, for reference)
/// an attack must do this much damage after armor in order to roll for being a wound (incremental pressure damage need not apply) #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 #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 /// 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 #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) /// set wound_bonus on an item or attack to this to disable checking wounding for the attack
#define WOUND_MAX_CONSIDERED_DAMAGE 35 #define CANT_WOUND -100
// ~wound severities
#define WOUND_SEVERITY_TRIVIAL 0 // for jokey/meme wounds like stubbed toe, no standard messages/sounds or second winds /// 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_MODERATE 1
#define WOUND_SEVERITY_SEVERE 2 #define WOUND_SEVERITY_SEVERE 2
#define WOUND_SEVERITY_CRITICAL 3 #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 /// any brute weapon/attack that doesn't have sharpness. rolls for blunt bone wounds
#define WOUND_BLUNT 1 #define WOUND_BLUNT 1
/// any brute weapon/attack with sharpness = SHARP_EDGED. rolls for slash wounds /// 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 /// any concentrated burn attack (lasers really). rolls for burning wounds
#define WOUND_BURN 4 #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_MODERATE 1
#define WOUND_DETERMINATION_SEVERE 2.5 #define WOUND_DETERMINATION_SEVERE 2.5
#define WOUND_DETERMINATION_CRITICAL 5 #define WOUND_DETERMINATION_CRITICAL 5
#define WOUND_DETERMINATION_LOSS 7.5 #define WOUND_DETERMINATION_LOSS 7.5
/// the max amount of determination you can have /// the max amount of determination you can have
#define WOUND_DETERMINATION_MAX 10 #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 // 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), 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), 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) 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, 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/slash/critical, /datum/wound/slash/severe, /datum/wound/slash/moderate,
/datum/wound/pierce/critical, /datum/wound/pierce/severe, /datum/wound/pierce/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)) /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 // Thresholds for infection for burn wounds, once infestation hits each threshold, things get steadily worse
/// below this has no ill effects from infection /// below this has no ill effects from infection
#define WOUND_INFECTION_MODERATE 4 #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 // 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 /// how quickly sanitization removes infestation and decays per tick
#define WOUND_BURN_SANITIZATION_RATE 0.15 #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 /// 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) /// 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 #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): // 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 // 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 // 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_FLESH 2
#define BODYPART_MANGLED_BOTH 3 #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 // 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 /// golems and androids, cannot suffer any wounds
#define BIO_INORGANIC 0 #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 #define BIO_JUST_BONE 1
/// nothing right now, maybe slimepeople in the future, can only suffer slashing, piercing, and burn wounds /// nothing right now, maybe slimepeople in the future, can only suffer slashing, piercing, and burn wounds
#define BIO_JUST_FLESH 2 #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 #define BIO_FLESH_BONE 3
// ~wound flag defines
/// If this wound requires having the HAS_FLESH flag for humanoids /// If this wound requires having the HAS_FLESH flag for humanoids
#define FLESH_WOUND (1<<0) #define FLESH_WOUND (1<<0)
/// If this wound requires having the HAS_BONE flag for humanaoids /// 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 /// If this wound marks the limb as being allowed to have gauze applied
#define ACCEPTS_GAUZE (1<<4) #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 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(!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 original_human.save_persistent_scars(TRUE)
ending_human.client.prefs.scars_list["[ending_human.client.prefs.scars_index]"] = ""
else else
for(var/k in ending_human.all_wounds) original_human.save_persistent_scars()
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()

View File

@@ -325,15 +325,20 @@ SUBSYSTEM_DEF(ticker)
else else
stack_trace("[S] [S.type] found in start landmarks list, which isn't a start landmark!") 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) for(var/i in GLOB.player_list)
if(!ishuman(i)) if(!ishuman(i))
continue continue
var/mob/living/carbon/human/hardcore_player = i var/mob/living/carbon/human/iter_human = i
if(!hardcore_player.hardcore_survival_score)
iter_human.increment_scar_slot()
iter_human.load_persistent_scars()
if(!iter_human.hardcore_survival_score)
continue continue
if(hardcore_player.mind?.special_role) if(iter_human.mind?.special_role)
hardcore_player.hardcore_survival_score *= 2 //Double for antags iter_human.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>") 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 //These callbacks will fire after roundstart key transfer
/datum/controller/subsystem/ticker/proc/OnRoundstart(datum/callback/cb) /datum/controller/subsystem/ticker/proc/OnRoundstart(datum/callback/cb)

View File

@@ -73,6 +73,8 @@
var/list/known_skills = list() 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 ///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 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. ///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 var/experience_multiplier = 1
///Skill multiplier list, just slap your multiplier change onto this with the type it is coming from as key. ///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 ///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) /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) 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 /datum/scar
var/obj/item/bodypart/limb var/obj/item/bodypart/limb
var/mob/living/carbon/victim 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 var/severity
/// The description of the scar for examining
var/description 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 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 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 /// 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 var/visibility = 2
/// Whether this scar can actually be covered up by clothing /// Whether this scar can actually be covered up by clothing
var/coverable = TRUE var/coverable = TRUE
/// What zones this scar can be applied to /// 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/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) var/biology = BIO_FLESH_BONE
/datum/scar/Destroy(force, ...) /datum/scar/Destroy(force, ...)
if(limb) 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) * * 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) /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 limb = BP
severity = W.severity severity = W.severity
if(limb.owner) if(limb.owner)
@@ -53,9 +52,11 @@
if(victim) if(victim)
LAZYADD(victim.all_scars, src) 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" 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" description = pick(strings(FLESH_SCAR_FILE, W.scar_keyword)) || "general disfigurement"
precise_location = pick(strings(SCAR_LOC_FILE, limb.body_zone)) precise_location = pick(strings(SCAR_LOC_FILE, limb.body_zone))
@@ -78,17 +79,23 @@
LAZYADD(victim.all_scars, src) LAZYADD(victim.all_scars, src)
/// Used to "load" a persistent scar /// Used to "load" a persistent scar
/datum/scar/proc/load(obj/item/bodypart/BP, version, description, specific_location, severity=WOUND_SEVERITY_SEVERE) /datum/scar/proc/load(obj/item/bodypart/BP, version, description, specific_location, severity=WOUND_SEVERITY_SEVERE, biology=BIO_FLESH_BONE)
if(!(BP.body_zone in applicable_zones) || !BP.is_organic_limb()) if(!BP.is_organic_limb())
qdel(src) qdel(src)
return return
limb = BP limb = BP
src.severity = severity if(limb.owner)
LAZYADD(limb.scars, src) victim = limb.owner
if(BP.owner) if(victim.get_biological_state() != biology)
victim = BP.owner qdel(src)
return
LAZYADD(victim.all_scars, src) LAZYADD(victim.all_scars, src)
src.severity = severity
src.biology = biology
LAZYADD(limb.scars, src)
src.description = description src.description = description
precise_location = specific_location precise_location = specific_location
switch(severity) switch(severity)
@@ -143,10 +150,9 @@
/// Used to format a scar to safe in preferences for persistent scars /// Used to format a scar to safe in preferences for persistent scars
/datum/scar/proc/format() /datum/scar/proc/format()
if(!fake) return fake ? null : "[SCAR_CURRENT_VERSION]|[limb.body_zone]|[description]|[precise_location]|[severity]|[biology]"
return "[SCAR_CURRENT_VERSION]|[limb.body_zone]|[description]|[precise_location]|[severity]"
/// Used to format a scar to safe in preferences for persistent scars /// Used to format a scar to safe in preferences for persistent scars
/datum/scar/proc/format_amputated(body_zone) /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")) 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 var/hearted_until
/// Agendered spessmen can choose whether to have a male or female bodytype /// Agendered spessmen can choose whether to have a male or female bodytype
var/body_type var/body_type
/// If we have persistent scars enabled /// If we have persistent scars enabled
var/persistent_scars = TRUE 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) /datum/preferences/New(client/C)
parent = C parent = C
@@ -1721,12 +1716,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
persistent_scars = !persistent_scars persistent_scars = !persistent_scars
if("clear_scars") if("clear_scars")
to_chat(user, "<span class='notice'>All scar slots cleared. Please save character to confirm.</span>") var/path = "data/player_saves/[user.ckey[1]]/[user.ckey]/scars.sav"
scars_list["1"] = "" fdel(path)
scars_list["2"] = "" to_chat(user, "<span class='notice'>All scar slots cleared.</span>")
scars_list["3"] = ""
scars_list["4"] = ""
scars_list["5"] = ""
if("hear_midis") if("hear_midis")
toggles ^= SOUND_MIDI toggles ^= SOUND_MIDI

View File

@@ -291,7 +291,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
if(newtype) if(newtype)
pref_species = new newtype pref_species = new newtype
scars_index = rand(1,5)
//Character //Character
READ_FILE(S["real_name"], real_name) 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_wings"], features["moth_wings"])
READ_FILE(S["feature_moth_markings"], features["moth_markings"]) READ_FILE(S["feature_moth_markings"], features["moth_markings"])
READ_FILE(S["persistent_scars"] , persistent_scars) 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)) if(!CONFIG_GET(flag/join_with_mutant_humans))
features["tail_human"] = "none" features["tail_human"] = "none"
features["ears"] = "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") features["moth_markings"] = sanitize_inlist(features["moth_markings"], GLOB.moth_markings_list, "None")
persistent_scars = sanitize_integer(persistent_scars) 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)) joblessrole = sanitize_integer(joblessrole, 1, 3, initial(joblessrole))
//Validate job prefs //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_wings"] , features["moth_wings"])
WRITE_FILE(S["feature_moth_markings"] , features["moth_markings"]) WRITE_FILE(S["feature_moth_markings"] , features["moth_markings"])
WRITE_FILE(S["persistent_scars"] , persistent_scars) 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 //Custom names
for(var/custom_name_id in GLOB.preferences_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>") to_chat(humanc, "<span class='userdanger'><i>THERE CAN BE ONLY ONE!!!</i></span>")
humanc.make_scottish() humanc.make_scottish()
humanc.increment_scar_slot()
humanc.load_persistent_scars()
if(GLOB.summon_guns_triggered) if(GLOB.summon_guns_triggered)
give_guns(humanc) give_guns(humanc)
if(GLOB.summon_magic_triggered) if(GLOB.summon_magic_triggered)
@@ -432,16 +435,6 @@
is_antag = TRUE is_antag = TRUE
client.prefs.copy_to(H, antagonist = is_antag, is_latejoiner = transfer_after) 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) client.prefs.copy_to(H, antagonist = is_antag)
H.dna.update_dna_identity() H.dna.update_dna_identity()

View File

@@ -176,7 +176,24 @@
if(isclothing(wear_mask) && (wear_mask.clothing_flags & SCAN_REAGENTS)) if(isclothing(wear_mask) && (wear_mask.clothing_flags & SCAN_REAGENTS))
return TRUE 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() /mob/living/carbon/human/proc/format_scars()
var/list/missing_bodyparts = get_missing_limbs() var/list/missing_bodyparts = get_missing_limbs()
if(!all_scars && !length(missing_bodyparts)) if(!all_scars && !length(missing_bodyparts))
@@ -200,7 +217,50 @@
return return
var/obj/item/bodypart/the_part = get_bodypart("[scar_data[SCAR_SAVE_ZONE]]") var/obj/item/bodypart/the_part = get_bodypart("[scar_data[SCAR_SAVE_ZONE]]")
var/datum/scar/scaries = new 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() /mob/living/carbon/human/get_biological_state()
return dna.species.get_biological_state() return dna.species.get_biological_state()