Go to the first, previous, next, last section, table of contents.

## Scorekeeper Forms

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.

Form: `scorekeeper` name properties...

This form creates or modifies a scorekeeper with the given name, with the given properties.
NOTE: Specifying name is not supported (as of 2005/02/06).

- Scorekeeper Properties
- Scorekeeper Bodies
- Scorekeeper Functions
- Scorekeeper Examples
- Scorefile

### Scorekeeper Properties

ScorekeeperProperty: `title` str

This property is a string that identifies the scorekeeper to the players. Defaults to `""`.

ScorekeeperProperty: `when` (type [ exp ])

This property is when the scorekeeper will be checked or updated. Defaults to `after-turn`.

ScorekeeperWhenType: `before-turn` exp

This indicates that the scorekeeper will run at the start of each turn matching exp, or after every turn if exp is not given.
NOTE: This property is currently ignored (as of 2005/01/23).

ScorekeeperWhenType: `after-turn` exp

This indicates that the scorekeeper will run at the end of each turn for which exp is true, or after every turn if exp is not given. If exp is a number rather than a full expression, then a test of exp >= current turn number will be made. See the examples subsection for a full expression.

ScorekeeperWhenType: `after-event` exp

This indicates that the scorekeeper will run after every event matching exp, or after every event if exp is not given.
NOTE: Specifying exp is not supported (as of 2005/01/23).

ScorekeeperWhenType: `after-action` exp

This indicates that the scorekeeper will run at the end of each action matching exp, or after every action if exp is not given.
NOTE: Specifying exp is not supported (as of 2005/01/23).

ScorekeeperProperty: `applies-to` side-and-sideclass-list

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 `nil`, which means all sides.

ScorekeeperProperty: `known-to` side-and-sideclass-list

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 `nil`, which means all sides.
NOTE: This property is currently ignored (as of 2005/01/23).

ScorekeeperProperty: `trigger` form

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 `false`.

ScorekeeperProperty: `triggered` t/f

This property is true if the scorekeeper is currently triggered. Defaults to `true`.

ScorekeeperProperty: `do` forms...

This property is a list of forms to execute in order each time the scorekeeper runs. Defaults to `()`.

ScorekeeperProperty: `keep-score` t/f

If this property is `false`, then no numeric score is kept. Defaults to `true`.

ScorekeeperProperty: `initial-score` value

This property is the value of the score upon game startup.

### Scorekeeper Bodies

The forms in the body (the `do` property) of the scorekeeper may be any of the forms listed here.

ScorekeeperForm: `last-side-wins`

If supplied as the only symbol in the body, then the scorekeeper implements the usual "last side left in the game wins" behavior.

ScorekeeperForm: `last-alliance-wins`

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.

ScorekeeperForm: `if` test action [ else-action ]

If the test evaluates to a non-`nil` result, then the action will be done. Else, the else-action will be done, if there is one.

ScorekeeperForm: `cond` (test actions...) ...

This is like Lisp's cond.

ScorekeeperForm: `win`

This scorekeeper action causes the side to win immediately.

ScorekeeperForm: `lose`

This scorekeeper action causes the side to lose immediately.

ScorekeeperForm: `end`

This scorekeeper action ends the game immediately, with a draw for all remaining sides.

ScorekeeperForm: `add-score` exp

This adds the result of evaluating exp to the score of the given side. The value may be a negative number. This form cannot be used with a non-numeric scorekeeper.

ScorekeeperForm: `set-score` exp

This sets the result of evaluating exp as the score of the given side. The value may be a negative number. This form cannot be used with a non-numeric scorekeeper.

### Scorekeeper Functions

Scorekeepers can use all of the general GDL functions such as `add`, `remove-list`, `>=`, 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 `when` conditions, in `if` test clauses, or the form of `set-score`, for example.

ScorekeeperFunction: `turn`

This GDL keyword gives the current turn number.

ScorekeeperFunction: `score`

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.

ScorekeeperFunction: `sum-uprop` types property

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 `point-value` or `hp-max`. The `point-value` 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.

### Scorekeeper Examples

One of the most simple and ubiquitous scorekeepers is:

    (scorekeeper (do last-side-wins))

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.

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 `applies-to` property to restruct which sides the scorekeeper applies to.

    (scorekeeper
      (applies-to (not "independent"))
      (do last-side-wins)
    )

The above says to apply the scorekeeper to every side except those belonging to the `"independent"` side class. By default, only the independent side belongs to that side class.

Alternatively, one can use side ID numbers.

    (scorekeeper
      (applies-to (not 0))
      (do last-side-wins)
    )

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

We can also talk in terms of inclusion rather than exclusion.

    (scorekeeper
      (applies-to ("chaotic" 0))
      (do last-side-wins)
    )

This causes the scorekeeper to be applied to all sides belonging to the `"chaotic"` side class as well as the independent side.

And, we can include a side class, but exclude specific members of it.

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

Note that the `and` 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:

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

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

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

    (scorekeeper
      (applies-to (1 2 3))
      (do last-side-wins)
    )

is equivalent to:

    (scorekeeper
      (applies-to (or 1 (or 2 3)))
      (do last-side-wins)
    )

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

    (scorekeeper (do last-side-wins))

is equivalent to:

    (scorekeeper
      (when (after-turn))
      (do last-side-wins)
    )

is equivalent to:

    (scorekeeper
      (when (after-turn nil))
      (do last-side-wins)
    )

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.

    (scorekeeper
      (when (after-turn 5))
      (do last-side-wins)
    )

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

There is more verbose way of writing this, and this involves a full expression:

    (scorekeeper
      (when (after-turn (>= turn 5)))
      (do last-side-wins)
    )

The `(>= turn 5)` is a test expression. `turn` is a keyword that gives back the current turn number.

Note that you can put together test expressions using the other available operators.

    (scorekeeper
      (when (after-turn (<= turn 30)))
      (do last-side-wins)
    )

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.

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

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 `2` with `3` in the above when condition, you can make your scorekeeper run every third turn, and so and so forth.

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.

    (scorekeeper
      (when (after-turn 20))
      (do (if (>= (sum-uprop victory-point point-value) 15) win))
    )

In the above example, the scorekeeper checks to see if the sum of the `point-value` property of `victory-point` 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).

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

    (scorekeeper
      (do (if (>= (sum-uprop (cv bb nuke) point-value) 50) win))
    )

We could also do something rather bizarre such as:

    (scorekeeper
      (do (if (>= (sum-uprop u* cp) 15000) end))
    )

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

Scorekeepers can set or add to the score.

    (scorekeeper
      (do (set-score (* turn 10)))
    )

The above scorekeeper sets the current side's score to be the turn number times `10`. Equivalently, one can write:

    (scorekeeper
      (do (add-score 10))
    )

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

Scorekeeper bodies can be even more complex.

    (scorekeeper
      (do (
        (add-score 10)
        (if (> (* score turn) 1000) end)
        (if (= (sum-uprop capital-city point-value) 0) lose)
      ))
    )

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

    ; 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 (>= 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 (>= score 40) win)
        (if (>= (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 (< (sum-uprop leader-u* point-value) 50) lose))
    )

### Scorefile

GlobalVariable: `scorefile-name` str

This variable supplies the name of the file to be used for recording scores of people playing the game. The default value is `""`, which disables the recording of scores.

Go to the first, previous, next, last section, table of contents.