Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
CUAL(6) 			  Games Manual				 CUAL(6)

NAME
     Cual - Cuyo Animation Language

     Cual  is  the  main  language  used  to  describe	the  animations in cuyo.
     Strictly speaking it's the stuff between the << >> brackets  in  the  level
     description files (xxx.ld).

     On the other hand this man page aims at being a complete description of how
     to write levels for cuyo.	But it's still under construction.  See the file
     "example.ld" to get an idea of how the rest of the level description works.
     There's  also  a  bit of example Cual code in "example.ld".  And of course,
     all the existing levels are examples.

     Note that Cual is probably still very buggy.  So if strange  things  happen
     and you're sure it's not your fault, tell me (cuyo@karimmi.de).

HOW IT WORKS
     The  level description is organized in sections.  There is a global section
     and every level has its own section, which is a subsection  of  the  global
     section.	It  is	common	practice to place each level in a separate file,
     which then basically starts by opening its section and ends by closing it.

     A section is defined by name = {contents}.  name is the  name  of	the  new
     section and contents contains the definitions that pertain to that section.
     This is a sequence of definitions of the form name = stuff.  Here stuff can
     be  {contents} as above, or it can be a single datum, or it can be a comma-
     separated list of data.  Inside such a list, datum * number can be used  as
     a	shorthand for datum, ..., datum, i.e. a number-fold repetition of datum.
     A datum can be an identifier, a string (enclosed by '"'), a word, or a num-
     ber.  In place of a number <expression> can be used, where expression is an
     arbitrary expression made up from literal numbers, previously  defined  nu-
     meric data, and the operators +, -, *, / and %.

     Definitions can also depend on versions.  See section VERSIONING below.

     Apart  from  definitions,	a section can also contain cual definitions (see
     below).  These have to be enclosed in << and >>.

     Each blob has its own (main) Cual procedure which does the drawing and  the
     animation	stuff.	The procedure only depends on the kind of the blob, that
     is, it is the same for blobs of the same kind.  However each blob	has  its
     own instance of the variables.

     In  every	game  step,  the  procedure of each of the blobs is called once.
     (There are 12.5 game steps per second.)  It has to draw the blob each time,
     even if nothing has changed.  (However, there's an internal routine in cuyo
     which checks if the same is drawn as in the last step and	which  then  su-
     presses the drawing.)

     There  may be other procedures associated to a kind of blob, which are exe-
     cuted at special events, for example when a falling blob  lands.	In  con-
     trast  to	the main procedure, these event handlers are not allowed to draw
     anything.	See section EVENT HANDLERS for a list of the existing events.

     The name of the main procedure of a blob (the one which draws the blob)  is
     the  name	of the kind of the blob.  Normally, that name is the word listed
     after pics= entry in the .ld file; but if that "word" contains a dot,  only
     the  part	before	the  dot  makes  up  the  name.   (E.  g. with pics=red-
     blob.xpm,greenblob.xpm, the names are "redblob" and "greenblob".)

     The name of an event handler procedure is the name of the kind, followed by
     a dot, followed by the event name.  (E.g. "redblob.land"  for  the  landing
     event of the redblob from above.)

     [Explain the default procedures.]

LEVEL DATA
   String valued data
     name   The  name  of the level.  This appears in the list of levels as well
	    as in the level intro.

     description
	    This is an optional further description of the level in its intro.

     author
	    The name of the level author(s) for credit at  the	beginning  of  a
	    level.

   Identifier valued data
     bgpic  Background	picture  (file	name).	 If too small, placed at bottom.
	    Defaults to none.

     toppic
	    Appearance of the top border coming down (file name).   Defaults  to
	    none.

     explosionpic
	    Appearance of the explosions (file name).  Has a default.

   Number valued data
     numexplode
	    The  size  that  a	group of blobs has to reach in order to explode.
	    This is only the level-wide default.  Each kind can  override  this.
	    Whether the group does explode is also controlled by behaviour.  See
	    section VARIABLES AND CONSTANTS for details.

     toptime
	    Time  the  border takes to come down, in number of game steps.  Each
	    game step lasts 80ms.  The default value is 50 (i.e. one pixel every
	    four seconds).

     topoverlap
	    Placement of toppic relative to the actual border.	More  precisely,
	    number of pixels the lower border of the picture is below the actual
	    border.  Defaults to the height of the picture.

     topstop
	    When the border comes down at the end of the level, number of pixels
	    it	should	stop  before  the bottom.  Set this to the same value as
	    topoverlap if you want your toppic to be comletely	visible  at  the
	    end.  Defaults to 0.

     chaingrass
	    Must  be 0 or 1.  If set to 1, chain reactions are necessary to kill
	    the grass.	Defaults to 0.	More precisely, chaingrass only controls
	    the default for behaviour for grass blobs.	 See  section  VARIABLES
	    AND CONSTANTS for details.

     mirror
	    Must  be  0  or 1.	If set to 1, the level appears upside-down.  De-
	    faults to 0.

     randomfallpos
	    Must be 0 or 1.  If set to 1, the initial fall position  is  random-
	    ized horizontally.	Defaults to 0.

     neighbours
	    Determines	in  which directions the blobs can connect to each other
	    in order to form groups.  This is only the level-wide default.  Each
	    kind can override this.  See section  VARIABLES  AND  CONSTANTS  for
	    values.  Defaults to neighbours_rect.

     hexflip
	    In	hex  mode,  determines	whether  the even or the odd columns are
	    shifted upwards.  By default (hexflip =  0),  the  odd  columns  are
	    shifted.  1  means:  shift	even columns of player 1; 2 means: shift
	    even columns of player 2; 3 means: shift even columns of both  play-
	    ers.

     randomgreys
	    The expected time between two randomly appearing greys in game steps
	    (80ms).  Use -1 for none at all, which is the default.

     nogreyprob
	    The  probability  that  a  grey  does  not appear.	See greyprob and
	    colourprob in section KIND DATA for details.  The default is 0.

     aiu_color, aiu_grass, aiu_grey, aiu_two_above, aiu_monochromic_vertical,
     aiu_height
	    Parameters for the AI player's utility  function.	Default  respec-
	    tively   to   <10*(number	of   kinds)>,	20,  10,  <aiu_color/2>,
	    <aiu_color>, and 10.  See section THE AI UTILITY  FUNCTION	for  de-
	    tails.

   Colour valued data
     (A colour is an RGB triple of numbers between 0 and 255.)

     bgcolor
	    The background colour.  Defaults to white.

     textcolor
	    Colour  of	any text.  This includes the beginning-of-level informa-
	    tion, message()s, and score.  Defaults to a certain  shade	of  dark
	    grey.

     topcolor
	    The  colour  of the top border comming down (where not determined by
	    toppic).  Defaults to a certain shade of light grey.

   Other data
     startdist
	    Distribution of blobs at the beginning of the level.  It is  a  list
	    of	strings,  the format of which is described in the section START-
	    DIST.

     pics, greypic, startpic, emptypic
	    Lists of kinds.  These can be either file  names  referring  to  the
	    picture to be used, or declarations of kinds that have to be defined
	    later  on.	The different keywords (e.g. pics, emptypic) define dif-
	    ferent defaults.  In fact, only the first three may be  real  lists,
	    emptypic is limited to exactly one entry.  In these lists, it is ad-
	    visable to use * whenever possible.  Besides being shorter to write,
	    it	also  speeds up loading of the level and cuts down memory usage.
	    This is because cuyo does some initializations only  once  for  each
	    entry with multiplier.

	    The  intentions of these lists are normal blob kinds resp. grey blob
	    kind resp. grass blob kind resp. nothing-blob.   However,  the  only
	    differences  between pics, greypic and startpic are the default val-
	    ues for behaviour, colourprob, goalprob, greyprob, versions and dis-
	    tkey (see there).  All of these can also be overridden individually.
	    Also, the default drawing code is different.  (The	default  drawing
	    code for startpic does not draw connections.)

     kind   Each kind can have its own section.  See KIND DATA below for the en-
	    tries of that section.

KIND DATA
     numexplode, neighbours
	    Defining  these  data  in the section of a kind overrides the level-
	    wide value for the kind.  See section LEVEL DATA for  a  description
	    of these data.

     pics   A  list of file names of pictures to be used for this kind.  The nth
	    entry can later be accessed in cual with file=n-1.

     colourprob
	    The probability that this kind appears as one  of  the  two  steered
	    falling  blobs.   More  precisely,	this  is  a  nonnegative integer
	    weight.  For determining the actual probability, the  value  is  di-
	    vided  by the sum of the colourprobs of all kinds.	This sum must be
	    positive.  The default is 1 for kinds declared with pics= and 0  for
	    all  other	kinds.	The probability is also used for + in startdist.
	    For more details see section STARTDIST.

     goalprob
	    This affects the semantics of * in startdist in  the  same	way,  as
	    colourprob	does  for  +.	The default is 1 for kinds declared with
	    startpic= and 0 for all other kinds.

     greyprob
	    The probability that this kind appears as a grey blob.  This is sim-
	    ilar to colourprob, but there is a	difference:  For  greyprob,  no-
	    greyprob  is  included  in	the sum, so that it might happen that no
	    blob appears at all.  There is a notable difference between a  posi-
	    tive  nogreyprob  and a positive greyprob in kind nothing, when sev-
	    eral lines of grey blobs appear: In the latter case, empty blobs ap-
	    pear in the wall of greys, making holes.  In the  former  case,  the
	    wall is made less high.  Usually this is preferable.  The default is
	    1  for  kinds declared with greypic= and 0 for all other kinds.  The
	    value also affects the semantics of - in startdist.  In  this  case,
	    nogreyprob is not included in the sum.

     versions
	    At	the  creation  of  a  blob, its version variable is initialized.
	    Usually, it is chosen at random from 0 to versions-1, but  startdist
	    provides  the possibility to specify it exactly.  See section START-
	    DIST for details.  The default is 1.

     distkey
	    An alphanumerical key, which is used in startdist to  identify  this
	    kind of blob.  The default is A for kinds declared with startpic and
	    undefined for all other kinds.  See section STARTDIST for details.

CUAL DEFINITIONS
     Inside << >>, variable and procedure definitions are expected.

     procname = code ;
	    Defines  a	"procedure".   The next section describes how code looks
	    like.  Example:

	      redblob = {
		schema16; 0*;
		1; A,B,C; *;
	      };

     var varname1 [= def1 [: reapply]], varname2 [= def2 [: reapply]], ... ;
	    Defines variables with default values.  If no default is  specified,
	    zero is used.  See section VARIABLES AND CONSTANTS about the meaning
	    of the default value and the optional suffix : reapply.

     default varname1 = def1 [: reapply], varname2 = def2 [: reapply], ... ;
	    Changes  the default for already defined variables.  Again, the suf-
	    fix : reapply is optional.	This is useful to give to a single  kind
	    a  different  default for a variable than to the other kinds.  Also,
	    the default of a system variable can be changed this way.

CODE
     A code fragment can be one of the following:

     { code; code; ...}
	    Executes one command after the other.

     code, code, ...
	    This is useful for simple animations.  Executes exactly one  of  the
	    commands:  In the n-th call, the n-th command is executed. After the
	    last command, the first one is executed again.  However, if  one  of
	    the commands is "busy" (see section BUSIENESS), this one will be ex-
	    ecuted until it stops being busy, and only after that, the next com-
	    mand will be executed.

     procname
	    Executes  the  procedure  procname, which has to be already defined.
	    The result is the same as if the code from procname would have  been
	    inserted in that place.

     &procname
	    Executes  the  procedure procname; however, every instance of such a
	    procname is the same.  This concerns busieness and the state  of  an
	    animation sequence.  (See sections BUSIENESS and AMPERSAND-CALL.)

     busy   Does nothing except being busy.  (See section BUSIENESS.)

     varname = expr
	    Sets the variable.	See section VARIABLES AND CONSTANTS for details.

     The same with +=, -=, *=, /=, %=, .+=, .-=.
	    Does what you would expect.

     [ varname = expr ] code
	    Sets the variable varname to expr, executes code and then resets the
	    variable to the old value.

     number
	    A shortcut for file = number.

     letter
	    A  shortcut for pos = number, where different letters mean different
	    numbers: A: 0, B: 1, ..., Z: 25, a: 26, ..., z: 51

     *	    Draw the icon specified by the variables kind, file  and  pos.   May
	    also  draw	only a part of the icon, if specified by the variable qu
	    (see section VARIABLES AND CONSTANTS).

     *@(position)
	    Like *, but draws the icon at some other position.	This drawing  is
	    performed after all drawing by *.  If *@ is used from several blobs,
	    the  further  order  of drawing is not specified.  It is guaranteed,
	    however, that at any given time this order is the same for all posi-
	    tions.  (See section VARIABLES AND CONSTANTS for more details  about
	    @.)

     @(position)*
	    Like  *, but draws the icon at some other position.  This drawing is
	    performed before all drawing by *.	 If  @*  is  used  from  several
	    blobs, the further order of drawing is not specified.  It is guaran-
	    teed, however, that at any given time this order is the same for all
	    positions.	 (See  section	VARIABLES AND CONSTANTS for more details
	    about @.)

     if expr if-arrow if-code ;
     if expr if-arrow if-code else [else-arrow] else-code ;
	    The arrows can be either "->" or "=>".  If you use "->"  arrows,  it
	    does  exactly what you would expect.  If the if-arrow  is "=>", then
	    once the expression gets true, the if-code will  be  executed  every
	    subsequent	time  (without	testing the condition), as long as it is
	    "busy".  For more details see section BUSIENESS.  If the  else-arrow
	    is	"=>", then once the expression gets false, the else-code will be
	    executed every subsequent time as long as it is busy.  The	else-ar-
	    row may only be omitted, if the if-arrow is "->".  Then the else-ar-
	    row also is "->".  (But this might change in the future.)

     switch {
       expr1 arrow1 code1 ;
       expr2 arrow2 code2 ;
       ...
     }	    The arrows can be either "->" or "=>".  Does the same as:

	      if expr1 arrow1 code1
	      else => if expr2 arrow2 code2
	      ...

	    The  last  expr may be omitted.  This is equivalent to setting it to
	    true.

     bonus(expr)
	    The player gets expr bonus points.

     message(String)
	    The string is displayed (blinking) on the screen.  To  be  used  to-
	    gether with bonus(...).  Example:

	      bonus(50);
	      message("You get 50 bonus points");

     explode
	    Makes  the	blob  explode.	 For the next 8 steps or so, the blob is
	    still what it was before, but the explosion is drawn over the graph-
	    ics.  After that, it's changed to a nothing-blob.

     lose   The players immediately lose the level.

     sound(Filename)
	    Plays the given sound file.

     You can also omit the code completely.  Then, of course,  it  does  not  do
     anything.	This can be useful as part of ,-sequences.

     There's  a  shortcut  for drawing: You may omit the ";" between a number, a
     letter and the "*".

EXPRESSIONS
     The only data type in cual is int.  Bools are represented by 0 and 1,  like
     in C.  (And any number other than 0 is interpreted as true, if a boolean is
     expected.)

     Of  course,  variables,  constants and numbers are expressions, and you can
     use parentheses.  There are the following operators (listed here  in  order
     of increasing precedence):

	    ||	   Boolean or

	    &&	   Boolean and

	    ==, !=, <, >, <=, >=
		   Comparison

	    ==..   A special comparison

	    !	   Boolean not

	    +, -   Add, substract

	    :	   Special operator

	    *, /, %
		   Multiply, divide, modulo

	    &, |, .+, .-
		   Bitwise  and,  bitwise  or,	setting of bits (same as bitwise
		   or), unsetting of bits

	    -	   Unary minus

	    .	   Testing of bits (a.b is the same as a&b != 0)

     / and % work mathematically correct and do not make funny changes when  the
     sign  of  the numerator changes.  More specifically, if b is positive, then
     a/b is the largest integer n such that n*b<=a.  If b is negative, then  a/b
     is  the largest integer n such that n*b>=a.  In both cases a%b is such that
     (a/b)*b+a%b = a.  Examples:

     13/5=2	  13%5=3
     -13/5=-3	  -13%5=2
     13/-5=-3	  13%-5=-2
     -13/-5=2	  -13%-5=-3

     The following are the special operators:

     expr1 == expr2 .. expr3
	    Is true, if expr1 lies between expr2 and expr3.  You may  also  omit
	    one  of  expr2  and expr3.	(Then, it does the same as <= resp. >=.)
	    The precedence implies that x==y==2..3 is the same	as  x==(y==2..3)
	    and is neither (x==y)==2..3 nor x==(y==2)..3.  Note that this opera-
	    tor might change in the future. (I plan to make something like "expr
	    in set" in Pascal.)

     expr1 : expr2
	    Is true (that is, 1) with probability expr1/expr2

     neighbour_pattern
	    neighbour_pattern  is a sequence of six or eight characters 0, 1 and
	    ?.	It is true if the sequence fits to the neighbour sequence of the
	    blob.  The neighbour sequence is a string of "0"s and  "1"s  with  a
	    "1"  for  each  neighbour of the same kind, starting above and going
	    clockwise.	This way, you get a string of  "0"s  and  "1"s	(six  or
	    eight, depending on wether this level is in hex mode).

	    Example:  1???0???	is  true  iff the blob above this blob is of the
	    same kind and the blob below it is of different kind.

	    For an empty blob the semantics is slightly different:  If	in  some
	    direction  there  is no neighbour, because the field ends there, the
	    entry in the neighbour sequence is 1 nevertheless.	So for an  empty
	    blob  1???0???  is true, iff the blob above this blob does not exist
	    or is empty as well, and the blob below this blob exists and is  not
	    empty.

	    If	some  blob  changes  its kind during a step, the expression will
	    still test the neighbours as they were at the beginning of the step.
	    (See the section VARIABLES AND CONSTANTS for details.)

     The following functions exist:

     rnd(expr)
	    Returns a random value between 0 and expr-1

     gcd(expr1, expr2)
	    Returns the greatest common divisor of expr1 and expr2

VARIABLES AND CONSTANTS
     The following kinds of variables and constants exist:

     --
	User defined variables (see section CUAL DEFINITIONS).	At the start  of
	the  level  (or  at  the  creation of the blob) the value is the default
	value you provided.  If you supplied the default with :  reapply,  when-
	ever a blob's kind changes, the value of the variable is also set to the
	default  of the new kind.  There is a subtlety: This only happens if the
	new value of kind is in fact different from the old one.

     --
	System variables.  These variables are always defined and  have  special
	meanings, e.g. file and pos.  Some of them are read-only.

     --
	User  defined constants.  These are defined in the main .ld part, not in
	cual (not inside << >>).

     --
	System constants.  Some of them depend on properties of the level,  some
	are really constant.

     Of  each variable, there's one instance in each blob.  Normally, you access
     the instance in your own blob, but with the following syntax, you	can  ac-
     cess variables of other blops:

       varname@@(x, y; side)
       varname@@(x; side)
       varname@@(; side)
       varname@(dx, dy; side)
       varname@(dx; side)
       varname@()

     If  x and y are given, these are absolute coordinates in the grid of blops,
     that is the variable is taken from the blob with loc_x=x and  loc_y=y  (see
     under  The  system variables).  If only x is given, it specifies one of the
     two blobs that are currently falling.  If there is only one such blob left,
     because the other one got stuck on some tower, the remaining blob's coordi-
     nate is 0.  Otherwise one of the two has coordinate 0, the other 1.

     In the @ variants, the coordinates are relative to the current  blob.   The
     variant  @@(;  side)  refers to the semiglobal blob, the variant @() to the
     global blob (See section THE GLOBAL BLOB).  The extra part ;  side  is  op-
     tional and specifies the side of the game.  This is only meaningful in two-
     player  mode.   side  =  <  specifies  the  left player, side = > the right
     player, side = = the player to which the current blob pertains, and side  =
     ! the other player.  @() and @@() can also be given as @ respectively @@.

     This  can	be  done for both, reading and writing variables.  It also works
     for system variables (but not for constants).

     In hex mode levels, for odd dx, dy should be a "half integer",  that  is  a
     number  ending  in ".5".  This is the only place in Cual where non-integers
     appear.  Especially, ".5" is not allowed in composite expressions.   There-
     fore, also integer dy is always allowed.  If a half-integer is expected and
     an  integer  is given, it is assumed to be rounded to above, that is 5 then
     represents 4.5 and -5 represents -5.5.

     Caution: With mirror=1 the absolute and the relative coordinates  use  dif-
     ferent coordinate systems.  Handle with extreme care.

     Accessing	foreign  variables  is	not  as  easy  as it might look at first
     glance; it might easily introduce a dependence of the internal order of ex-
     ecution of the blob codes.  For this reason,

     --
	reading variables with @ or @@ always returns the value of the	variable
	it  had at the beginning of the current step, that is, before any of the
	blob codes has been executed.

     --
	when writing variables with @ or @@, the write operation  will	only  be
	executed  at  the  end	of  the current step.  (The write operations are
	stored in a kind of queue.)

     This is also true if a blob accesses its own variables with @(0,0).

     The operators +=, -=, etc.  are also performed in the future  if  the  left
     hand  side  is  an @-variable.  (To be more precice, the right hand side is
     calculated instantanousely.)

     For illustration, look at the following six statements:

     1)   X += 1
     2)   X@(0, 0) += 1
     3)   X = X + 1
     4)   X = X@(0, 0) + 1
     5)   X@(0, 0) = X + 1
     6)   X@(0, 0) = X@(0, 0) + 1

     Only 1) and 3) do the same; they simply increment X  by  1.   Statement  4)
     sets  X  to  one more than it was at the beginning of the step.  Statements
     2), 5) and 6) cause the value of X to be changed in the future  (after  the
     current step): X is set to one more than:

     2)     the  value of X just before the change (that is, X is incremented in
	    the future),

     5)     the current value of X,

     6)     the value of X at the beginning of the step.

   Some more details
     --
	Whenever you try to access a variable at a location which doesn't exist,
	you will get the default value.  If default values depend on  the  kind,
	the default pertaining to the blob executing the code is used.	This may
	change in the future.

     --
	Changing  a  variable which doesn't exist does nothing (and does not re-
	sult in an error).

     [Add explanation of time slices; roughly:
	@-access of variables in reality don't access the value  at  the  begin-
	ning/end  of the game step, but of the time slice.  The call of the main
	procedure of all blobs happens in the same time slice,	but  each  other
	kind of event has its own time slice.]

   The system variables
     file   Specifies  the file number from which to take the icon that is drawn
	    by "*".  This variable is reset to 0 before the drawing procedure is
	    executed.

     pos    Specifies the position in the file of the icon that is drawn by "*".
	    This variable is reset to 0 before the  drawing  procedure	is  exe-
	    cuted.

     kind   The  kind  of the blob.  There are constants for the possible values
	    of this variable.  If you change the kind, you should  be  aware  of
	    three things:

	    --
	       Expressions like "001???01" test the neighbour pattern at the be-
	       ginning	of the current step.  So the change of the variable kind
	       will not be reflected.

	    --
	       In the current step, the program to draw  the  blob  has  already
	       been  invoked  (it  might  even be the program which changed this
	       variable); so in this step, the blob will still look like one  of
	       the  old  kind.	 However, if things are drawn after the kind has
	       been changed, icons from the new kind are taken.

	    --
	       Defaults of the new kind that are declared with : reapply are ap-
	       plied.  This happens at the same time that kind changed, but only
	       if the new kind is different from the old one.

     version
	    Is assigned a hopefully distinctive value at  the  blob's  creation.
	    See versions in section KIND DATA for details.

     qu     Tells "*" which part of the icon to draw.  It's possible to draw the
	    whole icon, or only one of its quarters.  If a quarter is drawn, you
	    may specify independently which of the quarters to take and at which
	    position  to draw it.  Use the constants (see below).  This variable
	    is reset to "draw all" before the drawing procedure is executed.

     out1, out2
	    Set these Variables for debug output.  The values will be printed on
	    top of the blob.  These variable are reset to "output  nothing"  be-
	    fore  the drawing procedure is executed.  (In fact, "output nothing"
	    is one special big value.)

     weight
	    When calculate_size is set in behaviour, size will be regularly  up-
	    dated  to the sum of weight in the connected component.  The default
	    is 1.

     inhibit
	    Set this variable to a sum of the constants DIR_...; this  will  in-
	    hibit  that  this  blob connects into the given directions.  This is
	    not for the graphics but for the calculation of the connected compo-
	    nents and the explosions.

     behaviour
	    This is a bit field.  Refer to The Constants below for the	meaning-
	    ful of its bits.  The default is calculate_size+explodes_on_size for
	    normal  blobs,  explodes_on_explosion+explodes_on_chainreaction  for
	    grey blobs, floats for the empty blob  and	goalblob+explodes_on_ex-
	    plosion+explodes_on_chainreaction or goalblob+explodes_on_chainreac-
	    tion (depending on whether chaingrass is set) for grass blobs.

     falling_speed, falling_fast_speed
	    These  variables are only used in the semiglobal blobs.  They define
	    the vertical speed of the steered falling blobs.  The unit is pixels
	    per game step.  The defaults are 6 and 32.

   The system read-only variables
     time   The number of time steps since the level was started.

     turn   Is 1 resp. 2 if the blob is falling and just  being  turned  by  the
	    user and 0 otherwise.  (1 in the first turning step, 2 in the second
	    one.)   Be	aware that if the user presses the turn key fast several
	    times, some of these steps may be omitted.	(Use the turn  event  if
	    you  want to be sure that a program block is executed once for every
	    turn.)

     connect
	    Contains internal data.  Will be removed.  Probably.

     size   The size of the component of the blob.  (That is, how many blobs are
	    connected.)

     basekind
	    The value of the constant generated for the name of the kind of  the
	    blop.  Example:

	      pics = orange, pear, apple * 3, banana, apple

	    Here,  all	four  kinds  apple have the same value for basekind, and
	    this value is apple.

     loc_x, loc_y
	    The absolute coordinates of the blob.  (0,0) = top left corner

     loc_xx, loc_yy
	    The absolute coordinates of the blob in pixels.  This is not  always
	    the  same  as  loc_x*32  and  loc_y*32, particularly for the steered
	    falling blobs.

     loc_p  The player of the blob (1 or 2)

     falling
	    true, if the blob is falling or it is a preview of a  falling  blob.
	    (Falling  in the sense of steered by the player.  Grey blobs are not
	    falling in that sense.)

     falling_fast
	    True, if the blob is falling fast, that is,  the  user  pressed  the
	    down key.

     informational
	    True,  if  the blob is one of the info-blobs at the side of the game
	    area.  In this sense, the previews of the falling blobs  also  count
	    as info-blobs.

     players
	    The number of players.

     exploding
	    When  the blob is exploding, the position in the explosion animation
	    (1 to 8); 0 else.

	    Currently, there is one exception: if the explosion has  been  trig-
	    gered  by the explode command, then exploding will have value 1 only
	    after the current game step [more precisely: time slice; fix  that].
	    Reason:  when  reading exploding@(x,y), we maybe don't know yet that
	    the other blob calls explode.

   The Constants:
     Constants for behaviour:

     goalblob
	    Set goalblob if this blob should act like grass: You  will	have  to
	    get  rid  of  it  to win the level and making this blob explode will
	    give more points.

     calculate_size
	    When this bit is set, size will be regularly updated to the  sum  of
	    weight in the connected component.

     explodes_on_size
	    When  this	bit  is set, a connected component explodes, when it has
	    size>=numexplode.

     explodes_on_explosion, explodes_on_chainreaction
	    When these bits are set, the blob  explodes  whenever  an  explosion
	    that was triggered by explodes_on_size happens in its neighbourhood.
	    explodes_on_chainreaction refers to those triggering explosions that
	    are  the  second or later part of a chain reaction.  explodes_on_ex-
	    plosion refers to the other ones.

     floats
	    When this bit is set, the blob keeps its vertical position	even  if
	    there is an empty blob below.  This bit has no effect on the steered
	    falling blobs.

     Constants for kind:

     <name of kind of blob>
	    For  each  kind  of blob, there's one constant with the name of that
	    kind. Use it to check if a blob is of that kind using kind@(x,y)  ==
	    aKind  or to change to that kind using kind = aKind.  See kind under
	    The system variables for the side-effects of setting kind.

	    Sometimes it is necessary to perform arithmetic on kinds, for  exam-
	    ple  when  several	have  been declared using the * multiplier.  The
	    values of the constants are successive in the order,  in  which  the
	    kinds  have  been  declared.  When a name is used several times, the
	    first use defines the value.  Example:

	      startpic = apple, orange
	      pics = orange, pear, apple * 3, banana
	      greypic = pineapple

	    This initializes 2 kinds with the defaults	for  startpic,	6  kinds
	    with  the  defaults  for  pics,  and  1  kind  with the defaults for
	    greypic.  The value of the constant orange is 1 more  than	that  of
	    apple,  pear  is  2 more than orange, banana is 4 more than pear and
	    pineapple is 1 more than banana.  We do not specify what these  val-
	    ues actually are.

	    This  constant  also  exists for the empty kind, if one has been de-
	    clared using emptypic.  In this case the  value's  relation  to  the
	    other values is not specified at all.

     global, semiglobal
	    Denote the kind of the global, respectively semiglobal, blob.

     nothing
	    Is	the  same  as the constant for the empty kind.	Is provided, be-
	    cause sometimes, you don't have an empty kind, but you still need to
	    test if a blob is empty.

     outside
	    The value of kind if the coordinates are outside of the game board.

     Constants for neighbours:

     neighbours_rect
	    A blob connects up, down, left, and right.	This is the default.

     neighbours_horizontal
	    A blob connects left and right.

     neighbours_vertical
	    A blob connects up and down.

     neighbours_diagonal
	    A blob connects diagonally.

     neighbours_hex6
	    When used in the level-wide neighbours, this sets hex mode.  A  blob
	    connects  up,  down,  left	with a slight upwards shift, left with a
	    slight downwards shift, right with a slight upwards shift, and right
	    with a slight downwards shift.

     neighbours_hex4
	    When used in the level-wide neighbours, this sets hex mode.  A  blob
	    connects  left with a slight upwards shift, left with a slight down-
	    wards shift, right with a slight upwards shift,  and  right  with  a
	    slight downwards shift.

     neighbours_knight
	    A  blob connects in knight moves (Two forward and then one sideways.
	    Forward is one of up, down, left or right.	Sideways is  perpendicu-
	    lar to forward.  This makes a total of eight directions.).

     neighbours_eight
	    Combines neighbours_rect with neighbours_diagonal.

     neighbours_3D
	    A  more obscure mode created especially for 3d.ld.	When used in the
	    level-wide neighbours, this sets hex  mode.   A  blob  connects  up,
	    down,  two (but not one) to the left, and two to the right.  In even
	    columns it also connects right with a slight upwards shift.  In  odd
	    columns it also connects left with a slight downwards shift.

     neighbours_none
	    A blob does not connect at all.

     Constants for qu:

     Q_ALL  Value for qu, which means "draw the complete picture".

     Q_TL, Q_TR, Q_BL, Q_BR
	    Values for qu.  "TL" means draw top-left quarter, etc.  (See the "*"
	    command in the Code section.)

     Q_SRC_DST
	    SRC  and DST may be TL, TR, BL, BR.  Take quarter SRC and draw it at
	    position DST.

     Miscellanious constants:

     DIR_XX
	    To be used with the variable inhibit to prevent the blob  connecting
	    in	the given directions.  XX can be U, D, L, R (horizontal and ver-
	    tical); UL, UR, DL, DR (diagonal); UUL, UUR,  DDL,	DDR,  LLU,  LLD,
	    RRU, RRD (knight); F, B (3d)

VERSIONING
     Sometimes	it  is necessary to define a level slightly differently for dif-
     ferent purposes.  For example you might need to decrease numexplode for the
     two-player version lest it becomes  unplayable.   The  difficulty	settings
     from cuyo's main menu provide another example.

     This  is  done by qualifiing a definition with the versions it should apply
     to.  It is best explained by an example:

       numexplode = 8
       numexplode[2] = 6
       numexplode[1,hard] = 10

     This specifies that normally numexplode should be 8.  In two-player mode it
     should be 6.  In one-player hard mode it should be 10.  Here the specifiers
     2 for two-player mode, 1 for one-player mode and hard  for  hard  mode  are
     used.   Along  with  easy for easy mode these are all predefined specifiers
     intended for levels.  Additionally (and for internal purposes),  there  are
     specifiers for the level tracks: main, all, game, extreme, nofx, weird, and
     contrib.

     Furthermore,  you	can  make  up and use your own specifiers.  In order for
     them to take effect, though, you have to give cuyo  additional  information
     about  the  current  version.   This  is done on the command line using the
     --version option.	For example

       cuyo --version=hard,geek

     Specifies both hard version (you can change that in the menu)  and  version
     "geek", which is not predefined.

     There are several constraints to be observed:

     --
	All  versions  of  a definition must be made before the first use of the
	thing defined.	As sometimes it is not obvious where the  defined  thing
	is  used (for example startpic uses a previous greypic by assigning suc-
	cessive numbers to kinds), it is best to group all these  versions  into
	one block.

     --
	A  given  version  also  applies  to every more specialized version, for
	which no definition is given.  In the above example, numexplode  is  set
	to 6 in two-player hard mode and in two-player easy mode as well.

	All  resulting	conflicts  must be resolved.  For example, if you make a
	definition for [2] and one for [hard], you must also make  a  definition
	for  [2,hard]  (or,  equivalently,  for  [hard,2]), because otherwise it
	would be ambiguous which of the two former should  apply  in  two-player
	hard mode.

     --
	Cuyo  knows  that easy and hard exclude each other.  Consequently, it is
	unnecessary (and indeed prohibited) to give an	[easy,hard]  definition,
	even  if  both [easy] and [hard] are given.  The same holds for 1 and 2,
	and for level tracks.

     --
	Furthermore, cuyo knows that 1 and 2 are exhaustive: There  is	no  mode
	which  is  neither  single-player  nor two-player.  (The human-versus-AI
	mode counts as two-player as far as cual is concerned.)   Therefore,  if
	there  are  definitions for both, it is unnecessary, (and again illegal)
	also to define a version without any of both.  For  example,  if  [1,de]
	and [2,de] are given, [de] must be omitted.  Alternatively, you could of
	course	give [1,de] and [de] or [de] and [de,2].  The level track speci-
	fiers are exhaustive as well.

BUSIENESS
     (No, not Business ;-)

     Busieness is a concept to make it easier to implement simple  animated  se-
     quences  which  are triggered by certain events.  Each code fragment has an
     internal state which tells if it is busy.

     --
	Normal statements like assignments are never busy.

     --
	A chain of commands separated by "," is busy as long as not all  of  the
	commands have been executed.

     --
	code1  ;  code2  is  busy as long as at least one of code1 and code2 are
	busy.

     Here's an example of how to use busieness for an animation which appears at
     random intervals:

       switch {
	 1:100 => {B*, C*, D*, E*};
	 -> A*;
       };

     This code fragment normally draws the icon at position A (0).  But in  each
     step,  with  a  probability  of  1/100, an animation sequence consisting of
     icons B, C, D and E is started.  With  a  normal  arrow  ("->")  after  the
     "1:100", after the step in which B has been drawn, the probability would be
     99/100 that A is drawn again.  But with the double arrow, the switch state-
     ment won't switch back to A until the animation has terminated.

     (Btw:  It	doesn't  matter  if there's a "->" or a "=>" before the "A*"; A*
     isn't busy anyway.)

THE GLOBAL BLOB
     Apart from the normal blobs which you can see on screen, there's one global
     blob (for the whole game, not one for each player), which, well, isn't  re-
     ally  a  blob, but behaves a bit like it.	It has its own set of variables,
     and it can have a program which is run once every step.  To define  such  a
     global  program,  use  global=code.  However, the global variables do exist
     even if you don't define global code.  See section VARIABLES AND  CONSTANTS
     on how to access them.  Note that the global blob is always executed before
     any of the normal blobs.

     There  are also semiglobal blobs.	There is one for each player.  These are
     programmed with semiglobal=code.

EVENT HANDLERS
     The following events exist:

     init   Is called only once, when the blob gets into life, just  before  the
	    first time its main drawing routine is called.

     turn   Is called for falling blobs each time they are rotated.

     land   Is called when the steered blob lands (just after it landed).

     changeside
	    Is called when a blob moves from one player to the other, just after
	    the blob has arrived at the new player.

     connect
	    Is called when the connection of blobs is recalculated.

     row_up
	    Is	called when a player got a row from the other side, after every-
	    thing is finished and just after the loc_y of all blobs has been de-
	    creased by 1.  Is only called for the semiglobal blob, though.

     row_down
	    Is called when a player gives a row to the other side,  before  any-
	    thing  visible  happens,  but  just after the loc_y of all blobs has
	    been increased by 1.   Is  only  called  for  the  semiglobal  blob,
	    though.

     keyleft, keyright, keyturn, keyfall
	    Are  called  when  the  player presses the left, right, turn or fall
	    key.  Are only called for the steered falling blobs  and  the  semi-
	    global  blob,  though.   (Note that, in contrast to turn, keyturn is
	    called even if the steered blob cannot be rotated due to some obsta-
	    cles, and also if there is no steered blob.)

THE LIFE OF A BLOB
     Normal blobs come into life at the beginning of the game, or they fall into
     life: either as colored blobs, steered by the user, or as grey blobs.  More
     precisely, the steered blobs already come into life when they appear as the
     preview.  When a blob moves (by gravitiy or when rows go from one player to
     another), it takes its variables with it.	When a blob  explodes,	it  does
     not  stop	existing.  Rather, it transforms into an empty blob.  That's im-
     portant for the variables: The empty blob still has all the  variables  set
     to the values they had before; only its kind is different.  Empty blobs are
     everywhere  where	there's  no  other  blob.   (However,  the falling blobs
     steered by the user are in some sense "above" everything  else;  there  are
     empty blobs beneath them.)

     The  life	of empty blobs is different from the one of normal blobs.  Empty
     blobs are not affected by gravity, and they often start or  stop  existing.
     For  example, when a single grey blob is falling down, the empty blob below
     it stops existing when the grey blob arrives and a new  empty  blob  starts
     existing when the grey blob moves on.  There is only one situation in which
     empty blobs move: When a row moves from one player to the other, and every-
     thing moves up resp. down, the empty blobs move, too.

STARTDIST
     The format of the startdist field is rather complicated.  On the plus side,
     this  means  that many things can be done with little effort.  We first de-
     scribe the single-character format, which, at the time of this writing, has
     sufficed for all needs.  After that, we describe the general format  as  an
     extension.

     Every  line of the startdist describes one row of blobs in the level's ini-
     tial state.  The lines are aligned to the bottom and the topmost lines come
     first (normal reading order).  Each line must contain exactly 10 or exactly
     20 characters, except the last which is special.  In a line  of  length  20
     the  first 10 characters describe the left player, the second 10 characters
     describe the right player.  A line of length  10  describes  both	players.
     Hence, each character describes one blob.	The semantics are:

     .	    An empty blop.

     +, -, *
	    A  blop  chosen  at  random  according  to	colourprob, respectively
	    greyprob, respectively goalprob.  The value of nogreyprob has no in-
	    fluence.

     0..9, A..Z, a..z
	    These characters denote a specific kind.  If the  character  matches
	    the  distkey of some kinds, the first of these is chosen.  More gen-
	    erally, these characters are ordered such that "9" comes before  "A"
	    and "Z" comes before "a".  In this order, the maximal distkey, which
	    does  not  come after the character, specifies the blob's kind.  The
	    difference between the character and the distkey then specifies  the
	    blob's version.

	    Example  1: In the special case, where the character exactly matches
	    a distkey, version is set to 0.

	    Example 2: Suppose kind apple has distkey =  "A",  kind  orange  has
	    distkey = "O" and no further distkeys exist.  Then the character "C"
	    denotes  an apple with version=2, the character "N" denotes an apple
	    with version=13, the character "O" denotes an orange with version=0,
	    the character "S" denotes an orange with  version=4,  the  character
	    "a"  denotes  an  orange with version=12, and the character "8" does
	    not denote anything (and hence is illegal).

     %	    An info blop with the version set according to the level-wide neigh-
	    bours.

     &	    An info blop with the version set according to the level-wide chain-
	    grass.

     The last line may have length 4, 8, 10, or 20.  If it has length 10 or  20,
     it  is  just  a  normal line as above.  Otherwise it describes the informa-
     tional blops next to the field.  In case of length 4, the first  entry  de-
     scribes  the  blop which depicts the number of greys.  The second entry de-
     scribes the blop which depicts the number of grass blops.	The third  entry
     describes	the blop which depicts connection information.	The fourth entry
     describes the blop whoch depicts chaingrass information.  In case of length
     8, the above holds for the left player.  The remaining 4 entries  then  de-
     scribe  the  same for the right player, but in reversed order.  The default
     is "-*%&&%*-" (or equivalently "-*%&").

     As seen above, startdist can reference  62  kind/version  combinations  di-
     rectly  (and  more  at  random).	Because  this  might at some time not be
     enough, the multichar extension has been introduced.  In  this  case,  each
     blob is described by more than one character.  However, the number of char-
     acters  per  blob	must  be  the  same for all keys.  Hence, the lengths of
     startdist lines then must be this number multiplied by 10 or by 20.   Every
     multicharacter  combination  starting with ".", "+", "-", or "*" is treated
     as the corresponding character in single-character format.  All other char-
     acter combinations are treated as numbers in base 62 representation.  Here,
     "A" to "Z" are digits with decimal value 10 to 35, and "a" to "z" are  dig-
     its with decimal value 36 to 61.  Leading spaces are allowed instead of ze-
     roes  (however,  the  all-space  string is forbidden).  The maximal distkey
     which (as a number) is not larger than the number given in startdist, spec-
     ifies the blob's kind.  The difference between the startdist number and the
     distkey then specifies the blob's version.  In the case of  multichar  dis-
     tkeys,  the  default  for	distkeys of kinds declared by startpic= is 10 in
     decimal.

     For blops whose kinds are chosen at random (i.e. characters "+",  "-",  "*"
     in  single-character  startdists), cuyo tries to make these as different as
     possible.	That means, by a certain heuristic, cuyo minimizes the number of
     neighbouring blobs of the same kind.  "Neighbouring", of course, refers  to
     the neighbours entry.  inhibit and the calculate_size bit of behaviour have
     no  effect  (these  are  mutable during the lifetime of blobs, while at the
     time of startdist processing, no blob's lifetime has started yet).  So  the
     only  way to influence the unneighbouring (if you really wish to do so), is
     by setting neighbours appropriately.  (Of course, this possibility is  even
     more  limited,  when  you	intend	to set the calculate_size bit during the
     blob's lifetime.)

WHERE DO I PUT THE CUAL CODE?
     Cual procedures and variables can be defined in different sections  of  the
     .ld files:

     --
	Outside  of  everything; that code is accessible from every level coming
	after that definition.

     --
	In the section of a level.

     --
	In the section of a kind.

     This basically does what you expect.  However, there's one thing you  might
     want  to  know:  Even if you define a variable inside a kind, every blob in
     that level will have that variable.  The only effect of defining the  vari-
     able  in  the section of a kind is that this kind is the only one which can
     access it.

AMPERSAND-CALL
     To explain a bit what calling a procecure with an & means, here  two  exam-
     ples:

     Example 1:
     <<
     myblob = {
       ...
       switch {
	 myvar -> { 0A*; 1; A,B,C,D; *; 2A*};
	       -> { 0B*; 1; A,B,C,D; *; 2B*};
       };
     };
     >>

     Example 2:
     <<
     anim = {1; A,B,C,D; *};

     myblob = {
       ...
       switch {
	 myvar -> { 0A*; &anim; 2A*};
	       -> { 0B*; &anim; 2B*};
       };
     };
     >>

     The  difference  between these examples is what happens when myvar changes.
     In example 1, the animation "A, B, C, D" will restart at the beginning (be-
     cause the two animations are different ones); in example 2, the "same" ani-
     mation is used in both cases, so the animation will simply continue.   (Re-
     moving  the ampersands from example 2 will turn the behaviour to the one of
     example 1.)

THE AI UTILITY FUNCTION
     When deciding how to place the steered falling blobs, the AI  player  tries
     to maximize a certain utility function.  Its value is the sum of the values
     for  both	steered falling blobs plus aiu_monochromic_vertical in case both
     blobs have the same color and they get placed vertically.	The value for  a
     single blob is the sum of the following:

     --
	For each new neighbour of blob, the neighbour utility.

     --
	aiu_two_above, if the blob is two above a blob of same kind.

     --
	aiu_height*20/(the blob's y coordinate).

     The  neighbour  utility  for  a single new blob and a single one of its new
     neighbours is the sum of the following:

     --
	aiu_color, if the neighbour has the same kind as the blob.

     --
	aiu_grass, if the neighbour fulfills behaviour.goalblob.

     --
	aiu_grey, if the neighbour fulfills behaviour.explodes_on_explosion.

SEE ALSO
     cuyo(6)

BUGS
     Probably a lot.  The following are just a few known ones:

     There are several problems with busieness and that stuff.	There  are  sev-
     eral  situations  in which Cual doesn't behave in the way I would like, and
     in other situations I don't know how Cual should behave.

				   2014-10-25				 CUAL(6)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=cual&sektion=6&manpath=FreeBSD+Ports+15.1.quarterly>

home | help