Save a high score (or anything) without cheating possibility !

In this tutorial we’re going to take a look at a pretty interesting feature of the TI-Nspire framework in Lua : save and restore any kind of data directly in Lua, that lets us playing around with a high score for a game or any other configuration data for a more complex program.

Example : You just released a wonderful game. You’d like to share it with your friends, that way they can challenge you thanks to your high-scores system. But how is that working?

The first way you could think of is to use the var API. Therefore, we save the high score in the document as a global variable (math variable).

Your high score system is done ! Hum … wait a second, one of your friend managed to score 10 000 000 points to your game ! What the heck ? He simply modified the global variable you’re using as an high score, since it’s freely accessible via a Calculator application. Here, it is not hard to cheat !

A second way is to protect the first one by using math.eval() which lets us launch any TI-Basic instruction, as the Lock one for example. Then, if we do like so :

math.eval("Unlock highscore")
var.store("highscore", highscore)
math.eval("Lock highscore")

our high score variable will be write protected. But, since Lock is a TI-Basic command, it can be launch outside the Lua program. Things aren’t going to be better.

What about looking for a specific Lua command ? Actually, there is var.monitor() that probes a specified variable and checks if this variable will be changed. If so, on.varChange() event is called. This lets us to control any variable changes.

Here is an example :

function on.create()
  if not var.recall("highscore") then
    highscore = 0
    var.store("highscore", highscore)
  end
  var.monitor("highscore")
end
 
function on.varChange(list)
  for k, v in pairs(list) do
    if k == "highscore" then
      if var.recall(k) ~= highscore then
        return 1 -- it is an external change, block modifications
      else
        return 0 -- it is an internal change, allow modifications
      end
    end
  end
  return 0 -- allow modifications of other monitored variables if any
end

This code will disallow any external modification of the highscore variable, with the following error message :

Cannot accept change : Invalid input

Obviously, if you have to do this for multiple variable, for example configuration data, don’t do this since it is a heavy and repetitive method …
It is at this moment that we take a look to the documentation. We can see two trivial events : on.save() & on.restore().
In fact, this event couple does exactly what we expected to do from the beginning !

Actually, when the widget get closed (when we close the document, or copy/cut the widget) the on.save() event is called. You have to define on.save() to make it return any kind of value (boolean, number, string, table etc …). The next time the widget will open (when we open the document, or paste the widget), the on.restore() event will be called, with the data returned by on.save() as the parameter !

Here we are, easy-going :

function on.save()
  return highscore
end
 
function on.restore(data)
  if type(data) == "number" then
    highscore = data
  end
end
 
function on.create()
  if not highscore then
    highscore = 0 -- first time we initialize highscore
  end
end

Leave a Reply