THE WAR OF THE SHIRES (part 2 of 3)
by Alan Davis
from ZX Computing Dec.1986

Welcome to the second instalment of "War of the Shires" by
Alan Davis. Sharpen your sword, polish your shield, and let's
enter the fray.


In this article we'll be laying the programming foundations for
our "fantasy epic", namely Listing 1 [see SHIRES.TAP:SHIRE2L1].
It's a rather lengthy dollop of program to type in, but you can
take comfort from the fact that the bulk of the game mechanics
and data are contained here. The consequence is that next month
you'll be able to get the full game up and running pretty
quickly, with relatively little wear and tear on the old
fingers. Once you've typed in Listing 1, I strongly recommend
that you save a master copy of it without auto-run, and set that
aside until next month when we'll make the necessary additions.
However, you do need to try out what you have so far - so here's
what you should do to make a temporary "test" version.

With Listing 1 held in memory, enter CLEAR 59999 and then load
in the two code blocks and the map array from the first article
(LOAD "PRINT" CODE: LOAD "UDGS" CODE: LOAD "MAP" DATA x$().)
Next type GO TO 9998 and all the necessary bits and pieces will
be saved to tape for you in the correct order. Rewind the tape,
and load the whole thing from scratch. There will be a delay of
some seconds after everything has loaded while the extensive
initialisation routines perform their appointed task - on
completion of which you'll be invited to press a key in order to
get things started in earnest.


Main menu

The first thing to greet you is the main character selection
menu, as in Figure 1 [see SHIRE2F1.GIF]. Your choice is pretty
limited at this stage, but things will improve! You can try out
the option to display the map symbols (useful to a player until
he becomes familiar with them), but of course the "Suspend play"
option isn't relevant yet! Selecting option "A", however, calls
up something rather more interesting - as shown in Figure 2 [see
SHIRE2F2.GIF]. This is essentially a description of Roland of
Greenways, who is the only controllable character at present,
and provides information about where he is, the size and state
of his army, and the options available. You can try out the
"SEARCH" option - though it won't be terribly informative yet -
and indeed the only option of real interest is "View map or
move" which puts the program into "Map" mode. The world map will
be displayed, with Roland's position indicated by a bright
cursor. All movement in the game takes place in "Map" mode, and
the relevant keypresses are indicated at the bottom of the
screen.

You can move Roland and his men in any one of four directions
using keys 5, 6, 7 and 8 - and at any time you can quit "Map"
mode by pressing key "0"; which will return you to "character
description" mode. (It's worth doing this at intervals during
movement in order to see how the army tires during a long
march). There's one other important option in "Map" mode:
pressing key "1" will cause all army positions to be shown on
the map, with enemy armies given in black ink on white paper,
and Shire armies in black ink on bright white paper. Don't be
alarmed by the fact that you see only one enemy army symbol -
this is because all enemy armies are in the same place (the Keep
of Darkness), and they'll stay there until next month. It's
quite safe to explore!

We'll have more to say about "Armies" mode next time, but for
now just press a key to return to simple "Map" mode, and try
moving Roland to one of the other keeps. When you arrive, leave
"Map" mode - whereupon you'll find a new option presents itself
so that you can greet another character, and you'll find from
this point onwards that you can switch between characters using
the "Change character" option. Incidentally, you'll find that
searching a location is a little more interesting when another
character and his army are present - though it will offer a
great deal more in due course. You're now in a position to
wander about at will, meeting, greeting, and then (if you wish)
controlling all the Shire leaders.


D.I.Y.

As I said in last month's article, it's my aim in this series
not merely to offer you a game to play, but to provide you with
a program base to which you can add developments of your own. So
it's important that you understand exactly what each stage of
the program is doing in relation to what you see on the screen.
You can get a useful overall view of the structure from the
"flow chart" I've given in Figure 3 [see SHIRE2F3.GIF], which
shows how the various sections of the program are related by the
menu selections. Armed with this, let's take a closer look at
Listing 1 - starting at the most logical place with the
initialisation sequence from line 8000 onwards. After the
loading instructions for the code blocks and map array, we find
at line 8900 a range of string and numeric arrays being
dimensioned. Let's examine the meaning of the string arrays
first:

1) f$(12,20) holds the names of the characters followed
   immediately by the names of the shires they lead.

2) p$(10,20) holds the descriptions of landscape features.

3) v$(10,21) holds the descriptions of army strength and morale
   (five descriptions for strength, and five for morale).

Information is extracted from these arrays using defined
functions (see the first few lines of Listing 1) in a way which
will be familiar to those of you who read my earlier "Realms of
Interaction" series. The method gives you an immensely powerful
system of generating text in games like this, and the relevant
functions are as follows:

1) FN n$(x) returns the shortened name of the "xth" character.
   Thus FN n$(1) gives "Roland".

2) FN f$(x) returns the full title of the "xth" character. Thus
   FN f$(1) gives "Roland of Greenways".

3) FN s$(x) returns the name of the "xth" shire - so that FN
   s$(1) is "Greenways".

4) FN d$(x) returns a location description corresponding to the
   contents of the map array at the current location. Thus FN
   d$(2) gives "upon rolling downs".

5) FN b$(x) returns the mere name of a landscape feature, thus
   FN b$(2) gives "rolling downs".

We need to look at the numeric arrays next. These are used to
store important parameters concerning the characters and their
armies (many of which change as the game progresses). The most
important - and the most complex - is a(12,9). Each of its
twelve rows corresponds to one of the characters, and each of
the nine columns gives a particular parameter for that character
as shown in Figure 4.


= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Figure 4. Parameters held in the arrays a(12,9) and u(70,5).

			a(12,9)
Column  Parameter
1       Size of army
2       Strength of men (0-249)
3       Morale of men (0-249)
4 & 5   (x,y) coordinates of current position on map
6       "Recruitment" flag (1 if required, 0 if not)
7 & 8   (x,y) coordinates of keep owned by character
9       Provisions available (0 at start of game)

			u(70,5)
Column  Parameter
1       Size of army
2       Strength of warriors (starts at 200)
3       "Target" character
4 & 5   (x,y) coordinates of current position on map
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


Initial values for the array are established in line 8950. Note
that the DATA statements used here (see line 9100) contain the
(x,y) coordinates of the keeps, where each character is
positioned at the start. Now you know why I asked you to be
careful when positioning the keeps on your map last month! Those
array elements not defined here start off, of course, at zero -
with the exception of a(1,6) which is set to 1 in line 8940
(Roland being the only "recruited" or controllable character at
the start).

The second most important array is u(70,5) which performs the
similar, though simpler task of data storage for the 70 enemy
armies. Each row corresponds to one of those armies, while each
column corresponds to one of five parameters (see Figure 4).


Targets

A word of explanation is needed about the 3rd parameter. The
enemy armies are going to be "intelligent", in the sense that
each one will be allocated a specific job - that of seeking out
and attacking a specific character (the "target"). Parameter 3
is the code of a given army's "target" - so that if Roland is
the target, this parameter will take a value of 1. Initial
values for the array are set in line 8970. Note that since all
enemy armies start off at the keep of Darkness, parameters 4 and
5 are the same in each case, i.e. the map coordinates of the
keep. Targets are allocated at random, by the way, so that the
overall strategy of the enemy will vary from one game to
another. This means that each new game presents a fresh
challenge to the player.

There are two arrays that I haven't mentioned yet; t(22,32) is
used to keep track of the total number of enemy warriors at each
location. The need for this will become apparent next month,
when we'll also examine the purpose of m$(22,32) which for the
present must remain a mystery ...

We're now in a position to examine the remaining defined
functions. FN n(x) and FN s(x) return a number between 1 and 5
related to the strength and morale respectively of the army led
by character "x". FN v$(x) and FN q$(x) use those numbers to
generate an appropriate text description of strength and morale,
extracted from the array v$(). FN r(x) returns a random integer
between 1 and x. FN i(x) returns the INK colour appropriate for
a particular UDG (CHR$ x) so that individual map graphic symbols
can be printed up from BASIC if necessary. The rather lengthy
function FN c(y,x) is used to divide the whole world up into
shires, returning for a given pair of map coordinates the number
corresponding to a particular shire (1=Greenways, 2=Deepmeads,
etc). I've shown in Figure 5 [see SHIRE2F5.GIF] how this
division occurs, so that you can relate the conditions implicit
in the function to the actual divisions on the map. Finally, FN
p() is a handy little function for centralising things like
titles on screen - see the little subroutine at line 40 for an
example of its use.

Before we move on to look at the rest of the program structure,
a few general points, largely concerned with presentation, are
worth making. The bulk of the text display is achieved by first
building up the text in the string z$, and then letting machine
code handle the word wrapping and printing (see the subroutine
at line 30, which endures heavy use by the program). Now it's
possible to achieve this entirely in BASIC in fact, though the
result is rather "tacky" or "lumpy" printing. This not only
slows down the gameplay to some degree, but also lacks polish in
presentation, and this is one of those situations where just a
dash of machine code makes a world of difference to the flow and
smoothness of a game. Another example of how presentation can be
improved at little cost is seen in the subroutine at line 15.
The program uses this to "decorate" page titles using the UDG
corresponding to the current map location. This not only
produces pleasant variety in visual impact as the game
progresses, but also adds atmosphere in its own right. Simple,
but effective - try leaving it out, and see for yourself what
you lose.


The program

As you saw in Figure 3, the program so far consists of only a
few routines and the REMs should help you find your way about,
together with the following notes on each section:

1) Main character selection menu (lines 5000-5050). Line 5010
   may baffle you a little: this checks each character to see if
   all his army has been destroyed (in which case he's declared
   dead) but of course since there are no battles yet this could
   hardly occur!

2) Character description and options (lines 500-599). Notice
   that since all characters stay at their respective keeps
   unless you move them, the "Greet" option is only available if
   the current location is a keep (CHR$ 149 on the map) and if
   the potential recruit hasn't already been co-opted (line 540).

3) Search location (lines 1000 onwards). We'll be adding more
   routines to this next time. The only item of note here
   concerns what happens when other characters are present at
   the current location, where the necessary sorting of details
   to be printed is done in lines 1010-1025. It's a little more
   complex than you might expect because we must allow for the
   possible circumstance whereby lots of characters are gathered
   at the same location - the problem being that the text
   printing routine can cope only if LEN z$ is less the 255. The
   difficulty is overcome by printing up z$ in two parts if more
   than five characters are present.

4) Movement (lines 400-499). The temporary variables nx and ny
   are used to check conditions of movement, with the
   appropriate entries for movement to a new location being made
   in the array a() only when the movement is decreed "legal".
   This section would have been much simpler had I not decided
   to incorporate ships into the game, and indeed apart from
   line 460 (which prevents movement if a mountain blocks the
   way, or if an army is exhausted) most of the condition tests
   here concern the business of sailing. Thus you can't move
   across water unless you're on a ship (line 455): you can't
   board a ship which is already full (line 458); and if a ship
   is moved, the map must be changed to leave water in the old
   location and the ship in the new location (line 465). LIne
   468 causes the moving army to tire by an amount appropriate
   to the terrain at the current location. The subroutines for
   printing the map (lines 45-49) and displaying armies (lines
   50-53) are, I hope, fairly straightforward. Don't worry if
   the line numbering seems odd, by the way; just enter the line
   numbers as they are given so that we can make the necessary
   insertions next month.

Finally, a word about keyboard input (lines 20-25). The
completed game will run in real time, i.e. we shall require the
enemy to move and attack even though you may be doing nothing
but sitting and biting your nails! This means that the usual
PAUSE 0: LET i$=INKEY$ method of picking up a keypress won't do,
as it would halt the game indefinitely if no key is pressed. For
this reason, input is always collected using GO SUB 20, whereby
the time is continually checked - with repeated jumps to the
mysterious subroutine at line 100 as necessary. At present this
merely allows tired armies to recover their strength as time
passes, but in the third and final article we'll make this a
little more exciting! Keep that shield polished - you're going
to need it!


--
Another Fine Product transcribed by:
Jim Grimwood (jimg@globalnet.co.uk), Weardale, England
--
