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

FreeBSD Manual Pages


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

       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 de-
       scription works.	 There's also a	bit of example	Cual  code  in	"exam-
       ple.ld".	 And of	course,	all the	existing levels	are examples.

       Note that Cual is probably still	very buggy.  So	if strange things hap-
       pen and you're sure it's	not your fault,	tell me	(

       The level description is	organized in sections.	There is a global sec-
       tion  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	 sepa-
       rate  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 sec-
       tion.  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  (en-
       closed by '"'), a word, or a number.  In	place of a number <expression>
       can be used, where expression is	an arbitrary expression	made  up  from
       literal	numbers, previously defined numeric 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  rou-
       tine  in	cuyo which checks if the same is drawn as in the last step and
       which then supresses the	drawing.)

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

       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=redblob.xpm,greenblob.xpm, the names  are  "redblob"  and  "green-

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

       [Explain	the default procedures.]

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

	      This is an optional further description of the level in its  in-

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

   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.

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

   Number valued data
	      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  be-
	      haviour.	See section VARIABLES AND CONSTANTS for	details.

	      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).

	      Placement	 of  toppic  relative to the actual border.  More pre-
	      cisely, number of	pixels the lower border	of the picture is  be-
	      low the actual border.  Defaults to the height of	the picture.

	      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 vis-
	      ible at the end.	Defaults to 0.

	      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.
	      Defaults to 0.

	      Must be 0	or 1.  If set to 1, the	initial	fall position is  ran-
	      domized horizontally.  Defaults to 0.

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

	      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

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

	      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_verti-
       cal, aiu_height
	      Parameters  for  the  AI player's	utility	function.  Default re-
	      spectively to <10*(number	of  kinds)>,  20,  10,	<aiu_color/2>,
	      <aiu_color>,  and	 10.   See section THE AI UTILITY FUNCTION for

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

	      The background colour.  Defaults to white.

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

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

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

       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 de-
	      fined  later  on.	  The different	keywords (e.g. pics, emptypic)
	      define different defaults.  In fact, only	the first three	may be
	      real  lists, emptypic is limited to exactly one entry.  In these
	      lists, it	is advisable to	use * whenever possible.  Besides  be-
	      ing shorter to write, it also speeds up loading of the level and
	      cuts down	memory usage.  This is because cuyo does some initial-
	      izations 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 values for behaviour,  colourprob,  goalprob,  greyprob,
	      versions	and  distkey  (see  there).   All of these can also be
	      overridden individually.	Also, the default drawing code is dif-
	      ferent.	(The  default  drawing code for	startpic does not draw

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

       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 de-
	      scription	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.

	      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
	      divided  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.

	      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.

	      The probability that this	kind appears as	a grey blob.  This  is
	      similar  to colourprob, but there	is a difference: For greyprob,
	      nogreyprob is included in	the sum, so that it might happen  that
	      no blob appears at all.  There is	a notable difference between a
	      positive nogreyprob and a	positive  greyprob  in	kind  nothing,
	      when  several  lines  of	grey blobs appear: In the latter case,
	      empty blobs appear 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.

	      At  the creation of a blob, its version variable is initialized.
	      Usually, it is chosen at random from 0 to	versions-1, but	start-
	      dist  provides  the possibility to specify it exactly.  See sec-
	      tion STARTDIST for details.  The default is 1.

	      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	START-
	      DIST for details.

       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	speci-
	      fied,  zero  is used.  See section VARIABLES AND CONSTANTS about
	      the meaning of the default value and the optional	suffix : reap-

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

       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.  How-
	      ever, if one of the commands is "busy" (see section  BUSIENESS),
	      this  one	 will  be executed until it stops being	busy, and only
	      after that, the next command will	be executed.

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

	      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	AMPER-

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

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

       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 dif-
	      ferent 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 vari-
	      able qu (see section VARIABLES AND CONSTANTS).

	      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 positions.  (See section  VARIABLES	AND  CONSTANTS
	      for more details about @.)

	      Like *, but draws	the icon at some other position.  This drawing
	      is performed before all drawing by *.  If	@* is used  from  sev-
	      eral  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  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  BUS-
	      IENESS.	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-arrow may only	be omitted, if
	      the if-arrow is "->".  Then the else-arrow 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.

	      The player gets expr bonus points.

	      The string is displayed (blinking) on the	screen.	  To  be  used
	      together with bonus(...).	 Example:

		message("You get 50 bonus points");

	      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
	      graphics.	 After that, it's changed to a nothing-blob.

       lose   The players immediately lose the level.

	      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	"*".

       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

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

	      ==..   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 posi-
       tive, then a/b is the largest integer n such that n*b<=a.  If b is neg-
       ative,  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 operator 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	 is a sequence of six or eight characters 0, 1
	      and ?.  It is true if the	sequence fits  to  the	neighbour  se-
	      quence  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,	start-
	      ing  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:

	      Returns a	random value between 0 and expr-1

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

       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  de-
	  fault	 value you provided.  If you supplied the default with : reap-
	  ply, whenever	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 spe-
	  cial 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 ac-
       cess  the instance in your own blob, but	with the following syntax, you
       can access variables of other blops:

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

       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 spec-
       ifies  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 coordinate is 0.  Otherwise	one of the two has co-
       ordinate	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	 optional  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-in-
       tegers appear.  Especially, ".5"	is not allowed	in  composite  expres-
       sions.	Therefore, also	integer	dy is always allowed.  If a half-inte-
       ger 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
       different 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
       execution of the	blob codes.  For this reason,

       -- reading variables with @ or @@ always	returns	the value of the vari-
	  able	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.	State-
       ments 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
	  result in an error).

       [Add explanation	of time	slices;	roughly:
	  @-access of variables	in reality don't access	the value at  the  be-
	  ginning/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 executed.

       kind   The kind of the blob.  There are constants for the possible val-
	      ues 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
		 beginning 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
		 applied.  This	happens	at the same time  that	kind  changed,
		 but only if the new kind is different from the	old one.

	      Is  assigned  a  hopefully  distinctive value at the blob's cre-
	      ation.  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"	before	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
	      updated  to  the	sum of weight in the connected component.  The
	      default is 1.

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

	      This is a	bit field.  Refer to The Constants below for the mean-
	      ingful  of  its  bits.   The   default   is   calculate_size+ex-
	      plodes_on_size   for   normal  blobs,  explodes_on_explosion+ex-
	      plodes_on_chainreaction for grey blobs,  floats  for  the	 empty
	      blob  and	 goalblob+explodes_on_explosion+explodes_on_chainreac-
	      tion or goalblob+explodes_on_chainreaction (depending on whether
	      chaingrass is set) for grass blobs.

       falling_speed, falling_fast_speed
	      These variables are only used in the semiglobal blobs.  They de-
	      fine 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.)

	      Contains internal	data.  Will be removed.	 Probably.

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

	      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 al-
	      ways 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)

	      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.)

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

	      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.

	      The number of players.

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

	      Currently,  there	 is  one  exception: if	the explosion has been
	      triggered	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:

	      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.

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

	      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 neighbour-
	      hood.   explodes_on_chainreaction	refers to those	triggering ex-
	      plosions that are	the second or later part of a chain  reaction.
	      explodes_on_explosion 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
	      example 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 values actually are.

	      This constant also exists	for the	empty kind, if	one  has  been
	      declared	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.

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

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

       Constants for neighbours:

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

	      A	blob connects left and right.

	      A	blob connects up and down.

	      A	blob connects diagonally.

	      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.

	      When used	in the level-wide neighbours, this sets	hex  mode.   A
	      blob  connects  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.

	      A	 blob connects in knight moves (Two forward and	then one side-
	      ways.  Forward is	one of up, down, left or right.	  Sideways  is
	      perpendicular  to	 forward.   This makes a total of eight	direc-

	      Combines neighbours_rect with neighbours_diagonal.

	      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 down-
	      wards shift.

	      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.)

	      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 con-
	      necting in the given directions.	XX can be U, D,	L, R (horizon-
	      tal  and	vertical);  UL,	 UR, DL, DR (diagonal);	UUL, UUR, DDL,
	      DDR, LLU,	LLD, RRU, RRD (knight);	F, B (3d)

       Sometimes it is necessary to define a level  slightly  differently  for
       different  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 ap-
       ply 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  in-
       ternal 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 informa-
       tion 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 ver-
       sion "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  as-
	  signing  successive 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

	  All  resulting conflicts must	be resolved.  For example, if you make
	  a definition for [2] and one for [hard], you must also make a	 defi-
	  nition for [2,hard] (or, equivalently, for [hard,2]),	because	other-
	  wise 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]	 defi-
	  nition,  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-ver-
	  sus-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 specifiers are exhaustive as	well.

       (No, not	Business ;-)

       Busieness  is  a	concept	to make	it easier to implement simple animated
       sequences 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

       Here's  an  example  of how to use busieness for	an animation which ap-
       pears 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 consist-
       ing of icons B, C, D and	E is started.  With a normal arrow ("->")  af-
       ter  the	 "1:100", after	the step in which B has	been drawn, the	proba-
       bility would be 99/100 that A is	drawn again.  But with the double  ar-
       row,  the  switch  statement 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.)

       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  really 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.

       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).

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

	      Is called	when the connection of blobs is	recalculated.

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

	      Is called	when a player gives a row to the  other	 side,	before
	      anything	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
	      semiglobal  blob,	though.	 (Note that, in	contrast to turn, key-
	      turn is called even if the steered blob cannot be	rotated	due to
	      some obstacles, and also if there	is no steered 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 important 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  everything	moves up resp. down, the empty
       blobs move, too.

       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 describe the single-character format, which, at the time of  this
       writing,	 has sufficed for all needs.  After that, we describe the gen-
       eral format as an extension.

       Every line of the startdist describes one row of	blobs in  the  level's
       initial	state.	 The  lines  are aligned to the	bottom and the topmost
       lines come first	(normal	reading	order).	 Each line  must  contain  ex-
       actly  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

       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 generally, 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  dis-
	      tkey 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  ver-
	      sion=4, the character "a"	denotes	an orange with version=12, and
	      the character "8"	does not denote	anything (and hence  is	 ille-

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

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

       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  in-
       formational  blops  next	 to the	field.	In case	of length 4, the first
       entry describes the blop	which depicts the number of greys.  The	second
       entry  describes	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 informa-
       tion.  In case of length	8, the above holds for the left	 player.   The
       remaining 4 entries then	describe 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 characters 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 character 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 digits with	decimal	value 36 to 61.	 Lead-
       ing spaces are allowed instead of zeroes	(however, the all-space	string
       is forbidden).  The maximal distkey which (as a number) is  not	larger
       than  the  number  given	 in startdist, specifies the blob's kind.  The
       difference between the startdist	number and the distkey then  specifies
       the blob's version.  In the case	of multichar distkeys, 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 dif-
       ferent 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.)

       Cual procedures and variables can be defined in different  sections  of
       the .ld files:

       -- Outside of everything; that code is accessible from every level com-
	  ing 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	defin-
       ing the variable	in the section of a kind is that this kind is the only
       one which can access it.

       To explain a bit	what calling a procecure with an & means, here two ex-

       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  (because  the	two animations are different ones); in example
       2, the "same" animation is used in both cases, so  the  animation  will
       simply continue.	 (Removing the ampersands from example 2 will turn the
       behaviour to the	one of example 1.)

       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.


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

       There  are  several  problems with busieness and	that stuff.  There are
       several 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:

home | help