• Hey! Guest! The 40th (!!!) GMC Jam will take place between February 25th, 12:00 UTC to March 1st 12:00 UTC. Why not join in this very special anniversary jam! Click here to find out more!

GMS 2.3+ Creating and storing complex enemy data

I'm working on sort of a 1st-person 1-on-1 fighting game, involving attacking different parts of the body to deal different types of injuries and such. There would be a lot of different enemies with many different body types and sprites, and by extension, different "hardpoints" to attack. So, there would need to be a lot of information about how many hardpoints there are, their positions, hitpoint values, as well as what effects they have. Rather than try to hardcode this information (which would be an absolute nightmare), I setup a room that acts as a building environment, where I can add/remove/modify these hardpoints. But obviously, doing things this way, the information would have to end up as external files.

My question is, how best can/should this information be saved, stored, and loaded in the actual game? I'm not too experienced external file handling, but my main concern is with user tampering, so what would like is somehow having these files included in the .exe and extracted or loaded in at runtime, so even if someone were to obtain and edit the file, it would just be erased and reloaded. I know this was actually fully and easily doable back in GM8 (having files included in the .exe and extracted to the temp folder), but obviously things have changed massively afterward, so I don't know what's actually possible anymore. Since these files would (or at least should) always remain the same, I'm hoping that would help simplify things.
 

Alice

Toolmaker of Bucuresti
Forum Staff
Moderator
Since you're using GM:S 2.3+, how about storing enemies data in structs? Something like:
GML:
global.torso_definitions = {
    regular: { arm_x: 16, arm_y: 16, leg_x: 16, leg_y: 40 width: 32, height: 48 },
    slim: { arm_x: 12, arm_y: 12, leg_x: 12, leg_y: 48, width: 24, height: 56 },
    // ... and so on?
};

// and then make a bunch of definitions for other parts
That way you prevent tampering and also easily define the parameters in GML (without doing massive switch/cases or whatever would be the alternative).
 
Since you're using GM:S 2.3+, how about storing enemies data in structs? Something like:
GML:
global.torso_definitions = {
    regular: { arm_x: 16, arm_y: 16, leg_x: 16, leg_y: 40 width: 32, height: 48 },
    slim: { arm_x: 12, arm_y: 12, leg_x: 12, leg_y: 48, width: 24, height: 56 },
    // ... and so on?
};

// and then make a bunch of definitions for other parts
That way you prevent tampering and also easily define the parameters in GML (without doing massive switch/cases or whatever would be the alternative).
Well, that's actually partially what I've been doing. But like I said, hardcoding that for every animation for every single enemy would be (I feel) far more tedious than necessary, especially if I'm not physically looking at the sprites as they would appear in the "fight." But maybe that's just the way to go?

I was hoping I could use the little "builder" room I have to set up the rigs, then save the final setup to be loaded in-game. Were I to go the hardcode route with structs and such, perhaps I could have the builder room save the result as a file that tells me what to hardcode in?
 

Yal

🍋 *lemon noises*
GMC Elder
I'm not sure if you really need to worry about user tampering these days where modding and romhacks are more popular than ever, you'd potentially lose out on popularity if you make your game too tamper-resistant.

It's relatively easy to save all the contents of a room with a with loop:
GML:
var f = file_text_open_write("dude2.karasu");
with(parent_enemyBodyPart){
  file_text_write_string(f,string(x)); file_text_writeln(f);
  file_text_write_string(f,string(y)); file_text_writeln(f);
  file_text_write_string(f,object_get_name(object_index)); file_text_writeln(f);
}
file_text_close(f)
Just running the testing room with an object that runs that loop should save all the objects in the room for you, then you can load them later by parsing the file. If you're really crafty, you could make the save function create GML code strings instead of just a list of data - then you could just paste it into a script for easy deployment and a lot of tamper resistance!

Since resource IDs change each time you compile, you specifically need to save object names to be able to load them later (unless you set up an array of all usable objects and then save the array index instead).

Included Files still exists in Studio 2; they're basically external read-only files. The files are extracted to the "game bundle" when the game is run (location changes for each export target), however it's possible to override them if the end user knows where the game's working directory is and places a file with the same name there. You can improve tamper resistance by checking the SHA256 of all the files when finalizing them, and before loading them, verify that the SHA is the same as you expect, or else throw a tantrum.
 

Alice

Toolmaker of Bucuresti
Forum Staff
Moderator
I was hoping I could use the little "builder" room I have to set up the rigs, then save the final setup to be loaded in-game. Were I to go the hardcode route with structs and such, perhaps I could have the builder room save the result as a file that tells me what to hardcode in?
Yeah, seems like a sensible approach. Don't know how your rigs work exactly, but I guess you could resonably create some mechanism that generates a string with appropriate structs-defining GML.
That, or have the room running every time you start the game, and setup the correct global variables directly, then move immediately to the next room. This should be even simpler, I think, and maybe the overhead of retrieving all that information from room objects isn't so large compared to hardcoded variables in the first place...? 🤔
 
Yeah, seems like a sensible approach. Don't know how your rigs work exactly, but I guess you could resonably create some mechanism that generates a string with appropriate structs-defining GML.
That, or have the room running every time you start the game, and setup the correct global variables directly, then move immediately to the next room. This should be even simpler, I think, and maybe the overhead of retrieving all that information from room objects isn't so large compared to hardcoded variables in the first place...? 🤔
Yeah, Yal kinda got me thinking about that. Doesn't sound like half-bad an idea actually, especially since they completely reworked scripts. My idea now is to setup a folder in scripts, and make a new script for each enemy. Each rig I make with my "builder" could be saved as a text file containing a GML code that I could then copy-and-paste into a new enemy script. The scripts would run at startup and load and compile each respective struct. I feel that there are perks as well as drawbacks with this approach, a latter being that they would all have a global scope when they might not need to. I might also end up with redundancy issues if at somepoint I decide to rewrite how these rigs are actually defined after already compiling a bunch of enemies using an older definition.
 
Top