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.
* Specifically a few things are saved either at round end or when you cryo:
  * 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.
  * Your weight is saved (also any extra or deficient nutrition is resolved into weight gain/loss)
  * Your limbs settings are updated based on your status at end of round (whether limbs are normal, missing, robotic, etc)
  * Your markings are saved so they will be the same as when they were at end of round.
* ALL of these changes are optional, toggled on the VORE tab of character setup.
* Replaced hard coded numbers for weight gain with constant defines.
This commit is contained in:
Leshana
2017-04-03 17:57:08 -04:00
parent cf8a7a8bee
commit f17ea64bbe
11 changed files with 269 additions and 40 deletions
+7
View File
@@ -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
+4
View File
@@ -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)
+11 -1
View File
@@ -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."
desc = "An interface between visitors and the residential oversight systems tasked with keeping track of all visitors in the residential district."
@@ -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()
. += "<b>Round-to-Round Persistence</b><br>"
. += "<table>"
. += "<tr><td title=\"Set spawn location based on where you cryo'd out.\">Save Spawn Location: </td>"
. += make_yesno(PERSIST_SPAWN)
. += "</tr>"
. += "<tr><td title=\"Save your character's weight until next round.\">Save Weight: </td>"
. += make_yesno(PERSIST_WEIGHT)
. += "</tr>"
. += "<tr><td title=\"Update organ preferences (normal/amputated/robotic/etc) and model (for robotic) based on what you have at round end.\">Save Organs: </td>"
. += make_yesno(PERSIST_ORGANS)
. += "</tr>"
. += "<tr><td title=\"Update marking preferences (type and color) based on what you have at round end.\">Save Markings: </td>"
. += make_yesno(PERSIST_MARKINGS)
. += "</tr>"
. += "</table>"
return jointext(., "")
/datum/category_item/player_setup_item/vore/persistence/proc/make_yesno(var/bit)
if(pref.persistence_settings & bit)
return "<td><span class='linkOn'><b>Yes</b></span></td> <td><a href='?src=\ref[src];toggle_off=[bit]'>No</a></td>"
else
return "<td><a href='?src=\ref[src];toggle_on=[bit]'>Yes</a></td> <td><span class='linkOn'><b>No</b></span></td>"
/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 ..()
@@ -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()
@@ -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
+3
View File
@@ -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
//
+162
View File
@@ -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)
@@ -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."
@@ -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."
+2
View File
@@ -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"