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_clear_map

Declaration

  u61_clear_map()
  • Arguments: none.
  • Return values: none.
  • Rights: map_write.

Description

Clears the map, ie removes all the squares.

Keep in mind that this function clears all squares but does not perform a "total reset" since some parameters - such as active curses and score - still keep their values after the map has been cleared.

Example

This function puts a square in the middle of the map, after clearing it:

  function square_in_the_middle()
      u61_clear_map()
      u61_set_square_color(u61_get_width()/2,u61_get_height()/2,1)
  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 returns a value between 5 and 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.

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 returns a value between 2 and 10. In previous versions of U61 it used to return 10 all the time, since map size was not configurable. This is not the case anymore, and script programmers should not assume that map width is always 10 (the default value).

You might argue that since the map width is controlled by a user script (see u61_set_width), it's useless and cumbersome to call u61_get_width() when one knows that width is for instance of 8 because one called u61_set_width(8) before. My opinion is that it's much cleaner and less error prone to use u61_get_width() in all scripts.

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 6000, 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_height

Declaration

  u61_set_height(h)
  • Arguments: the new map height.
  • Return values: none.
  • Rights: map_write

Description

Changes the height of the map.

This function can safely be called "on the fly" while a player is playing and moving his block arround. All present squares will automatically be shifted so that the bottom squares stay at the bottom after resizing.

The height can range from 5 to 25. Note that depending on the block size, resizing the map to a "too small" size might make it simply impossible to play at all. Use with caution!

Example

The following function divides the height by 2:

  function half_height()
      u61_set_height(u61_get_height()/2)
  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 scripts 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

u61_set_width

Declaration

  u61_set_width(w)
  • Arguments: the new map width.
  • Return values: none.
  • Rights: map_write

Description

Changes the width of the map.

This function can safely be called "on the fly" while a player is playing and moving his block arround. All present squares will automatically be shifted and/or deleted so that they are globally "in the middle" of the resized map.

The width can range from 2 to 10. Note that depending on the block size, resizing the map to a "too small" size might make it simply impossible to play at all. Use with caution!

Example

The following function doubles the width of the map:

  function double_width()
      u61_set_width(u61_get_width()*2)
  end

u61_shift_map

Declaration

  u61_shift_map(x,y)
  • Arguments: 2 integers which define how squares will be translated.
  • Return values: none.
  • Rights: map_write

Description

Shifts/translates all the map squares.

This function can be usefull when you've just resized a map and/or want to move all the squares in the map at once. Note that it's automatically called whenever the map is resized, still the default behaviour might not be the one you expect.

Squares which are outside the map limits after being translated are simply deleted/ignored.

Example

The following function shifts the map down:

  function shift_down()
      u61_shift_map(0,1)
  end
Page generated by UWiKiCMS 1.1.8 on Thu Mar 28 2024.
Copyright © 2005 Christian Mauduit. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
Updated on Sun May 29 2005.