[ SOLVED ]

Fredrik

Member
Hey.
I'm making a dungeon crawler, and the entire game takes place in only one game maker room.
I've made a system which will generate a random dungeon, and when you find the way down to the next floor it will delete the current generated level and generate a new one. However, if you want you can still go back up to the previous floor, but that one has been removed and will be regenerated. This system works just fine, but there's a big flaw, which is that everything you did in that previous floor / dungeon will not be saved and will be generated again. So if you throw a sword on the ground, go down a floor and then back up again, that sword will not be there as it has been deleted. The same goes for everything else you can interact with, like chests, crates, enemies and so on.
What I'm wondering is if someone has a great idea to perhaps be able to save the progress you did in the previous dungeon so it will stay that way when you go back up?

I have one suggestion for this, but I have no idea if it will work, and it would take alot of work and time to try it out.

Idea:
As of now I use .ini files to save everything. Everything from your inventory, settings, dungeon seed and so on. The idea I have is to use game maker's save system as well. It will have to make a new save file for each floor for the entire game, but I don't think that's gonna be a problem. So each time you enter a new floor, it will save the game with game maker's save function, and it will also do so right before you enter a new floor, and each time you go back up a floor it will first load the save file which is saved for that specific floor (which actually takes you back in time / to a previously saved file), and right after that it will load all the info from the .ini files, so all the progress you did after you went down from the floor that you now have went back up to (like items you've found, health you've taken and so on...) will still remain even though you've kinda restored an "older" save file.

I have no idea if this will work or not, and I hope maybe there's a game maker guru that might have some thoughts about it. If it works like I hope, result will be just as it is in the game right now, but when you go back to a previous floor, everything you did there, like killing enemies, open chests, items thrown on the ground and what not, will remain just the way that you left it.

If anyone has any other ideas for this I'd really appreciate it!

Edit:
I want to mention that I've tried using game maker's save system before, but that was before I started using .ini files. I know I decided to go for ini as game maker's save system didnt work properly. It worked perfectly if you saved and loaded while playing, but if you saved, then quit the game, and then reopened it it would mess up some of the 3D lights, and some blending, as well as some stuff from shaders. I never tried to make it so it loaded the save file, and then set the lighs, blends, shaders, whatever, so that might work.
I believe that it will work, but I'm afraight that I might put lots of time and effort into making it, only to realise that it will mess with the lightning, blend, shaders and stuff like that :/

Thanks for reading :]
 
Last edited:

Fredrik

Member
ini files would work but I would say use a ds_map it works logically the same with keys and values and you can do a secure save that handles the security for you.
https://docs2.yoyogames.com/source/_build/3_scripting/4_gml_reference/data_structures/ds maps/index.html
Thanks for replying.
So I tried to play around with game maker's save/load function, and I still get the same bugs + more that I used to get the last time I tried it. So using that is out of the question.
I tried looking into ds_list and ds_map and watched some tutorials, and I see how I could use this, but I would need some help :p

So, when a level is generated it will generate lots of instances you can interact with, like creates, barrels, jars, vases, planks (boarded on doors), doors, locks (on doors), enemies, items and lots of other instances. I assume that if I were to use data structures I would have to make a system to loop thought every instance of a given object that is currently in the room and store it's values that I want to store ? Like, look thought all crates in the room, and store their position and if they've been broken by the player or not, or something like that. As mentioned I watched some tutorials, but I'm not quite sure how to do this in my particular situation.

Also, quick question: when a level is generated it's filled with lots of instances as mentioned, and all these instances have an instance id. So let's say that a level is generated and all the instances have an id. So now, if I quit the game and reopen it, it will regenerate the same level based on what is saved in my .ini file, but will all the instances in the level still have the same instance id as they had before I quit the game? or will they have exactly the same instance id?
 

Fredrik

Member
I found a working solution and thought I'd share it incase anyone else need help with something similiar in the future.

I basically did it like this, when the dungeon is generated:

Code:
/// test new save system (create).
var br = "breakable.ini";

ini_open(br);
    
with obj_breakable
    {
    ini_write_real('breakable',string(id)+"a",broke);
    ini_write_real('breakable',string(id)+"b",breakable);
    }
    
ini_close();
and when reloading the game after qutting:

Code:
/// load state.
var br = "breakable.ini";

if file_exists(br)
    {
    ini_open(br);
    broke     = ini_read_real('breakable',string(id)+"a",0);
    breakable = ini_read_real('breakable',string(id)+"b",choose(1,2,3));
    ini_close();
    }
this works just fine, and all crates / barrels that I break will stay broken when I reload the game :)
 

Fredrik

Member
Just be careful with using instance id's in your save system, they are not always the same each time you run the game.
Is there a way to make sure the id always will stay the same? because all instances that are being generated in-game now will always be spawned in in the same order, so I thought as long as they all get spawned in in the same order they'd get the same id (?)
 

curato

Member
I think there was an old version that gave consistent instance id's but that isn't the case in the current version. I think that tutorial I link suggests a way to create a unique id for your instances
 

Fredrik

Member
I think there was an old version that gave consistent instance id's but that isn't the case in the current version. I think that tutorial I link suggests a way to create a unique id for your instances
This tutorial actually explains exactly what I'm trying to do. It was of great help :)
 

Fredrik

Member
@IndianaBones
You were right. I'm confident that the system I made using id's would work if the id's were consistent.

@curato
I tried using the tutorial you posted to copy PixelatedPope's system, since it actually did exactly what I was trying to do. However, I could not manage to implement it into my own project, but his tutorial... especially the script he made to give all instances an unique id, gave me ideas for my own similiar system using ini. I decided to use ini as the current working save system I have for my game uses ini files, and it works perfecly + I already have experience with ini compared to data structures.
I thought I'd share this as well, in case anyone else needs something similiar, and I can confirm that this system works (atleast with my project). I also want to point out that in my project I'm already saving everything else with a ini system, and this current example is only to demonstrate a way to make "props" like crates, barrels, jars, chests, enemies and what not stay broken / killed whenever you go back and forth between dungeon levels.

First of all, the instance id generate script:

Code:
return string(global.currentfloor) + object_get_name(object_index) + string(x) + string(y);
Then in the Create Event for each type of object I want to be affected by this (ex: obj_crate):

Code:
/// load state.
var _br = "breakable.ini";

myid = generate_instance_id();
save_state = 0;

if file_exists(_br)
    {
    ini_open(_br);
    
    broke = ini_read_real('breakable',myid,0);
    
    ini_close();
    }
Then in the save event in my game (whenever you go down / up to a new / previous floor):

Code:
/// save state.
if save_state = 1
    {
    var _br = "breakable.ini";

    if file_exists(_br)
        {
        ini_open(_br);
        
        ini_write_real('breakable',myid,broke);
        
        ini_close();
        }
    
    save_state = 0;
    }
This simple system will save if the current crate has been broken or not, and save the state so it keeps being broken.
This system is based on checking if the obj_breakable is at floor 1, is in fact obj_breakable, and if it's at it's x and y position.
 

Yal

šŸ§ *penguin noises*
GMC Elder
Not just instance IDs change each time you restart a game, asset IDs potentially change as well. If you need to save e.g. an object, the easiest way is to save its name and then use asset_get_index on those while loading (though it's not exactly the most efficient or tamper-proof way, of course).

If you generate the entire level, shouldn't it be enough to just save the seed to be able to recreate it?
 
Is there a way to make sure the id always will stay the same? because all instances that are being generated in-game now will always be spawned in in the same order, so I thought as long as they all get spawned in in the same order they'd get the same id (?)
That may well be the case, but as id assignment is internally controlled by GMS, there is no guarantee this will always stay the same down the road.

I ended up saving all my assets using a similar method to the ds_map tutorial above, using object_get_name()/asset_get_index(). In addition, I assign a guid to all my instances as well, due to having to maintain links between some instances. For example, one instance might be set to rotate around another. So it will record the guid of the instance it orbits, and once I have loaded the level, I can then find the target instance via the guid, and save a reference to its instance id for use during the game. That way it won't matter if the instance id changes, I'll always be able to locate the correct target.

Your method of using object name plus position is the same principle, just using a different unique identifier. There may be the odd chance of two instances having the same identifier though. If an instance was at position (55,150), and another instance of the same object was at (551, 50), they would conceivably end up with the same key.
 

Fredrik

Member
@Yal
That's nice to know. Yeah that's true. Dungeon generation and saving works just fine. The save system I posted above is only to save certain states for certain instances. Like if you've broken certain crates or barrels, or if you left a door open and what not. So it saves it even if you go down to a new dungeon floor and then back up again. It's probably not the most efficient way of doing it, but it works ^^

@IndianaBones
Thanks for sharing that :) yeah that's probably true, but if two instances happend to get the same id, the worst thing that can happend is that a door what you left open might be closed, or a crate you've broken might not be broken any more, and so far when testing I've not experienced it, so hopefully it wont happend often :)

Thanks for replying.
 
Top