Horde
=====
Jordi Fita <jfita@geishastudios.com>
:comments:

Introduction
------------

[role="figure-right"]
.Screenshot of horde
image::screenshots/horde.png["Screenshot of horde", width=214, height=320]

http://en.wikipedia.org/wiki/The_Horde_(video_game)['The Horde'] is an hybrid
action-strategy game developed by http://www.toysforbob.com/[Toys For Bob] in
1994.  In The Horde you play as Chauncey, a serving lad who saves his monarch,
King of Franzpowanki, from choking on his meal.  The King rewards you with his
magical monster slayer sword, the Grimthwacker, and a plot of land known as the
Shimto Plains.  Unfortunately, these particular lands are constantly under
attack by “The Horde”, a group of destructive and hungry monsters, called
'hordlings', who are bent on eating everything in the province.

This remake of The Horde is a simpler ASCII-based turn-based version written in
C and using the
http://en.wikipedia.org/wiki/Curses_(programming_library)[curses library] in
which the goal is to reach $2000 in gold to pay the taxes while keeping The
Horde away from the cattle with the help of the Grimthwacker.  At each season's
beginning you receive $10 in gold per cow still alive but it is possible to buy
additional cows for $20 the head.  Also, to slow down the hungry wave of
hordlings, is possible to build, and then improve, fences for $1 apiece.  Some
of the more expensive fences can even kill hordlings.

[role="downloadbar"]
****
image:images/down_win.png["Windows Download",link="http://www.geishastudios.com/download/horde-win32.zip"]
image:images/down_source.png["Source Code Download",link="http://www.geishastudios.com/download/horde.tar.bz2"]
****


The Level
---------

Much like chess, the game's level is a board in which every cell can contain a
cow, a piece of fence, a hordling, the player, or be empty.  For no particular
reason other than to look good on screen, I've chosen the level to be 24 cells
wide and 24 cells tall.

[source, c]
----
<<constants>>=
#define LEVEL_WIDTH 24
#define LEVEL_HEIGHT 24
----

Given the nature of the curses library, every game's entity -- cows, fences,
hordlings, and the player -- is represented as a single character on screen.
Thus, the level can be defined as a multidimensional array of `chtype`, the
character type used by curses; generally an integer.

[source, c]
----
<<main variables>>=
chtype level[LEVEL_HEIGHT][LEVEL_WIDTH];
----

Contrary to most representations of 2D coordinates, the first index of `level`
is the Y coordinate and the second index is X.  I've done this to follow the
same convention used in
curses, which asks for the Y coordinate first and then X, but more importantly
because I am usually going to traverse the array row by row, as for example
when drawing the level to the screen.

[source, c]
----
<<main variables>>=
int y;
----

[source, c]
----
<<draw level>>=
for (y = 0 ; y < LEVEL_HEIGHT ; ++y) {
    mvaddchnstr(y, 0, level[y], LEVEL_WIDTH);
}
----

Laying the array row by row, then, makes better use of the cache because this
way I access data linearly, although for the relatively small size of the level
wouldn't make a noticeable difference.

Before I can draw the level, though, I need to initialize it.  I am going to
start of with an empty level by setting each level's cell to the empty
character, which I've chosen to be a dot (`.`), to follow the conventions of
http://en.wikipedia.org/wiki/NetHack[NetHack], a well known ASCII-based game.

[source, c]
----
<<constants>>=
#define EMPTY_CHAR '.'
----

In the case of `level`, I can't use standard C functions such as `memset` to
initialize the level because this function accesses the array byte by byte, and
`level` is an integer array.  Thus, I need to use `for` loops.

[source, c]
----
<<main variables>>=
int x;
----

[source, c]
----
<<initialize level>>=
for (y = 0 ; y < LEVEL_HEIGHT ; ++y) {
    for (x = 0 ; x < LEVEL_WIDTH ; ++x) {
        level[y][x] = EMPTY_CHAR;
    }
}
----

With the level emtpy, I'll then place some cows.  The cows are randomly placed
within the center of the level, between row 8 and 13 and between column 8 and
13, to keep them away from the hordlings, that comes from the borders.  I am
going to place a random number of cows between 1 and 10 solely by setting the
cow character, which I've chosen to be `%`, on the level without checking if
the destination cell if empty.  If there was already a cow in the same cell,
this will replace the already existing cow.

[source, c]
----
<<constants>>=
#define COW_CHAR '%'
----

[source, c]
----
<<main variables>>=
int cow;
----

[source, c]
----
<<initialize level>>=
for (cow = 0 ; cow < 10 ; ++cow) {
    level[rand() % 6 + 8][rand() % 6 + 8] = COW_CHAR;
}
----

That means that is possible to start with just one cow, and hence with less
money.  But it also means that there is less area to defend initially.  So, in
the end the game balances.

To use the `rand` function, I first must initialize the random number generator
with a 'seed', which needs to be different each time the game starts to
generate different outcome each play.  A good seed value is the time in which
the game starts up.

[source, c]
----
<<initialize random number generator>>=
srand(time(NULL));
----

`srand` and `rand` are declared in the `stdlib.h` header; `time` in `time.h`.
I need to include both headers.

[source, c]
----
<<headers>>=
#include <stdlib.h>
#include <time.h>
----


Turns
~~~~~

This version of The Horde is turn based which means that in each turn the
player and the hordlings can make a 'move'.  A move can either be an actual
movement to an adjacent cell, building a fence, or buying a cow.  The player is
the only that can make the last two.

Based on the number of turns the player lasts against The Horde, the game sends
in a new wave of hordlings or even increases the difficulty.  To know the
number of turns played, I need a new variable.  Using an unsigned integer to
make the number of turns practically unlimited.

[source, c]
----
<<main variables>>=
unsigned int current_turn;
----

When the game starts, this variable is set to zero: the first turn.

[source, c]
----
<<initialize level>>=
current_turn = 0;
----

For each game's loop, I need to increment the turn counter by one.

[source, c]
----
<<update turn counter>>=
++current_turn;
----


Gold
~~~~

As stated, the game's objective is to reach a minimum of $2000 in gold.

[source, c]
----
<<constants>>=
#define GOLD_GOAL 2000
----

That means that the game must keep account of the current amount of gold.
Given the defined upper limit of gold, using a `short` to store the amount is
enough.  I can't use an `unsigned` because it is possible to reach a negative
amount due to attacks from the hordlings, in which case the game ends and the
player loses.

[source, c]
----
<<main variables>>=
short gold;
----

This amount needs to be zero at the beginning.

[source, c]
----
<<initialize level>>=
gold = 0;
----

The game reward the player with gold once every new 'season', which starts
after an arbitrary number of turns.  Through trial and error, I've defined the
number of turns to start a season to be 150 that gives enough time to stop the
current wave and prepare for the next.

[source, c]
----
<<constants>>=
#define SEASON_TURNS 150
----

Thus, when a new season starts the game counts how many cows still remain on
the level and increment the amount of gold by $10 for each still alive.

[source, c]
----
<<constants>>=
#define COW_PROFIT 10
----

[source, c]
----
<<new season>>=
if (current_turn % SEASON_TURNS == 0) {
    for (y = 0 ; y < LEVEL_HEIGHT ; ++y) {
        for (x = 0 ; x < LEVEL_WIDTH ; ++x) {
            if (COW_CHAR == level[y][x]) {
                gold += COW_PROFIT;
            }
        }
    }
----

Notice how the first turn being zero forces to start a new season to start
right at the beginning therefore allowing the player to start with some money
to spend coming from the cows placed randomly.  Unfortunately, for the player,
it also means that the first wave of hordlings starts to attack immediately.

As with real life, spending or losing money can happen any time, not only at a
new season's start.  The player can build a fence or buy a cow any turn.  Also,
when a hordling attacks a player instead of going after the cattle, the player
loses some of the money.  The game, thus, needs to check each turn if the
player lost all her money.  I also check if the player reached the goal at the
same time, because either way the logic to quit the game is almost the same,
and I want to avoid repetition.

[source, c]
----
<<check gold>>=
if (gold < 0 || gold >= GOLD_GOAL) {
    mvprintw(LEVEL_HEIGHT / 2, LEVEL_WIDTH + 1, (gold < 0) ? "LOSE" : "WIN");
    getch();
    quit = TRUE;
}
----

When the game is over, either because the player won or lost, I print out the
outcome on the level's right side and then way for a key before quiting the
game.


Status
~~~~~~

Besides the position of all entities, the player needs to see other information
such as the amount of gold remaining, to be know whether has the possibly to
build a fence or buy a cow; and the current turn, to know when a new season
starts.

I print the this extra status at the first row next the level.

[source, c]
----
<<draw level>>=
mvprintw(0, LEVEL_WIDTH + 1, "$%i T%i ", gold, SEASON_TURNS - (current_turn % SEASON_TURNS));
----

Instead of the actual current turn I print the number of turns remaining until
the next season.  With this is easier to know when a new season starts than
with the actual turn number, which gives no extra information to the player.

The additional space written after the turn is there to erase any digit left
over when the number of turns gets smaller and uses a digit less (i.e., it goes
down from 100 to 99, and from 10 to 9.)


Player
------

Following NetHack's conventions, the player is represented on screen as the
'at' character (`@`).

[source, c]
----
<<constants>>=
#define PLAYER_CHAR '@'
----

The player is the only game entity than instead of her position being reflected
in the `level` array has its own pair of variables, one for the row and the
other for the column.

[source, c]
----
<<main variables>>=
int playerx;
int playery;
----

This difference between the player and the other entities is due the fact that
the player is the only entity that can be, on some occasions, on top of another
entity.  This can happen in two situations:

  1. At the beginning, the player is randomly placed in the same area as the
  cows and thus on top of one of them.

  2. When the player builds a new fence or buys a cow, it is placed at the same
  position where the player is located at.

The first case might be removed if instead of allowing the player to be on top
of a cow, I remove the cow replacing it with the player.  But the second case
is trickier to remove, because if I tried to put a new fence or cow in front of
the player, for example, then I would need to keep the current player's
direction.  Instead, I keep the player's position because is easier to
understand than the direction.

Therefore, to draw the player at her position I need to move the curses to the
right cell on the screen and write the character, all this *after* drawing the
level, otherwise the player wouldn't be visible.

[source, c]
----
<<draw level>>=
mvaddch(playery, playerx, PLAYER_CHAR);
----

I also need to set the player's initial position.  As said, I am going to place
the player at the same area where the cows are, to keep her away from the wave
of hordlings.

[source, c]
----
<<initialize level>>=
playerx = rand() % 6 + 8;
playery = rand() % 6 + 8;
----


Moving Around
~~~~~~~~~~~~~

To move the player around the level, I am going to use the same keys as used
by NetHack, which has two sets of keys.

The first set use the 'numeric pad', where `4`, `2`, `8`, and `6` move the
player to the adjacent cell west, south, north, or east respectively.  `1`,
`3`, `7`, and `9` move the player diagonally.

The second is similar to the set used by 'vi' to move the cursor around, with
keys `h`, `j`, `k`, and `l` to move the character to the adjacent cell west,
south, north, or east respectively.  The `y`, `u`, `b`, and `n` keys move the
player diagonally.

As the player moves around the screen, the game needs to check whether the
player is going to step in a cell within the level's limit, if is going to
attack a hordling, and other similar cases.  To avoid repeating all this checks
throughout the code that received the input, I am going to have a pair of
variables that tell the position the player should move given the input.

[source, c]
----
<<main variables>>=
int new_playerx;
int new_playery;
----

Thus, I need to set these variables based on the current player's position as
well as the character received from the keyboard.  If the key is not a movement
command, the new player's position is set outside the level on purpose.

[source, c]
----
<<handle keyboard input>>=
new_playerx = -1; /* set outside the level to know whether the key was */
new_playery = -1; /* a movement command or any other command. */
switch (getch()) {
    /* west */
    case 'h':
    case '4':
        new_playerx = playerx - 1;
        new_playery = playery;
        break;

    /* south */
    case 'j':
    case '2':
        new_playerx = playerx;
        new_playery = playery + 1;
        break;

    /* north */
    case 'k':
    case '8':
        new_playerx = playerx;
        new_playery = playery - 1;
        break;

    /* east */
    case 'l':
    case '6':
        new_playerx = playerx + 1;
        new_playery = playery;
        break;

    /* north-west */
    case 'y':
    case '7':
        new_playerx = playerx - 1;
        new_playery = playery - 1;
        break;

    /* north-east */
    case 'u':
    case '9':
        new_playerx = playerx + 1;
        new_playery = playery - 1;
        break;

    /* south-west */
    case 'b':
    case '1':
        new_playerx = playerx - 1;
        new_playery = playery + 1;
        break;

    /* south-east */
    case 'n':
    case '3':
        new_playerx = playerx + 1;
        new_playery = playery + 1;
        break;
----

With these variables correctly set, I can now check whether the new position is
within the level's limits and if the cell in which the player is going to move
is empty.  If so, the movement is permitted.

[source, c]
----
<<update player position>>=
if (new_playerx > 0 && new_playerx < LEVEL_WIDTH - 1 &&
    new_playery > 0 && new_playery < LEVEL_HEIGHT - 1 ) {

    <<check collision with hordlings>>

    if (EMPTY_CHAR == level[new_playery][new_playerx]) {
        playerx = new_playerx;
        playery = new_playery;
    }
----


Buying Cows
~~~~~~~~~~~

To buy a cow and place at the player's position, the game needs to check
whether there are enough gold to buy a new cow based on their cost.

[source, c]
----
<<constants>>=
#define COW_PRICE 20
----

It must also check if the player's position is actually empty.  Remember that
the player could be on top of a cow or fence.

[source, c]
----
<<buy and place cow>>=
if (gold >= COW_PRICE && EMPTY_CHAR == level[playery][playerx]) {
    gold -= COW_PRICE;
    level[playery][playerx] = COW_CHAR;
}
----

To place a new cow the user must enter the `c` key.  This sets a new cow
character at the player's position and also decrease the amount of gold.

[source, c]
----
<<handle keyboard input>>=
    case 'c':
        <<buy and place cow>>
        break;
----


Fences
~~~~~~

The fences the player can put on can have different strength, from the
'weakest' to the 'stronger'.  Both building a new fence and upgrading a fence
to be stronger has the same cost of $1.

[source, c]
----
<<constants>>=
#define FENCE_COST 1
----

To make easier upgrading and downgrading the fences' strength, the different
strengths have consecutive characters on screen.  Thus, with simple increments
and decrements I can change a fence's strength.  Therefore, the difference
between a fence's character and the weakest fence character is the fence's
strength.

[source, c]
----
<<constants>>=
#define FENCE_WEAKEST_CHAR 176
#define FENCE_STRONGEST_CHAR 180
----

The characters that I've selected for the fences are from the extended ASCII
table, also known as http://en.wikipedia.org/wiki/Code_page_437[code page 437].
The intended output for these characters is only correct when running in a
terminal set to this code page; all other configurations will show different
characters for the fences.  This is a 'known issue' that won't be fixed,
because there is no characters in the regular ASCII set that looks as a fence
to me, and using a suitable character for different configurations isn't worth
it.

Building a new fence, then, is a matter of placing the weakest fence on the
position where the player is located at, if that position is empty and there is
enough gold.  This is done when the user presses the `f` key.

[source, c]
----
<<handle keyboard input>>=
    case 'f':
        if (gold >= FENCE_COST && EMPTY_CHAR == level[playery][playerx]) {
            gold -= FENCE_COST;
            level[playery][playerx] = FENCE_WEAKEST_CHAR;
        }
        break;
----

To upgrade an existing fence I have to come up with another way, because the
player can't pass over a fence, forcing the user to think better fence
placement strategies.  Instead, the I will upgrade the fences when the player
tries to move to a cell already occupied by a fence.  That is, instead of
passing over she will upgrade the fence, if there is enough money and the fence
is not at the strongest already.  Remember how the different fences' strengths
have consecutive values and thus a simple increment upgrades a fence.

[source, c]
----
<<update player position>>=
    else if (level[new_playery][new_playerx] >= FENCE_WEAKEST_CHAR &&
        level[new_playery][new_playerx] < FENCE_STRONGEST_CHAR &&
        gold >= FENCE_COST) {
        gold -= FENCE_COST;
        ++level[new_playery][new_playerx];
    }
}
----


Hordlings
---------

Like NetHack, this game represents the hordlings on screen using capitals
letters from 'A' to 'Z', with `A` the weakest hordling and `Z` the strongest.

[source, c]
----
<<constants>>=
#define HORDLING_WEAKEST_CHAR 'A'
#define HORDLING_STRONGEST_CHAR 'Z'
----

At the each season's beginning, the game spawns at least two new hordlings.
These new hordlings always appear on the levels borders, one either north or
south while the other always east or west.  To make things more interesting,
every year -- every 4 seasons -- The Horde will increase the attack's
difficulty by adding two hordlings to the wave and by sending stronger
hordlings.

[source, c]
----
<<constants>>=
#define HORDLING_LEVEL_UP_TURN (SEASON_TURNS * 4)
----

As with the cows, the game will choose random positions for hordlings and place
them on the level each new season.  That means that it is possible for a
hordling to replace another, and thus having one less hordling than expected.
That is a lucky season.

[source, c]
----
<<main variables>>=
int hordling;
int hordling_level;
----

[source, c]
----
<<new season>>=
    hordling_level = current_turn / HORDLING_LEVEL_UP_TURN + 1;
    for (hordling = 0 ; hordling < hordling_level ; ++hordling)
    {
        /* north or south */
        level[(rand() % 2) * (LEVEL_HEIGHT - 1)][rand() % LEVEL_WIDTH] = HORDLING_WEAKEST_CHAR + (rand() % hordling_level);
        /* east or west */
        level[rand() % LEVEL_HEIGHT][(rand() % 2) * (LEVEL_WIDTH - 1)] = HORDLING_WEAKEST_CHAR + (rand() % hordling_level);
    }
}
----


Cooooooowsssss
~~~~~~~~~~~~~~

At each turn, every hordling on the screen will move a step closer to its
nearer cow.  But first, the game needs to know which hordling to update by
looping over the level and looking for hordlings in it.  If there is no
hordling to move, then we can continue with the turn.

[source, c]
----
<<update hordlings position>>=
while (TRUE) {
    int hordlingx = -1;
    int hordlingy = -1;
    <<other hordling position variables>>

    for (y = 0 ; y < LEVEL_HEIGHT ; ++y) {
        for (x = 0 ; x < LEVEL_WIDTH ; ++x) {
            if (level[y][x] >= HORDLING_WEAKEST_CHAR &&
                level[y][x] <= HORDLING_STRONGEST_CHAR) {
                hordlingx = x;
                hordlingy = y;
            }
        }
    }

    if (hordlingx < 0) {
        /* No more hordlings. */
        break;
    }
----

With the hordling position, I need to find the nearest cow to move toward.
Also, if the player is nearer to the hordling than any cow, the hordling
instead will move towards the player to steal a piece of gold.  I do this by
comparing the distance in the X and Y coordinates between each cow and the
hordling, and the distance between the hordling and the player.  Whichever is
the shorter distance, becomes the hordling's target.

[source, c]
----
<<other hordling position variables>>=
int distance;
int targetx;
int targety;
----

[source, c]
----
<<update hordlings position>>=
    /* find nearest cow, or use the player if nearer. */
    targetx = playerx;
    targety = playery;
    distance = abs(hordlingx - playerx) + abs(hordlingy - playery);
    for (y = 0 ; y < LEVEL_HEIGHT ; ++y) {
        for (x = 0 ; x < LEVEL_WIDTH ; ++x) {
            if (COW_CHAR == level[y][x]) {
                int new_distance = abs(hordlingx - x) + abs(hordlingy - y);
                if (new_distance < distance) {
                    targetx = x;
                    targety = y;
                    distance = new_distance;
                }
            }
        }
    }
----

Here I am using the `abs` function declared in `math.h`.

[source, c]
----
<<headers>>=
#include <math.h>
----

With the target's position in the `targetx` and `targety` variables, now I can
compute the new position for the hordling in order to move in.  Like the
player, the hordlings only can move a cell per turn.

[source, c]
----
<<other hordling position variables>>=
int new_hordlingx;
int new_hordlingy;
----

[source, c]
----
<<update hordlings position>>=
    new_hordlingx = hordlingx + (hordlingx == targetx ? 0 : (hordlingx < targetx ? 1 : -1));
    new_hordlingy = hordlingy + (hordlingy == targety ? 0 : (hordlingy < targety ? 1 : -1));
----

Before I can move the hordling I need to check whether there is any impediment
on its way.  For the case of a hordling, either a fence or the player.

When there is a fence in front of the hordling, the hordling will hit the fence
and will weaken it.  If the fence was of the weakest strength, then it will
vanish.

[source, c]
----
<<update hordlings position>>=
    if (level[new_hordlingy][new_hordlingx] >= FENCE_WEAKEST_CHAR &&
        level[new_hordlingy][new_hordlingx] <= FENCE_STRONGEST_CHAR) {
        --level[new_hordlingy][new_hordlingx];
        if (level[new_hordlingy][new_hordlingx] < FENCE_WEAKEST_CHAR) {
            level[new_hordlingy][new_hordlingx] = EMPTY_CHAR;
        }
----

Otherwise, if the fence wasn't crushed and it is still a bit stronger than just
the bare bone fence, is the hordling who will also take a hit.  Like the fence,
if the hordling was of the lowest strength, it will perish.

[source, c]
----
<<update hordlings position>>=
        else if (level[new_hordlingy][new_hordlingx] > FENCE_WEAKEST_CHAR) {
           --level[hordlingy][hordlingx];
           if (level[hordlingy][hordlingx] < HORDLING_WEAKEST_CHAR) {
               level[hordlingy][hordlingx] = EMPTY_CHAR;
               /* next monster */
               continue;
           }
        }
    }
----

If instead of a fence, the hordling hits the player, it will steal a piece of
gold from her.  Remember that the player's position is not in the `level` array
but kept by two separate variables.

[source, c]
----
<<update hordlings position>>=
    else if (new_hordlingy == playery && new_hordlingx == playerx) {
        --gold;
    }
----

If it is not any of these cases, check whether the cell to move is either empty
or has a cow.  In both cases, the hordling moves to the new position.  If the
cell has a cow, then the hordling replaces -- or eats -- the cow as if it were
an empty cell.

[source, c]
----
<<update hordlings position>>=
    else if (level[new_hordlingy][new_hordlingx] == EMPTY_CHAR ||
        level[new_hordlingy][new_hordlingx] == COW_CHAR) {
        level[new_hordlingy][new_hordlingx] = level[hordlingy][hordlingx];
        level[hordlingy][hordlingx] = EMPTY_CHAR;
        /* update the position. */
        hordlingx = new_hordlingx;
        hordlingy = new_hordlingy;
    }
----

Finally, to mark that the hordling has already moved and thus no need to update
it again until the next turn, I'll convert its character to lower case.  Since
the hordlings characters are all uppercase (from `A` to `Z`), converting it to
lowercase the previous loop that looks for hordling will skip all already moved
hordlings and stop when all of them have moved.

[source, c]
----
<<update hordlings position>>=
    level[hordlingy][hordlingx] = tolower(level[hordlingy][hordlingx]);
}
----

The `tolower` function is declared in the `ctype.h` header that I need to
include.

[source, c]
----
<<headers>>=
#include <ctype.h>
----

After all the hordlings have moved, I must change all them back to uppercase to
make them ready for the next turn.  I'll use the fact that only hordlings are
lowercase letters to my advantage and use the `islower` function, also declared
in the `ctype.h` header, to find the hordlings and the `toupper` function to
convert them back to capitals.

[source, c]
----
<<update hordlings position>>=
for (y = 0 ; y < LEVEL_HEIGHT ; ++y) {
    for (x = 0 ; x < LEVEL_WIDTH ; ++x) {
        if (islower(level[y][x])) {
            level[y][x] = toupper(level[y][x]);
        }
    }
}
----

I am aware that all this looping around the level has a complexity of
'O(n^2^)', but given the size of the grid (24x24 cells) this is hardly an
issue.  If the level was any bigger, a I would advise a different approach,
such as keeping a list of hordlings and cows.


The Foretold Death of a Hordling
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Killing hordlings is done in the same way as upgrading fences, and reciprocally
how hordlings steal from the player: when the player is adjacent to a hordling
and moves towards it, the hordling receives a hit and lowers its strength.

[source, c]
----
<<check collision with hordlings>>=
if (level[new_playery][new_playerx] >= HORDLING_WEAKEST_CHAR &&
    level[new_playery][new_playerx] <= HORDLING_STRONGEST_CHAR) {
    --level[new_playery][new_playerx];
----

If the hordling was of the weakest strength, then it dies and leaves its cell
empty, in which case the player now can move in it.  That is why checking for
collision with hordlings is done before trying to actually update the player's
position.

[source, c]
----
<<check collision with hordlings>>=
    if (level[new_playery][new_playerx] < HORDLING_WEAKEST_CHAR) {
        level[new_playery][new_playerx] = EMPTY_CHAR;
    }
}
----


Skipping Turns
--------------

It is possible to skip to the next season, for instance when the player no
longer wants or can build fences due a shortage of gold.

Skipping to the next session is accomplished by pressing the `s` key in a turn
that itself doesn't start already a new season.

Keep in mind that the turn counter is incremented once per turn, thus to start
a new session, I need to add to the number of turns required until the next
season's beginning, short by one turn, which is added at the end of the current
turn.

[source, c]
----
<<handle keyboard input>>=
    case 's':
        if (0 != current_turn % SEASON_TURNS) {
            current_turn += SEASON_TURNS - (current_turn % SEASON_TURNS) - 1;
        }
        break;
----


The Game Loop
-------------

The main game's loop is kept in the `main` function.  The whole game loops
until either the player reached the goal or the hordlings left the player
without money.  This is stored in a boolean variable called `quit`.

[source, c]
----
<<main variables>>=
char quit;
----

This variable is set to `FALSE` when initializing the level and is only
changed to `TRUE` when the game needs to quit.

[source, c]
----
<<initialize level>>=
quit = FALSE;
----

The main loop, thus, looks like this:

[source, c]
----
<<main>>=
int main()
{
    <<main variables>>

    <<initialize curses>>
    <<initialize random number generator>>
    <<initialize level>>
    while (!quit) {
        <<new season>>
        <<draw level>>
        <<check gold>>
        if (!quit) {
            <<handle keyboard input>>
            <<update player position>>
            <<update hordlings position>>
            <<update turn counter>>
        }
    }

    return EXIT_SUCCESS;
}
----

It is also possible to quit the game at any moment by hitting the `q` key.

[source, c]
----
<<handle keyboard input>>=
    case 'q':
        quit = TRUE;
        break;
}
----


Setting up curses
-----------------

Before the game can draw anything on the screen, it needs to initialize the
curses library.  First of all, to be able to call any curses function, I need
to include its header file.

[source, c]
----
<<headers>>=
#include <curses.h>
----

Then, I need to initialize the main terminal screen.

[source, c]
----
<<initialize curses>>=
initscr();
----

`initscr` will already show an error message and call `exit` if it can't
initialize the library.  That means I don't need to add any additional check
for errors.

This game don't need to show the cursor while writing all the characters
around the screen, nor show the entered keys from the keyboard.

[source, c]
----
<<initialize curses>>=
curs_set(0); /* 0 == cursor is invisible. */
noecho();
----

By default, curses will wait until the user presses `enter` before giving any
input to the application.  As it would be cumbersome to expect the user to
press enter every time, I tell curses to give out the key as soon as entered,
but at the same time for the library to handle break and other interrupts.

[source, c]
----
<<initialize curses>>=
cbreak();
----

For this game I require the library to wait until the player pressed a key, as
this is the basis for each game turn.  It turns out that by default, curses
already does that and thus I don't need to add any other call.

Finally, once the game is over and must quit, I need to clean up curses.  I
will use `atexit` to clean up the window when `exit` get called, but I can't
pass `endwin` directly as a parameter to `atexit` because the prototypes don't
match: `endwin` returns an `int` but `atexit` expects a function that returns
nothing.  Instead, I'll write a new function, called `cleanup`, with the
proper function signature for `atexit` which calls `endwin`.

[source, c]
----
<<curses clean up function>>=
void
cleanup_curses()
{
    endwin();
}
----

Now I can use this function to clean up curses at exit.

[source, c]
----
<<initialize curses>>=
atexit(cleanup_curses);
----

ifndef::doctype-book[]
[appendix]
endif::doctype-book[]
horde.c
-------

A single C source code module holds all the building blocks I've described
earlier.

[source, c]
----
<<*>>=
/*
    Horde - A curses based action-strategy game.
    Copyright (c) 2010 Jordi Fita <jfita@geishastudios.com>

    <<license>>
*/
<<headers>>

<<constants>>

<<curses clean up function>>

<<main>>
----


ifndef::doctype-book[]
[appendix]
endif::doctype-book[]
Makefile
--------

Being a simple application, an small Makefile would be sufficient to build and
link `horde` from the source document.

The first thing that needs to be done is to extract the C source code from the
AsciiDoc document using `atangle`.  It is necessary, therefore, to have a
`atangle` installed to extract the source code.

[source, make]
----
<<extract c source code>>=
horde.c: horde.txt
	atangle $< > $@
----

Then is possible to link the executable from the extracted C source code.
Although, I have to take into account the platform executable suffix and the
curse library used.

For Linux and other UNIX systems, the suffix is the empty string, but for
Windows I need to append '.exe' to the executable.

For Linux and other UNIX systems, the curses library is `ncurses`, but for
Windows I'll use `pdcurses`

To know which system is the executable being build, I'll use the `uname -s`
command, available both in Linux and also in MinGW or Cygwin for Windows.  In
this case, I only detect the presence of MinGW because I don't want to add yet
another dependency to Cygwin's DLL.

[source, make]
----
<<determine executable suffix>>=
UNAME = $(shell uname -s)
MINGW = $(findstring MINGW32, $(UNAME))
----

Later, I just need to check if the substring 'MINGW' is contained in the
output of `uname`.  If the `findstring` call's result is the empty string, then
we assume we are building in a platform that doesn't have executable suffix.

[source, make]
----
<<determine executable suffix>>=
ifeq ($(MINGW),)
EXE = 
CURSES = -lncurses
else
EXE = .exe
CURSES = -lpdcurses -Wl,--enable-auto-import -mwindows
endif
----

With this suffix, I can now build the final executable.  Of course, I need to
link also with the curses library for it to work.

[source, make]
----
<<build horde executable>>=
horde$(EXE): horde.c
	gcc -o $@ $< $(CURSES)
----

Sometimes, it is necessary to remove the executable as well as the intermediary
building artifacts.  For this, I'll add a target named `clean` that will build
all the files built by the Makefile and only left the original document.  I
have to mark this target as `PHONY` in case there is a file named `clean` in
the same directory as the Makefile.

[source, make]
----
<<clean build artifacts>>=
.PHONY: clean

clean:
	rm -f horde$(EXE) horde.c
----

As the first defined target is the Makefile's default target, I'll place the
executable first and then all the dependences, until the original document.
After all source code targets, I'll put the `clean` target.  This is not
required, but a personal choice.  The final Makefile's structure is thus the
following.

----
<<Makefile>>=
<<determine executable suffix>>

<<build horde executable>>

<<extract c source code>>

<<clean build artifacts>>
----


ifndef::doctype-book[]
[appendix]
endif::doctype-book[]
License
-------

This program is distributed under the terms of the GNU General Public License
(GPL) version 2.0 as follows:

----
<<license>>=
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2.0 as
published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
----
