U61 (v1.0.0) - Script API reference




Introduction
============


  The API functions are functions you can call within Lua, when you are
  scripting, to get information from the core C++ engine, and also modify
  what's happening in the game.

  Technically speaking, these functions are just plain Lua functions mapped
  over C functions in the core engine, and these C functions call C++ methods
  off the "U61_Map" and "U61_Block" C++ objects. In this document, I will later
  say that the C++ engine calls some API fonctions automatically. In fact, it
  does not call the Lua functions but the C++ methods directly. But the result
  is exaclty the same, only the C++ engine does not make as many checks as the
  API functions do.

  Those functions are quite "crash proof". I mean that various checks are
  triggered when you call them. For instance, calling a function which requires
  an array index with a bad, inexisting index will simply result in returning a
  default value, but there should not be (such a bug should be reported) a
  system crash of the core C++ engine.

  The design of this API is not perfect, so maybe I'll create more functions
  later, since the functions I provide here are very low-level functions.
  However, I'll try and do my best not to remove any functions, so that in the
  long run scripts can be re-used easyly, and remain compatible with each
  other.



u61_add_antidote
================


  Declaration
  -----------

    u61_add_antidote()

    * Arguments: none.

    * Return values: none.

    * Rights: map_write.

  Description
  -----------

    Gives an antidote to the current player.

    The given antidote should appear in the status zone (a little heart in the
    default theme). The player is not forced to use it right away. In fact, as
    long as there's at least one antidote available, any press on the "use
    antidote" key will run the "user_use_antidote" function.

    Note that even if the antidote does not appear in the status zone for there
    are already too many antidotes available, the "u61_add_antidote" will
    function correctly, and "u61_get_nb_antidotes" should always return the
    exact value.

  Example
  -------

    In this example, we give an antidote and a score bonus to the player.

    function nice_present()
        u61_add_score(1000)
        u61_add_antidote()
    end



u61_add_item
============


  Declaration
  -----------

    u61_add_item(x,y,color)

    * Arguments: coordinates and color of the square to add.

    * Return values: none.

    * Rights: block_write

  Description
  -----------

    This function adds a new square to the current block. It is the function
    which should be called in the "user_do_shape" callback, to build new blocks
    before they start falling.

    You can consider this function as an "append" method on the block object.
    In a way, the block is a vector of squares, which grows as you call
    "u61_add_item", and can be emptied with "u61_clear_block". If you had a
    block with 3 squares, after a call to this function, it will have 4
    squares. The added square has an index of [n-1
    ]
    , if the size of the block is n.

    Of course, the square properties which are set up by this function
    (position and color), can be changed later in the game.

  Example
  -------

    In this example, we add a square with a parameterd color at the right of
    the square which is already at the right extremity of the block.

    function expand_right(color)
        local max_x
        local x
        local y
        local i
    
        max_x=0
        y=0
    
        i = u61_get_nb_items()-1
        while i>=0 do
            x=u61_get_item_x(i)
            if x>max_x then
                max_x=x
                y=u61_get_item_y(i)
            end
            i=i-1 
        end
    
        u61_add_item(x,y,color) 
    end



u61_add_score
=============


  Declaration
  -----------

    u61_add_score(score_diff)

    * Arguments: the value which should be added to the score.

    * Return values: none.

    * Rights: map_write.

  Description
  -----------

    This function adds some points to the current score.

    You can also use this function with negative values, if you want to
    decrease the score of a player. In fact, this function is really equivalent
    to a manual call to "u61_get_score" and then "u61_set_score". It is there
    to avoid you the pain of calling 2 functions where 1 is enough in most of
    the cases.

  Example
  -------

    The following function adds some points to the player only if the
    "NO_POINTS" curse is not activated.

    ID_NO_POINTS=33
    
    function tweaked_add_score(score_diff)
        if u61_get_curse_age(ID_NO_POINTS)    <    0 then
            u61_add_score(score_diff)
        end
    end



u61_blow_up_square
==================


  Declaration
  -----------

    u61_blow_up_square(x,y)

    * Arguments: the coordinates of a block in the map.

    * Return values: none.

    * Rights: map_write.

  Description
  -----------

    This function starts an explosion at the given location, it should be used
    in the "user_match_pattern" function.

    Of course, in the "user_match_pattenr" function, you could directly remove
    squares from the map, but you can get a nicer effect by calling the
    "u61_blow_up_square" function. It will indeed start an explosion on a given
    square, and at the end of the explosion - that's to say a few game cycles
    after the explosion has started -, the C++ core engine will call your
    "user_square_blown_up" callback. This way you may start an explosion, let
    the game run while the explosion is displayed to the player, and then get
    some control of what's happening at the end of the explosion with the
    "user_square_blown_up" function.

    This function is very usefull if you want to create some cascading effects.
    In fact, I don't know about any other way to do it yet...

  Example
  -------

    This example blows up the bottom line of the map. What has to be done when
    the explosion is over is not defined here, for it is defined i the
    "user_square_blown_up" function.

    function blow_bottom()
        local x
        local y
    
        y=u61_get_height()-1
        x=u61_get_width()-1
        while x>=0 do
            if u61_get_square_color(x,y)>=0 then
                u61_blow_up_square(x,y)
            end
            x=x-1 
        end    
    end



u61_cancel_curse
================


  Declaration
  -----------

    u61_cancel_curse(curse)

    * Arguments: the id of a curse.

    * Return values: none.

    * Rights: map_write.

  Description
  -----------

    This function cancels a persistent curse which had been set up with
    "u61_register_curse".

    This function cures the illness caused by a curse by disactivating it. It
    can be used in the "user_use_antidote" function for instance. Of course any
    persistent curse is automatically removed with time, but this function is
    very usefull in the case of a pseudo-permanent curse which has a very long
    delay.

  Example
  -------

    In this example, we disable the "ID_CURSE_HUNGRY" curse manually.

    ID_CURSE_HUNGRY=10
    
    function feed_the_beast()
        u61_cancel_curse(ID_CURSE_HUNGRY)
    end



u61_center_block
================


  Declaration
  -----------

    u61_center_block()

    * Arguments: None

    * Return values: None

    * Rights: block_write

  Description
  -----------

    This function centers the block, this means that after it has been called,
    the gravity center of the block (approximately), will be located at (x,y),
    x and y being the global coordinates of the block.

    This is very usefull when you want to code something like a rotation or a
    symetry. You can indeed code things in a simple manner using "x=-x" like
    algorithms, and then call "u61_center_block" to center the block. If you
    had not this function, there could be situations where after a sequence of
    rotations/symetries, a block could have moved to the left and/or right.
    Worse, a rotation could cause the block to move down, which is bad in a
    block-based game. Please note that this function does note change the
    global (x,y) values of the block (access by "u61_get_block_x" for
    instance). Its role is only to make (x,y) be the actual center of the
    block.

    This function is automatically called by the script engine after the
    following user callbacks:

    * user_rotate_left

    * user_rotate_right

    * user_move_left

    * user_move_right

    * user_move_down

  Example
  -------

    The following example leaves the block in a unchanged state. Indeed, the
    squares are translated, but "u61_center_block" cancels the translation.

    function leave_block_unchanged()
        local i
    
        i = u61_get_nb_items()-1
        while i>=0 do
            u61_set_item_x(i,u61_get_item_x(i)+1) 
            i=i-1
        end
        u61_center_block()
    end



u61_clear_block
===============


  Declaration
  -----------

    u61_clear_block()

    * Arguments: None

    * Return values: None

    * Rights: block_write

  Description
  -----------

    This function clears the current block, this means it removes all the
    squares from it.

    Beware not to leave a cleared, empty block falling in the players map,
    because it might cause some problems, since the C++ engine will not be able
    to find out when the block is supposed to have landed.

  Example
  -------

    In this example, we imagine that we want to change the shape of the block
    as it falls. Since "user_do_shape()" is always called on an empty block,
    the functions which prepare shapes usually do not clear the block first. So
    we need to force the block clear in we want to change completely the shape
    of the block outside the "user_do_shape" function.

    function change_shape_to_tetramino_bar()
        u61_clear_block()
        tetramino_bar()
    end



u61_delete_antidote
===================


  Declaration
  -----------

    u61_delete_antidote()

    * Arguments: none.

    * Return values: none.

    * Rights: map_write.

  Description
  -----------

    Removes an antidote from the player available antidotes.

    Note that it's not necessary to call this function within the
    "user_use_antidote" function, since the number of antidotes is
    automatically decreased by the C++ core engine. However, you might want to
    use this function if you want to remove manually some antidotes.

    If you call this function too many times, the number of antidotes will
    remain 0, it should never get negative, since the C++ engine will not allow
    it.

  Example
  -------

    This function clears all the antidotes of a player.

    function clear_antidote()
        while u61_get_nb_antidotes()>0 do
            u61_delete_antidote()
        end
    end



u61_get_anticipation_state
==========================


  Declaration
  -----------

    u61_get_anticipation_state()

    * Arguments: none.

    * Return values: true (1) if anticipation mode is on, or false (0).

    * Rights: map_read.

  Description
  -----------

    This function returns the state of the anticipation mode, that means wether
    the player should see where the block will land if he presses the "drop"
    key right away.

    You may have noticed that this parameter seems available in the player
    options menu, and the player might choose to have this information or not.
    However, the "u61_get_anticipation_state" function does not return the
    state of the menu item. Indeed, the "anticipation frame" is drawn only if
    the menu option has been set to "on" *and* the "u61_get_anticipation_state"
    returns true. So if you set the option to false in the menu, you will never
    see it, no matter what happens in the game.

  Example
  -------

    In this example, we return true if both anticipation and preview mode are
    set to true.

    function is_game_easy()
        local result
    
        if u61_get_anticipation_state() and u61_get_preview_state() then
            result=1
        else
            result=0
        end
    
        return result
    end



u61_get_block_x
===============


  Declaration
  -----------

    u61_get_block_x()

    * Arguments: None

    * Return values: The x coordinate of the block.

    * Rights: block_read

  Description
  -----------

    This function returns the x coordinate of the block. This value should
    approximately correspond to the center of gravity of the block.

  Example
  -------

    The following function returns the real position of a square in a block, ie
    the position this square has on the map.

    function get_absolute_x(i)
        return u61_get_block_x()+u61_get_item_x(i)
    end



u61_get_block_y
===============


  Exactly the same as "u61_get_block_x", but x becomes y...



u61_get_curse_age
=================


  Declaration
  -----------

    u61_get_curse_age(curse)

    * Arguments: the id of a curse.

    * Return values: the age of the curse.

    * Rights: map_read.

  Description
  -----------

    This function returns the time ellapsed since the last call to
    "u61_register_curse" with the same curse id. If the curse is not active at
    all, then the function returns -1.

    The time is counted in game cycles. It takes 100 game cycles to make one
    second. It's in fact the same unit used in "u61_get_time()".

    This function's primary goal is to allow the scripter to know wether a
    curse has been registered with "u61_register_curse". These registered
    curses appear in the player's status zone, and are representent by little
    skulls in the default theme. A typical use of this function would be to
    test if its return value is greater or equal to 0, and decide to disable
    and/or enable features in the game.

  Example
  -------

    In this example, we don't allow the user to use the rotate left key if he's
    doomed with the "ID_CURSE_NO_ROTATE" curse. It supposes there's a
    "low_level_rotate_left" function that does the dirty job of rotating the
    block.

    ID_CURSE_NO_ROTATE=20
    
    function my_rotate_left()
        if u61_get_curse_age(ID_CURSE_NO_ROTATE)    <    0 then
            low_level_rotate_left()
        end
    end



u61_get_curse_state
===================


  Declaration
  -----------

    u61_get_curse_state()

    * Arguments: none.

    * Return values: 1 if the curse mode is on, 0 if not.

    * Rights: map_read.

  Description
  -----------

    Returns true if there should be a special "curse square" on the map.

    This function is very different from "u61_is_curse_available". Indeed, it
    returns true if the map is in such a mode that a curse square could exists.
    But this does not garantee there's a curse square available. A trivial
    example is the empty map. If there are no squares at all on the map, you
    can oviously not have a special square anywhere. In fact, this function is
    merely to return the value set by "u61_set_curse_state" but in most of the
    cases what you'll need to call is "u61_is_curse_available".

  Example
  -------

    In this example, the player has his score freezed when he can't have any
    curse square on his map. This is a very unfair script since he is already
    disadvantaged by having no weapon at hand.

    function add_score_unfair(points)
        if not (u61_get_curse_state()==0) then
            u61_add_score(points)
        end
    end



u61_get_curse_x
===============


  Declaration
  -----------

    u61_get_curse_x()

    * Arguments: none.

    * Return values: the x coordinate of the "curse square" in the map.

    * Rights: map_read.

  Description
  -----------

    This function gives the x position of the "curse square". This special
    square is the black and white "?" in the default theme.

    When this special square disappears (after an explosion), then the
    "user_do_curse" function is called. Of course you can start curses on other
    events, such as a special pattern match, but the explosion of this special
    square should remain the most common method to issue a curse - at least
    this is the way I view things, you may agree or not with me on this point.

    This special square historically comes from EITtris. Since U61 is quite
    extensible I could have honestly imagined a more original and flexible way
    to launch curses but I was too lazy and I just like this idea since it
    reminds me of all the nights spent playing EITtris with 3 friends on a
    single computer in a small student room =8-)

  Example
  -------

    In this example, the player gets a score bonus if the curse square was
    located in the right or left columns of the map.

    function bonus_if_curse_on_sides()
        local x
    
        x=u61_get_curse_x()
    
        if x==0 or x==(u61_get_width()-1) then
            u61_add_score(1000)
        end
    end



u61_get_curse_y
===============


  Exactly the same as "u61_get_curse_x", but x becomes y...



u61_get_global
==============


  Declaration
  -----------

    u61_get_global(i)

    * Arguments: the index of the global value.

    * Return values: the value of the global.

    * Rights: map_read.

  Description
  -----------

    This function returns the global value associated to a given index (between
    0 and 99).

    This function is by no way related to the luac "getglobal" function. For
    more information about how to use it, see the documentation of
    "u61_set_global".

  Example
  -------

    This function returns the value of the ID_COUNTER value. Note that the lua
    object ID_COUNTER is a global lua value. However, you can use it safely
    since it is a constant. It's just a way to write things in a cleanier way.
    Without such constants, the code would rapidly become ununderstandable. But
    the value returned by the function is not a global lua value, it's a local
    value which has been initialized with a value stored internally by the C++
    core engine.

    ID_COUNTER=8
    
    function get_counter()
        return u61_get_global(ID_COUNTER)
    end



u61_get_height
==============


  Declaration
  -----------

    u61_get_height()

    * Arguments: none.

    * Return values: the height of the map.

    * Rights: map_read.

  Description
  -----------

    Returns the height of the map.

    This function always returns 25. It is pretty much like the "u61_get_width"
    function, so please read the documentation of "u61_get_width" to understand
    why you should use this function even if you are pretty sure it will always
    return 25.

  Example
  -------

    The following example colors the whole map, using the example function
    "colorize_row".

    function colorize_map(color)
        local y
    
        y=u61_get_height()-1
        while y>=0 do
            colorize_row(y,color)
            y=y-1 
        end
    end



u61_get_item_color
==================


  Declaration
  -----------

    u61_get_item_color(i)

    * Arguments: the index of the square.

    * Return values: the color of the square.

    * Rights: block_read

  Description
  -----------

    Returns the color of a square in the block.

    The color should normally always be a regular color (ie between 0 and 7),
    since having an empty square in a block does not really make any sense.

  Example
  -------

    The following function returns true if a given color is present in the
    block.

    function is_color_present(color)
        local i
        local present
    
        present=0
    
        i = u61_get_nb_items()-1
        while i>=0 do
            if u61_get_item_color(i)==color then
                present=1
            end
            i=i-1 
        end
    end



u61_get_item_x
==============


  Declaration
  -----------

    u61_get_item_x(i)

    * Arguments: the index of the square.

    * Return values: the x coordinate of the square.

    * Rights: block_read

  Description
  -----------

    This function returns the x coordinate of a square in the block.

    Note that the returned coordinate is not absolute. This means that if you
    want to have the real position of this square in the map, you'll have to
    call the "u61_get_block_x" function too and add the results.

  Example
  -------

    This function returns the width of a block, by getting the min and max x
    values.

    function get_block_width()
        local i
        local min_x
        local max_x
    
        min_x=1
        max_x=-1
    
        i = u61_get_nb_items()-1
        while i>=0 do
            x=u61_get_item_x(i)
            min_x=min(min_x,x)
            max_x=max(max_x,x)
            i=i-1 
        end
    
        return max_x-min_x
    end



u61_get_item_y
==============


  Exactly the same as "u61_get_item_x", but x becomes y...



u61_get_nb_antidotes
====================


  Declaration
  -----------

    u61_get_nb_antidotes()

    * Arguments: none.

    * Return values: the number of antidotes available.

    * Rights: map_read.

  Description
  -----------

    This function returns the number of antidotes available. It is very similar
    to "u61_get_nb_curses".

    The number of antidotes available is not updated by the C++ core engine.
    You need to give antidotes to players explicitly, by calling the
    "u61_add_antidote" function.

    You can easily view the value this function would return by counting on the
    screen the number of little hearts (assuming you are playing with the
    default theme) in the status zone. Still, if there are too many antidotes
    available, only a limited number of them is displayed. Howvever, the
    "u61_get_nb_antidotes" will always return the exact value, even if it's too
    great to be displayed accurately.

  Example
  -------

    In this example, we increase the score of the player if he has more than 5
    antidotes.

    function update_score()
        if u61_get_nb_antidotes()>=5 then
            u61_add_score(10)
        end
    end



u61_get_nb_curses
=================


  Declaration
  -----------

    u61_get_nb_curses(good)

    * Arguments: the type of curse to get information about.

    * Return values: the number of persistent curses currently active.

    * Rights: map_read.

  Description
  -----------

    This function returns the number of persistent curses which have been set
    up with "u61_register_curse".

    Calling it with a value of 0 will return you the number of "bad" curses,
    and calling it with a value of 1 will return the number of "good" curses.
    For more informations on bad and good curses, see "u61_register_curse".

    You can easily view the value this function would return by counting on the
    screen the number of little skulls (assuming you are playing with the
    default theme) in the status zone. Still, if there are too many curses
    activated, only a limited number of them is displayed. Howvever, the
    "u61_get_nb_curses" will always return the exact value, even if it's too
    great to be displayed accurately.

  Example
  -------

    In this example, we decrease the score of the player if he is affected by
    more than 5 persistent curses.

    function update_score()
        if u61_get_nb_curses(0)>=5 then
            u61_add_score(-1)
        end
    end



u61_get_nb_items
================


  Declaration
  -----------

    u61_get_nb_items()

    * Arguments: none

    * Return values: the number of squares in the current block.

    * Rights: block_read

  Description
  -----------

    Returns the number of squares in the current block. It is very usefull if
    you want to program a loop on all the squares of the block.

    If this function returns 4, it means that there are 4 squares available,
    which can be accessed with indexes 0,1,2 and 3. Any call outside this range
    to function like "u61_set_block_x" will simply do nothing.

  Example
  -------

    In the following example, the x and y coordinate of each square are
    exchanged.

    function flip_xy()
        local i
        local x
        local y
    
        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



u61_get_oldest_curse
====================


  Declaration
  -----------

    u61_get_oldest_curse(good)

    * Arguments: the type of curse to get information about.

    * Return values: the id of the oldest curse.

    * Rights: map_read.

  Description
  -----------

    This function returns the id of the oldest curse which has been set with
    "u61_register_curse".

    Calling it with a value of 0 will return the oldest "bad" curse, and
    calling it with a value of 1 will return the oldest "good" curse. For more
    informations on bad and good curses, see "u61_register_curse".

    It's important to be able to know rapidly which of the active persistent
    curses is the oldest one. A very simple example is a basic
    "user_use_antidote" where you want to remove a curse. You need a way to
    choose which one to delete. A possibility is to remove the oldest one, and
    this way the list of curse behaves like a FIFO (first in/first out) queue.
    And there you need the "u61_get_oldest_curse" function, or you would have
    to poll manually each curse to know his age and compare them...

    The id returned by this function could typically be used with
    "u61_cancel_curse".

  Example
  -------

    In this example, we remove the oldest curse, except if it is the
    "ID_CURSE_BAD_LUCK" curse.

    ID_CURSE_BAD_LUCK=13
    
    function special_antidote()
        local curse
    
        curse=u61_get_oldest_curse(0)
     
        if curse~=ID_CURSE_BAD_LUCK then
            u61_cancel_curse(curse)
        end
    end



u61_get_preview_state
=====================


  Declaration
  -----------

    u61_get_preview_state()

    * Arguments: none.

    * Return values: true (1) if the preview should be displayed, of false(0).

    * Rights: map_read.

  Description
  -----------

    Returns the preview state of the player. The preview is what shows the
    player what kind of block he will get next time a block falls.

    Unlike the anticipation state, the preview state can not be controlled from
    the menus. By default, it is set to true at the beginning of the game, and
    may be changed by calls to "u61_set_preview_state".

  Example
  -------

    This function gives more points to the player if preview state is off.

    function tweaked_add_score(points)
        if u61_get_preview_state()==1 then
            u61_add_score(2*points)
        else
            u61_add_score(points)
        end
    end



u61_get_score
=============


  Declaration
  -----------

    u61_get_score()

    * Arguments: none.

    * Return values: the current score.

    * Rights: map_read.

  Description
  -----------

    This function returns the current score.

    One important thing about the score is that it is set to 0 each time the
    game restarts. The core C++ engine knows what is the player's highest
    score, but it does not inform the script about it on purpose. In fact,
    different high scores might be displayed for the same player on different
    machines. This occurs when someone has been playing for hours and has
    luckily got a high score of 999999. Then a remote player decides to connect
    himself to the game. In this case, he will not be informed that there's
    someone with a 999999 high score. I don't consider it a bug since it has
    been designed like this. High scores and frags are counted differently on
    every machine. Indeed, each machine calculates the high scores according to
    what it sees. What has happened before does not count at all. No matter if
    the guy playing on the server has a high score of 999999, what you see if
    how much he managed to score playing with you.

  Example
  -------

    This example returns true if the score is greater than a given value.

    function is_score_enough(limit)
        local result
    
        result=0
    
        if u61_get_score()>=limit then
            result=1
        end
    end



u61_get_square_color
====================


  Declaration
  -----------

    u61_get_square_color(x,y)

    * Arguments: the coordinates of a square in the map.

    * Return values: the color of the square.

    * Rights: map_read.

  Description
  -----------

    This function returns the color of a square in the map. The possible return
    values are:

    * -1 if the square is not activated, ie there's no colored square at the
      given coordinates.

    * 0-7 if there's a colored the square. There are 8 colors, ranging from 0
      to 7.

    This function is very important in the game, and you'll probably end up in
    using it all the time if you create scripts for U61. It is the best way to
    know if there's a square at a given position. You just have to call it and
    if it returns something greater than 0, then it means there's something.

    It is important to note that it is quite different from
    "u61_get_item_color". Indeed, "u61_get_item_color" takes an index as a
    single argument, since the block is a vector of squares, whereas
    "u61_get_block_color" takes the coordinates of the square as an argument.
    This is because the map and block objects have fundamentaly different
    structures.

  Example
  -------

    In this example, we return 1 if there's a square at a given location, and 0
    if there's none. This way we have a true/false function which tells us if
    the place is free.

    function is_there_a_square(x,y)
        local exists
    
        exists=0
    
        if u61_get_square_color(x,y)>=0 then
            exists=1
        end
    
        return exists
    end



u61_get_time
============


  Declaration
  -----------

    u61_get_time()

    * Arguments: none.

    * Return values: the current system time.

    * Rights: map_read.

  Description
  -----------

    This function returns the system time associated to the map. The unit is
    0.01 sec, this means that 100 equals one second.

    The time can be very usefull, you can for instance use it as a
    pseudo-random value. This is very important, since the use of any other
    random value in a script could raise serious problems. Indeed, in U61, all
    the computers make all the calculus about all the players. So if a script
    generates internally a random number, then the game may not behave the same
    on 2 computers which are linked during a network game. By using the time
    value, you are sure that your pseudo-random number will be exactly the same
    on any computer, so the game will behave correctly. To sum up, the only
    pseudo-random values that should be use in U61 are:

    * The value returned by "u61_get_time".

    * The value returned by "u61_get_score".

    * The argument of "user_new_block".

    * The argument of "user_new_shape".

    The time is always positive, but you should not assume that games start at
    time 0. Indeed, when a player looses, the game ends, and another game
    starts, but there's no time reset. This is for the core C++ engine to
    handle messages correctly. Therefore, the time value can get very great.

  Example
  -------

    In this example, we use the time as a pseudo-random value. The result is a
    random number between 0 and range-1.

    function pseudo_random(range)
        return mod(u61_get_time(),range)
    end



u61_get_width
=============


  Declaration
  -----------

    u61_get_width()

    * Arguments: none.

    * Return values: the width of the map.

    * Rights: map_read

  Description
  -----------

    Returns the width of the map.

    This function always returns 10. So what's the interest in calling it since
    everyone knows the map is 10 squares wide. Well, it's a good habit to use
    it, one never knows, U61 scripts might someday be used in a context where
    maps are lager.

    However, I don't think the width of maps is likely to change, since it
    would induce many changes in the themes. I mean that a theme desgined for
    10 columns might look ugly if you use it with 16 columns. I can't think of
    a nice solution to this problem, I mean one that would enable players to
    choose their themes/scripts independently and get a good looking result.

    So as a conclusion, just use this function to get the width of the map, but
    please do not plan to use another value than 10 since it would mess up all
    the themes.

  Example
  -------

    This function modify the color of a whole line in the map. Only the active
    colored squares are affected.

    function colorize_row(y,color)
        local x
    
        x=u61_get_width()-1
        while x>=0 do
            if u61_get_square_color(x,y)>=0 then
                u61_set_square_color(x,y,color)
            end
            x=x-1 
        end
    end



u61_is_block_ok
===============


  Declaration
  -----------

    u61_is_block_ok()

    * Arguments: none.

    * Return values: 1 if the block is correctly placed, 0 if there's a
      conflict with the map.

    * Rights: map_read, block_read.

  Description
  -----------

    Returns true if the block is correctly placed, and has a correct shape. By
    "correct" we mean that:

    * there are no squares in the block which are in conflict with the map
      squares, that's to say we could freeze the block as is without
      superposing a map square and a block square.

    * there are no squares in the block that are outside the map, that's to say
      too much on the right, left or too low. If the block is too high it does
      not matter (think of when the block just start falling for instance, and
      you'll understand why it's obviously possible).

    You may use this function when you want to move the block in a complex
    manner, or completely change it, and really need to keep an accurate
    control on what's happening. Indeed, this function is called very often by
    the C++ core engine, and for instance it's perfectly useless to call it in
    functions like "user_move_down" for instance, since the check is already
    performed, and you'll only slow down the game by calling it twice.

    But a good example of when "u61_is_block_ok" is usefull is a script that
    needs to make the block cross the entire map, or move it for say at least
    10 squares. Then the C++ core engine won't be able to detect if there are
    squares between the initial and final position. All what the C++ core
    engine is aware of is the initial and final positions. So this way the
    block might (from the player point of view) go through a solid wall, which
    is not what the scripter wants. The scripter wants the block to stop if
    there's a wall. So what he'll have to do is move the block by steps of 1
    square and call "u61_is_block_ok" each time and stop if there's a problem.

    It's usually not a problem if at the end of the script function you leave
    the block in an incorret state, with a conflict. Since the C++ core engine
    performs himself a check, he will move the block up or sideways so that it
    fits, or sometimes perform a plain rollback and cancel all your script
    functions. But if you want to control exactly what's happening, then you'll
    have to do it yourself in your script.

  Example
  -------

    In this example, the block is moved in both directions x and y, only if
    there are no squares on its path. The block is left in an incorrect state
    but this is not a problem since the C++ core engine will automatically cure
    the problem.

    function translation_yx_safe(n)
        local i
    
        i=n
        while i>0 do
            u61_translate_x(1)
    	u61_translate_y(1)
            if u61_is_block_ok()==0 then
                i=0
            end
            i=i-1 
        end
    end



u61_is_curse_available
======================


  Declaration
  -----------

    u61_is_curse_available()

    * Arguments: none.

    * Return values: 1 if there is actually a special curse square on the map,0
      if there is none.

    * Rights: map_read.

  Description
  -----------

    Returns true if there's a special curse square available, that's to say if
    the "curse state" parameter is set to true *and* the curse square is
    located on an active square in the map.

    This function is very different from "u61_get_curse_state". Indeed, if the
    special curse square is badly placed, or if it is impossible to place it
    correctly, for instance when there are no squares at all, then you might
    get a situation where "u61_get_curse_state" returns true and
    "u61_is_square_available" returns false. For instance, this is often the
    case when a new game starts, since there are no squares on the map, and by
    default the "curse state" parameter is set to true.

  Example
  -------

    In this example, we return true if we the special curse square is badly
    placed, ie when "u61_get_curse_state" and "u61_is_curse_available" do not
    return the same value.

    function is_curse_badly_placed()
        local result
    
        result=0
    
        if u61_get_curse_state()==1 and u61_is_curse_available()==0 then
            result=1
        end
    
        return result
    end



u61_is_square_exploding
=======================


  Declaration
  -----------

    u61_is_square_exploding(x,y)

    * Arguments: the coordinates of a square in the map.

    * Return values: 1 if the square is exploding, 0 if not.

    * Rights: map_read.

  Description
  -----------

    This function tells if the square is exploding, that's to say if the player
    can see an explosion at this location.

    When this function is called, the square is "still there". Im mean that it
    is still possible to test its color for instance. Basically, a square is in
    the exploding state after "u61_blow_up_square" and before
    "u61_square_blown_up" have been called.

  Example
  -------

    This function counts all the exploding squares from the map.

    function count_explosions()
        local x
        local y
        local count
    
        count=0
    
        y=u61_get_height()-1
        while y>=0 do
            x=u61_get_width()-1 
            while x>=0 do
                if not (u61_is_square_exploding(x,y)==0) then
                    count=count+1
                end
                x=x-1 
            end
            y=y-1
        end    
    
        return count
    end



u61_register_curse
==================


  Declaration
  -----------

    u61_register_curse(curse,time,good)

    * Arguments: the id of a curse, the time it should last, and the kind of
      curse it is.

    * Return values: none.

    * Rights: map_write.

  Description
  -----------

    This function registers the curse, ie it adds it to the list of active
    curses. The curse will be active for a limited time, counted in 1/100 of
    seconds, but a value of 0 should make it last forever - or at least most
    player won't notice the difference since if you use 0 the curse will last
    for about 10 hours...

    Used with the "u61_get_curse_age", this function allows you program
    "persistent" curses. By persistent curse I mean a curse which is displayed
    in the player's status zone (represented with a little skull in the default
    theme) and can be cancelled by an antidote. A typical non-persistent curse
    is a curse that fills your map with grabage. A typical persistent curse is
    the curse that forbids you to use some of your keyboard keys.

    Curses set up with "u61_register_curse" can be cancelled manually with
    "u61_cancel_curse". Otherwise they will disappear automatically after some
    time.

    The third parameter allows you to choose wether the curse is a real bad
    curse or if it's a "good" curse. Basically, it's up to you to decide which
    curses are good and which aren't. Basically a curse that accels the player
    is a bad one, and one that slows the player is a good one, since it makes
    the game easier. So in fact a "good" curse is an "anti-curse", it's a
    benediction opposed to a malediction. For U61's C++ engine, the only
    difference between good curses and bad curses is that the icons used to
    represent them on the screen are not the same.

  Example
  -------

    In this example, we have defined a function that handles remote curses (see
    the definition of "u61_send_curse"). And if the curse id is greater than
    50, then we assume the curse is a persistent one, so we set it up for a
    time of 60, that's to say about 1 minute.

    function my_handle_remote_curse(curse)
        if curse>50 then
            u61_register_curse(curse,6000,0)
        end
    end



u61_send_curse
==============


  Declaration
  -----------

    u61_send_curse(curse)

    * Arguments: the id of a curse.

    * Return values: none.

    * Rights: map_write.

  Description
  -----------

    This function sends a curse to the default victim of the current player.

    It is probably one the most interesting function in U61. At least it is
    definitely *the* function which makes U61 a cool (?) game. Basically, this
    function sends a message over the network - if needed of course - to a
    remote player, and on the remote machine, the "user_do_curse" function is
    called. This allows a player to alter the map of another player.

    A mojor pitfall is to get confused with the difference between what I call
    a local curse and a remote curse:

    * A local curse is issued when the special "curse square" explodes for
      instance. The consequence is a call to "user_do_curse" in the map where
      the square disappeared with the second parameter set to 0. In most of the
      cases, a local curse will do something positive on the player's map, such
      as clearing it.

    * A remote curse is issued after an explicit call to "u61_send_curse". The
      consequence is a call to "user_do_curse" in the map of the default victim
      (the name of the victim is displayed in the player's status zone), with
      the second parameter set to 1. Any script code that has a "map_write"
      access may call "u61_send_curse". This way, remote curses can be launched
      in many situations. In most of the cases, a remote curse will do
      something negative on the player'smap, such as filling it with garbage.

  Example
  -------

    In this example, the player sends a "SPECIAL_CURSE_1" and a
    "SPECIAL_CURSE_2" to its default victim. This function might be called
    within "user_do_curse", but it'snot necessary, you could also call it when
    the player has matched a very rare pattern.

    SPECIAL_CURSE_1=51
    SPECIAL_CURSE_2=52
    
    function send_special_package()
        u61_send_curse(SPECIAL_CURSE_1)
        u61_send_curse(SPECIAL_CURSE_2)
    end



u61_set_anticipation_state
==========================


  Declaration
  -----------

    u61_set_anticipation_state(state)

    * Arguments: a boolean (1 or 0) telling if this mode should be on or off.

    * Return values: one.

    * Rights: map_write.

  Description
  -----------

    This function sets the state of the anticipation mode, that means wether
    the player should see where the block will land if he presses the "drop"
    key right away.

    As mentionned in the doc of "u61_get_anticipation_state", this parameter is
    mixed with the value entered by the player in the menus, and the preview of
    where the block will land is drawn only if both are true. Basically, it
    should be easier to play with this mode set to true, but some players (me
    for instance) find that in the long run it's not so great to have it set
    on. So in your scripts, you might decide that a curse disables this mode
    (to make the game harder) and enables it back when the curse is over. But
    for players like me who do not like the anticipation mode, it would be
    annoying to see this mode appearing when I have said in my options that I
    do not want to have it. So it's OK to call this function with false if you
    want to make things a little harder, but just remember that it will do
    nothing on players who have the option set to false anyway.

  Example
  -------

    In this example, we set the mode to false or true according to a curse
    state.

    ID_HALF_BLIND=8
    
    function update_half_blind()
        if u61_get_curse_age(ID_HALF_BLIND)>=0 then
            u61_set_anticipation_state(0) 
        else
            u61_set_anticipation_state(1)
        end
    end



u61_set_block_x
===============


  Declaration
  -----------

    u61_set_block_x(x)

    * Arguments: The x coordinate of the block.

    * Return values: None

    * Rights: block_write

  Description
  -----------

    This function changes the global x coordinate of the block. Basically, it
    allows translation.

    This function is very important, since it's not possible to perform a
    translation by calling "u61_set_item_x". Indeed, the "u61_center_block",
    which is called quite often, modifies the individual coordinates of each
    squares in a block so that it's centered on (x,y), x and y being set by
    "u61_set_block_x" and "u61_set_block_y". So you *need* to call this
    function if you want to translate the block horizontally.

  Example
  -------

    In this example, we move the block to the middle of the map.

    function to_middle()
        u61_set_block_x(5) 
    end



u61_set_block_y
===============


  Exactly the same as "u61_set_block_x", but x becomes y...



u61_set_curse_state
===================


  Declaration
  -----------

    u61_set_curse_state(state)

    * Arguments: 1 if the special curse square is to be activated, 0 if not.

    * Return values: none.

    * Rights: map_write.

  Description
  -----------

    Sets the current "curse state", ie tells if there should be a special curse
    square available on the map.

    As I'm writting this document, the "curse_state" parameter is set to true
    on a regular basis, so if you really want to remove the curse permanently,
    you have to call "u61_set_curse_state" continuously. By default, the curse
    will be disable for a given time (corresponding to a curse period, that's
    to say the delay until the curse moves and/or changes).

  Example
  -------

    In this example, we disable the special curse square when the user has more
    than 100000 points. This should prevent scores from getting too high...

    function limit_score_with_curse()
        if u61_get_score()>100000 then
            u61_set_curse_state(0)
        end
    end



u61_set_curse_x
===============


  Declaration
  -----------

    u61_set_curse_x(x)

    * Arguments: the x coordinate of the special curse square.

    * Return values: none.

    * Rights: map_write.

  Description
  -----------

    Sets the x position of the special curse square - that's to say the square
    which launches curses when it explodes, in the default theme it is the
    black and white "?".

    Note that if you call this function with an invalid parameter, ie a
    position which is outside the map or where there's no active square, then
    the special curse square won't be visible. In fact, you'll end up in a
    situation where "u61_get_curse_state" returns true and
    "u61_is_curse_available" returns false, even if you have set the curse
    square as active with "u61_set_curse_state".

    You should also keep in mind that it's not really necessary to call this
    function to move the curse square on a regular basis, since this is already
    done by the C++ core engine. In fact, this function is usefull when you
    mess up the whole map with calls to "u61_set_square_color", remove
    accidentally the square which was at the special square's location, and
    still want the special square to be available. In this case, you have to
    move the special curse square manually.

  Example
  -------

    In this example, we put the curse square on the first active square
    founded. The search starts at the bottom of the map.

    function put_curse_on first()
        local x
        local y
    
        y=u61_get_height()-1
        while y>=0 do
            x=u61_get_width()-1 
            while x>=0 do
                if u61_get_square_color(x,y)>=0 then
                    u61_set_curse_x(x)
                    u61_set_curse_y(y)
                    x=-1
                    y=-1
                end
                x=x-1 
            end
            y=y-1
        end    
    end



u61_set_curse_y
===============


  Exactly the same as "u61_set_curse_x", but x becomes y...



u61_set_global
==============


  Declaration
  -----------

    u61_set_global(i,value)

    * Arguments: an index and a value.

    * Return values: none.

    * Rights: map_write.

  Description
  -----------

    This function updates the global value associated to a given index (between
    0 and 99).

    This function is by no way related to the luac "setglobal" function.
    Indeed, in U61, you must *not* use any global lua variable to store
    parameters. Lua globals can only be used to store constants. This is due to
    the fact that if you use global lua variables:

    * They will be shared by all the players, which might not be what you want.

    * They won't be shared accross the network, since the core engine does not
      transmit lua globals between computers.

    Therefore, the chances that you end up with a wrecked game are important.
    Please do not try to do it, for this kind of bug never appears when you
    test your script with a single player, but will always occur during a
    thrilling internet play. See Murphy's theory.

    So "u61_get_global" and "u61_set_global" are here to help you in case you
    want to have a persistent value stored. The values accessed with these
    functions are different for each player, and do not generate any
    inconsistency when used in a network game. Basically thay consist in a
    array of numbers, where you can store your own values, for instance
    parameters linked to a curse. These numbers are set to 0 each time a new
    game starts, ie each time the map is filled with squares and the player
    looses.

    As of today, numbers are the only lua type which is usable with this
    function. It's actually a severe limitation, since being possible to store
    any lua object would make the writting of scripts a lot easier. However, I
    haven't yet managed to find a nice solution to this problem. It's true that
    lua offers the possibility to get a reference on any object, but I fear
    such a method would lead to memory problems - at least until I or someone
    else finds a way to handle references in a clean manner.

    Please keep in mind that if you want to use a global value such as a
    boolean telling if the player has the right to do some special action, then
    "u61_register_curse" might be a better choice than "u61_set_global".

  Example
  -------

    The following function decrements the value of a global counter.

    ID_COUNTER=8
    
    function decrement_counter()
        u61_set_global(ID_COUNTER,u61_get_global()-1)
    end



u61_set_item_color
==================


  Declaration
  -----------

    u61_set_item_color(i,color)

    * Arguments: the index and color of the square.

    * Return values: none.

    * Rights: block_write

  Description
  -----------

    Modifies the color of a square in the block.

    The color should normally always be a regular color (ie between 0 and 7),
    since having an empty square in a block does not really make any sense.

  Example
  -------

    The following example sets all the squares of the block to the given color.

    function set_color(color)
        local i
    
        i = u61_get_nb_items()-1
        while i>=0 do
            u61_set_item_color(i,color)
            i=i-1 
        end
    end



u61_set_item_x
==============


  Declaration
  -----------

    u61_set_item_x(i,x)

    * Arguments: the index of the square, and its x coordinate.

    * Return values: none.

    * Rights: block_write

  Description
  -----------

    This function modifies the x coordinate of a square in the block.

    Note that the returned coordinate is not absolute. This means that if you
    want to set the real position of this square in the map, you'll need to
    call the "u61_get_block_x" function too.

  Example
  -------

    This function sets the absolute position of a square in the block, ie its
    position in the map. So wherever the block may be, calling
    "set_absolute_x(0,0)" will place the first square of the block in the
    leftmost column of the map.

    function set_absolute_x(i,x)
        u61_set_item_x(i,x-u61_get_block_x())
    end



u61_set_item_y
==============


  Exactly the same as "u61_set_item_x", but x becomes y...



u61_set_preview_state
=====================


  Declaration
  -----------

    u61_set_preview_state(state)

    * Arguments: the state for the preview mode (1=on, 0=off).

    * Return values: none.

    * Rights:

  Description
  -----------

    Sets the preview state of the player. The preview is what shows the player
    what kind of block he will get next time a block falls.

    This function would typically used in a curse, to remove the great help
    provided by the preview, and put the player in a difficult position.

  Example
  -------

    This example sets the preview mode to false if the score is greater than
    100000. It assumes that any player capable of getting such a high score is
    good enough to play without a preview.

    function disable_preview_for_good_players()
        if u61_get_score()>100000 then
            u61_set_preview_state(0)
        end
    end



u61_set_score
=============


  Declaration
  -----------

    u61_set_score(score)

    * Arguments: the new score.

    * Return values: none.

    * Rights: map_write.

  Description
  -----------

    This function updates the current score.

    You'll have to remember that scores should not exceed 999.999, so that they
    can fit on 6 digits. However, if you exceed this limit, the value will be
    truncated to 999.999 anyway.

  Example
  -------

    The following example doubles the score of the player.

    function double_score()
        u61_set_score(u61_get_score()*2)
    end



u61_set_square_color
====================


  Declaration
  -----------

    u61_set_square_color(x,y,color)

    * Arguments: the coordinates of a square, and its color.

    * Return values: none.

    * Rights: map_write.

  Description
  -----------

    This function sets the color of a square in the map. The possible values
    for color are:

    * -1 if the square is to be disabled.

    * 0-7 if one whishes to put a colored square in this location.

    Any call with an invalid color (lower than 0 or greater than 7) will result
    in setting the color to -1. The question is: "why should the game be
    limited to 8 colors?". well, in fact, I had to fix a limited number of
    colors, since theme creation would have been too complex with a flexible
    number of colors. Indeed, you would have risked to get a 16-color based
    script with an 8-color based theme. And then you can't play since you can
    not distinguish all types of squares. So I had to set up a limit. I chose 8
    and think it's a good compromise between rich gameplay and easyness of
    theme creation.

    In the scritps and themes I have created, I have tried to respect the
    following rules:

    * Colors 0-6 are standard colors for blocks.

    * Color 7 is a special color, used for squares that are generated by curses
      and which in a general manner don't come with standard blocks. In the
      "classic" theme, theses are the grey squares.

    However, this is just a convention, and you can bypass it. Still, players
    might find the game more consistent if you respect it,

  Example
  -------

    This example moves all the squares from the current block to the map. This
    is what is done before the "user_match_pattern" function is called.
    However, you should never need such a function - it's only an example -
    since this work is automatically done by the C++ core engine.

    function block_to_map()
        local i
        local x
        local y
        local color
    
        i = u61_get_nb_items()-1
        while i>=0 do
            x=u61_get_item_x(i)+u61_get_block_x(i)
            y=u61_get_item_y(i)+u61_get_block_y(i)
            color=u61_get_item_color(i)
            u61_set_square_color(x,y,color)
            i=i-1
        end
        u61_clear_block()
    end

