diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index 34f06d7b64a..47a8e266812 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -47,6 +47,10 @@ ///from base of mob/living/death(): (gibbed) #define COMSIG_LIVING_DEATH "living_death" +///from base of mob/living/Write_Memory(): (dead, gibbed) +#define COMSIG_LIVING_WRITE_MEMORY "living_write_memory" + #define COMPONENT_DONT_WRITE_MEMORY (1<<0) + /// from /proc/healthscan(): (list/scan_results, advanced, mob/user, mode) /// Consumers are allowed to mutate the scan_results list to add extra information #define COMSIG_LIVING_HEALTHSCAN "living_healthscan" diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index fb37a17ef09..a04df4f373b 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -353,6 +353,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_SPARRING "sparring" /// The user is currently challenging an elite mining mob. Prevents him from challenging another until he's either lost or won. #define TRAIT_ELITE_CHALLENGER "elite_challenger" +/// For living mobs. It signals that the mob shouldn't have their data written in an external json for persistence. +#define TRAIT_DONT_WRITE_MEMORY "dont_write_memory" #define TRAIT_NOBLEED "nobleed" //This carbon doesn't bleed /// This atom can ignore the "is on a turf" check for simple AI datum attacks, allowing them to attack from bags or lockers as long as any other conditions are met @@ -767,6 +769,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define DRONE_SHY_TRAIT "drone_shy" /// Pacifism trait given by stabilized light pink extracts. #define STABILIZED_LIGHT_PINK_TRAIT "stabilized_light_pink" +/// Given by the multiple_lives component to the previous body of the mob upon death. +#define EXPIRED_LIFE_TRAIT "expired_life" /// Trait given to a ghost when they orbit something. #define GHOST_ORBITING_TRAIT "ghost_orbiting" diff --git a/code/datums/components/multiple_lives.dm b/code/datums/components/multiple_lives.dm index f4206885857..f0db99f0f56 100644 --- a/code/datums/components/multiple_lives.dm +++ b/code/datums/components/multiple_lives.dm @@ -17,15 +17,24 @@ /datum/component/multiple_lives/RegisterWithParent() RegisterSignal(parent, COMSIG_LIVING_DEATH, .proc/respawn) RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine) + RegisterSignal(parent, COMSIG_LIVING_WRITE_MEMORY, .proc/on_write_memory) /datum/component/multiple_lives/UnregisterFromParent() - UnregisterSignal(parent, list(COMSIG_LIVING_DEATH, COMSIG_PARENT_EXAMINE)) + UnregisterSignal(parent, list(COMSIG_LIVING_DEATH, COMSIG_PARENT_EXAMINE, COMSIG_LIVING_WRITE_MEMORY)) + +/// Stops a dying station pet from overriding persistence data before we respawn it and thus causing issues. +/datum/component/multiple_lives/proc/on_write_memory(mob/living/source, dead, gibbed) + if(dead && !source.suiciding) + return COMPONENT_DONT_WRITE_MEMORY /datum/component/multiple_lives/proc/respawn(mob/living/source, gibbed) SIGNAL_HANDLER if(source.suiciding) //Freed from this mortail coil. qdel(src) return + //Gives the old mob this trait in case it gets revived, so we won't end up eventually overriding data + //that would be read by the current holder when he respawns if the old corpse is ever revived. + ADD_TRAIT(source, TRAIT_DONT_WRITE_MEMORY, EXPIRED_LIFE_TRAIT) var/mob/living/respawned_mob = new source.type (source.drop_location()) source.mind?.transfer_to(respawned_mob) lives_left-- diff --git a/code/modules/mob/living/carbon/human/monkey/monkey.dm b/code/modules/mob/living/carbon/human/monkey/monkey.dm index bb3b7995b36..24e7771094a 100644 --- a/code/modules/mob/living/carbon/human/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/human/monkey/monkey.dm @@ -97,7 +97,10 @@ relic_hat = json["relic_hat"] relic_mask = json["relic_hat"] -/mob/living/carbon/human/species/monkey/punpun/proc/Write_Memory(dead, gibbed) +/mob/living/carbon/human/species/monkey/punpun/Write_Memory(dead, gibbed) + . = ..() + if(!.) + return var/json_file = file("data/npc_saves/Punpun.json") var/list/file_data = list() if(gibbed) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 5e95384b79f..5da76cace07 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -2259,3 +2259,17 @@ span_userdanger("You're thrown violently into [lattice], smashing through it and punching straight through!")) apply_damage(rand(5,10), BRUTE, BODY_ZONE_CHEST) lattice.deconstruct(FALSE) + +/** + * Proc used by different station pets such as Ian and Poly so that some of their data can persist between rounds. + * This base definition only contains a trait and comsig to stop memory from being (over)written. + * Specific behavior is defined on subtypes that use it. + */ +/mob/living/proc/Write_Memory(dead, gibbed) + SHOULD_CALL_PARENT(TRUE) + if(HAS_TRAIT(src, TRAIT_DONT_WRITE_MEMORY)) //always prevent data from being written. + return FALSE + // for selective behaviors that may or may not prevent data from being written. + if(SEND_SIGNAL(src, COMSIG_LIVING_WRITE_MEMORY, dead, gibbed) & COMPONENT_DONT_WRITE_MEMORY) + return FALSE + return TRUE diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm index 571a286f4de..9f9fd7e96bf 100644 --- a/code/modules/mob/living/simple_animal/friendly/cat.dm +++ b/code/modules/mob/living/simple_animal/friendly/cat.dm @@ -113,7 +113,7 @@ unique_pet = TRUE var/list/family = list()//var restored from savefile, has count of each child type var/list/children = list()//Actual mob instances of children - var/cats_deployed = 0 + var/static/cats_deployed = 0 var/memory_saved = FALSE held_state = "cat" @@ -158,7 +158,10 @@ if(isnull(family)) family = list() -/mob/living/simple_animal/pet/cat/runtime/proc/Write_Memory(dead) +/mob/living/simple_animal/pet/cat/runtime/Write_Memory(dead, gibbed) + . = ..() + if(!.) + return var/json_file = file("data/npc_saves/Runtime.json") var/list/file_data = list() family = list() diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm index 09b64b7d926..1c37ae1875c 100644 --- a/code/modules/mob/living/simple_animal/friendly/dog.dm +++ b/code/modules/mob/living/simple_animal/friendly/dog.dm @@ -530,7 +530,10 @@ GLOBAL_LIST_INIT(strippable_corgi_items, create_strippable_list(list( if(saved_head) place_on_head(new saved_head) -/mob/living/simple_animal/pet/dog/corgi/ian/proc/Write_Memory(dead) +/mob/living/simple_animal/pet/dog/corgi/ian/Write_Memory(dead, gibbed) + . = ..() + if(!.) + return var/json_file = file("data/npc_saves/Ian.json") var/list/file_data = list() if(!dead) diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm index 07d01f48eb0..137c592369a 100644 --- a/code/modules/mob/living/simple_animal/parrot.dm +++ b/code/modules/mob/living/simple_animal/parrot.dm @@ -953,7 +953,10 @@ GLOBAL_LIST_INIT(strippable_parrot_items, create_strippable_list(list( if(!islist(speech_buffer)) speech_buffer = list() -/mob/living/simple_animal/parrot/poly/proc/Write_Memory(dead) +/mob/living/simple_animal/parrot/poly/Write_Memory(dead, gibbed) + . = ..() + if(!.) + return var/json_file = file("data/npc_saves/Poly.json") var/list/file_data = list() if(islist(speech_buffer))