mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-31 20:43:38 +00:00
Convert bellies to save using JSON
This commit is contained in:
90
code/modules/persistence/persistence.dm
Normal file
90
code/modules/persistence/persistence.dm
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Returns a byond list that can be passed to the "deserialize" proc
|
||||
* to bring a new instance of this atom to its original state
|
||||
*
|
||||
* If we want to store this info, we can pass it to `json_encode` or some other
|
||||
* interface that suits our fancy, to make it into an easily-handled string
|
||||
*/
|
||||
/datum/proc/serialize()
|
||||
var/data = list("type" = "[type]")
|
||||
return data
|
||||
|
||||
/*
|
||||
* This is given the byond list from above, to bring this atom to the state
|
||||
* described in the list.
|
||||
* This will be called after `New` but before `initialize`, so linking and stuff
|
||||
* would probably be handled in `initialize`
|
||||
*
|
||||
* Also, this should only be called by `list_to_object` in persistence.dm - at least
|
||||
* with current plans - that way it can actually initialize the type from the list
|
||||
*/
|
||||
/datum/proc/deserialize(var/list/data)
|
||||
return
|
||||
|
||||
/atom
|
||||
// This var isn't actually used for anything, but is present so that
|
||||
// DM's map reader doesn't forfeit on reading a JSON-serialized map
|
||||
var/map_json_data
|
||||
|
||||
// This is so specific atoms can override these, and ignore certain ones
|
||||
/atom/proc/vars_to_save()
|
||||
return list("color","dir","icon","icon_state","name","pixel_x","pixel_y")
|
||||
|
||||
/atom/proc/map_important_vars()
|
||||
// A list of important things to save in the map editor
|
||||
return list("color","dir","icon","icon_state","layer","name","pixel_x","pixel_y")
|
||||
|
||||
/area/map_important_vars()
|
||||
// Keep the area default icons, to keep things nice and legible
|
||||
return list("name")
|
||||
|
||||
// No need to save any state of an area by default
|
||||
/area/vars_to_save()
|
||||
return list("name")
|
||||
|
||||
/atom/serialize()
|
||||
var/list/data = ..()
|
||||
for(var/thing in vars_to_save())
|
||||
if(vars[thing] != initial(vars[thing]))
|
||||
data[thing] = vars[thing]
|
||||
return data
|
||||
|
||||
|
||||
/atom/deserialize(var/list/data)
|
||||
for(var/thing in vars_to_save())
|
||||
if(thing in data)
|
||||
vars[thing] = data[thing]
|
||||
..()
|
||||
|
||||
|
||||
/*
|
||||
Whoops, forgot to put documentation here.
|
||||
What this does, is take a JSON string produced by running
|
||||
BYOND's native `json_encode` on a list from `serialize` above, and
|
||||
turns that string into a new instance of that object.
|
||||
|
||||
You can also easily get an instance of this string by calling "Serialize Marked Datum"
|
||||
in the "Debug" tab.
|
||||
|
||||
If you're clever, you can do neat things with SDQL and this, though be careful -
|
||||
some objects, like humans, are dependent that certain extra things are defined
|
||||
in their list
|
||||
*/
|
||||
/proc/object_to_json(var/atom/movable/thing)
|
||||
return json_encode(thing.serialize())
|
||||
|
||||
/proc/json_to_object(var/json_data, var/loc)
|
||||
return list_to_object(json_decode(json_data), loc)
|
||||
|
||||
/proc/list_to_object(var/list/data, var/loc)
|
||||
if(!islist(data))
|
||||
throw EXCEPTION("You didn't give me a list, bucko")
|
||||
if(!("type" in data))
|
||||
throw EXCEPTION("No 'type' field in the data")
|
||||
var/path = text2path(data["type"])
|
||||
if(!path)
|
||||
throw EXCEPTION("Path not found: [path]")
|
||||
|
||||
var/atom/movable/thing = new path(loc)
|
||||
thing.deserialize(data)
|
||||
return thing
|
||||
@@ -9,7 +9,7 @@
|
||||
/datum/belly
|
||||
var/name // Name of this location
|
||||
var/inside_flavor // Flavor text description of inside sight/sound/smells/feels.
|
||||
var/vore_sound = 'sound/vore/gulp.ogg' // Sound when ingesting someone
|
||||
var/vore_sound = "Gulp" // Sound when ingesting someone
|
||||
var/vore_verb = "ingest" // Verb for eating with this in messages
|
||||
var/human_prey_swallow_time = 100 // Time in deciseconds to swallow /mob/living/carbon/human
|
||||
var/nonhuman_prey_swallow_time = 30 // Time in deciseconds to swallow anything else
|
||||
@@ -107,7 +107,6 @@
|
||||
new_belly.emote_time = emoteTime
|
||||
new_belly.digest_brute = digest_brute
|
||||
new_belly.digest_burn = digest_burn
|
||||
new_belly.digest_tickrate = digest_tickrate
|
||||
new_belly.immutable = immutable
|
||||
new_belly.can_taste = can_taste
|
||||
new_belly.escapable = escapable
|
||||
|
||||
@@ -13,14 +13,13 @@
|
||||
/obj/belly
|
||||
name = "belly" // Name of this location
|
||||
desc = "It's a belly! You're in it!" // Flavor text description of inside sight/sound/smells/feels.
|
||||
var/vore_sound = 'sound/vore/gulp.ogg' // Sound when ingesting someone
|
||||
var/vore_sound = "Gulp" // Sound when ingesting someone
|
||||
var/vore_verb = "ingest" // Verb for eating with this in messages
|
||||
var/human_prey_swallow_time = 100 // Time in deciseconds to swallow /mob/living/carbon/human
|
||||
var/nonhuman_prey_swallow_time = 30 // Time in deciseconds to swallow anything else
|
||||
var/emote_time = 60 SECONDS // How long between stomach emotes at prey
|
||||
var/digest_brute = 2 // Brute damage per tick in digestion mode
|
||||
var/digest_burn = 2 // Burn damage per tick in digestion mode
|
||||
var/digest_tickrate = 3 // Modulus this of air controller tick number to iterate gurgles on
|
||||
var/immutable = 0 // Prevents this belly from being deleted
|
||||
var/escapable = 0 // Belly can be resisted out of at any time
|
||||
var/escapetime = 60 SECONDS // Deciseconds, how long to escape this belly
|
||||
@@ -100,6 +99,37 @@
|
||||
//List has indexes that are the digestion mode strings, and keys that are lists of strings.
|
||||
var/tmp/list/emote_lists = list()
|
||||
|
||||
//For serialization, keep this updated, required for bellies to save correctly.
|
||||
/obj/belly/vars_to_save()
|
||||
return ..() + list(
|
||||
"name",
|
||||
"desc",
|
||||
"vore_sound",
|
||||
"vore_verb",
|
||||
"human_prey_swallow_time",
|
||||
"nonhuman_prey_swallow_time",
|
||||
"emote_time",
|
||||
"digest_brute",
|
||||
"digest_burn",
|
||||
"immutable",
|
||||
"can_taste",
|
||||
"escapable",
|
||||
"escapetime",
|
||||
"digestchance",
|
||||
"absorbchance",
|
||||
"escapechance",
|
||||
"transferchance",
|
||||
"transferlocation",
|
||||
"bulge_size",
|
||||
"shrink_grow_size",
|
||||
"struggle_messages_outside",
|
||||
"struggle_messages_inside",
|
||||
"digest_messages_owner",
|
||||
"digest_messages_prey",
|
||||
"examine_messages",
|
||||
"emote_lists"
|
||||
)
|
||||
|
||||
/obj/belly/initialize()
|
||||
. = ..()
|
||||
//If not, we're probably just in a prefs list or something.
|
||||
@@ -125,7 +155,9 @@
|
||||
|
||||
//Sound w/ antispam flag setting
|
||||
if(vore_sound && !recent_sound)
|
||||
playsound(src, vore_sound, vol = 100, vary = 1, falloff = VORE_SOUND_FALLOFF, preference = /datum/client_preference/eating_noises)
|
||||
var/soundfile = vore_sounds[vore_sound]
|
||||
if(soundfile)
|
||||
playsound(src, soundfile, vol = 100, vary = 1, falloff = VORE_SOUND_FALLOFF, preference = /datum/client_preference/eating_noises)
|
||||
recent_sound = TRUE
|
||||
|
||||
//Messages if it's a mob
|
||||
@@ -503,8 +535,10 @@
|
||||
if(!(content in src) || !istype(target))
|
||||
return
|
||||
content.forceMove(target)
|
||||
if(!silent)
|
||||
playsound(src, target.vore_sound, vol = 100, vary = 1, falloff = VORE_SOUND_FALLOFF, preference = /datum/client_preference/digestion_noises)
|
||||
if(!silent && target.vore_sound && !recent_sound)
|
||||
var/soundfile = vore_sounds[target.vore_sound]
|
||||
if(soundfile)
|
||||
playsound(src, soundfile, vol = 100, vary = 1, falloff = VORE_SOUND_FALLOFF, preference = /datum/client_preference/digestion_noises)
|
||||
owner.updateVRPanel()
|
||||
for(var/mob/living/M in contents)
|
||||
M.updateVRPanel()
|
||||
@@ -524,7 +558,6 @@
|
||||
dupe.emote_time = emote_time
|
||||
dupe.digest_brute = digest_brute
|
||||
dupe.digest_burn = digest_burn
|
||||
dupe.digest_tickrate = digest_tickrate
|
||||
dupe.immutable = immutable
|
||||
dupe.can_taste = can_taste
|
||||
dupe.escapable = escapable
|
||||
|
||||
@@ -184,11 +184,17 @@
|
||||
|
||||
P.digestable = src.digestable
|
||||
P.allowmobvore = src.allowmobvore
|
||||
P.belly_prefs = src.vore_organs
|
||||
P.vore_taste = src.vore_taste
|
||||
P.can_be_drop_prey = src.can_be_drop_prey
|
||||
P.can_be_drop_pred = src.can_be_drop_pred
|
||||
|
||||
var/list/serialized = list()
|
||||
for(var/belly in src.vore_organs)
|
||||
var/obj/belly/B = belly
|
||||
serialized += list(B.serialize()) //Can't add a list as an object to another list in Byond. Thanks.
|
||||
|
||||
P.belly_prefs = serialized
|
||||
|
||||
return 1
|
||||
|
||||
//
|
||||
@@ -201,27 +207,15 @@
|
||||
|
||||
var/datum/vore_preferences/P = client.prefs_vr
|
||||
|
||||
vore_organs = list()
|
||||
digestable = P.digestable
|
||||
allowmobvore = P.allowmobvore
|
||||
vore_taste = P.vore_taste
|
||||
can_be_drop_prey = P.can_be_drop_prey
|
||||
can_be_drop_pred = P.can_be_drop_pred
|
||||
|
||||
var/force_save = FALSE
|
||||
for(var/I in P.belly_prefs)
|
||||
if(isbelly(I)) //Belly system 2.0
|
||||
var/obj/belly/saved = I
|
||||
saved.copy(src)
|
||||
else if(istext(I)) //Belly name for old datum system
|
||||
force_save = TRUE
|
||||
log_debug("[src] had legacy belly [I], converting.")
|
||||
var/datum/belly/Bp = P.belly_prefs[I]
|
||||
var/obj/belly/new_belly = new(src)
|
||||
Bp.copy(new_belly) //Rewritten to convert to a 2.0 belly
|
||||
|
||||
if(force_save)
|
||||
save_vore_prefs()
|
||||
vore_organs.Cut()
|
||||
for(var/entry in P.belly_prefs)
|
||||
list_to_object(entry,src)
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
@@ -41,12 +41,12 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE
|
||||
|
||||
/datum/vore_preferences
|
||||
//Actual preferences
|
||||
var/digestable = 1
|
||||
var/allowmobvore = 1
|
||||
var/digestable = TRUE
|
||||
var/allowmobvore = TRUE
|
||||
var/list/belly_prefs = list()
|
||||
var/vore_taste
|
||||
var/can_be_drop_prey
|
||||
var/can_be_drop_pred
|
||||
var/vore_taste = "nothing in particular"
|
||||
var/can_be_drop_prey = FALSE
|
||||
var/can_be_drop_pred = FALSE
|
||||
|
||||
//Mechanically required
|
||||
var/path
|
||||
@@ -58,7 +58,7 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE
|
||||
if(istype(C))
|
||||
client = C
|
||||
client_ckey = C.ckey
|
||||
load_vore(C)
|
||||
load_vore()
|
||||
|
||||
//
|
||||
// Check if an object is capable of eating things, based on vore_organs
|
||||
@@ -80,34 +80,49 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE
|
||||
//
|
||||
// Save/Load Vore Preferences
|
||||
//
|
||||
/datum/vore_preferences/proc/load_path(ckey,slot,filename="character",ext="json")
|
||||
if(!ckey || !slot) return
|
||||
path = "data/player_saves/[copytext(ckey,1,2)]/[ckey]/vore/[filename][slot].[ext]"
|
||||
|
||||
|
||||
/datum/vore_preferences/proc/load_vore()
|
||||
if(!client || !client_ckey) return 0 //No client, how can we save?
|
||||
if(!client || !client_ckey)
|
||||
return 0 //No client, how can we save?
|
||||
if(!client.prefs || !client.prefs.default_slot)
|
||||
return 0 //Need to know what character to load!
|
||||
|
||||
slot = client.prefs.default_slot
|
||||
|
||||
path = client.prefs.path
|
||||
load_path(client_ckey,slot)
|
||||
|
||||
if(!path) return 0 //Path couldn't be set?
|
||||
if(!fexists(path)) //Never saved before
|
||||
save_vore() //Make the file first
|
||||
return 1
|
||||
|
||||
var/savefile/S = new /savefile(path)
|
||||
if(!S) return 0 //Savefile object couldn't be created?
|
||||
var/list/json_from_file = json_decode(file2text(path))
|
||||
if(!json_from_file)
|
||||
return 0 //My concern grows
|
||||
|
||||
S.cd = "/character[slot]"
|
||||
var/version = json_from_file["version"]
|
||||
json_from_file = patch_version(json_from_file,version)
|
||||
|
||||
S["digestable"] >> digestable
|
||||
S["allowmobvore"] >> allowmobvore
|
||||
S["belly_prefs"] >> belly_prefs
|
||||
S["vore_taste"] >> vore_taste
|
||||
S["can_be_drop_prey"] >> can_be_drop_prey
|
||||
S["can_be_drop_pred"] >> can_be_drop_pred
|
||||
digestable = json_from_file["digestable"]
|
||||
allowmobvore = json_from_file["allowmobvore"]
|
||||
vore_taste = json_from_file["vore_taste"]
|
||||
can_be_drop_prey = json_from_file["can_be_drop_prey"]
|
||||
can_be_drop_prey = json_from_file["can_be_drop_pred"]
|
||||
belly_prefs = json_from_file["belly_prefs"]
|
||||
|
||||
//Quick sanitize
|
||||
if(isnull(digestable))
|
||||
digestable = 1
|
||||
digestable = TRUE
|
||||
if(isnull(allowmobvore))
|
||||
allowmobvore = 1
|
||||
allowmobvore = TRUE
|
||||
if(isnull(can_be_drop_prey))
|
||||
allowmobvore = FALSE
|
||||
if(isnull(can_be_drop_pred))
|
||||
allowmobvore = FALSE
|
||||
if(isnull(belly_prefs))
|
||||
belly_prefs = list()
|
||||
|
||||
@@ -115,16 +130,34 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE
|
||||
|
||||
/datum/vore_preferences/proc/save_vore()
|
||||
if(!path) return 0
|
||||
if(!slot) return 0
|
||||
var/savefile/S = new /savefile(path)
|
||||
if(!S) return 0
|
||||
S.cd = "/character[slot]"
|
||||
|
||||
S["digestable"] << digestable
|
||||
S["allowmobvore"] << allowmobvore
|
||||
S["belly_prefs"] << belly_prefs
|
||||
S["vore_taste"] << vore_taste
|
||||
S["can_be_drop_prey"] << can_be_drop_prey
|
||||
S["can_be_drop_pred"] << can_be_drop_pred
|
||||
var/version = 1 //For "good times" use in the future
|
||||
var/list/settings_list = list(
|
||||
"version" = version,
|
||||
"digestable" = digestable,
|
||||
"allowmobvore" = allowmobvore,
|
||||
"vore_taste" = vore_taste,
|
||||
"can_be_drop_prey" = can_be_drop_prey,
|
||||
"can_be_drop_pred" = can_be_drop_pred,
|
||||
"belly_prefs" = belly_prefs,
|
||||
)
|
||||
|
||||
//List to JSON
|
||||
var/json_to_file = json_encode(settings_list)
|
||||
if(!json_to_file)
|
||||
log_debug("Saving: [path] failed jsonencode")
|
||||
return 0
|
||||
|
||||
//Write it out
|
||||
if(fexists(path))
|
||||
fdel(path) //Byond only supports APPENDING to files, not replacing.
|
||||
text2file(json_to_file,path)
|
||||
if(!fexists(path))
|
||||
log_debug("Saving: [path] failed file write")
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
//Can do conversions here
|
||||
/datum/vore_preferences/proc/patch_version(var/list/json_from_file,var/version)
|
||||
return json_from_file
|
||||
|
||||
@@ -525,12 +525,11 @@
|
||||
"Struggle Message (outside)",
|
||||
"Struggle Message (inside)",
|
||||
"Examine Message (when full)",
|
||||
"Reset All To Default",
|
||||
"Cancel - No Changes"
|
||||
"Reset All To Default"
|
||||
)
|
||||
|
||||
alert(user,"Setting abusive or deceptive messages will result in a ban. Consider this your warning. Max 150 characters per message, max 10 messages per topic.","Really, don't.")
|
||||
var/choice = input(user,"Select a type to modify. Messages from each topic are pulled at random when needed.","Pick Type") in messages
|
||||
var/choice = input(user,"Select a type to modify. Messages from each topic are pulled at random when needed.","Pick Type") as null|anything in messages
|
||||
var/help = " Press enter twice to separate messages. '%pred' will be replaced with your name. '%prey' will be replaced with the prey's name. '%belly' will be replaced with your belly's name."
|
||||
|
||||
switch(choice)
|
||||
@@ -567,9 +566,6 @@
|
||||
selected.struggle_messages_outside = initial(selected.struggle_messages_outside)
|
||||
selected.struggle_messages_inside = initial(selected.struggle_messages_inside)
|
||||
|
||||
if("Cancel - No Changes")
|
||||
return 0
|
||||
|
||||
if(href_list["b_verb"])
|
||||
var/new_verb = html_encode(input(usr,"New verb when eating (infinitive tense, e.g. nom or swallow):","New Verb") as text|null)
|
||||
|
||||
@@ -580,15 +576,16 @@
|
||||
selected.vore_verb = new_verb
|
||||
|
||||
if(href_list["b_sound"])
|
||||
var/choice = input(user,"Currently set to [selected.vore_sound]","Select Sound") in vore_sounds + "Cancel - No Changes"
|
||||
|
||||
if(choice == "Cancel")
|
||||
var/choice = input(user,"Currently set to [selected.vore_sound]","Select Sound") as null|anything in vore_sounds
|
||||
if(!choice)
|
||||
return 0
|
||||
|
||||
selected.vore_sound = vore_sounds[choice]
|
||||
selected.vore_sound = choice
|
||||
|
||||
if(href_list["b_soundtest"])
|
||||
user << selected.vore_sound
|
||||
var/soundfile = vore_sounds[selected.vore_sound]
|
||||
if(soundfile)
|
||||
user << soundfile
|
||||
|
||||
if(href_list["b_tastes"])
|
||||
selected.can_taste = !selected.can_taste
|
||||
|
||||
@@ -2295,6 +2295,7 @@
|
||||
#include "code\modules\paperwork\photography.dm"
|
||||
#include "code\modules\paperwork\silicon_photography.dm"
|
||||
#include "code\modules\paperwork\stamps.dm"
|
||||
#include "code\modules\persistence\persistence.dm"
|
||||
#include "code\modules\planet\planet.dm"
|
||||
#include "code\modules\planet\time.dm"
|
||||
#include "code\modules\planet\weather.dm"
|
||||
|
||||
Reference in New Issue
Block a user