Sophie

Sophie

distrib > Mandriva > 2010.0 > i586 > media > contrib-release > by-pkgid > 74fbd0eb33bb08f719b79951bc4e329e > files > 84

xconq-7.5.0-1.20050612.5mdv2009.1.i586.rpm

<HTML>
<HEAD>
<!-- This HTML file has been created by texi2html 1.39
     from ./xcdesign.texi on 12 June 2005 -->

<TITLE>Designing Games with Xconq - Scorekeeper Forms</TITLE>
</HEAD>
<BODY>
Go to the <A HREF="xcdesign_1.html">first</A>, <A HREF="xcdesign_36.html">previous</A>, <A HREF="xcdesign_38.html">next</A>, <A HREF="xcdesign_61.html">last</A> section, <A HREF="xcdesign_toc.html">table of contents</A>.
<HR>


<H2><A NAME="SEC175" HREF="xcdesign_toc.html#SEC175">Scorekeeper Forms</A></H2>

<P>
Scorekeepers are the objects that manage scoring, winning, and losing.
A game design need not define any scorekeepers, and none are created by
default.  A scorekeeper may either maintain a numeric score that is used
at the end of the game to decide rankings, or simply declare a side to
have won or lost.  Perhaps it would be better to refer to scorekeepers as 
victory condition watchers.

</P>
<P>
<U>Form:</U> <B><CODE>scorekeeper</CODE></B> <I>name properties...</I><P>
<A NAME="IDX280"></A>
This form creates or modifies a scorekeeper with the given <VAR>name</VAR>,
with the given <VAR>properties</VAR>.<BR>
NOTE: Specifying <VAR>name</VAR> is not supported (as of 2005/02/06).

</P>

<UL>
<LI><A HREF="xcdesign_37.html#SEC176">Scorekeeper Properties</A>
<LI><A HREF="xcdesign_37.html#SEC177">Scorekeeper Bodies</A>
<LI><A HREF="xcdesign_37.html#SEC178">Scorekeeper Functions</A>
<LI><A HREF="xcdesign_37.html#SEC179">Scorekeeper Examples</A>
<LI><A HREF="xcdesign_37.html#SEC180">Scorefile</A>
</UL>



<H3><A NAME="SEC176" HREF="xcdesign_toc.html#SEC176">Scorekeeper Properties</A></H3>

<P>
<U>ScorekeeperProperty:</U> <B><CODE>title</CODE></B> <I>str</I><P>
<A NAME="IDX281"></A>
This property is a string that identifies the scorekeeper to the
players.  Defaults to <CODE>""</CODE>.

</P>
<P>
<U>ScorekeeperProperty:</U> <B><CODE>when</CODE></B> <I>(type [ exp ])</I><P>
<A NAME="IDX282"></A>
This property is when the scorekeeper will be checked or updated.
Defaults to <CODE>after-turn</CODE>.

</P>
<P>
<U>ScorekeeperWhenType:</U> <B><CODE>before-turn</CODE></B> <I>exp</I><P>
<A NAME="IDX283"></A>
This indicates that the scorekeeper will run at the start of each turn
matching <VAR>exp</VAR>, or after every turn if <VAR>exp</VAR> is not given.<BR>
NOTE: This property is currently ignored (as of 2005/01/23).

</P>
<P>
<U>ScorekeeperWhenType:</U> <B><CODE>after-turn</CODE></B> <I>exp</I><P>
<A NAME="IDX284"></A>
This indicates that the scorekeeper will run at the end of each turn
for which <VAR>exp</VAR> is true, or after every turn if <VAR>exp</VAR> is not 
given. If <VAR>exp</VAR> is a number rather than a full expression, then 
a test of <VAR>exp</VAR> &#62;= current turn number will be made. See the examples 
subsection for a full expression.

</P>
<P>
<U>ScorekeeperWhenType:</U> <B><CODE>after-event</CODE></B> <I>exp</I><P>
<A NAME="IDX285"></A>
This indicates that the scorekeeper will run after every event
matching <VAR>exp</VAR>, or after every event if <VAR>exp</VAR> is not given.<BR>
NOTE: Specifying <VAR>exp</VAR> is not supported (as of 2005/01/23).

</P>
<P>
<U>ScorekeeperWhenType:</U> <B><CODE>after-action</CODE></B> <I>exp</I><P>
<A NAME="IDX286"></A>
This indicates that the scorekeeper will run at the end of each action
matching <VAR>exp</VAR>, or after every action if <VAR>exp</VAR> is not given.<BR>
NOTE: Specifying <VAR>exp</VAR> is not supported (as of 2005/01/23).

</P>
<P>
<U>ScorekeeperProperty:</U> <B><CODE>applies-to</CODE></B> <I>side-and-sideclass-list</I><P>
<A NAME="IDX287"></A>
This property is the set of sides or side classes to which the
scorekeeper applies.  Scorekeepers apply only to sides that are in the
game.  Defaults to <CODE>nil</CODE>, which means all sides.

</P>
<P>
<U>ScorekeeperProperty:</U> <B><CODE>known-to</CODE></B> <I>side-and-sideclass-list</I><P>
<A NAME="IDX288"></A>
This property is the list of sides that know about this scorekeeper, and
can see the value of the score for each side that it applies to.
Defaults to <CODE>nil</CODE>, which means all sides.<BR>
NOTE: This property is currently ignored (as of 2005/01/23).

</P>
<P>
<U>ScorekeeperProperty:</U> <B><CODE>trigger</CODE></B> <I>form</I><P>
<A NAME="IDX289"></A>
This property is an expression that is true when it is time to start
checking the scorekeeper's main test.  Once a scorekeeper is triggered,
it remains active.  Defaults to <CODE>false</CODE>.

</P>
<P>
<U>ScorekeeperProperty:</U> <B><CODE>triggered</CODE></B> <I>t/f</I><P>
<A NAME="IDX290"></A>
This property is true if the scorekeeper is currently triggered.
Defaults to <CODE>true</CODE>.

</P>
<P>
<U>ScorekeeperProperty:</U> <B><CODE>do</CODE></B> <I>forms...</I><P>
<A NAME="IDX291"></A>
This property is a list of forms to execute in order each time the
scorekeeper runs.  Defaults to <CODE>()</CODE>.

</P>
<P>
<U>ScorekeeperProperty:</U> <B><CODE>keep-score</CODE></B> <I>t/f</I><P>
<A NAME="IDX292"></A>
If this property is <CODE>false</CODE>, then no numeric score is kept.
Defaults to <CODE>true</CODE>.

</P>
<P>
<U>ScorekeeperProperty:</U> <B><CODE>initial-score</CODE></B> <I>value</I><P>
<A NAME="IDX293"></A>
This property is the value of the score upon game startup.  

</P>



<H3><A NAME="SEC177" HREF="xcdesign_toc.html#SEC177">Scorekeeper Bodies</A></H3>

<P>
The forms in the body (the <CODE>do</CODE> property) of the scorekeeper may be
any of the forms listed here.

</P>
<P>
<U>ScorekeeperForm:</U> <B><CODE>last-side-wins</CODE></B><P>
<A NAME="IDX294"></A>
If supplied as the only symbol in the body, then the scorekeeper
implements the usual "last side left in the game wins" behavior.

</P>
<P>
<U>ScorekeeperForm:</U> <B><CODE>last-alliance-wins</CODE></B><P>
<A NAME="IDX295"></A>
If supplied as the only symbol in the body, then the scorekeeper
implements the "last alliance left in the game wins" behavior.  For
the purposes of this scorekeeper, an alliance means that the sides in
the alliance all trust each other.

</P>
<P>
<U>ScorekeeperForm:</U> <B><CODE>if</CODE></B> <I>test action [ else-action ]</I><P>
<A NAME="IDX296"></A>
If the <VAR>test</VAR> evaluates to a non-<CODE>nil</CODE> result, then the
<VAR>action</VAR> will be done. Else, the <VAR>else-action</VAR> will be done, if 
there is one.

</P>
<P>
<U>ScorekeeperForm:</U> <B><CODE>cond</CODE></B> <I>(test actions...) ...</I><P>
<A NAME="IDX297"></A>
This is like Lisp's cond.

</P>
<P>
<U>ScorekeeperForm:</U> <B><CODE>win</CODE></B><P>
<A NAME="IDX298"></A>
This scorekeeper action causes the side to win immediately.

</P>
<P>
<U>ScorekeeperForm:</U> <B><CODE>lose</CODE></B><P>
<A NAME="IDX299"></A>
This scorekeeper action causes the side to lose immediately.

</P>
<P>
<U>ScorekeeperForm:</U> <B><CODE>end</CODE></B><P>
<A NAME="IDX300"></A>
This scorekeeper action ends the game immediately, with a draw for all
remaining sides.

</P>
<P>
<U>ScorekeeperForm:</U> <B><CODE>add-score</CODE></B> <I>exp</I><P>
<A NAME="IDX301"></A>
This adds the result of evaluating <VAR>exp</VAR> to the score of the given
side.  The value may be a negative number. This form cannot be used 
with a non-numeric scorekeeper.

</P>
<P>
<U>ScorekeeperForm:</U> <B><CODE>set-score</CODE></B> <I>exp</I><P>
<A NAME="IDX302"></A>
This sets the result of evaluating <VAR>exp</VAR> as the score of the given 
side.  The value may be a negative number.  This form cannot be used 
with a non-numeric scorekeeper.

</P>



<H3><A NAME="SEC178" HREF="xcdesign_toc.html#SEC178">Scorekeeper Functions</A></H3>

<P>
Scorekeepers can use all of the general GDL functions such as 
<CODE>add</CODE>, <CODE>remove-list</CODE>, <CODE>&#62;=</CODE>, etc....  They can also 
use special functions, which are mentioned below.  Scorekeeper functions 
can be used in any place where a scorekeeper test expression is allowed. 
This means that they can be used in <CODE>when</CODE> conditions, in <CODE>if</CODE> 
test clauses, or the form of <CODE>set-score</CODE>, for example.

</P>
<P>
<U>ScorekeeperFunction:</U> <B><CODE>turn</CODE></B><P>
<A NAME="IDX303"></A>
This GDL keyword gives the current turn number.

</P>
<P>
<U>ScorekeeperFunction:</U> <B><CODE>score</CODE></B><P>
<A NAME="IDX304"></A>
This GDL keyword returns the current score in the current scorekeeper for 
the current side.  A warning will be produced if you attempt to use this 
keyword with a non-numeric scorekeeper.

</P>
<P>
<U>ScorekeeperFunction:</U> <B><CODE>sum-uprop</CODE></B> <I>types property</I><P>
<A NAME="IDX305"></A>
The result is the sum of the property values for all units of the given
type(s).  The property must be an integer value, such as <CODE>point-value</CODE>
or <CODE>hp-max</CODE>.  The <CODE>point-value</CODE> property is treated specially 
in that an unit's actual point assignment is used if it exists;  if the 
point assignment does not exist, then the summation behavior is the 
default, namely the value for the unit type is used.

</P>



<H3><A NAME="SEC179" HREF="xcdesign_toc.html#SEC179">Scorekeeper Examples</A></H3>

<P>
One of the most simple and ubiquitous scorekeepers is:

<PRE>
(scorekeeper (do last-side-wins))
</PRE>

<P>
This specifies that the last side standing will win. It should be noted 
that if the independent side is not being controlled by an AI, then it is 
not considered in this case. If the independent side is being controlled 
by an AI, then it is considered.

</P>
<P>
If you do not wish a side (such as an AI-controlled independent side) to be 
considered for a given scorekeeper, then you can use the <CODE>applies-to</CODE> 
property to restruct which sides the scorekeeper applies to.

<PRE>
(scorekeeper
  (applies-to (not "independent"))
  (do last-side-wins)
)
</PRE>

<P>
The above says to apply the scorekeeper to every side except those belonging 
to the <CODE>"independent"</CODE> side class. By default, only the independent 
side belongs to that side class.

</P>
<P>
Alternatively, one can use side ID numbers.

<PRE>
(scorekeeper
  (applies-to (not 0))
  (do last-side-wins)
)
</PRE>

<P>
This again excludes the independent side, but, this time, by its exact ID 
number rather than its side class (to which other sides could belong).

</P>
<P>
We can also talk in terms of inclusion rather than exclusion.

<PRE>
(scorekeeper
  (applies-to ("chaotic" 0))
  (do last-side-wins)
)
</PRE>

<P>
This causes the scorekeeper to be applied to all sides belonging to the 
<CODE>"chaotic"</CODE> side class as well as the independent side.

</P>
<P>
And, we can include a side class, but exclude specific members of it.

<PRE>
(scorekeeper
  (applies-to (and "chaotic" (not (2 5 7))))
  (do last-side-wins)
)
</PRE>

<P>
Note that the <CODE>and</CODE> is important. All boolean operators must be in 
the higher levels of the expression. Once a list of side classes and/or 
side ID numbers is encountered, then boolean evaluation is not performed 
at the level of the list or below it. The following example is INCORRECT:

<PRE>
(scorekeeper
  (applies-to ("chaotic" (not (2 5 7))))
  (do last-side-wins)
)
</PRE>

<P>
As stated previously, the above example is INCORRECT. It is incorrect 
because the <CODE>not</CODE> appears inside a list of side classes and side ID 
numbers. Do not attempt to use this example.

</P>
<P>
If this seems confusing, you may wish to consider a list of side classes 
and side ID numbers as being shorthand for <CODE>or</CODE> boolean expressions.
Thus:

<PRE>
(scorekeeper
  (applies-to (1 2 3))
  (do last-side-wins)
)
</PRE>

<P>
is equivalent to:

<PRE>
(scorekeeper
  (applies-to (or 1 (or 2 3)))
  (do last-side-wins)
)
</PRE>

<P>
Now that we have pretty much beaten the <CODE>applies-to</CODE> horse to death, 
let us move on to <CODE>when</CODE> conditions. By default, <CODE>when</CODE> is 
assigned <CODE>nil</CODE>, and this is equivalent to <CODE>after-turn</CODE>. So:

<PRE>
(scorekeeper (do last-side-wins))
</PRE>

<P>
is equivalent to:

<PRE>
(scorekeeper
  (when (after-turn))
  (do last-side-wins)
)
</PRE>

<P>
is equivalent to:

<PRE>
(scorekeeper
  (when (after-turn nil))
  (do last-side-wins)
)
</PRE>

<P>
With the turn-granularity scorekeepers, one can use a shorthand notation 
to specify that they should only run on or after a certain turn number.

<PRE>
(scorekeeper
  (when (after-turn 5))
  (do last-side-wins)
)
</PRE>

<P>
In the above example, the scorekeeper will only be checked at the end of 
turn 5 and at the ends of all turns thereafter.

</P>
<P>
There is more verbose way of writing this, and this involves a full 
expression:

<PRE>
(scorekeeper
  (when (after-turn (&#62;= turn 5)))
  (do last-side-wins)
)
</PRE>

<P>
The <CODE>(&#62;= turn 5)</CODE> is a test expression. <CODE>turn</CODE> is a keyword 
that gives back the current turn number.

</P>
<P>
Note that you can put together test expressions using the other available 
operators.

<PRE>
(scorekeeper
  (when (after-turn (&#60;= turn 30)))
  (do last-side-wins)
)
</PRE>

<P>
The above example only runs the scorekeeper at the end of the turn for the 
first 30 turns, and then the scorekeeper ceases to be relevant.

</P>

<PRE>
(scorekeeper 
  (title "Every Other Turn")
  (when (after-turn (/= (/ turn 2) (/ (+ turn 1) 2))))
  (applies-to (not "independent"))
  (do last-side-wins)
)
</PRE>

<P>
Since we do not have a modulo arithmetic operator as of this writing 
(2005/02/06), if we want to get a scorekeeper to run at some interval, we 
must use a trick like the above. All above test does is check to see if 
our current turn number divided by some interval has the same quotient as 
the next turn number divided by the same interval. If yes, then the 
scorekeeper should not run. If no, then the scorekeeper should run.
Simply replacing <CODE>2</CODE> with <CODE>3</CODE> in the above when condition, you 
can make your scorekeeper run every third turn, and so and so forth.

</P>
<P>
Scorekeeper bodies can be simple, as already seen, or they can be quite 
sophisticated. Side scores can be manipulated and victory or loss can be 
forced based on some condition.

</P>

<PRE>
(scorekeeper
  (when (after-turn 20)) 
  (do (if (&#62;= (sum-uprop victory-point point-value) 15) win))
)
</PRE>

<P>
In the above example, the scorekeeper checks to see if the sum of the 
<CODE>point-value</CODE> property of <CODE>victory-point</CODE> units is greater than 
or equal to 15.  If so, then it declares the current side the winner 
(and, by extension, other sides as losers).

</P>
<P>
Suppose we wanted to modify the <I>Default</I> game.  We could state that 
any side having more than a certain number of points worth of nukes and 
capital ships wins.

<PRE>
(scorekeeper
  (do (if (&#62;= (sum-uprop (cv bb nuke) point-value) 50) win))
)
</PRE>

<P>
We could also do something rather bizarre such as:

<PRE>
(scorekeeper
  (do (if (&#62;= (sum-uprop u* cp) 15000) end))
)
</PRE>

<P>
The above example ends the game in a draw when any one side builds too much.

</P>
<P>
Scorekeepers can set or add to the score.

</P>

<PRE>
(scorekeeper
  (do (set-score (* turn 10)))
)
</PRE>

<P>
The above scorekeeper sets the current side's score to be the turn number 
times <CODE>10</CODE>. Equivalently, one can write:

<PRE>
(scorekeeper
  (do (add-score 10))
)
</PRE>

<P>
In this example, the scorekeeper adds 10 to the current side's score 
every turn.

</P>
<P>
Scorekeeper bodies can be even more complex.

</P>

<PRE>
(scorekeeper
  (do (
    (add-score 10)
    (if (&#62; (* score turn) 1000) end)
    (if (= (sum-uprop capital-city point-value) 0) lose)
  ))
)
</PRE>

<P>
So, putting everything together thus far, we might get something like:

<PRE>
; Last non-indep side standing wins.
(scorekeeper 1
  (title "Attrition Victory")
  (keep-score false)
  (applies-to (not "independent"))
  (do last-side-wins)
)
; First side to acquire 30 victory points wins.
(scorekeeper 2
  (title "Greedy Victory")
  (applies-to (not "independent"))
  (do (
    (set-score (sum-prop victory-point point-value))
    (if (&#62;= score 30) win)
  ))
)
; First side to produce an overwhelming arsenal wins.
(scorekeeper 3
  (title "Inevitable Victory")
  (applies-to (not "independent"))
  (when (after-turn 50))
  (do (
    (set-score (/ (sum-uprop godlike-u* cp) 20))
    (if (&#62;= score 40) win)
    (if (&#62;= (sum-prop (append horde-u* nuke) cp) 30000) win)
  ))
)
; Any side that loses nearly all of its commanding units loses.
(scorekeeper 4
  (title "Loss by Collapsed Command")
  (keep-score false)
  (do (if (&#60; (sum-uprop leader-u* point-value) 50) lose))
)
</PRE>



<H3><A NAME="SEC180" HREF="xcdesign_toc.html#SEC180">Scorefile</A></H3>

<P>
<U>GlobalVariable:</U> <B><CODE>scorefile-name</CODE></B> <I>str</I><P>
<A NAME="IDX306"></A>
This variable supplies the name of the file to be used for recording
scores of people playing the game.  The default value is <CODE>""</CODE>,
which disables the recording of scores.

</P>

<HR>
Go to the <A HREF="xcdesign_1.html">first</A>, <A HREF="xcdesign_36.html">previous</A>, <A HREF="xcdesign_38.html">next</A>, <A HREF="xcdesign_61.html">last</A> section, <A HREF="xcdesign_toc.html">table of contents</A>.
</BODY>
</HTML>