• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GML Getting values from a string

Magicwaterz

Member
Hello, I'm currently making a game similar to Bookworm Adventures and I've already set up the basic attacks. I am now trying to add code that basically checks what attacks it contains.
So, these are the variables where it gets its attacks:

Code:
///Attack Lore
AttackLore[0] = "[Att,3]Damage";
AttackLore[1] = "[Fir,1]Fire Tile";
AttackLore[2] = "[Att,3|Sms,2,3|Chr,2,3]Char and Smash";
AttackLore[3] = "[Att,2|Fir,4]Fiery Lineup";
AttackLore[4] = "[Sms,6,2]Smash Tiles";
And this is the code I tried to get values:

Code:
///scr_get_StatLore(exclude character, string, getLore);
var a, b, c;
a = argument0;//characters enclosed to get the string
b = argument1;//the string used
c = argument2;//which data to retrieve
//d = argument3;

var AttLore = ds_list_create();
var AttString = "";
var AttTurn = ds_list_create();
var AttAmnt = ds_list_create();

var chkOpen = string_char_at(a, 1);
var chkClose = string_char_at(a, 2);

//get Attack Lore String
var extractLore = string_copy(b, string_pos(chkClose, b) + 1, string_length(b) - string_pos(chkClose, b));

AttString = extractLore;

//add attacks to a list
var extractAttacks = string_copy(b, string_pos(chkOpen, b) + 1, string_pos(chkClose, b) - 1);

if string_pos("Att", extractAttacks) != 0 {
    ds_list_add(AttLore, 0);
}
if string_pos("Fir", extractAttacks) != 0 {
    ds_list_add(AttLore, 1);
}
if string_pos("Chr", extractAttacks) != 0 {
    ds_list_add(AttLore, 2);
}
if string_pos("Sms", extractAttacks) != 0 {
    ds_list_add(AttLore, 3);
}

//extract values

switch(c) {
    case 0: return AttLore; ds_list_destroy(AttLore); break;
    case 1: if AttString != "" {return AttString} else {return "<MISSING_VALUES!>"}; break;
    //case 3: return AttTurn; break;
    //case 4: return AttAmnt; break;
    default: return "<MISSING_VALUES!>"
}

ds_list_destroy(AttTurn);
ds_list_destroy(AttAmnt);
And an example as how it is used


Code:
var getUnit = obj_Enemy;
var yy = 0;
var xx = 0;
//Draw text
for (var a = 0; a < array_length_1d(getUnit.AttackLore); a++) {
    draw_sprite(spr_LoreBorder_Att, 0, room_width - 196, (room_height div 2) + 96 + yy);
    var getBW = (sprite_get_width(spr_LoreBorder_Att) / 2) - 16;
    var getStr = scr_get_StatLore("[]", getUnit.AttackLore[a], 1);
    var getIco = scr_get_StatLore("[]", getUnit.AttackLore[a], 0);
    draw_set_font(fnt_AttackLore);
   
    //Draw text  
    for (var b = 0; b < ds_list_size(getIco); b++) {
        var multi = false;
        if ds_list_size(getIco) != 1 {
            multi = true;
        }
        switch(getIco[| b]) {
            case 0:
                if multi == false {
                    draw_sprite(spr_AttackIcons, 0, room_width - 196 - getBW + xx, (room_height div 2) + 96 + yy);
                }
                else
                {
                    draw_sprite_ext(spr_LoreBorder_Att, 1, room_width - 196, (room_height div 2) + 96 + yy, 1, 1, 0, c_white, 0.5);
                    xx -= 32;
                }
                ;
                break;
            case 1: draw_sprite(spr_AttackIcons, 1, room_width - 196 - getBW + xx, (room_height div 2) + 96 + yy); break;
            case 2: draw_sprite(spr_AttackIcons, 2, room_width - 196 - getBW + xx, (room_height div 2) + 96 + yy); break;
            case 3: draw_sprite(spr_AttackIcons, 3, room_width - 196 - getBW + xx, (room_height div 2) + 96 + yy); break;
        }
        xx += 32;
    }
    var getdef = string_height(getStr);
    var getHt = string_height_ext(getStr, -1, 312);
    draw_text(64, 64 + yy, getHt);
    draw_text_ext_transformed(room_width - 156, (room_height div 2) + 96 + yy, getStr, -1, 312, getdef / getHt, getdef / getHt, 0);
    xx = 0;
    yy += 32;
   
    //Draw Icons
   
}
Now this seem to work for now but I don't want to repeatedly use the string_pos() block of code in the script just to get the sprites I wanted when used.

I just want to know if there's anyway I can make the script smaller wherein I can.
1) Return the string of the attack name (So that "[Att,3]Damage" will only return "Damage")
2) Return the string of the attack type so that it can identify what sprite to use (So that "[Att,3]Damage" will return "Att" and it will assign a sword sprite)
3) Return a value from the attack type, so that it can assign how much damage it deals ("[Att,3]Damage" will return a damage value of 3) ;
or assign the number of objects to be affected and how long it lasts ("[Sms,6,2]Smash Tiles" will return a value of tiles = 6 and turns = 2)
4) Able to segragate the attack types ("[Att,3|Sms,2,3|Chr,2,3]Char and Smash" are all different and should return "Att" with 3, "Sms" with tiles = 2 and turns = 3, and "Chr" with tiles = 2 and turns = 3)

I know this all too much to ask so a nice easy to understand terms and step is of great help as I only know coding up to a surface level. And I am using GMS 1.4 by the way.
 

FrostyCat

Redemption Seeker
Don't call that script on-demand. Instead try parsing all of the moves in an earlier one time event (e.g. at game start) into an array or data structure, making it so that picking at individual properties is a simple lookup instead of a function call. This is a classic example of space-time tradeoff.
 

Magicwaterz

Member
Don't call that script on-demand. Instead try parsing all of the moves in an earlier one time event (e.g. at game start) into an array or data structure, making it so that picking at individual properties is a simple lookup instead of a function call. This is a classic example of space-time tradeoff.
Exactly what I wanted but that's the thing, I don't know how exactly I'm gonna parse these properties. I wanted them to be in a ds_map for easy access. That way when it calls for a "Sms", it will then just refer to its contents of turns and amounts.

EDIT:
Well, parsing for the attack name is easy since it is always found at the end of the string. How about parsing those enclosed in the brackets? That's the one I have the most trouble with.
 
Last edited:

FrostyCat

Redemption Seeker
Is this data hard-coded into the game, or is it read from a file or another external source? If it is built-in, I think you should just give up on this system and redo it without any parsing. A data model that makes you bend over backwards to do its most commonly performed work is wrong.

Here's an example with a 2D array and an enum:
Code:
enum LORE {
  NAME,
  ATT,
  FIR,
  SMS_TILES,
  SMS_TURNS,
  CHR_TILES,
  CHR_TURNS,
  N
}
// Set number of entries here
var total_count = 5;
// Set up all default values
for (var i = total_count-1; i >= 0; i--) {
  for (var j = LORE.N-1; j >= 0; j--) {
    AttackLore[i, j] = undefined;
  }
}
// Add specific values
AttackLore[0, LORE.NAME] = "Damage";
AttackLore[0, LORE.ATT] = 3;
AttackLore[1, LORE.NAME] = "Fire Tile";
AttackLore[1, LORE.FIR] = 1;
AttackLore[2, LORE.NAME] = "Char and Smash";
AttackLore[2, LORE.ATT] = 3;
AttackLore[2, LORE.SMS_TILES] = 2;
AttackLore[2, LORE.SMS_TURNS] = 3;
AttackLore[2, LORE.CHR_TILES] = 2;
AttackLore[2, LORE.CHR_TURNS] = 3;
AttackLore[3, LORE.NAME] = "Fiery Lineup";
AttackLore[3, LORE.FIR] = 4;
AttackLore[4, LORE.NAME] = "Smash Tiles";
AttackLore[4, LORE.SMS_TILES] = 6;
AttackLore[4, LORE.SMS_TURNS] = 2;
It's easy to see how this form has efficient one-line solutions for everything you've asked for. Even if you're getting data from a file, chances are you'll be parsing it down to a form similar to this for easy access later.
 
Top