ID:272919
 
I want a way to save a mob, in my save file or whatever, and be able to duplicate that mob as many times as I want, regardless if the server has rebooted

Does such a library exist? Want to check before I embark on a quest to make one myself.

EDIT: A little bit of information on what i'm asking for. For a Dungeons & Dragons type of game, it would be nice to save created NPCs for the dungeon master to spawn multiple versions of later on, such as Bats/Monsters/Townsfolk, etc.
This would not require a library in any way. It is exactly the same as saving and loading anything else from a savefile. There's no requirement that what you load from a savefile be a special, unique flower with no copies ever created.

var/savefile/sandviches

obj/sandvich
verb
addtopping(var/T as text|null)
if(!T) return
if(name == "sandvich")
name = T
else
name += ", "
name += T
look()
if(name == "sandvich")
usr << "Just bread."
else
usr << "A sandvich with [name]."
save(var/N as text|null)
if(!N) return
if(!sandviches) sandviches = new("sandviches.food")
//save, the prefix sandvich_ is used so no silly buggers can be played by naming a sandvich "names"
sandviches["sandvich_[N]"] << src

//keep a list of sandvich names, too
var/list/names
sandviches["names"] >> names
if(!names) names = list()
//no duplicate names
if(!(N in names))
names += N
sandviches["names"] << names

mob/verb/makesandvich()
if(!sandviches) sandviches = new("sandviches.food")

//get a list of sandviches we have saved
var/list/names
sandviches["names"] >> names

//if none have been saved, create bread
if(!names)
new /obj/sandvich(usr)

else
var/N = input("which sandvich do you wish to make?", "make sandvich") as null|anything in names

//lettuce create an empty sandvich
if(!N)
new /obj/sandvich(usr)

//otherwise, load one
else
var/obj/sandvich/S
sandviches["sandvich_[N]"] >> S
//double-check that we actually loaded something (but it should always exist, anyway)
if(S)
S.loc = src
//look at it, of course.
S.look()


I guess that went on a bit longer than I expected it to. You have to be careful with savefiles.
In response to Garthor
Garthor wrote:
This would not require a library in any way. It is exactly the same as saving and loading anything else from a savefile. There's no requirement that what you load from a savefile be a special, unique flower with no copies ever created.

I guess that went on a bit longer than I expected it to. You have to be careful with savefiles.

I see. Using this system, i'd be able to save entire mobs, correct? Of course, couldn't i just use a list for that?

var/list/moblist=new()

var/mob/savedmob=moblist[55] or something or other? Sorry if i'm not sounding logical. I'm sick atm >.>.
In response to Mista-mage123
There is no functional difference between saving mobs and saving objs, so yes. The difference between using a list and using a savefile is that a savefile is saved between sessions. You could, of course, use a list and then save that list in a savefile, but it would mean that you're rewriting the whole savefile every time you save a single new mob, which could result in a lot of overhead if you did it a lot.
In response to Garthor
Garthor wrote:
There is no functional difference between saving mobs and saving objs, so yes. The difference between using a list and using a savefile is that a savefile is saved between sessions. You could, of course, use a list and then save that list in a savefile, but it would mean that you're rewriting the whole savefile every time you save a single new mob, which could result in a lot of overhead if you did it a lot.

I see..

So instead, something like this would be applicable?

//Trying to type this from memory alone

var/savefile/hypermemory

mob/verb/makemob()
var/mob/a = new()
a.name="[rand(1,9999)]" //Give it a random name to distinct it from the rest

mob/proc/savemob()
var/N=hypermemory["Length"]
if(!N) N=0
N++
hypermemory["Slot [N]"] << src
hypermemory["Length"] << N

world/proc/loadmobs()
var/N=hypermemory["Length"]
if(!N) N=0
while(N>0)
var/mob/a
hypermemory["Slot [N]"] >> a
N--



//Is saving done automatically? Not sure where to put it in the code.
In response to Mista-mage123
Saving is not done automatically, so you'd need to do it whenever you want to save things. Generally, the answer is, "periodically, and on world/Del()", if you're planning on saving the entire world. If you just want to keep your list of created mobs, then you'd simply want to save them whenever you create a new one, so you'd put it in makemob().

What you have would work, but I should point out that loc does not get saved, nor would any other tmp variable. Generally, variables are tmp if they cannot be saved and loaded properly, such as the built-in loc (as it's an instance of a turf which may no longer exist when loaded) or if you user-define it, such as a player's target for example (which has the same issue and so should be declared tmp, ie var/tmp/mob/target). So, the classic way of saving loc:

mob
Write(var/savefile/F)
..()
//only save our x,y,z if we're standing on a turf
if(isturf(loc))
F["x"] << x
F["y"] << y
F["z"] << z

Read(var/savefile/F)
..()
var/ lx, ly, lz
F["x"] >> lx
F["y"] >> ly
F["z"] >> lz
if(lx && ly && lz)
loc = locate(lx, ly, lz)


Write() is called when you save something via F << something, and Read() is called when you load something via F >> something. You should look them up in the reference.
In response to Garthor
Garthor wrote:
Saving is not done automatically, so you'd need to do it whenever you want to save things. Generally, the answer is, "periodically, and on world/Del()", if you're planning on saving the entire world. If you just want to keep your list of created mobs, then you'd simply want to save them whenever you create a new one, so you'd put it in makemob().

I would put what in make mob? What would I do to make the save file save whenever i make a new mob, or am I already set as far as saving/loading goes?


Oh, and locs don't really concern me too much. In my games, i never save locs generally. Thanks though ^_^
In response to Mista-mage123
You'd simply call the savemob() proc you've already written whenever you created a new mob that you wanted to save.

It really is just, "save when you want to save."
In response to Garthor
So I don't need to put Write() or Read() in that code? Phew. >.>

Thanks man, you've helped me a lot.
In response to Mista-mage123
Ugh, what'd I do wrong this time?

I've made a basic test, compiled it, no errors. And ran. The mobs never loaded when i rebooted the world.

#define DEBUG

var/savefile/hypermemory

mob/verb/makemob()
var/mob/a = new()
a.name="[rand(1,9999)]" //Give it a random name to distinct it from the rest
usr << "Created [a.name]"
a.savemob()

mob/proc/savemob()
if(!hypermemory)
hypermemory = new("hypermemory.mobs")

var/N=hypermemory["Length"]
if(!N) N=0
N++
hypermemory["Slot [N]"] << src
hypermemory["Length"] << N

proc/loadmobs()
var/N=hypermemory["Length"]
if(!N) N=0
while(N>0)
var/mob/a
hypermemory["Slot [N]"] >> a
world << "[a.name] says hi!"
N--


world.New()
if(!hypermemory)
hypermemory = new("hypermemory.mobs")
loadmobs()
In response to Mista-mage123
Write() and Read() are called every time you save / load an object. You need to override them if you need additional functionality besides simply saving every variable that isn't tmp, const, or global. As another example, if you have a method for changing the icons of the mobs, then every entry will contain the entire icon file in it, even if the icon is only one of a limited number of choices. This will make your savefile Very Big and A Little Bit Slower. So, you'd want to not save the icon (you can prevent Write() from not saving something with something=initial(something) on some line before ..()) and instead save simply the selection you made earlier, and then in Read() you'd grab that selection and set the icon properly.
In response to Mista-mage123
They did load, but world/New() occurs before you connect, so you never received the messages. And, if you were to look for the mobs after the fact, you would not find them, because they were deleted by the garbage collector (no location, no running procs, no references to them, so they're deleted).
In response to Garthor
Garthor wrote:
They did load, but world/New() occurs before you connect, so you never received the messages. And, if you were to look for the mobs after the fact, you would not find them, because they were deleted by the garbage collector (no location, no running procs, no references to them, so they're deleted).

How would I prevent the garbage collector from deleting it?

#define DEBUG

var/savefile/hypermemory

mob/verb/makemob()
var/mob/a = new()
a.name="[pick(list("Alpha","Beta","Charlie","Delta","Echo","Foxtrot"))] [rand(1,9999)]" //Give it a random name to distinct it from the rest
usr << "Created [a.name]"
a.savemob()

mob/proc/savemob()
if(!hypermemory)
hypermemory = new("hypermemory.mob")

var/N=hypermemory["Length"]
if(!N) N=0
N++
hypermemory["Slot [N]"] << src
hypermemory["Length"] << N

proc/loadmobs()
var/N=hypermemory["Length"]
if(!N) N=0
while(N>0)
var/mob/a
hypermemory["Slot [N]"] >> a
world << "[a.name] says hi!"
N--
a.loc=locate(1,1,1) //Doesn't seem to work. Though there is no map, but some games I'd like to work this into don't have maps either.

mob/verb/search()
for(var/mob/a in world)
usr << "found [a]"

mob/verb/initiateload()
if(!hypermemory)
hypermemory = new("hypermemory.mob")
loadmobs()
In response to Mista-mage123
If you want the garbage collector to not delete the mobs, then they need to be used. If you want them to simply exist, then you'll have to keep a list of them, which satisfies there being a reference to them, and so they won't be deleted. So, when you load them, just add them to some global list and they'll be left alone.

Basically: if there's some way for something to happen with that mob, without having to use for(var/mob/M in world), then it won't be deleted by the garbage collector.