• 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!

Legacy GM Trying to make a leaderboard, but it won't read part of my code?

L

Linkruler

Guest
Before I get too far, I followed this tutorial to get this code.

So I've been working a couple of days now to make a working leaderboard. Not knowing of a reliable way to make this, I followed slasher's tutorial on making a leaderboard. After following all of the steps, the system does not work still, and I am not sure why.

Let me explain my current setup. When the player gets a game over in-game, they will be taken to a continue screen. If they select no to continue or let the timer run out, then it brings up another game over screen. From here, they have to push the jump button to proceed, where it will ask for their name (which uses a get_string_async command). From there it follows the async dialogue command below:
Code:
var i_d = ds_map_find_value(async_load, "id")

if i_d == name
{
    if ds_map_find_value(async_load, "status") //user selecting ok
    {
        if ds_map_find_value(async_load, "result") != "" //name not blank
        {
            global.name = ds_map_find_value(async_load, "result") //get the name entered
            //open ini file
            ini_open("config.ini")
            for (i = 0; i<10; i++)
            {
                global.score_array[i,0] = ini_read_string(string(i), "Name", "unknown")
                global.score_array[i,1] = ini_read_string(string(i), "Score", "0")
                global.score_array[i,2] = ini_read_string(string(i), "Completion", "incomplete")
            }
            ini_close()
           
            //find first spot where player's score is greater
            for (i = 0; i < 10; i++)
            {
                if (score >= global.score_array[i, 1])
                {
                    for (j = 9; j>i; j--)
                    {
                        global.score_array[j,0] = global.score_array[j-1,0];
                        global.score_array[j,1] = global.score_array[j-1,1];
                        global.score_array[j,2] = global.score_array[j-1,2];
                    }
                    global.score_array[i,0] = global.name;
                    global.score_array[i,1] = score;
                    global.score_array[i,2] = global.completion;
                    break;
                }
            }
            ini_open("config.ini")
            for(i=0; i<10; i++)
            {
                ini_write_string(string(i), "Name", global.score_array[i,0]);
                ini_write_string(string(i), "Score", global.score_array[i,1]);
                ini_write_string(string(i), "Completion", global.score_array[i,2]);
            }
            ini_close()
            room_goto(rm_menu1)
        }
    }
}
From here, things seem to not work. For one, it ignores all of the code inside the if (score >= global.score_array[i, 1]) brackets. I tested the different sections by playing a sound at different sequences.

Concerning other parts of this system, I currently don't have it loading the data at the start, since I'm not exactly sure what to write. This is the code I have at bootup to initialize the variables:
Code:
//Load scores and name for leaderboard
ini_open("config.ini")
for (i = 0; i < 10; i++)
{
    global.score_array[i,0] = "Name"
    global.score_array[i,1] = 0
    global.score_array[i,2] = "incomplete"
}
ini_close()
The data in the .ini will read after going through the async dialogue, but I'm not sure why I can't get it to run beforehand (I tried to set the same commands in the boot room's creation code and it errored out saying that it was not an array)

If you have need for any other code, feel free to ask
 
L

Linkruler

Guest
Is there any other information I can provide to get this solved? I've still been messing around with this without finding any success :(
 
S

Squareworx Studio

Guest
Hi, just a quick tip. You are trying to compare variable score to global.score_array, however you are saving global.score_array as a string. Change the code for the global.score_array part to ini_write_real and ini_read real. Then when you compare the two it should work.

Hope this helps
Kind Regards
Squareworx studio
 
L

Linkruler

Guest
Hi, just a quick tip. You are trying to compare variable score to global.score_array, however you are saving global.score_array as a string. Change the code for the global.score_array part to ini_write_real and ini_read real. Then when you compare the two it should work.

Hope this helps
Kind Regards
Squareworx studio
It's starting to work now, thank you! I can get the leaderboard loaded and it can also write in the new values when the game over screen is entered. Now that I have it fundamentally working, I'm a little unsure how to fix the next set of issues I'm facing. Currently, the name and completion status are being written into the ini as numeric values (seems to mainly assign to 0, but the name variable also sometimes writes as 1?).

When it's being written, it follows this string:
for(i=0; i<10; i++)
{
ini_write_real(string(i), "Name", global.score_array[i,0]);
ini_write_real(string(i), "Score", global.score_array[i,1]);
ini_write_real(string(i), "Completion", global.score_array[i,2])

And just before this, I made saved the variables as such:

global.score_array[i,0] = global.name;
global.score_array[i,1] = score;
global.score_array[i,2] = "Incomplete";

Even when the array should just equal "Incomplete" it sets it to 0 in the ini. What would be the best way to change it?
 
S

Squareworx Studio

Guest
remember when you write to an ini with the suffix "_real", then it should always be a number. however if you write to an ini with the suffix "_string" then it should always be a string captured within -> "example"

the same would apply when reading from an ini.

in other words:

ini_write_real(string(i), "Name", global.score_array[i,0]); <- this is flawed, it should be: ini_write_string(), but if you had a number for an answer that you wanted to use <=>/*+- with or any other math functions then you use ini_write/read_real();

please note as well the arguments you are providing to the ini_write/read is incorrect it should be someting in this fashion -> ini_write_real("Leaderboards/Scores",global.score_array[i,0],global.score_array[i,1]);
var scoregetvalue = ini_read_real("Leaderboards/Scores",global.score_array[i,0],0);

I hope this helps
 
L

Linkruler

Guest
remember when you write to an ini with the suffix "_real", then it should always be a number. however if you write to an ini with the suffix "_string" then it should always be a string captured within -> "example"

the same would apply when reading from an ini.

in other words:

ini_write_real(string(i), "Name", global.score_array[i,0]); <- this is flawed, it should be: ini_write_string(), but if you had a number for an answer that you wanted to use <=>/*+- with or any other math functions then you use ini_write/read_real();

please note as well the arguments you are providing to the ini_write/read is incorrect it should be someting in this fashion -> ini_write_real("Leaderboards/Scores",global.score_array[i,0],global.score_array[i,1]);
var scoregetvalue = ini_read_real("Leaderboards/Scores",global.score_array[i,0],0);

I hope this helps
Aha, I got things fixed now! After changing the commands to ini_write/read_string I finally got the leaderboard finally working. One thing to note is that I needed to keep the string(i) in the read/write files or it would not read the data as an array, and instead write one line of data. Thank you for your help, I really appreciate it :)

One more question I have, if someone has an answer to it, is that I'm trying to limit the length of the name to 15 characters. I'm trying to work with the string_length command to get this to work, but I'm not sure where to place it in my code and I don't know which variable I should be using (I assumed I needed the variable I have (name) but it doesn't seem like that's going through properly)
 
S

Squareworx Studio

Guest
var lengthlimit = 10;
for (i = 0; i < 10; i++)
{
global.score_array[i,0] = "Name"
if string_length(global.score_array[i,0]) > lengthlimit
{
global.score_array[i,0] = string_copy(global.score_array[i,0], 1,lengthlimit);
}
global.score_array[i,1] = 0
global.score_array[i,2] = "incomplete"
}

perhaps something like this, you would always do the string copy once directly after giving the variable a string ""
 

Fabseven

Member
I am not fammiliar with ds_map but i have done this using arrays only :
project :: https://we.tl/XBKZ8bUhFr

Code:
script : string_explode
var str = argument0
var sep = argument1
var n = argument2
var l = string_width(str)
show_debug_message("*** explode "+ str + " with sep = "+ sep + " ; n = " + string(n)+"***")
show_debug_message("str l = " + string(l))

var j=1;
var str_return = ""
var str_start=0
var str_count=0
for(var iii=0 ; iii < l ; iii++)
{
    //show_debug_message("char =" + string_char_at(str,iii)) 1;????;0
    if( string_char_at(str,iii) == sep)
    {
        show_debug_message("## char == sep")
        show_debug_message(" j == n ?" + string(j) +"/"+string(n))
        if( j == n)
        {
            str_return = string_copy(str,str_start,str_count-1)
            show_debug_message("return = "+ str_return)
            return str_return
        }
        j++
        str_start=iii+1
        str_count=0
    }
    str_count++
}
Code:
Information about object: obj_scoreboard
Sprite:
Solid: false
Visible: true
Depth: 0
Persistent: false
Parent:
Children:
Mask:
No Physics Object
Create Event:
execute code:

///variables

tabScore[10] = 0
fname = "highscore2016.txt" //filename
stream = noone
sep = ";"
stream = file_text_open_read( working_directory + fname)
show_debug_message("working@" + working_directory + " stream =" + string(stream))

if( stream == -1) //-1 = file not existing
{
   show_debug_message("file not exist")
    //init values
    //file_text_close(stream);
    stream = file_text_open_write(working_directory + fname);
    show_debug_message("file created :" + string(stream))

  
    i=1
    s = 1000
    n = "???"
    repeat(10)
    {
        if(i==1) { n = "fabseven";} else { n = "???";}
  
        line = string(i)+sep+n+sep+ string(s)+sep
        show_debug_message("inserting :: " + line)
        file_text_write_string(stream, line);
        file_text_writeln(stream)  
        i++
        s = s - irandom_range(0,100)
    }
  
  
    file_text_close(stream);
  
  
}

    stream = file_text_open_read( working_directory + fname)
    i=0
    j=1
    c=0
    repeat(10)
    {
       line_str = file_text_readln(stream);
       show_debug_message("line" + string(i) + " = " + line_str)
    
        tabScore[i,0] = string_explode( line_str,sep,1)
        tabScore[i,1] = string_explode( line_str,sep,2)          
        tabScore[i,2] = string_explode( line_str,sep,3)          
       i++
       j++                  
    }

Draw GUI Event:
execute code:

var r=0
var margey = 15
var starty = y + 50
var startx = x + 50

draw_sprite(spr_highscore,0,x,y)
  draw_text(startx,starty, "n°")
        draw_text(startx+50,starty,   "Name")
            draw_text(startx+200,starty,    "Score")

starty += margey*1.5

repeat(10)
{
    if(r == 0)
    {
        draw_sprite_ext(spr_top,0,startx - 15,starty ,0.5,0.5,0,c_white,1)
    }
    draw_text(startx,starty,    tabScore[r,0])
        draw_text(startx+50,starty,    tabScore[r,1])
            draw_text(startx+200,starty,    tabScore[r,2])

          
    r++
    starty += margey
}
final result : file created and reading it and then draw it :
highscore_capture.PNG
You wanted something like that ?
Got some hard times with it because explode doesnot exist as a built-in function in gms1.4 (such a shame !)
 
L

Linkruler

Guest
var lengthlimit = 10;
for (i = 0; i < 10; i++)
{
global.score_array[i,0] = "Name"
if string_length(global.score_array[i,0]) > lengthlimit
{
global.score_array[i,0] = string_copy(global.score_array[i,0], 1,lengthlimit);
}
global.score_array[i,1] = 0
global.score_array[i,2] = "incomplete"
}

perhaps something like this, you would always do the string copy once directly after giving the variable a string ""
Amazing, you're the best! Now I have my full leaderboard working exactly how I need! Thank you for all the help man

Yeah, that looks pretty similar to what I've got! I actually am not sure of the relevance of the ds_map command (I was only following a tutorial haha) but in the end it seems like both systems are pretty close. Hopefully I might find another way to include arrays; they're pretty useful and I want to keep this new info in my brain :p
 
Top