diff --git a/code/__defines/belly_modes_vr.dm b/code/__defines/belly_modes_vr.dm index 423db8c03f..8555b4d91f 100644 --- a/code/__defines/belly_modes_vr.dm +++ b/code/__defines/belly_modes_vr.dm @@ -18,3 +18,10 @@ // Stance for hostile mobs to be in while devouring someone. #define HOSTILE_STANCE_EATING 99 + +// Defines for weight system +#define MIN_MOB_WEIGHT 70 +#define MAX_MOB_WEIGHT 500 +#define MIN_NUTRITION_TO_GAIN 450 // Above this amount you will gain weight +#define MAX_NUTRITION_TO_LOSE 50 // Below this amount you will lose weight +// #define WEIGHT_PER_NUTRITION 0.0285 // Tuned so 1050 (nutrition for average mob) = 30 lbs diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index 5068c3ee56..8ad89a520b 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -389,6 +389,10 @@ for(var/mob/M in to_despawn) despawn_occupant(M) + // VOREStation + hook_vr("despawn", list(to_despawn, src)) + // VOREStation + //Drop all items into the pod. for(var/obj/item/W in to_despawn) to_despawn.drop_from_inventory(W) diff --git a/code/game/machinery/cryopod_vr.dm b/code/game/machinery/cryopod_vr.dm index be97c15958..78707df287 100644 --- a/code/game/machinery/cryopod_vr.dm +++ b/code/game/machinery/cryopod_vr.dm @@ -1,5 +1,13 @@ //Overrides! +/obj/machinery/cryopod + // The corresponding spawn point type that user despawning here will return at next round. + // Note: We use a type instead of name so that its validity is checked at compile time. + var/spawnpoint_type = /datum/spawnpoint/cryo + +/obj/machinery/cryopod/robot + spawnpoint_type = /datum/spawnpoint/cyborg + /obj/machinery/cryopod/robot/door/gateway name = "public teleporter" desc = "The short-range teleporter you might've came in from. You could leave easily using this." @@ -9,6 +17,7 @@ occupied_icon_state = "tele1" on_store_message = "has departed via short-range teleport." on_enter_occupant_message = "The teleporter activates, and you step into the swirling portal." + spawnpoint_type = /datum/spawnpoint/gateway /obj/machinery/computer/cryopod/gateway name = "teleport oversight console" @@ -17,7 +26,8 @@ /obj/machinery/cryopod/robot/door/dorms desc = "A small elevator that goes down to the residential district." on_enter_occupant_message = "The elevator door closes slowly, ready to bring you down to the residential district." + spawnpoint_type = /datum/spawnpoint/elevator /obj/machinery/computer/cryopod/dorms name = "residential oversight console" - desc = "An interface between visitors and the residential oversight systems tasked with keeping track of all visitors in the residential district." \ No newline at end of file + desc = "An interface between visitors and the residential oversight systems tasked with keeping track of all visitors in the residential district." diff --git a/code/modules/client/preference_setup/vore/05_persistence.dm b/code/modules/client/preference_setup/vore/05_persistence.dm new file mode 100644 index 0000000000..5919ae4495 --- /dev/null +++ b/code/modules/client/preference_setup/vore/05_persistence.dm @@ -0,0 +1,65 @@ +#define PERSIST_SPAWN 0x01 // Persist spawnpoint based on location of despawn/logout. +#define PERSIST_WEIGHT 0x02 // Persist mob weight +#define PERSIST_ORGANS 0x04 // Persist the status (normal/amputated/robotic/etc) and model (for robotic) status of organs +#define PERSIST_MARKINGS 0x08 // Persist markings +#define PERSIST_COUNT 4 // Number of valid bits in this bitflag. Keep this updated! +#define PERSIST_DEFAULT PERSIST_SPAWN|PERSIST_ORGANS|PERSIST_MARKINGS // Default setting for new folks + +// Define a place to save in character setup +/datum/preferences + var/persistence_settings = PERSIST_DEFAULT // Control what if anything is persisted for this character between rounds. + +// Definition of the stuff for Sizing +/datum/category_item/player_setup_item/vore/persistence + name = "Persistence" + sort_order = 5 + +/datum/category_item/player_setup_item/vore/persistence/load_character(var/savefile/S) + S["persistence_settings"] >> pref.persistence_settings + +/datum/category_item/player_setup_item/vore/persistence/save_character(var/savefile/S) + S["persistence_settings"] << pref.persistence_settings + +/datum/category_item/player_setup_item/vore/persistence/sanitize_character() + pref.persistence_settings = sanitize_integer(pref.persistence_settings, 0, (1<<(PERSIST_COUNT+1)-1), initial(pref.persistence_settings)) + +/datum/category_item/player_setup_item/vore/persistence/content(var/mob/user) + . = list() + . += "Round-to-Round Persistence
" + . += "" + + . += "" + . += make_yesno(PERSIST_SPAWN) + . += "" + + . += "" + . += make_yesno(PERSIST_WEIGHT) + . += "" + + . += "" + . += make_yesno(PERSIST_ORGANS) + . += "" + + . += "" + . += make_yesno(PERSIST_MARKINGS) + . += "" + + . += "
Save Spawn Location:
Save Weight:
Save Organs:
Save Markings:
" + return jointext(., "") + +/datum/category_item/player_setup_item/vore/persistence/proc/make_yesno(var/bit) + if(pref.persistence_settings & bit) + return "Yes No" + else + return "Yes No" + +/datum/category_item/player_setup_item/vore/persistence/OnTopic(var/href, var/list/href_list, var/mob/user) + if(href_list["toggle_on"]) + var/bit = text2num(href_list["toggle_on"]) + pref.persistence_settings |= bit + return TOPIC_REFRESH + else if(href_list["toggle_off"]) + var/bit = text2num(href_list["toggle_off"]) + pref.persistence_settings &= ~bit + return TOPIC_REFRESH + return ..() diff --git a/code/modules/mob/living/carbon/human/life_vr.dm b/code/modules/mob/living/carbon/human/life_vr.dm index 2c0e594f7a..0c67f276a2 100644 --- a/code/modules/mob/living/carbon/human/life_vr.dm +++ b/code/modules/mob/living/carbon/human/life_vr.dm @@ -1,9 +1,9 @@ /mob/living/carbon/human/proc/weightgain() if (nutrition > 0 && stat != 2) - if (nutrition > 450 && weight < 500 && weight_gain) + if (nutrition > MIN_NUTRITION_TO_GAIN && weight < MAX_MOB_WEIGHT && weight_gain) weight += metabolism*(0.01*weight_gain) - else if (nutrition <= 50 && stat != 2 && weight > 70 && weight_loss) + else if (nutrition <= MAX_NUTRITION_TO_LOSE && stat != 2 && weight > MIN_MOB_WEIGHT && weight_loss) weight -= metabolism*(0.01*weight_loss) // starvation weight loss /mob/living/carbon/human/proc/handle_hud_list_vr() diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 2797a19f6c..28be4a02de 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -463,6 +463,10 @@ new_character.real_name = pick(clown_names) //I hate this being here of all places but unfortunately dna is based on real_name! new_character.rename_self("clown") mind.original = new_character + // VOREStation + mind.loaded_from_ckey = client.ckey + mind.loaded_from_slot = client.prefs.default_slot + // VOREStation mind.transfer_to(new_character) //won't transfer key since the mind is not active new_character.name = real_name diff --git a/code/modules/vore/hook-defs_vr.dm b/code/modules/vore/hook-defs_vr.dm index 629b1ba8f3..06734e8245 100644 --- a/code/modules/vore/hook-defs_vr.dm +++ b/code/modules/vore/hook-defs_vr.dm @@ -16,6 +16,9 @@ //Hooks for interactions /hook/living_attackby +// Hook for when a mob de-spawns! +/hook/despawn + // //Hook helpers to expand hooks to others // diff --git a/code/modules/vore/persist/persist_vr.dm b/code/modules/vore/persist/persist_vr.dm new file mode 100644 index 0000000000..85373c9ba5 --- /dev/null +++ b/code/modules/vore/persist/persist_vr.dm @@ -0,0 +1,162 @@ +/** + * Stuff having to do with inter-round persistence. + */ + +// Minds represent IC characters. +// Therefore it is the MIND we actually want to track here to find out +// what "character" a mob is. +// However right now minds don't keep track of what save file & slot they came from. +// So that is what we need to add! Whenever a mind is initialized from a save file slot, +// we record that so we can save it back when persisting! + +/datum/mind + var/loaded_from_ckey = null + var/loaded_from_slot = null + +// Handle people leaving due to round ending. +/hook/roundend/proc/persist_locations() + for(var/mob/Player in player_list) + if(!Player.mind || isnewplayer(Player)) + continue // No mind we can do nothing, new players we care not for + else if(Player.stat == DEAD) + if(istype(Player,/mob/observer/dead)) + var/mob/observer/dead/O = Player + if(O.started_as_observer) + continue // They are just a pure observer, ignore + // Died and were not cloned - Respawn at centcomm + persist_interround_data(Player, /datum/spawnpoint/arrivals) + else + var/turf/playerTurf = get_turf(Player) + if(isAdminLevel(playerTurf.z)) + // Evac'd - Next round they arrive on the shuttle. + persist_interround_data(Player, /datum/spawnpoint/arrivals) + else + // Stayed on station, go to dorms + persist_interround_data(Player, /datum/spawnpoint/elevator) + return 1 + +/** + * Called when mob despawns early (via cryopod)! + */ +/hook/despawn/proc/persist_despawned_mob(var/mob/occupant, var/obj/machinery/cryopod/pod) + ASSERT(istype(pod)) + ASSERT(ispath(pod.spawnpoint_type, /datum/spawnpoint)) + persist_interround_data(occupant, pod.spawnpoint_type) + return 1 + +/proc/persist_interround_data(var/mob/occupant, var/datum/spawnpoint/new_spawn_point_type) + ASSERT(istype(occupant)) + + // Find out of this mob is a proper mob! + if (occupant.mind && occupant.mind.loaded_from_ckey) + // Okay this mob has a real loaded-from-savefile mind in it! + var/datum/preferences/prefs = preferences_datums[occupant.mind.loaded_from_ckey] + if(!prefs) + WARNING("mind [occupant.mind] was loaded from ckey [occupant.mind.loaded_from_ckey] but no prefs datum found") + return + + // Okay, lets do a few checks to see if we should really save tho! + if(!prefs.load_character(occupant.mind.loaded_from_slot)) + WARNING("mind [occupant.mind] was loaded from slot [occupant.mind.loaded_from_slot] but loading prefs failed.") + return // Failed to load character + + // For now as a safety measure we will only save if the name matches. + if(prefs.real_name != occupant.real_name) + log_debug("Skipping persist for [occupant] becuase [occupant.real_name] != [prefs.real_name]") + return + + if(!prefs.persistence_settings) + return // Persistence disabled by preference settings + + // Okay we can start saving the data + if(new_spawn_point_type && prefs.persistence_settings & PERSIST_SPAWN) + prefs.spawnpoint = initial(new_spawn_point_type.display_name) + if(ishuman(occupant) && occupant.stat != DEAD) + var/mob/living/carbon/human/H = occupant + testing("About to try saving stuff from [H] to [prefs] (\ref[prefs])") + if(prefs.persistence_settings & PERSIST_ORGANS) + apply_organs_to_prefs(H, prefs) + if(prefs.persistence_settings & PERSIST_MARKINGS) + apply_markings_to_prefs(H, prefs) + if(prefs.persistence_settings & PERSIST_WEIGHT) + resolve_excess_nutrition(H) + prefs.weight_vr = H.weight + prefs.save_character() + return + +// Saves mob's current organ state to prefs. +// This basically needs to be the reverse of /datum/category_item/player_setup_item/general/body/copy_to_mob() ~Leshana +/proc/apply_organs_to_prefs(var/mob/living/carbon/human/character, var/datum/preferences/prefs) + // Checkify the limbs! + testing("in apply_organs_to_prefs([character], \ref[prefs])") + for(var/name in list(BP_HEAD, BP_L_HAND, BP_R_HAND, BP_L_ARM, BP_R_ARM, BP_L_FOOT, BP_R_FOOT, BP_L_LEG, BP_R_LEG, BP_GROIN, BP_TORSO)) + var/obj/item/organ/external/O = character.organs_by_name[name] + if(!O) + prefs.organ_data[name] = "amputated" + else if(O.robotic >= ORGAN_ROBOT) + prefs.organ_data[name] = "cyborg" + if(O.model) + prefs.rlimb_data[name] = O.model + else + prefs.rlimb_data.Remove(name) // Missing rlimb_data entry means default model + else + prefs.organ_data.Remove(name) // Misisng organ_data entry means normal + + // Internal organs also + for(var/name in list(O_HEART,O_EYES,O_LUNGS,O_BRAIN)) + var/obj/item/organ/I = character.internal_organs_by_name[name] + if(I) + if(I.robotic == ORGAN_ASSISTED) + prefs.organ_data[name] = "assisted" + else if(I.robotic == ORGAN_ROBOT) + prefs.organ_data[name] = "mechanical" + else if(FALSE /* TODO - Need way to detect "digital" brains! */) + prefs.organ_data[name] = "digital" + else + prefs.organ_data.Remove(name) // Misisng organ_data entry means normal + +// Saves mob's current body markings state to prefs. +// This basically needs to be the reverse of /datum/category_item/player_setup_item/general/body/copy_to_mob() ~Leshana +/proc/apply_markings_to_prefs(var/mob/living/carbon/human/character, var/datum/preferences/prefs) + var/list/new_body_markings = list() + for(var/N in character.organs_by_name) + var/obj/item/organ/external/O = character.organs_by_name[N] + if(!O) continue // Skip missing limbs! + + for(var/name in O.markings) + // Expected to be list("color" = mark_color, "datum" = mark_datum). Sanity checks to ensure it. + var/list/ML = O.markings[name] + var/datum/sprite_accessory/marking/mark_datum = ML["datum"] + var/mark_color = ML["color"] + if(!istype(mark_datum) || !mark_color) + log_debug("[character]'s organ [O] ([O.type]) has marking [list2params(ML)] with invalid/missing color/datum!") + continue; + if(!(mark_datum.name in body_marking_styles_list)) + log_debug("[character]'s organ [O] ([O.type]) has marking [mark_datum] which is not in body_marking_styles_list!") + continue; + // Note: Since datums can cover multiple organs, we may encounter it multiple times, but this is okay + // because you're only allowed to have each marking type once! If this assumption changes, obviously update this. ~Leshana + new_body_markings[mark_datum.name] = mark_color + prefs.body_markings = new_body_markings // Overwrite with new list! + +/** +* Resolve any surplus/deficit in nutrition's effet on weight all at once. +* Normally this would slowly apply during the round; once we get to the end +* we need to apply it all at once. +*/ +/proc/resolve_excess_nutrition(var/mob/living/carbon/C) + if(C.stat == DEAD) + return // You don't metabolize if dead + if(!C.metabolism || !C.species || !C.species.hunger_factor) + return // You don't metabolize if you have no metabolism or your species doesn't eat! + // Each Life() tick, you gain/lose weight proportional to your metabolism, and lose species.hunger_factor nutrition + var/weight_per_nutrition = C.metabolism / C.species.hunger_factor + + if(C.nutrition > MIN_NUTRITION_TO_GAIN && C.weight < MAX_MOB_WEIGHT && C.weight_gain) + // Weight Gain! + var/gain = (C.nutrition - MIN_NUTRITION_TO_GAIN) * weight_per_nutrition * C.weight_gain/100 + C.weight = min(MAX_MOB_WEIGHT, C.weight + gain) + else if(C.nutrition <= MAX_NUTRITION_TO_LOSE && C.weight > MIN_MOB_WEIGHT && C.weight_loss) + // Weight Loss! + var/loss = (MAX_NUTRITION_TO_LOSE - C.nutrition) * weight_per_nutrition * C.weight_loss/100 + C.weight = max(MIN_MOB_WEIGHT, C.weight - loss) diff --git a/html/changelogs/Atermonera - Translators.yml b/html/changelogs/Atermonera - Translators.yml deleted file mode 100644 index 278506535c..0000000000 --- a/html/changelogs/Atermonera - Translators.yml +++ /dev/null @@ -1,37 +0,0 @@ -################################ -# Example Changelog File -# -# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. -# -# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) -# When it is, any changes listed below will disappear. -# -# Valid Prefixes: -# bugfix -# wip (For works in progress) -# tweak -# soundadd -# sounddel -# rscadd (general adding of nice things) -# rscdel (general deleting of nice things) -# imageadd -# imagedel -# maptweak -# spellcheck (typo fixes) -# experiment -################################# - -# Your name. -author: Atermonera - -# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. -delete-after: True - -# Any changes you've made. See valid prefix list above. -# INDENT WITH TWO SPACES. NOT TABS. SPACES. -# SCREW THIS UP AND IT WON'T WORK. -# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. -# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. -changes: - - rscadd: "Common simple animals now have their own language, and as such are no longer understandable by humans." - - bugfix: "Translators can't understand the same languages that recorders can't, including the new animal languages." diff --git a/html/changelogs/Leshana-vplk-persistence.yml b/html/changelogs/Leshana-vplk-persistence.yml new file mode 100644 index 0000000000..3e396d6634 --- /dev/null +++ b/html/changelogs/Leshana-vplk-persistence.yml @@ -0,0 +1,9 @@ +author: Leshana +delete-after: True +changes: + - rscadd: "Enables round-to-round persistence of a few aspects of characters. More accurately, it automates updating your character setup. None of this code does anything you could not already do manually on the Character Setup screen, it simply does it automatically for you. ALL of these changes are optional, toggled on the VORE tab of character setup." + - rscadd: "Your late-join spawn location is determined by which cryo/elevator/etc you used to leave last time. Departing thru the elevators will set your spawn location to elevators etc." + - rscadd: "Your weight is saved (also any extra or deficient nutrition is resolved into weight gain/loss)" + - rscadd: "Your limbs settings are updated based on your status at end of round (whether limbs are normal, missing, robotic, etc)" + - rscadd: "Your markings are saved so they will be the same as when they were at end of round." + - tweak: "Replaced hard coded numbers for weight gain with constant defines." diff --git a/vorestation.dme b/vorestation.dme index 253c02bdef..a62d9fd7c9 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -1273,6 +1273,7 @@ #include "code\modules\client\preference_setup\vore\02_size.dm" #include "code\modules\client\preference_setup\vore\03_egg.dm" #include "code\modules\client\preference_setup\vore\04_resleeving.dm" +#include "code\modules\client\preference_setup\vore\05_persistence.dm" #include "code\modules\clothing\chameleon.dm" #include "code\modules\clothing\clothing.dm" #include "code\modules\clothing\clothing_accessories.dm" @@ -2310,6 +2311,7 @@ #include "code\modules\vore\fluffstuff\custom_items_vr.dm" #include "code\modules\vore\fluffstuff\custom_mecha_vr.dm" #include "code\modules\vore\fluffstuff\custom_permits_vr.dm" +#include "code\modules\vore\persist\persist_vr.dm" #include "code\modules\vore\resizing\grav_pull_vr.dm" #include "code\modules\vore\resizing\holder_micro_vr.dm" #include "code\modules\vore\resizing\resize_vr.dm"