Convert bellies to save using JSON

This commit is contained in:
Arokha Sieyes
2018-03-02 02:22:20 -05:00
parent 03e8627fe0
commit 8a8c4d76d2
7 changed files with 214 additions and 67 deletions

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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"