U61 (v1.1.0) - Script tutorial




Disclaimer
==========


  Before you start, please note that this document is:

  * *not* a Lua tutorial (Lua is the language use for scripting in U61). Of
    course at the end of this document I hope you'll be able to do some basic
    Lua scripting since Lua is quite quick to learn, but if you want to do
    advanced Lua coding, go and check the official sources. I'm myself not a
    great Lua programmer so I won't be able to help you a lot anyway.

  * *not* a complete reference of what is possible to do with U61. It only
    shows how to get started with script writing, but if you really want to do
    complicated things, please read the rest of this site.

  However, it should help you write your first script lines, and I have good
  reasons to think these are the hardest to code.

  You do not need any special programming skills before reading this document.
  If you are curious and wish to learn how to toy with u61 it should be enough,
  provided that you know at least how to move, copy and edit files on your
  system. Of course it makes things easier to know about programming, but
  honestly Lua is not a difficult language to start with.



Step 1: create a script file
============================


  Well, let's not reinvent the wheel for instance, we'll just copy an existing
  file. Writing a complete file from scratch might indeed be too hard for a
  start.

  If you got an "official" U61 package (from http://www.ufoot.org for instance)
  you already have some scripts that came with the game. By the time I write
  this document, only the UNIX platform is supported, so the script files
  should be in "/usr/share/script/u61" or "/usr/local/share/script/u61" or in
  the directory where you installed U61.

  Now copy "/usr/local/share/u61/script/classic.lua" into
  "~/.u61/script/test.lua".

  If now you launch U61, and go to "Game options / Rules" you should see "test"
  appear in the list, use the arrows to move the selection on it, and the start
  a new game. You should have the impression to play with the "classic" rules,
  but in fact you are using the "test.lua" script.



Step 2: create an error
=======================


  OK, now scripting allows lots of liberty in programming. One of the basic
  consequences for U61 is that you can code almost anything in a script, you
  are pretty sure you won't get a protection fault. In fact the worst thing
  that can happen (and it does happen) is an infinite loop. The result is that
  the game hangs and you have to kill it.

  So what I propose is to deliberately create an error in the script and see
  what happens. This will help you deal with errors later. So just edit your
  brand new test.lua script file with your favorite editor (vim and GNU Emacs
  seem to work good but I would never mean to influence you in the choice of
  the editor) and go to, say line 93. There you just add the following text:

  \""56zboub!

  Now relaunch U61, which should have kept test.lua as your default script, and
  you should get nothing on the player(s) map(s) but instead a message on the
  console (provided that you have launched U61 from a terminal) that says:

  lua error: unexpected token;
    last token read: `\' at line 93 in file `/home/ufoot/.u61/test.lua'
  Lua error reading script, code is 1.

  And this is it. You have the line number of the error and a short description
  of it. This should help debugging.

  It is not necessary to quit and re-run completely u61 before trying out a new
  script. Indeed the script is reloaded from the disk each time you start a new
  game (with "Quick start" for instance). So all you need to do is:

  * Launch U61

  * Select your script with "Game options / Rules"

  * Start a game with "Quick start", view what happens.

  * Edit your file, save it.

  * Re-start the game with "Escape / Stop this game / Quick start" and view how
    your modifications influence the gameplay.

  As a start, just remove the faulty text I just told you to add from the
  script, same it and re-start a new game without quitting U61. The error
  should disappear.



Step 3: learn Lua basics
========================


  As I said before, this document is not a Lua reference, and it won't replace
  the reading of the official manual, which is available on this site anyway.
  Still, you do not need to be a Lua wizzard to tweak U61's scripts, as I'm not
  myself a very bright Lua programmer. So this short passage is just to give
  you a quick start.

  In U61, I essentially use Lua functions, there are other aspects of Lua
  programming than functions, but I think functions are easy to understand, so
  I use them. To declare a function, do like this:

  function my_function(par1,par2)
      ...
  end

  As you see, it's easy to declare a function, you might use this function
  elsewhere by calling:

  my_function("hello","world")

  Within a function, you can declare local values. Local values have a scope
  which is limited to the function where they are declared. Any function may
  return a value, here's an example:

  function calculate(a,b)
      local temp
      temp=a+b
      return temp
  end

  As you may have guessed, this function performs an addition, you can call:

  c=calculate(1,2)

  and the value of "c" will be 3.

  Lua has some common controls like "if...then" or "while...do". Here is a
  short example:

  if val==0 then
      result="zero"
  elseif val  <  0 then
      result="negative"
  else
      result="positive"
  end

  And another one:

  while i>0 do
      result=result*2
      i=i-1
  end

  To compare numeric values, you can use the operators:

  * == (equals)

  * ~= (different)

  * >
  * (greater)

  * <
  * (lower)

  * >
  * = (greater or equal)

  * <
  * = (lower or equal)

  Now if you have already programmed in another language like C, Pascal or
  Basic you know that almost as much as I do about Lua. I can tell you it's
  enough to start hacking.



Step 4: Try to understand the existing scripts
==============================================


  OK, now we know how to modify a script randomly and generate errors. Great,
  but you might want to do more than that! Let's start by a - very - short
  analysys of our test.lua script file.

  "user_rotate_left" is called when the rotate left key is pressed. In U61
  0.2.2 the code for user_rotate_left for the classic.lua script is:

  function user_rotate_left()
      rotate_block_left()    
  end

  This means the action to perform when "user_rotate_left" is called is to call
  "rotate_block_left". So what's the difference between "user_rotate_left" and
  "rotate_block_left"? Well, they do exactly the same but "user_rotate_left" is
  a reserved name, this function being what I call a "user callback", since
  it's called by the C++ engine and it's the responsibility of the scripter to
  code it correctly. "rotate_block_left" is totally unknown from the C++
  engine, it's just a function I created because I found it convenient to have
  a function that rotates a block already coded and usable elsewhere in the
  script. If we look at the code of "rotate_block_left", we find:

  function rotate_block_left()
      local x
      local y
      local i 
  
      i = u61_get_nb_items()-1
      while i>=0 do
          x = u61_get_item_x(i) 
          y = u61_get_item_y(i) 
          x,y = y,-x
          u61_set_item_x(i,x)
          u61_set_item_y(i,y)
          i = i-1
      end
  end

  Well, we won't detail the way it works, but we'll still notice that it uses
  the functions with a name like "u61_fonction_name". These functions belong to
  what I call the "system api". It's a set of functions which allow the user to
  query and modify U61's world. For instance "u61_get_nb_items" returns the
  size of the current block, which with the classic rules is generally 4. But
  beware, it could be more if you had a nasty curse, and in a general manner,
  it's good to write scripts that are usable in various situations.



Step 5: Toy arround
===================


  Now, we'll as a first example change our "test.lua" file so that when the
  user rotates a block, the block goes down of one square. This will forbid
  abusive rotation of the block and make the game harder.

  Just edit test.lua and find the code for "user_rotate_left" and
  "user_rotate_right". It should look like:

  function user_rotate_left()
      rotate_block_left()    
  end
  
  function user_rotate_right()
      rotate_block_right()    
  end

  Just replace this by:

  function user_rotate_left()
      rotate_block_left()
      u61_set_block_y(u61_get_block_y()+1)
  end
  
  function user_rotate_right()
      rotate_block_right()    
      translate_block_y(1)
  end

  And it should work! You'll notice that the 2 functions are coded differently.
  With "user_rotate_left" I used the U61 system API directly, whereas with
  "user_rotate_right" I used an Lua function which encapsulates the calls to
  the system API. I personnally find it a good idea to make very small
  functions but you are free to do whatever you want. But I believe some
  functions such as the user callbacks should be as small as possible, for in
  the long run it should make the sharing and merging of script files easier.



To be continued...
==================


  Well, that's all for now, I hope to enrich this document soon.

