how do you save a number?

Started by ponderitus, March 29, 2020, 11:21:12 AM

Previous topic - Next topic
I've made a little script/ fishing game where your fish wins you prizes...everything works fine until i save and reopen the file...its basically:

if size <= 6 then
blah
elseif size >
win = size
size reset to 0

and then theres a seperate npc with a dialog stating the win number:-

game:start_dialog("fisherman.young.talk.weight.tank", win, function()


now if i move maps and come back in it all works fine...but if i save the game and return...the value of "win" is set back to nil, how do i get the value of win to save?

or do i need to make save variables for each outcome..ie

if win = 1 then
game:set_value("win_is_1", true)
else if win 2 then.....


and then write out a dialog for each outcome?

March 30, 2020, 01:51:18 AM #1 Last Edit: March 30, 2020, 01:53:50 AM by Diarandor
To debug, try some prints:
Code (Lua) Select

print(size)
print(type(size))

If your variable is null, check if you used the saving function "game:save()" or if the savegame was really loaded when restarted.

EDIT: i don't think others can really help you if you don't post the real code of that  function.
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

yeah ive got prints for when the map starts to tell me the values, it says 8 for example if i go in and out the map but back to 0 if the game is reloaded...the game is saved but the value of win isnt. I have no idea how to save it is the problem. the lines "game:save(win)" were added after i read this but still didnt save the value...but the print said it did.

Heres the full code, the part which needs win saving is seperated below aswell.


function fisherman:on_interaction()
  hero:set_animation("stopped")
  if size == nil then
    size = 0
  else
  end
  if fisherman_talk == nil then
    fisherman_talk = 0
  else
  end
  if win == nil then
    win = 0
  else
  end
  game:set_hud_enabled(false)
  game:set_pause_allowed(false)
  if game_is_active then print("game_is_active", game_is_active)  ------------------ if the game is active
    print(size)
    game:start_dialog("fisherman.young.talk", function(answer)
      if answer == 1 then -- weigh fish
        if game:get_value("hylia_fish_young") then print("hylia_fish_young", hylia_fish_young)
          if size == 0 then
            game:start_dialog("fisherman.young.talk.weight.no_fish", function()
              game:set_hud_enabled(true)
              game:set_pause_allowed(true)
            end)
          elseif size > 0 and size < win then
            game:start_dialog("fisherman.young.talk.weight.small", size, function()
              game:set_hud_enabled(true)
              game:set_pause_allowed(true)
            end)
          else
            game:start_dialog("fisherman.young.talk.weight.woah", size, function()
              if size > win then
                game:set_hud_enabled(true)
                game:set_pause_allowed(true)
                win = size print(win, "=", scale)
                game:save(win) print("save win", win)
                local win = size print("local", win, "=", scale)
                sol.timer.start(01, function()
                  size = 0
                end)
              else
                game:set_hud_enabled(true)
                game:set_pause_allowed(true)
              end
            end)
          end
        elseif size == 0 then  print("size", size, "win", win)
          game:start_dialog("fisherman.young.talk.weight.no_fish", function()
            game:set_hud_enabled(true)
            game:set_pause_allowed(true)
          end)
        elseif size > 0 and size < 6 then
          game:start_dialog("fisherman.young.talk.weight.small", size, function()
            game:set_hud_enabled(true)
            game:set_pause_allowed(true)
          end)
        else
          game:start_dialog("fisherman.young.talk.weight.woah", size, function()
            win = size print(win, "=", scale)
            game:save(win) print("save win", win)
            local win = size print("local", win, "=", scale)
            sol.timer.start(01, function()
              sol.audio.play_sound("oot/fanfare/item")
              hero:start_treasure("heart_piece", 1)
              game:set_value("hylia_fish_young", true)
              size = 0
              game:set_hud_enabled(true)
              game:set_pause_allowed(true)
            end)
          end)
        end
      else  -- other
        game:start_dialog("fisherman.young.talk.other", function(answer)
          if answer == 1 then  -- talk to fisherman
            if fisherman_talk == 0 then print(fisherman_talk)
              fisherman_talk = 1 print(fisherman_talk)
              game:start_dialog("fisherman.young.talk.talk1", function()
                game:set_hud_enabled(true)
                game:set_pause_allowed(true)
              end)
            elseif fisherman_talk == 1 then
              fisherman_talk = 2 print(fisherman_talk)
              game:start_dialog("fisherman.young.talk.talk2", function()
                game:set_hud_enabled(true)
                game:set_pause_allowed(true)
              end)
            elseif fisherman_talk == 2 then
              fisherman_talk = 0 print(fisherman_talk)
              game:start_dialog("fisherman.young.talk.talk3", function()
                game:set_hud_enabled(true)
                game:set_pause_allowed(true)
              end)
            end
          else  -- exit fishing "game"
            game:set_hud_enabled(true)
            game:set_pause_allowed(true)
            game_is_active = false
          end
        end)
      end
    end)
  else print("game_is_active", game_is_active)  ------------------ if the game is NOT active
    game:start_dialog("fisherman.young.open", function(answer)
      if answer == 1 then -- Yes would like to play
        if game:get_money() < 20 then
          game:start_dialog("_shop.not_enough_money", function()
            game:set_hud_enabled(true)
            game:set_pause_allowed(true)
          end)
        else
          game:remove_money(20)
          phase_1()
        end
      else -- No wouldn't like to play
        game:start_dialog("fisherman.young.open.no", function()
          game:set_hud_enabled(true)
          game:set_pause_allowed(true)
        end)
      end
    end)
  end
end


more specifically this part, this is the "winning" function.

        else
          game:start_dialog("fisherman.young.talk.weight.woah", size, function()
            win = size print(win, "=", size)
            game:save(win) print("save win", win)
            local win = size print("local", win, "=", size)
            sol.timer.start(01, function()
              sol.audio.play_sound("oot/fanfare/item")
              hero:start_treasure("heart_piece", 1)
              game:set_value("hylia_fish_young", true)
              size = 0
              game:set_hud_enabled(true)
              game:set_pause_allowed(true)
            end)
          end)
        end

You forgot to load your savegame variable. Use this:
Code (Lua) Select
win = game:get_value("win")
You don't need to use
Code (Lua) Select
game:save()
since I guess that is being done in your menus when you save your game (isn't it?).
Savegame variables are saved and loaded with the functions: "game:get/set_value", which are the ones you need to use.

(By the way, the command "game:save()" has no parameters and saves ALL savegame variables:
https://www.solarus-games.org/doc/latest/lua_api_game.html#lua_api_game_save)

Always use the Solarus Lua API when you don't know how to do something. Usually the answer is there.
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

hmmm...that didnt work, not the way im trying things anyway. i dont get how that is saved tbh.

the size is obtained by the fish. i catch a fish and it randomly generates a weight (size) based on its species, i need that size to then become a saved value (which i have called win) and then the size can just reset...but the number will be saved as win. the value of win can be changed at any time...well anytime the player catches a "heavier" fish.

so if the size > 6 then nothing really happens
but if the size is greater than 6 then size value (anything above 6) becomes the win value...which is saved forever and then the size is discarded as normal.

i have never used game:save() before i only tried it because you suggested it, i would usually use game:set_value("", true). but thanks. I was going to look into an "autosave" function at some point.

I write this assuming you understood all this already, and it is me who isn't understanding the reply you gave lol. I keep trying different things though and im not getting much success

Please, first read carefully the savegame functions in the Solarus Lua API. That's the only way you can understand what those functions do. Again, this is the link for what you need:
https://www.solarus-games.org/doc/latest/lua_api_game.html

Also, reading code from others is very useful to learn.
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

yeah ive read that and i understand how to save something. but i wanted to make it a number...which im assuming you cant do then? Because this is the error doing that brings. (9 was the number that was randomly generated to become win)


Error: In timer callback: maps/Fishing.lua:138: bad argument #2 to set_value (Invalid savegame variable '9': the name should only contain alphanumeric characters or '_' and cannot start with a digit)



      game:start_dialog("fisherman.young.talk.weight.woah", size, function()
            win = size print(win, "=", size)
            sol.timer.start(01, function()
              sol.audio.play_sound("oot/fanfare/item")
              hero:start_treasure("heart_piece", 1)
              game:set_value("hylia_fish_young", true)
              size = 0
138       win = game:get_value(win)
              game:set_hud_enabled(true)
              game:set_pause_allowed(true)
            end)
          end)


i get that i can use loads of:
if win = 1 then
  game:set_value("win_is_one", true)
elseif win = 2 then
  game:set_value("win_is_two", true)
etc...

and then to call them its:

if game:get_value("win_is_one") then
  game:start_dialog("fisherman.open.won.win_is_one", win, function()
  end)
elseif game:get_value("win_is_two") then
  game:start_dialog("fisherman.open.won.win_is_two", win, function()
  end)
etc...

but i didnt want to have to write out dialogs for each condition and script for each condition. thought it would be easier to just call $v in the dialog and have that be win:
game:start_dialog("fisherman.open.won", win, function()
end)

which works initially, and then continues to work when walking inbetween maps and carrying on with the game, but as soon as the game is saved and reloaded the values are nil again.

I think that error means that
win = game:get_value(win)
should be replaced by
win = game:get_value("win")
Note that "win" is a string and win is a variable. You need to fix all errors where the console complains, or your code won't work.
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

March 31, 2020, 12:58:03 PM #8 Last Edit: March 31, 2020, 01:04:09 PM by froggy77
You can convert strings to numbers:
win = tonumber(game:get_value("win"))

March 31, 2020, 05:03:17 PM #9 Last Edit: March 31, 2020, 05:11:45 PM by Diarandor
Savegame values can be strings, numbers or booleans. His problem is just that he is not saving or loading the variable correctly. As I pointed above, the savegame functions get/set_value use a string in first parameter as a variable name, and he is not using a string, so he is getting an error.
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

that didn't seem to work either, I've only seen this about 5 mins ago though and only tried a couple of attempts, heres a much shorter version of what im trying to do, thanks for all the help from both of you by the way, its much appreciated. didn't want either of you to think id ignored your replies, for the moment i just made a new function called check_win() and call that whenever its needed and just save to that instance, seems to work. Wasnt that much work but would be if i had numbers for all possible numbers from 1-?...and not just from 6-10 (atm)


function man:on_interaction()
  local max_num = 6
  local min_num = 10
  local size = math.random(min_num, max_num)
  if size > 0 then
    win = tonumber(game:get_value(size))
    sol.timer.start(100, function()
      print(size)
      print(win)
    end)
  end
end


this gives the same errror about not being able to be a number:
: bad argument #2 to get_value (Invalid savegame variable '8': the name should only contain alphanumeric characters or '_' and cannot start with a digit)

and with -
    win = tonumber(game:get_value("size"))
it is just nil

If i'm not doing something correctly its because i don't actually know what is correct. and ive never been taught anything. I learn better watching and deconstructing things and i havent found anything that works like this, not that ive been able to read and understand anyway. So ive been writing things to just work...then when ive learnt more ive gone back and rewritten things

According the documentation, game:get_value(savegame_variable) returns a value saved.

In your function, 'size' is a local variable that has not yet been saved, so you cannot use game:get_value("size"), because it will return 'nil'.   

April 01, 2020, 12:29:04 AM #12 Last Edit: April 01, 2020, 12:36:12 AM by Diarandor
I will try to explain this with more detail:

1) Use game:set_value("win", win) to store the value of the local variable win of your script in a built-in savegame variable called "win". This does NOT save your variable in a file. This updates the value of the built-in variable "win" (which is not the local variable in your script). Only buit-in variables are saved in files, and to do that it is NECESSARY to call game:save().
2) Save your game with game:save(). In the games of the Solarus Team you will find a menu to save the game, and that menu, in its code, is calling that function. If you don't call that function in any way, your savegame built-in variables will not be saved into a file. So, please, don't skip this part.
3) When your game is restarted and your savegame is reloaded (make sure that your savegame is loaded! I don't remember where this is done or if this is automatically done), you can recover your variable with:
win = game:get_value("win") I insist that in your code above you don't need any conversion because Solarus can save strings, booleans and numbers, and your variable is a number.
4) Read the errors in the console and learn to understand them. Always fix them. Never ignore them. This is crucial. If you don't understand an error, you can ask us.
5) Please, read the API of those functions and absorb its knowledge. If you don't understand something, don't hesitate to ask. If you want to learn, you need to consult the API. We all use it all the time, and it's very well written and with many examples.

Remark: in this code you wrote
win = tonumber(game:get_value(size))
the compiler is complaining that size is not a string. Since the conversion to number is not necessary, that line could be replaced with this:
win = game:get_value("size")
although what you need is this:
local win = game:get_value("win")
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."