Implementing items holding creatures

Now I’m writing this for a pokemon mod, but it would be adventageous if it was possible to put your cat into a cat-carrier so that driving doesn’t result in predominantly dead pets(my poor dog)

I’m having an issue implementing it, as writing a unique_ptr as coolthulu suggested prevents compilation, and provides no end to awful error messages due to it never being initialized properly(and copy constructors make having a proper unique_ptr a difficult implementation).

Also there isn’t much precedent for nesting a creature (and it’s protected store method) into item serialization(which is already weird anyway). This leaves a rather unpalatable option, just using raw monster pointers. This has lead to complicated issues already, among the worst being that the creature can’t be placed properly without a segfault(I think)

Taking a creature like this also results in not having any control over where the creature ends up when it is added back to the map. All of my attempts to copy the monster instance and then have it move to the new location fail.

Do any of you have any tips on any of these issues?

I think I’ve got a simple trick to avoid dealing with unique_ptr problems:
Using a vector of monsters rather than unique_ptr or pointer to one.

That way most of the functions - including (de)serialization would probably be pretty simple and handled automatically.

You could just assume that this vector is 0 or 1 element. item::contents works like this, except with items rather than monsters.

Do you really need to bloat the item class with a member that is not used by 99.9% of all item instances?

I assume you don’t need to know or act upon the monster when it is in the item. In this case, you can serialize it into a nice JSON string and store that string in an item variable. Folding vehicles are implemented the same way (see [tt]vehicle::fold_up[/tt] and [tt]vehicle::restore[/tt] and [tt]iuse::unfold_generic[/tt].

const monster& mon = ...;
item new_item( ... );

try {
    new_item.set_var( "contained_monster", mon.serialize() );
} catch( const std::string &e ) {
    debugmsg( "Error storing monster: %s", e.c_str() );
}

try {
    monster new_monster;
    new_monster.deserialize( new_item.get_var( "contained_monster" ) );
    // don't use setpos, use spawn for the initial position:
    new_monster.spawn( ... );
    g->add_zombie( new_monster );
    new_item.erase_var( "contained_monster" );
} catch( const std::string &e ) {
    debugmsg( "Error restoring monster: %s", e.c_str() );
}

[quote=“Coolthulhu, post:2, topic:10240”]I think I’ve got a simple trick to avoid dealing with unique_ptr problems:
Using a vector of monsters rather than unique_ptr or pointer to one.

That way most of the functions - including (de)serialization would probably be pretty simple and handled automatically.

You could just assume that this vector is 0 or 1 element. item::contents works like this, except with items rather than monsters.[/quote]
Ah, I just used a shared_ptr in the end. It hasn’t produced anything unpleasant yet, however it does not stack the items properly based on the different contents.
Though it does end up lacking in terms of serialization. I’ll see if the archive function accepts that.

[quote=“BevapDin, post:3, topic:10240”]Do you really need to bloat the item class with a member that is not used by 99.9% of all item instances?

I assume you don’t need to know or act upon the monster when it is in the item. In this case, you can serialize it into a nice JSON string and store that string in an item variable. Folding vehicles are implemented the same way (see [tt]vehicle::fold_up[/tt] and [tt]vehicle::restore[/tt] and [tt]iuse::unfold_generic[/tt].

[code]
const monster& mon = …;
item new_item( … );

try {
new_item.set_var( “contained_monster”, mon.serialize() );
} catch( const std::string &e ) {
debugmsg( “Error storing monster: %s”, e.c_str() );
}

try {
monster new_monster;
new_monster.deserialize( new_item.get_var( “contained_monster” ) );
// don’t use setpos, use spawn for the initial position:
new_monster.spawn( … );
g->add_zombie( new_monster );
new_item.erase_var( “contained_monster” );
} catch( const std::string &e ) {
debugmsg( “Error restoring monster: %s”, e.c_str() );
}
[/code][/quote]
It would be ideal if the name of the monster was stored so that you could tell if the thing inside the carrier was, for example, a cat or a dog. I think that I could probably just add another variable using the same method to store the name of the monster.
Also thanks for the advice on the positioning, that was causing debug messages to pop up a lot.

Edit: Works like a charm, I’ll just get it to work in a more… carrier like way so that it has a place in the game. Finally, we can have pets and go for drives without them chasing the car and dying.

It would be ideal if the name of the monster was stored

You can use the item var “name”, just like the folded vehicle does. It is already looked up and used by [tt]item::tname[/tt] and similar functions.

Thanks. That actually makes it work completely well, though I did find that it was necessary to modify the item::info function to have it not stack all of the items together into a single stack ignoring the contained monster’s type. Anyway, it’s working well now, and it has enough functionality for me to consider making a pull request.

Thanks for all the help.