#include <exec/exec.h>
#include <intuition/intuition.h>
#include <utility/tagitem.h>
#include <graphics/gfx.h>
#include <clib/intuition_protos.h> // Object
#include <libraries/gadtools.h>    // struct NewMenu
#include <devices/timer.h>         // struct timeval
#include <clib/timer_protos.h>
#include <dos/dosextens.h>         // struct Process
#include <libraries/asl.h>         // ASL_FileRequest
#include <dos/dostags.h>           // SYS_Output
#include <dos/datetime.h>          // struct DateTime
#include <clib/dos_protos.h>
#include <libraries/locale.h>
#define OLD_GRAPHICS_GFXMACROS_H
#include <graphics/gfxmacros.h>
#include <hardware/custom.h>
#include <hardware/dmabits.h>

#include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE */
#include <assert.h>

#include "saga.h"

#define CATCOMP_NUMBERS
#define CATCOMP_CODE
#define CATCOMP_BLOCK
#include "saga_strings.h"

// #define ASSERT

#define NORMAL           0
#define GOOD             1
#define BAD              2

#define TURNS           20

#define UPPER            0
#define LOWER            1

#define SCOREDISTANCE   13

#define MESSAGEY       473

#define AMSIR            0
#define EON              1
#define GEOFU            2
#define ING              3
#define OGAL             4
#define SYGIL            5

#define HAGALL           1
#define IS               2
#define JARA             3
#define NIED             4
#define WYNN             5
#define YR               6

#define KEYBOARD         0
#define COUNTRY          1
#define COUNTER          2
#define ANYKEY           3
        
// scancodes
#define SCAN_F1         80
#define SCAN_F2         81
#define SCAN_F3         82
#define SCAN_F4         83
#define SCAN_F5         84
#define SCAN_F6         85
#define HELP            95
#define FIRSTQUALIFIER  96
#define LASTQUALIFIER  103
#define KEYUP          128 /* key release */

#define BLACK            0
#define WHITE            1
#define LIGHTGREY        2
#define MEDIUMGREY       3
#define DARKGREY         4
#define GREEN            5
#define BLUE             6
#define ORANGE          86
#define PURPLE          87
#define RED             88

#define FREY             0
#define LOKI             1
#define NJORD            2
#define ODIN             3
#define THOR             4
#define TYR              5

#define ABOUTXPIXEL    312
#define ABOUTYPIXEL     76

#define MN_PROJECT       0
#define MN_HELP          1
#define IN_NEW           0
#define IN_OPEN          1
#define IN_SAVE          3
#define IN_SAVEAS        4
#define IN_QUIT          6
#define IN_GAME_SUMMARY  0
#define IN_ABOUT         2

#define TITLEBAR         "Saga 1.22"
#define VERSION          "Saga 1.22 (5.11.2002)"

MODULE void place_monsters(void);
MODULE void place_jarls(void);
MODULE FLAG recruit(SLONG recruited, SLONG recruiterhero);
MODULE void flee(SLONG routertype, SLONG router, SLONG routerhero, SLONG routedtype, SLONG routed, SLONG routedhero);
MODULE void wound(SLONG woundertype, SLONG wounder, SLONG wounderhero, SLONG woundedtype, SLONG wounded, SLONG woundedhero);
MODULE void kill(SLONG killertype, SLONG killer, SLONG killerhero, SLONG killedtype, SLONG killed, SLONG killedhero);
MODULE void dobattle(SLONG defendtype, SLONG defender, SLONG attackhero);
MODULE SLONG d6(void);
MODULE SLONG getevent(SLONG mode, SLONG* countertype);
MODULE void say(SLONG position);
MODULE void newhero(SLONG whichhero, FLAG givesord);
MODULE void showcountry(SLONG country);
MODULE void phase1(void);
MODULE void phase2(void);
MODULE void phase3(void);
MODULE void newgame(void);
MODULE void gameloop(void);
MODULE void clearkybd(void);
MODULE void titlescreen(void);
MODULE void gain(SLONG whichhero, SLONG glory, SLONG luck);
MODULE void move(SLONG whichhero);
MODULE void attack(SLONG whichhero);
MODULE void helpabout(void);
MODULE void resettime(void); 
MODULE void anykey(void);
MODULE SLONG getluck(SLONG whichhero);
MODULE FLAG loadgame(FLAG aslwindow);
MODULE void savegame(FLAG saveas);
MODULE SLONG odin_tyr(LONG whichhero, FLAG attacking);
MODULE void gods(SLONG whichhero);
MODULE void pray(SLONG whichhero);
MODULE void amiga_rout(SLONG routed, SLONG routedtype);
MODULE void human_rout(SLONG routedtype, SLONG routed, SLONG routerhero);
MODULE SLONG getmoves(SLONG countertype, SLONG whichcounter, FLAG freyfaxi);
MODULE void faxi_disappear(void);
MODULE void thor(SLONG whichhero);
MODULE void cast(SLONG caster, SLONG whichspell);
MODULE void darken(void);
MODULE SLONG checkcountry(WORD mousex, WORD mousey);
MODULE void infowindow(SLONG countertype, SLONG whichcounter);
MODULE void getdefender(SLONG attackhero, SLONG here);
MODULE FLAG needsord(SLONG countertype, SLONG counter);
MODULE void brosung(SLONG countertype, SLONG whichcounter);
MODULE void flash(SLONG country);
MODULE FLAG assess(SLONG countertype, SLONG counter);
MODULE void promote(SLONG whichhero, SLONG whichjarl);
MODULE void withdraw(SLONG whichhero);
MODULE FLAG asksord(SLONG countertype, SLONG counter, SLONG whichsord);
MODULE void asktreasure(SLONG countertype, SLONG counter, SLONG whichtreasure);
MODULE void pad(STRPTR thestring);
MODULE void print_location(SLONG whichcountry, SLONG index);
MODULE void print_sea(SLONG sea_value, SLONG index);
MODULE void print_hagall(SLONG hagall_value, SLONG index);
MODULE void print_paralyzed(SLONG paralyzed_value, SLONG index);
MODULE void print_routed(SLONG routed_value, SLONG index);
MODULE void amiga_attack(SLONG attackhero, SLONG defendtype, SLONG defender);
MODULE FLAG ask_faxi(SLONG countertype, SLONG whichcounter);
MODULE void saywho(SLONG countertype, SLONG counter, FLAG comma, FLAG lowercase);
MODULE void callforaid(SLONG passedtype, SLONG passed);
MODULE FLAG attackersleft(void);
MODULE void dospell(SLONG spell, SLONG caster);
MODULE void waitkey(void);
MODULE void summarywindow(void);
MODULE SLONG getattackers(SLONG whichhero, SLONG whichcountry);

MODULE struct
{   UBYTE red, green, blue;
} taxcolours[10 + 1] =
{   {  0,  5,  0 }, // tax  0 (unused)
    {  1,  6,  1 }, // tax  1 (unused)
    {  2,  7,  2 }, // tax  2
    {  3,  8,  3 }, // tax  3
    {  4,  9,  4 }, // tax  4
    {  5, 10,  5 }, // tax  5
    {  6, 11,  6 }, // tax  6
    {  7, 12,  7 }, // tax  7
    {  8, 13,  8 }, // tax  8
    {  9, 14,  9 }, // tax  9
    { 10, 15, 10 }  // tax 10
};

#define ABOUTLINES     3
struct
{   WORD x, y;
    TEXT text[80 + 1];
} about[ABOUTLINES + 1] =
{   {72, 27},
    {72, 35},
    {72, 51},
    {72, 59}
};

#define MENUENTRIES 12
struct NewMenu NewMenu[MENUENTRIES + 1] =
{   { NM_TITLE, "",           0 , 0, 0, 0}, //  0
    {  NM_ITEM, "",          "" , 0, 0, 0}, //  1
    {  NM_ITEM, "",          "" , 0, 0, 0}, //  2
    {  NM_ITEM, NM_BARLABEL,  0 , 0, 0, 0}, //  3
    {  NM_ITEM, "",          "" , 0, 0, 0}, //  4
    {  NM_ITEM, "",          "" , 0, 0, 0}, //  5
    {  NM_ITEM, NM_BARLABEL,  0 , 0, 0, 0}, //  6
    {  NM_ITEM, "",          "" , 0, 0, 0}, //  7
    { NM_TITLE, "",           0 , 0, 0, 0}, //  8
    {  NM_ITEM, "",          "" , 0, 0, 0}, //  9
    {  NM_ITEM, NM_BARLABEL,  0 , 0, 0, 0}, // 10
    {  NM_ITEM, "",          "?", 0, 0, 0}, // 11
    {   NM_END, NULL,         0 , 0, 0, 0}  // 12
};

// These are better to not be allocated on the stack
MODULE ULONG table1[] = {(8L << 16) + 0,
    0x00000000, 0x00000000, 0x00000000, // 0 (BLACK)
    0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, // 1 (WHITE)
    0xCCCCCCCC, 0xCCCCCCCC, 0xCCCCCCCC, // 2 (LIGHTGREY)
    0x99999999, 0x99999999, 0x99999999, // 3 (MEDIUMGREY)
    0x66666666, 0x66666666, 0x66666666, // 4 (DARKGREY)
    0x66666666, 0xFFFFFFFF, 0x66666666, // 5 (GREEN)
    0x88888888, 0x88888888, 0xFFFFFFFF, // 6 (BLUE)
    0x00000000, 0x00000000, 0x00000000, // 7
    0};
MODULE ULONG table2[] = {(54L << 16) + 74,
    0x99999999, 0x99999999, 0xFFFFFFFF, // 74
    0x99999999, 0xFFFFFFFF, 0x99999999, // 75
    0xFFFFFFFF, 0xCCCCCCCC, 0x99999999, // 76
    0xFFFFFFFF, 0x99999999, 0xFFFFFFFF, // 77
    0xFFFFFFFF, 0xFFFFFFFF, 0x99999999, // 78
    0x00000000, 0x00000000, 0x00000000, // 79
    0x00000000, 0x00000000, 0x00000000, // 80
    0x00000000, 0x00000000, 0x99999999, // 81
    0x00000000, 0x00000000, 0x00000000, // 82
    0x00000000, 0x00000000, 0x99999999, // 83
    0x00000000, 0x00000000, 0x00000000, // 84
    0x00000000, 0x00000000, 0x99999999, // 85
    0xFFFFFFFF, 0x99999999, 0x88888888, // 86 (ORANGE)
    0xFFFFFFFF, 0x88888888, 0xFFFFFFFF, // 87 (PURPLE)
    0xFFFFFFFF, 0x55555555, 0x55555555, // 88 (RED)
    0x00000000, 0x00000000, 0x00000000, // 89
    0x00000000, 0x00000000, 0x00000000, // 90
    0x00000000, 0x00000000, 0x00000000, // 91
    0x00000000, 0x00000000, 0x00000000, // 92
    0x00000000, 0x00000000, 0xFFFFFFFF, // 93
    0x10101010, 0x14141414, 0xFFFFFFFF, // 94
    0x1F1F1F1F, 0x23232323, 0xFFFFFFFF, // 95
    0x2E2E2E2E, 0x32323232, 0xFFFFFFFF, // 96
    0x3D3D3D3D, 0x41414141, 0xFFFFFFFF, // 97
    0x4C4C4C4C, 0x4F4F4F4F, 0xFFFFFFFF, // 98
    0x5B5B5B5B, 0x5E5E5E5E, 0xFFFFFFFF, // 99
    0x6A6A6A6A, 0x6D6D6D6D, 0xFFFFFFFF, // 100
    0x79797979, 0x7C7C7C7C, 0xFFFFFFFF, // 101
    0x87878787, 0x89898989, 0xFFFFFFFF, // 102
    0x96969696, 0x98989898, 0xFFFFFFFF, // 103
    0xA5A5A5A5, 0xA7A7A7A7, 0xFFFFFFFF, // 104
    0xB4B4B4B4, 0xB6B6B6B6, 0xFFFFFFFF, // 105
    0xC3C3C3C3, 0xC4C4C4C4, 0xFFFFFFFF, // 106
    0xD2D2D2D2, 0xD3D3D3D3, 0xFFFFFFFF, // 107
    0xE1E1E1E1, 0xE2E2E2E2, 0xFFFFFFFF, // 108
    0xF0F0F0F0, 0xF1F1F1F1, 0xFFFFFFFF, // 109
    0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, // 110
    0x00000000, 0x00000000, 0xFFFFFFFF, // 111
    0x00000000, 0x88888888, 0xFFFFFFFF, // 112
    0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, // 113
    0x00000000, 0xFFFFFFFF, 0x88888888, // 114
    0x00000000, 0xFFFFFFFF, 0x00000000, // 115
    0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, // 116
    0xFFFFFFFF, 0xDDDDDDDD, 0x00000000, // 117
    0xFFFFFFFF, 0xC5C5C5C5, 0x00000000, // 118
    0xFFFFFFFF, 0xA7A7A7A7, 0x00000000, // 119
    0xFFFFFFFF, 0x89898989, 0x00000000, // 120
    0xFFFFFFFF, 0x72727272, 0x00000000, // 121
    0xFFFFFFFF, 0x54545454, 0x00000000, // 122
    0xFFFFFFFF, 0x36363636, 0x00000000, // 123
    0xFFFFFFFF, 0x1E1E1E1E, 0x00000000, // 124
    0xFFFFFFFF, 0x00000000, 0x00000000, // 125
    0x00000000, 0x00000000, 0x00000000, // 126
    0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, // 127
    0};

MODULE struct NewGadget SpeedGadget =
{   300, 312,
    128, 13,
    "",
    NULL,
    NULL,
    NULL,
    NULL,
    NULL
}, CycleGadget[HEROES + 1] = {
{   300, 200,
    128, 13,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL
},
{   300, 216,
    128, 13,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL
},
{   300, 232,
    128, 13,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL
},
{   300, 248,
    128, 13,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL
},
{   300, 264,
    128, 13,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL
},
{   300, 280,
    128, 13,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL
}
};

#define HERO_STRENGTH 5
#define HERO_MOVES    4

#define RUNES         5

SLONG cycleheropos[HEROES + 1] =
{   2,
    3,
    5,
    3,
    0,
    3
};

MODULE struct
{   UBYTE red, green, blue;
} herocolour[HEROES + 1] =
{ { 15,  12,   6}, // orange
  { 15,   6,   6}, // red
  { 15,  15,   3}, // yellow
  {  6,  15,  15}, // cyan
  { 10,  10,  15}, // light blue
  { 15,   6,  15}  // purple
};
STRPTR trueheroname[HEROES + 1] =
{   "Beowulf",
    "Brunhild",
    "Egil",
    "Ragnar",
    "Siegfried",
    "Starkad"
}, cycleheroname[HEROES + 1] =
{   "  Beowulf:",
    " Brunhild:",
    "     Egil:",
    "   Ragnar:",
    "Siegfried:",
    "  Starkad:"
}, runename[RUNES + 1] =
{   "Amsir",
    "Eon",
    "Geofu",
    "Ing",
    "Ogal",
    "Sygil",
};

AGLOBAL struct JarlStruct jarl[JARLS + 1] =
{ { 2, 3, "Amleth"    },
  { 3, 3, "Bjarki"    },
  { 3, 3, "Erik"      },
  { 2, 2, "Eyjolf"    },
  { 2, 2, "Gretter"   },
  { 2, 2, "Hagen"     },
  { 2, 3, "Harald"    },
  { 2, 3, "Helgi"     },
  { 2, 2, "Hengist"   },
  { 2, 2, "Horsi"     },
  { 4, 2, "Hrolfwulf" },
  { 4, 2, "Ivar"      },
  { 4, 3, "Kari"      },
  { 2, 3, "Skallagrim"},
  { 3, 3, "Thorolf"   },
  { 2, 3, "Thorvald"  },
  { 3, 3, "Welland"   },
  { 3, 3, "Wiglar"    }
};

#define BEOWULF         0
#define BRUNHILD        1
#define EGIL            2
#define RAGNAR          3
#define SIEGFRIED       4
#define STARKAD         5
AGLOBAL struct HeroStruct hero[HEROES + 1];

#define BALMUNG         0
#define DRAGVENDILL     1
#define GRAM            2
#define HRUNTING        3
#define LOVI            4
#define TYRFING         5
struct SordStruct sord[SORDS + 1] =
{ { "Balmung (+1)"    },
  { "Dragvendill (+2)"},
  { "Gram (+2)"       },
  { "Hrunting (+1)"   },
  { "Lovi (+1)"       },
  { "Tyrfing (+2)"    }
};

#define BROSUNGNECKLACE 0
#define FREYFAXI        1
#define MAGICSHIRT      2
#define MAILCOAT        3
struct TreasureStruct treasure[TREASURES + 1] =
{ {""         },
  {"Frey Faxi"},
  {""         },
  {""         }
};

#define DRAGON 0
#define DROW   1
#define GIANT  2
#define GHOST  3
#define TROLL  4
#define WITCH  5
AGLOBAL struct MonsterStruct monster[MONSTERS + 1] =
{ { DRAGON, 10, 1, "Aludreng" },
  { DRAGON, 11, 2, "Fafnir"   },
  { DRAGON, 10, 2, "Glerion"  },
  { DRAGON, 10, 2, "Hallbjorn"},
  { DRAGON,  9, 3, "Istvan"   },
  { DRAGON, 11, 2, "Stigandi" },
  { DROW,    2, 2, "Atli"     },
  { DROW,    3, 1, "Gizur"    },
  { DROW,    3, 1, "Hallgerd" },
  { GHOST,   4, 2, "Gizar"    },
  { GHOST,   4, 1, "Glam"     },
  { GHOST,   4, 0, "Gunnar"   },
  { GHOST,   4, 0, "Hrap"     },
  { GHOST,   4, 1, "Mord"     },
  { GHOST,   4, 1, "Trogrier" },
  { GIANT,   7, 0, "Angantyr" },
  { GIANT,   6, 1, "Hall"     },
  { GIANT,   8, 1, "Storvick" },
  { TROLL,   6, 2, "Grendall" },
  { TROLL,   5, 2, "Hallbjorn"},
  { TROLL,   5, 1, "Hauk"     },
  { TROLL,   6, 1, "Hogshead" },
  { TROLL,   5, 3, "Onund"    },
  { TROLL,   5, 2, "Svinafell"},
  { WITCH,   3, 4, "Gerdrak"  },
  { WITCH,   3, 5, "Grunhild" },
  { WITCH,   4, 4, "Hedin"    }
};

/* These are the statistical distribution of the taxation factors:
    4x  2 tax
   10x  3 tax
    3x  4 tax
    3x  5 tax
    6x  6 tax
    4x  7 tax
    1x  8 tax
    2x  9 tax
    3x 10 tax */

#define LAND      0
#define SEA       1
#define ISLE      2
#define PENINSULA 3
AGLOBAL struct WorldStruct world[36 + 30] =
{   {590,  39,  3, LAND,      "Finmark"  ,       1, -1, -1, -1, -1, -1, -1, -1}, // 1:1 ( 0) (inland)
    {584, 104,  3, LAND,      "Trondheim",       0,  2,  3, 60, -1, -1, -1, -1}, // 1:2 ( 1)
    {489, 102,  6, LAND,      "Mordaland",       1,  3,  4, 55, 59, 60, -1, -1}, // 1:3 ( 2)
    {573, 173,  2, LAND,      "Upland",          1,  2,  4,  5,  6, -1, -1, -1}, // 1:4 ( 3) (inland)
    {451, 176,  5, LAND,      "Agdar",           2,  3,  5, 48, 49, 54, 55, -1}, // 1:5 ( 4)
    {514, 201,  3, LAND,      "Romeirt",         3,  4,  6,  7, 47, 48, -1, -1}, // 1:6 ( 5)
    {569, 233,  7, LAND,      "Jamtland",        3,  5,  7,  8, 65, -1, -1, -1}, // 2:1 ( 6)
    {512, 262,  6, LAND,      "Vester Gotland",  5,  6,  8,  9, 47, -1, -1, -1}, // 2:2 ( 7)
    {549, 305,  7, LAND,      "Oster Gotland",   6,  7,  9, 63, 65, -1, -1, -1}, // 2:3 ( 8)
    {502, 323,  4, LAND,      "Suder Gotland",   7,  8, 11, 47, 63, -1, -1, -1}, // 2:4 ( 9)
    {420, 287,  6, LAND,      "Juteland",       11, 14, 46, 47, 48, 49, -1, -1}, // 2:5 (10)
    {441, 344,  3, ISLE,      "Scandia",         9, 10, 12, 13, 14, 47, 63, -1}, // 2:6 (11)
    {522, 442,  4, LAND,      "Pomerania",      11, 13, 63, 64, -1, -1, -1, -1}, // 3:1 (12)
    {393, 421,  6, LAND,      "Saxony",         11, 12, 14, 15, 16, 46, -1, -1}, // 3:2 (13)
    {392, 372,  7, LAND,      "Anglia",         10, 11, 13, 46, -1, -1, -1, -1}, // 3:3 (14)
    {305, 383,  7, LAND,      "Fenland",        13, 16, 17, 44, 45, 46, -1, -1}, // 3:4 (15)
    {305, 434, 10, LAND,      "Rhineland",      13, 15, 17, -1, -1, -1, -1, -1}, // 3:5 (16) (inland)
    {242, 428,  9, LAND,      "Frisia",         15, 16, 18, 44, -1, -1, -1, -1}, // 3:6 (17)
    {175, 438,  3, LAND,      "Frankland",      17, 19, 43, 44, -1, -1, -1, -1}, // 4:1 (18)
    { 97, 439, 10, LAND,      "Armorica",       18, 42, 43, -1, -1, -1, -1, -1}, // 4:2 (19)
    { 75, 318,  2, LAND,      "Cornwall",       21, 42, 43, -1, -1, -1, -1, -1}, // 4:3 (20)
    {109, 333, 10, LAND,      "Wessex",         20, 22, 23, 24, 25, 42, 43, -1}, // 4:4 (21)
    {153, 354,  9, LAND,      "Sussex",         21, 23, 24, 43, 44, -1, -1, -1}, // 4:5 (22)
    {190, 329,  6, LAND,      "East Anglia",    22, 24, 44, 45, -1, -1, -1, -1}, // 4:6 (23)
    {148, 313,  3, LAND,      "Mercia",         21, 22, 23, 25, 26, 27, 45, 51}, // 5:1 (24)
    {108, 287,  3, LAND,      "Daffyd",         21, 24, 26, 41, 42, -1, -1, -1}, // 5:2 (25)
    {145, 268,  2, LAND,      "Gwynedd",        24, 25, 27, 41, -1, -1, -1, -1}, // 5:3 (26)
    {186, 217,  8, LAND,      "Northumberland", 24, 26, 28, 41, 51, 52, -1, -1}, // 5:4 (27)
    {178, 157,  3, LAND,      "Dalriada",       27, 29, 30, 40, 41, 52, -1, -1}, // 5:5 (28)
    {222, 130,  5, LAND,      "Caledonia",      28, 30, 52, 57, -1, -1, -1, -1}, // 5:6 (29)
    {230,  85,  2, PENINSULA, "Pictland",       28, 29, 31, 40, 57, 58, 61, 62}, // 6:1 (30)
    {167,  66,  3, ISLE,      "Hebrides",       30, 36, 39, 40, 62, -1, -1, -1}, // 6:2 (31)
    { 62,  40,  3, LAND,      "Thule",          36, 37, -1, -1, -1, -1, -1, -1}, // 6:3 (32)
    { 54, 162,  5, LAND,      "Connacht",       34, 35, 38, 39, -1, -1, -1, -1}, // 6:4 (33)
    {109, 162,  4, LAND,      "Ulster",         33, 35, 39, 40, 41, -1, -1, -1}, // 6:5 (34)
    { 60, 203,  6, LAND,      "Leinster",       33, 34, 41, -1, -1, -1, -1, -1}, // 6:6 (35)
    {134,  32,  0, SEA,       "",               31, 32, 37, 39, -1, -1, -1, -1}, //     (36)
    { 52,  94,  0, SEA,       "",               32, 36, 38, 39, -1, -1, -1, -1}, //     (37)
    { 53, 130,  0, SEA,       "",               33, 37, 39, -1, -1, -1, -1, -1}, //     (38)
    { 82, 118,  0, SEA,       "",               31, 33, 34, 36, 37, 38, 40, -1}, //     (39)
    {137, 165,  0, SEA,       "",               28, 30, 31, 34, 39, 41, -1, -1}, //     (40)
    {116, 225,  0, SEA,       "",               25, 26, 27, 28, 34, 35, 40, 42}, //     (41)
    { 57, 292,  0, SEA,       "",               19, 20, 21, 25, 41, 43, -1, -1}, //     (42)
    {127, 389,  0, SEA,       "",               18, 19, 20, 21, 22, 42, 44, -1}, //     (43)
    {217, 370,  0, SEA,       "",               15, 17, 18, 22, 23, 43, 45, -1}, //     (44)
    {261, 328,  0, SEA,       "",               15, 23, 24, 44, 46, 50, 51, -1}, //     (45)
    {343, 334,  0, SEA,       "",               10, 13, 14, 15, 45, 49, 50, -1}, //     (46)
    {467, 282,  0, SEA,       "Kategatt",        5,  7,  9, 10, 11, 48, -1, -1}, //     (47)
    {445, 229,  0, SEA,       "Skagerrak",       4,  5, 10, 47, 49, -1, -1, -1}, //     (48)
    {376, 270,  0, SEA,       "",                4, 10, 48, 46, 50, 54, -1, -1}, //     (49)
    {311, 268,  0, SEA,       "",               45, 46, 49, 51, 53, 54, -1, -1}, //     (50) (deep waters)
    {240, 258,  0, SEA,       "",               24, 27, 45, 50, 52, 53, -1, -1}, //     (51)
    {248, 193,  0, SEA,       "",               27, 28, 29, 51, 53, 56, 57, -1}, //     (52)
    {324, 196,  0, SEA,       "",               50, 51, 52, 54, 55, 56, -1, -1}, //     (53) (deep waters)
    {379, 186,  0, SEA,       "",                4, 49, 50, 53, 55, -1, -1, -1}, //     (54)
    {386, 124,  0, SEA,       "",                2,  4, 53, 54, 56, 58, 59, -1}, //     (55)
    {318, 134,  0, SEA,       "",               52, 53, 55, 57, 58, -1, -1, -1}, //     (56) (deep waters)
    {267, 133,  0, SEA,       "",               29, 30, 52, 56, 58, -1, -1, -1}, //     (57)
    {338,  90,  0, SEA,       "",               30, 55, 56, 57, 59, 60, 61, -1}, //     (58)
    {427,  73,  0, SEA,       "",                2, 55, 58, 60, -1, -1, -1, -1}, //     (59)
    {456,  27,  0, SEA,       "",                1,  2, 58, 59, 61, -1, -1, -1}, //     (60)
    {341,  47,  0, SEA,       "",               30, 58, 60, 62, -1, -1, -1, -1}, //     (61)
    {257,  44,  0, SEA,       "",               30, 31, 61, -1, -1, -1, -1, -1}, //     (62)
    {509, 385,  0, SEA,       "",                8,  9, 11, 12, 64, 65, -1, -1}, //     (63)
    {587, 404,  0, SEA,       "",               12, 63, 65, -1, -1, -1, -1, -1}, //     (64)
    {587, 345,  0, SEA,       "",                6,  8, 63, 64, -1, -1, -1, -1}  //     (65)
};

#define NONE  0
#define HUMAN 1
#define AMIGA 2

#define MAXLINES 45
#define LEFTSIDE  0
#define RIGHTSIDE 1

IMPORT  struct ExecBase*      SysBase;
IMPORT  struct Custom         custom;

AGLOBAL struct GfxBase*       GfxBase       = NULL;
AGLOBAL struct GadToolsBase*  GadToolsBase  = NULL;
AGLOBAL struct IntuitionBase* IntuitionBase = NULL;
AGLOBAL struct LocaleBase*    LocaleBase    = NULL;
AGLOBAL struct Library*       TimerBase     = NULL;
AGLOBAL struct ASLBase*       ASLBase       = NULL;

AGLOBAL struct Window        *MainWindowPtr = NULL,
                             *HelpWindowPtr = NULL,
                             *InfoWindowPtr = NULL;
AGLOBAL UWORD                 DisplayDepth  = DEPTH;
AGLOBAL struct Screen*        ScreenPtr     = NULL;

MODULE  WORD                  speed         = 4;
MODULE  UBYTE                 IOBuffer[600];
MODULE  ULONG                 DisplayID     = HIRES_KEY | PAL_MONITOR_ID | LACE,
                              DisplayWidth  = SCREENXPIXEL,
                              DisplayHeight = SCREENYPIXEL;
MODULE  struct RDArgs*        ArgsPtr       = NULL;
MODULE  struct FileRequester* ASLRqPtr      = NULL;
MODULE  struct Process*       ProcessPtr    = NULL;
MODULE  struct Menu*          MenuPtr       = NULL;
MODULE  struct VisualInfo*    VisualInfoPtr = NULL;
MODULE  APTR                  OldWindowPtr  = NULL;
MODULE  FLAG                  gameover,
                              loaded,
                              cliload                    = FALSE;
MODULE  SLONG                 faxirides,
                              tickwait                   = 7, // measured in intuiticks (10ths of a second)
                              turn,
                              order[HEROES + 1];
MODULE  TEXT                  abouttitle[80 + 1],
                              saystring[256 + 1],
                              numberstring[13 + 1],
                              titlestring[80 + 1],
                              pathname[256 + 1],
                              line[2][MAXLINES + 1][80 + 1];
MODULE  struct Gadget        *SpeedGadgetPtr             = NULL,
                             *CycleGadgetPtr[HEROES + 1] = {NULL, NULL, NULL, NULL, NULL, NULL},
                             *GListPtr                   = NULL,
                             *PrevGadgetPtr              = NULL;
MODULE  struct LocaleInfo     li;
MODULE  STRPTR                CycleOptions[4],
                              monstertypes[6],
                              runedesc[RUNES + 1];

#define ONEKEY_YES           0
#define ONEKEY_NO            1
#define ONEKEY_WITHDRAW      2
#define ONEKEY_RESTART       3
#define ONEKEY_TRANSFER      4
#define ONEKEY_GLORY         5
#define ONEKEY_LUCK          6
#define ONEKEYS              ONEKEY_LUCK

TEXT onekey[ONEKEYS + 1] =
{   'Y', 'N', 'W', 'R', 'T', 'G', 'L'
};

MODULE void place_monsters(void)
{   /* .taken = FALSE: the monster is in the "pile of monsters" (spare).
                TRUE : the monster is either on the board or dead. */

    SLONG whichhero, whichmonster, whichtreasure;
    FLAG  available, ok;

    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   if (hero[whichhero].alive)
        {   available = FALSE;
            for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
            {   if (!monster[whichmonster].taken)
                {   available = TRUE;
                    break;
            }   }
            if (available)
            {   do
                {   whichmonster = rand() % (MONSTERS + 1);
                } while (monster[whichmonster].taken);
                monster[whichmonster].taken    =
                monster[whichmonster].alive    = TRUE;
                monster[whichmonster].where    = rand() % 36;
                monster[whichmonster].sea      = NORMAL;
                monster[whichmonster].hagall   = FALSE;

                if (monster[whichmonster].species == DRAGON)
                {   ok = FALSE;
                    for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
                    {   if (!treasure[whichtreasure].taken)
                        {   ok = TRUE; // at least one treasure is available
                            break; // for speed
                    }   }
                    if (ok)
                    {   do
                        {   whichtreasure = rand() % (TREASURES + 1);
                        } while (treasure[whichtreasure].taken);
                        treasure[whichtreasure].taken         = TRUE;
                        treasure[whichtreasure].possessortype = MONSTER;
                        treasure[whichtreasure].possessor     = whichmonster;
                        treasure[whichtreasure].where         = -1;

                        monster[whichmonster].wealth = 0;
                    } else
                    {   monster[whichmonster].wealth = 20;
                }   }
                else
                {   monster[whichmonster].wealth = 0;
                }
                // we don't unslot newborn counters
                move_monster(whichmonster, FALSE);
}   }   }   }

MODULE void place_jarls(void)
{   FLAG  available;
    SLONG whichhero, whichjarl;

    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   if (hero[whichhero].alive)
        {   available = FALSE;
            for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
            {   if (!jarl[whichjarl].taken)
                {   available = TRUE;
                    break;
            }   }
            if (available)
            {   do
                {   whichjarl = rand() % (JARLS + 1);
                } while (jarl[whichjarl].taken);
                jarl[whichjarl].taken     =
                jarl[whichjarl].alive     = TRUE;
                jarl[whichjarl].wealth    = 0;
                jarl[whichjarl].where     =
                jarl[whichjarl].homewhere = rand() % 36;
                jarl[whichjarl].hero      = -1;
                jarl[whichjarl].sea       = NORMAL;
                jarl[whichjarl].hagall    =
                jarl[whichjarl].loseturn  = FALSE;
                hidejarl(whichjarl, FALSE);
                // we don't unslot newborn counters
                move_jarl(whichjarl, FALSE);
}   }   }   }

int main(int argc, char** argv)
{   struct TextAttr             Topaz8 =
    {   (STRPTR) "topaz.font", 8, FS_NORMAL, FPF_ROMFONT | FPF_DESIGNED
    };
    struct DateTime             DateTime;
    struct ScreenModeRequester* smr;
    BPTR                        FileHandle /* = NULL */ ;
    FLAG                        ok;
    TEXT                        datestring[LEN_DATSTRING],
                                weekdaystring[LEN_DATSTRING],
                                tempstring[1 + 1],
                                smrstring[80 + 1],
                                supergels[2];
    SLONG                       whichcountry, whichhero,
                                args[7] = {0L, 0L, 0L, 0L, 0L, 0L, 0L};
    UWORD                       Pens[13] =
    {   BLACK,     /* DETAILPEN            text in title bar */
        WHITE,     /* BLOCKPEN             fill title bar */
        WHITE,     /* TEXTPEN              regular text on BACKGROUNDPEN (was BLACK) */
        LIGHTGREY, /* SHINEPEN             bright edge */
        DARKGREY,  /* SHADOWPEN            dark edge */
        BLUE,      /* FILLPEN              filling active window borders
                                           and selected gadgets */
        BLACK,     /* FILLTEXTPEN          text rendered over FILLPEN */
        BLACK,     /* BACKGROUNDPEN        background colour (was BLUE) */
        ORANGE,    /* HIGHLIGHTTEXTPEN     highlighted text on BACKGROUNDPEN
                                           and used against BLOCKPEN in ASL
                                           save requesters */
        BLACK,     /* BARDETAILPEN         text/detail in screen-bar/menus */
        WHITE,     /* BARBLOCKPEN          screen-bar/menus fill */
        BLACK,     /* BARTRIMPEN           trim under screen-bar */
        (UWORD) ~0 /* and used against BLOCKPEN in ASL save requesters */
    };

/* Colour allocations are as follows:
    colours 0-6 are used by the game itself.
    colour 7 is the black of the map.
    colours 8-43 are map land colours, except that
    colours 17-19 are mouse pointer colours.
    colours 44-73 are map sea colours.
    colour 74 is hero counter colour (blue).
    colour 75 is jarl counter colour (green).
    colour 76 is monster counter colour (orange).
    colour 77 is treasure counter colour (purple).
    colour 78 is sword counter colour (yellow).
    colour 79 is the black of the counters.
    colour 80 is Scandian coastline.
    colour 81 is Scandian sea.
    colour 82 is Pictish coastline.
    colour 83 is Pictish sea.
    colour 84 is Hebridean coastline.
    colour 85 is Hebridean sea.
    colours 86-88 are used by the game itself.
    colour 89 is Suder Gotland land (replacement for colour 17).
    colour 90 is Juteland land (replacement for colour 18).
    colour 91 is Scandian land (replacement for colour 19).
    colours 92-110 are used for the Saga logo.
    colours 111-125 (and others) are used for the Amigan Software logo.
    colour 126 is selected menu text.
    colour 127 is selected menu background.

    Start of program.

    version embedding into executable */
    if (0) /* that is, never */
    {   Printf("%s\n", VERSION);
    }

    // before the first possible point of failure
    init_counters();
    for (whichcountry = 0; whichcountry <= 65; whichcountry++)
    {   world[whichcountry].hero = -1;
    }
    pathname[0] = 0;

    if (!(IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 39L)))
    {   strcpy(saystring, "Saga: Can't open intuition.library V39+!)\n");
        Write(Output(), saystring, strlen(saystring));
        cleanexit(EXIT_FAILURE);
    }

    ProcessPtr = (struct Process *) FindTask(NULL);

    if (SysBase->LibNode.lib_Version < 36L)
    {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open exec.library V36+!\0", 24);
	cleanexit(EXIT_FAILURE);
    }

    // From this point onwards, we can be sure we have Kickstart 2.0+...

    if (GetVar("cybergfx/supergels", supergels, 2, NULL) == 1)
    {   if (supergels[0] == '1')
        {   Printf("Saga: ENV:cybergfx/supergels must be cleared to 0 before playing!\n");
            cleanexit(EXIT_FAILURE);
    }   }

    /* NOTES FOR TRANSLATORS:
      MSG_CHAR_FOO messages are single-character strings which are the
    first letter of the relevant word. MSG_UNCHAR_FOO messages are the
    rest of the word. Eg. in English, MSG_CHAR_GLORY is "G" and
    MSG_UNCHAR_GLORY is "lory". They must each be different among their
    'set' (yes/no, glory/luck, restart/transfer/withdraw). */

    li.li_Catalog = NULL;
    if (LocaleBase = OpenLibrary("locale.library", 38))
    {   li.li_LocaleBase   = LocaleBase;
        li.li_Catalog      = OpenCatalog(NULL, "Saga.catalog", TAG_DONE);
    }
    strcpy(tempstring, GetCatalogStr(li.li_Catalog, MSG_CHAR_YES,      "Y"));
    onekey[ONEKEY_YES]      = tempstring[0];
    strcpy(tempstring, GetCatalogStr(li.li_Catalog, MSG_CHAR_NO,       "N"));
    onekey[ONEKEY_NO]       = tempstring[0];
    strcpy(tempstring, GetCatalogStr(li.li_Catalog, MSG_CHAR_WITHDRAW, "W"));
    onekey[ONEKEY_WITHDRAW] = tempstring[0];
    strcpy(tempstring, GetCatalogStr(li.li_Catalog, MSG_CHAR_RESTART,  "R"));
    onekey[ONEKEY_RESTART]  = tempstring[0];
    strcpy(tempstring, GetCatalogStr(li.li_Catalog, MSG_CHAR_TRANSFER, "T"));
    onekey[ONEKEY_TRANSFER] = tempstring[0];
    strcpy(tempstring, GetCatalogStr(li.li_Catalog, MSG_CHAR_GLORY,    "G"));
    onekey[ONEKEY_GLORY]    = tempstring[0];
    strcpy(tempstring, GetCatalogStr(li.li_Catalog, MSG_CHAR_LUCK,     "L"));
    onekey[ONEKEY_LUCK]     = tempstring[0];
    CycleOptions[0] = GetCatalogStr(li.li_Catalog, MSG_GADGET_NONE, "None");
    CycleOptions[1] = GetCatalogStr(li.li_Catalog, MSG_HUMAN, "Human");
    CycleOptions[2] = "Amiga";
    CycleOptions[3] = NULL;
    strcpy(abouttitle, GetCatalogStr(li.li_Catalog, MSG_ABOUT, "About"));
    strcat(abouttitle, " Saga");
    strcpy(about[0].text, TITLEBAR);
    about[1].text[0] = 0;
    DateTime.dat_Format          = FORMAT_DOS;
    DateTime.dat_Flags           = NULL;
    DateTime.dat_StrDate         = "5-Nov-02";
    DateTime.dat_StrDay          = NULL;
    DateTime.dat_StrTime         = NULL;
    DateTime.dat_Stamp.ds_Minute = 0;
    DateTime.dat_Stamp.ds_Tick   = 0;
    if (StrToDate(&DateTime))
    {   // DateTime.dat_Stamp is now filled
        DateTime.dat_Format  = FORMAT_DEF;
        DateTime.dat_Flags   = NULL;
        DateTime.dat_StrDate = datestring;
        DateTime.dat_StrDay  = weekdaystring;
        DateTime.dat_StrTime = NULL;
        if (DateToStr(&DateTime))
        {   strcpy(about[1].text, weekdaystring);
            strcat(about[1].text, " ");
            strcat(about[1].text, datestring);
    }   }
    strcpy(about[2].text, "© 2002 Amigan Software");
    strcpy(about[3].text, GetCatalogStr(li.li_Catalog, MSG_BY, "By"));
    strcat(about[3].text, " James R. Jacobs");
    monstertypes[0] = GetCatalogStr(li.li_Catalog, MSG_DRAGON, "Dragon");
    monstertypes[1] = GetCatalogStr(li.li_Catalog, MSG_DROW  , "Drow"  );
    monstertypes[2] = GetCatalogStr(li.li_Catalog, MSG_GIANT , "Giant" );
    monstertypes[3] = GetCatalogStr(li.li_Catalog, MSG_GHOST , "Ghost" );
    monstertypes[4] = GetCatalogStr(li.li_Catalog, MSG_TROLL , "Troll" );
    monstertypes[5] = GetCatalogStr(li.li_Catalog, MSG_WITCH , "Witch" );
    runedesc[0] = GetCatalogStr(li.li_Catalog, MSG_THE_GODS, "rune of the gods");
    runedesc[1] = GetCatalogStr(li.li_Catalog, MSG_TIME    , "rune of time"    );
    runedesc[2] = GetCatalogStr(li.li_Catalog, MSG_PROPERTY, "rune of property");
    runedesc[3] = GetCatalogStr(li.li_Catalog, MSG_HEALING , "rune of healing" );
    runedesc[4] = GetCatalogStr(li.li_Catalog, MSG_FURY    , "rune of fury"    );
    runedesc[5] = GetCatalogStr(li.li_Catalog, MSG_THE_SUN , "rune of the sun" );
    for (whichcountry = 36; whichcountry <= 39; whichcountry++)
    {   world[whichcountry].name = GetCatalogStr(li.li_Catalog, MSG_ATLANTIC_OCEAN , "Atlantic Ocean" );
    }
    for (whichcountry = 40; whichcountry <= 42; whichcountry++)
    {   world[whichcountry].name = GetCatalogStr(li.li_Catalog, MSG_IRISH_SEA      , "Irish Sea"      );
    }
    for (whichcountry = 43; whichcountry <= 44; whichcountry++)
    {   world[whichcountry].name = GetCatalogStr(li.li_Catalog, MSG_ENGLISH_CHANNEL, "English Channel");
    }
    for (whichcountry = 45; whichcountry <= 62; whichcountry++)
    {   if (whichcountry < 47 || whichcountry > 48)
        {   world[whichcountry].name = GetCatalogStr(li.li_Catalog, MSG_NORTH_SEA  , "North Sea"      );
    }   }
    for (whichcountry = 63; whichcountry <= 65; whichcountry++)
    {   world[whichcountry].name = GetCatalogStr(li.li_Catalog, MSG_BALTIC_SEA     , "Baltic Sea"     );
    }
    treasure[BROSUNGNECKLACE].name = GetCatalogStr(li.li_Catalog, MSG_BROSUNG_NECKLACE, "Brosung Necklace");
    treasure[MAGICSHIRT].name      = GetCatalogStr(li.li_Catalog, MSG_MAGIC_SHIRT     , "Magic Shirt"     );
    treasure[MAILCOAT].name        = GetCatalogStr(li.li_Catalog, MSG_MAIL_COAT       , "Mail Coat"       );
    NewMenu[0].nm_Label   = GetCatalogStr(li.li_Catalog, MSG_PROJECT         , "Project"   );
    NewMenu[1].nm_Label   = GetCatalogStr(li.li_Catalog, MSG_NEW             , "New"       );
    NewMenu[1].nm_CommKey = GetCatalogStr(li.li_Catalog, MSG_SHORTCUT_NEW    , "N"         );
    NewMenu[2].nm_Label   = GetCatalogStr(li.li_Catalog, MSG_OPEN            , "Open..."   );
    NewMenu[2].nm_CommKey = GetCatalogStr(li.li_Catalog, MSG_SHORTCUT_OPEN   , "O"         );
    NewMenu[4].nm_Label   = GetCatalogStr(li.li_Catalog, MSG_SAVE            , "Save"      );
    NewMenu[4].nm_CommKey = GetCatalogStr(li.li_Catalog, MSG_SHORTCUT_SAVE   , "S"         );
    NewMenu[5].nm_Label   = GetCatalogStr(li.li_Catalog, MSG_SAVE_AS         , "Save As...");
    NewMenu[5].nm_CommKey = GetCatalogStr(li.li_Catalog, MSG_SHORTCUT_SAVE_AS, "A"         );
    NewMenu[7].nm_Label   = GetCatalogStr(li.li_Catalog, MSG_QUIT            , "Quit"      );
    NewMenu[7].nm_CommKey = GetCatalogStr(li.li_Catalog, MSG_SHORTCUT_QUIT   , "Q"         );
    NewMenu[8].nm_Label   = GetCatalogStr(li.li_Catalog, MSG_HELP            , "Help"      );
    NewMenu[9].nm_Label   = GetCatalogStr(li.li_Catalog, MSG_GAME_SUMMARY2   , "Game Summary...");
    NewMenu[9].nm_CommKey = GetCatalogStr(li.li_Catalog, MSG_SHORTCUT_GAME_SUMMARY, "G"    );
    NewMenu[11].nm_Label  = GetCatalogStr(li.li_Catalog, MSG_ABOUT2          , "About..."       );
    SpeedGadget.ng_GadgetText = GetCatalogStr(li.li_Catalog, MSG_MESSAGE_DELAY,"Message Delay:" );

    // we run in English if there is a locale problem

    resettime();

    if (!(GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 39L)))
    {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open graphics.library V39+!\0", 24);
	cleanexit(EXIT_FAILURE);
    }
    if (!(GadToolsBase = (struct GfxBase *) OpenLibrary("gadtools.library", 0L)))
    {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open gadtools.library!\0", 24);
	cleanexit(EXIT_FAILURE);
    }
    if (!(ASLBase = (struct ASLBase *) OpenLibrary("asl.library", 38L)))
    {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open ASL.library V38+!\0", 24);
	cleanexit(EXIT_FAILURE);
    }

    hero[BEOWULF  ].control = HUMAN;
    hero[BRUNHILD ].control = NONE;
    hero[EGIL     ].control = NONE;
    hero[RAGNAR   ].control = AMIGA;
    hero[SIEGFRIED].control = NONE;
    hero[STARKAD  ].control = NONE;

    ok = FALSE;
    if (FileHandle = Open("PROGDIR:Saga.config", MODE_OLDFILE))
    {   if (Read(FileHandle, IOBuffer, 21) == 21)
        {   ok = TRUE;
            for (whichhero = 0; whichhero <= HEROES; whichhero++)
            {   hero[whichhero].control = (SLONG) ((SBYTE) IOBuffer[whichhero]);
            }
            DisplayID     = (ULONG) (  (IOBuffer[ 6] * 16777216)
                                     + (IOBuffer[ 7] *    65536)
                                     + (IOBuffer[ 8] *      256)
                                     +  IOBuffer[ 9]            );
            DisplayWidth  = (ULONG) (  (IOBuffer[10] * 16777216)
                                     + (IOBuffer[11] *    65536)
                                     + (IOBuffer[12] *      256)
                                     +  IOBuffer[13]            );
            DisplayHeight = (ULONG) (  (IOBuffer[14] * 16777216)
                                     + (IOBuffer[15] *    65536)
                                     + (IOBuffer[16] *      256)
                                     +  IOBuffer[17]            );
            DisplayDepth  = (UWORD) (  (IOBuffer[18] *      256)
                                     +  IOBuffer[19]            );
            speed =         (WORD)      IOBuffer[20];
        }
        Close(FileHandle);
        // FileHandle = NULL;
    }

    /* argument parsing */

    if (argc) /* started from CLI */
    {   if (!(ArgsPtr = ReadArgs
        (   "FILE",
            (LONG *) args,
            NULL
        )))
        {   strcpy(smrstring, GetCatalogStr(li.li_Catalog, MSG_USAGE, "Usage"));
            strcat(smrstring, ": %s [[FILE=]<savedgame>]\n");
            Printf(smrstring, argv[0]);
            cleanexit(EXIT_FAILURE);
        }
        if (args[0])
        {   strcpy(pathname, args[0]);
            cliload = TRUE;
    }   }

    strcpy(smrstring, "Saga: ");
    strcat(smrstring, GetCatalogStr(li.li_Catalog, MSG_S_M_R, "Screen Mode Requester"));

    if (!ok)
    {   if (!(smr = (struct ScreenModeRequester *) AllocAslRequestTags
        (   ASL_ScreenModeRequest,
            ASLSM_TitleText,            smrstring,
            ASLSM_InitialDisplayID,     HIRES_KEY | PAL_MONITOR_ID | LACE,
            ASLSM_InitialDisplayWidth,  SCREENXPIXEL,
            ASLSM_InitialDisplayHeight, SCREENYPIXEL,
            ASLSM_InitialDisplayDepth,  DEPTH,
            ASLSM_DoWidth,              TRUE,
            ASLSM_DoHeight,             TRUE,
            ASLSM_DoDepth,              TRUE,
            ASLSM_MinWidth,             SCREENXPIXEL,
            ASLSM_MinHeight,            SCREENYPIXEL,
            ASLSM_MinDepth,             DEPTH,
            TAG_DONE
        )))
        {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't create ASL screen mode request!\0", 24);
            cleanexit(EXIT_FAILURE);
        }
        if (AslRequest(smr, 0L))
        {   DisplayID     = smr->sm_DisplayID;
            DisplayWidth  = smr->sm_DisplayWidth;
            DisplayHeight = smr->sm_DisplayHeight;
            DisplayDepth  = smr->sm_DisplayDepth;
        }
        FreeAslRequest(smr);
    }

    ScreenPtr = (struct Screen *) OpenScreenTags
    (   NULL,
        SA_Width,       DisplayWidth,
        SA_Height,      DisplayHeight,
        SA_Depth,       DisplayDepth,
        SA_DisplayID,   DisplayID,
        SA_Title,       TITLEBAR,
        SA_Font,        &Topaz8,
        SA_PubName,     "SAGA",
        SA_Colors32,    table1,
        SA_Pens,        Pens,
        SA_Interleaved, TRUE,
        TAG_DONE
    );
    if (!ScreenPtr)
    {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open screen!\0", 24);
        cleanexit(EXIT_FAILURE);
    }
    PubScreenStatus(ScreenPtr, NULL); // take the screen public

    for (whichcountry = 36; whichcountry <= 65; whichcountry++)
    {   SetRGB32(&ScreenPtr->ViewPort, 8 + whichcountry, 0x00000000, 0x00000000, 0x99999999);
    }
    LoadRGB32(&(ScreenPtr->ViewPort), table2);

    /* GadTools */
    if (!(VisualInfoPtr = (APTR) GetVisualInfo(ScreenPtr, TAG_DONE)))
    {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't get GadTools visual info!\0", 24);
	cleanexit(EXIT_FAILURE);
    }
    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   CycleGadget[whichhero].ng_VisualInfo = VisualInfoPtr;
    }
    SpeedGadget.ng_VisualInfo = VisualInfoPtr;

    if (!(MenuPtr = (struct Menu *) CreateMenus(NewMenu, TAG_DONE)))
    {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't create menus!\0", 24);
        cleanexit(EXIT_FAILURE);
    }
    if (!(LayoutMenus(MenuPtr, VisualInfoPtr, TAG_DONE)))
    {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't lay out menus!\0", 24);
	cleanexit(EXIT_FAILURE);
    }
    if (!(PrevGadgetPtr = (struct Gadget *) CreateContext(&GListPtr)))
    {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't create GadTools context!\0", 24);
	cleanexit(EXIT_FAILURE);
    }

    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   CycleGadgetPtr[whichhero] = PrevGadgetPtr = (struct Gadget *) CreateGadget
        (   CYCLE_KIND,
            PrevGadgetPtr,
            &CycleGadget[whichhero],
            GTCY_Labels, CycleOptions,
            GTCY_Active, hero[whichhero].control,
            TAG_DONE
	);
    }
    SpeedGadgetPtr = PrevGadgetPtr = (struct Gadget *) CreateGadget
    (   SLIDER_KIND,
        PrevGadgetPtr,
        &SpeedGadget,
        GA_RelVerify,  TRUE,
        GTSL_Min,      0,
        GTSL_Max,      4,
        GTSL_Level,    speed,
        GT_Underscore, '_',
        TAG_DONE
    );

    /* main window */
    if (!(MainWindowPtr = (struct Window *) OpenWindowTags(NULL,
        WA_Left,                0,
        WA_Top,                 11,
        WA_Width,               640,
        WA_Height,              501,
        WA_IDCMP,               IDCMP_RAWKEY
                              | IDCMP_VANILLAKEY
                              | IDCMP_MOUSEBUTTONS
                              | IDCMP_INTUITICKS
                              | IDCMP_CLOSEWINDOW
                              | IDCMP_REFRESHWINDOW
                              | IDCMP_MENUPICK
                              | IDCMP_MENUVERIFY
                              | CYCLEIDCMP,
        WA_Flags,               WFLG_BORDERLESS,
        WA_Gadgets,             GListPtr,
	WA_CustomScreen,	ScreenPtr,
	WA_Activate,		TRUE,
	TAG_DONE)))
        {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open window!\0", 24);
            cleanexit(EXIT_FAILURE);
	}

    /* redirection of AmigaDOS system requesters */
    OldWindowPtr = ProcessPtr->pr_WindowPtr;
    ProcessPtr->pr_WindowPtr = (APTR) MainWindowPtr;

    if (!(ASLRqPtr = AllocAslRequestTags(ASL_FileRequest, ASL_Pattern, "#?.saga", ASL_Window, MainWindowPtr, TAG_DONE)))
    {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't create ASL file request!\0", 24);
        cleanexit(EXIT_FAILURE);
    }

    SetMenuStrip(MainWindowPtr, MenuPtr);
    createcounters();

    while (1)
    {   titlescreen();
        if (!loaded)
        {   newgame();
        }
        gameloop();
}   }

MODULE void gameloop(void)
{   SLONG countertype,
          fastest,
          strongest,
          strongestjarl,
          result,
          whichhero,
          whichjarl,
          whichcountry,
          whichmonster,
          whichtreasure,
          whichsord;
    FLAG  transfer;

    do
    {   strcpy(titlestring, TITLEBAR);
        strcat(titlestring, ": ");
        strcat(titlestring, GetCatalogStr(li.li_Catalog, MSG_TURN, "Turn"));
        strcat(titlestring, " ");
        stcl_d(numberstring, turn);
        strcat(titlestring, numberstring);
        strcat(titlestring, " ");
        strcat(titlestring, GetCatalogStr(li.li_Catalog, MSG_OF, "of"));
        strcat(titlestring, " ");
        stcl_d(numberstring, TURNS);
        strcat(titlestring, numberstring);
        SetWindowTitles(MainWindowPtr, (UBYTE *) -1, titlestring); // this is not copied, it is a pointer

        strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_TURN, "Turn"));
        strcat(saystring, " ");
        stcl_d(numberstring, turn);
        strcat(saystring, numberstring);
        strcat(saystring, " ");
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_OF, "of"));
        strcat(saystring, " ");
        stcl_d(numberstring, TURNS);
        strcat(saystring, numberstring);
        strcat(saystring, "...");
        say(LOWER);

         OnMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_NEW,          NOSUB));
         OnMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVE,         NOSUB));
         OnMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVEAS,       NOSUB));
        result = getevent(KEYBOARD, NULL);
        if (result == -4)
        {   for (whichhero = 0; whichhero <= HEROES; whichhero++)
            {   hero[whichhero].alive    = FALSE;
                hero[whichhero].verydead = TRUE;
            }
            gameover = TRUE;
        }
        OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_NEW,    NOSUB));
        OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVE,   NOSUB));
        OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVEAS, NOSUB));

        if (!gameover)
        {
        for (whichhero = 0; whichhero <= HEROES; whichhero++)
        {   if (!hero[whichhero].alive && !hero[whichhero].verydead)
            {   transfer = FALSE;
                for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
                {   if (jarl[whichjarl].alive && jarl[whichjarl].hero == whichhero)
                    {   transfer = TRUE;
                        break; // for speed
                }   }

                if (hero[whichhero].control == AMIGA)
                {   if (transfer)
                    {   strongest = fastest = 0;
                        for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
                        {   if
                            (   jarl[whichjarl].alive
                             && jarl[whichjarl].hero == whichhero
                            )
                            {   if (jarl[whichjarl].strength > strongest)
                                {   strongest     = jarl[whichjarl].strength;
                                    fastest       = jarl[whichjarl].moves;
                                    strongestjarl = whichjarl;
                                } elif (jarl[whichjarl].strength == strongest)
                                {   if (jarl[whichjarl].moves > fastest)
                                    {   strongest     = jarl[whichjarl].strength;
                                        fastest       = jarl[whichjarl].moves;
                                        strongestjarl = whichjarl;
                        }   }   }   }
                        promote(whichhero, strongestjarl);
                        strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_DEAD_HERO, "Dead hero"));
                        strcat(saystring, " ");
                        strcat(saystring, hero[whichhero].name);
                        strcat(saystring, " ");
                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_PROMOTES_JARL, "promotes jarl"));
                        strcat(saystring, " ");
                        strcat(saystring, jarl[strongestjarl].name);
                        strcat(saystring, " (");
                        stcl_d(numberstring, jarl[strongestjarl].strength);
                        strcat(saystring, numberstring);
                        strcat(saystring, "-");
                        stcl_d(numberstring, jarl[strongestjarl].moves);
                        strcat(saystring, numberstring);
                        strcat(saystring, ").");
                        say(LOWER);
                        anykey();
                    } else
                    {   withdraw(whichhero);
                        strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_DEAD_HERO, "Dead hero"));
                        strcat(saystring, " ");
                        strcat(saystring, hero[whichhero].name);
                        strcat(saystring, " ");
                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_WITHDRAWS_FROM_PLAY, "withdraws from play"));
                        strcat(saystring, ".");
                        say(LOWER);
                        anykey();
                }   }
                elif (hero[whichhero].control == HUMAN)
                {   strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_DEAD_HERO, "Dead hero"));
                    strcat(saystring, " ");
                    strcat(saystring, hero[whichhero].name);
                    strcat(saystring, ", (");
                    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_CHAR_WITHDRAW, "W"));
                    strcat(saystring, ")");
                    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_UNCHAR_WITHDRAW, "ithdraw"));
                    strcat(saystring, "/(");
                    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_CHAR_RESTART, "R"));
                    strcat(saystring, ")");
                    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_UNCHAR_RESTART, "estart"));
                    if (transfer)
                    {   strcat(saystring, "/(");
                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_CHAR_TRANSFER, "T"));
                        strcat(saystring, ")");
                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_UNCHAR_TRANSFER, "ransfer"));
                        strcat(saystring, "?");
                        say(LOWER);
                        do
                        {   result = getevent(KEYBOARD, NULL);
                        } while (result != onekey[ONEKEY_WITHDRAW] && result != onekey[ONEKEY_RESTART] && result != onekey[ONEKEY_TRANSFER]);
                        if (result == onekey[ONEKEY_TRANSFER])
                        {   strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_DEAD_HERO, "Dead hero"));
                            strcat(saystring, " ");
                            strcat(saystring, hero[whichhero].name);
                            strcat(saystring, ", ");
                            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_S_W_J_T_P, "select which jarl to promote"));
                            strcat(saystring, "?");
                            say(LOWER);
                            do
                            {   whichjarl = getevent(COUNTER, &countertype);
                            } while
                            (   whichjarl < 0
                             || countertype != JARL
                             || jarl[whichjarl].hero != whichhero
                            );
                            promote(whichhero, whichjarl);
                    }   }
                    else
                    {   strcat(saystring, "?");
                        say(LOWER);
                        do
                        {   result = getevent(KEYBOARD, NULL);
                        } while (result != onekey[ONEKEY_WITHDRAW] && result != onekey[ONEKEY_RESTART]);
                    }
                    if (result == onekey[ONEKEY_WITHDRAW])
                    {   withdraw(whichhero);
                    } elif (result == onekey[ONEKEY_RESTART])
                    {   newhero(whichhero, FALSE);
        }   }   }   }

        phase1(); // movement
        phase2(); // combat
        phase3(); // kingdoms

        /* "4. PLACE MONSTERS. A number of monsters equal to the number
        of heroes in play are randomly placed face up by rolling two dice
        and placing the monster in the area indicated. (This is done every
        turn until all counters are used. "Dead" monsters may not be
        reused." */

        place_monsters(); // phase 4

        /* "5. PLACE jarls. A number of jarls equal to the number of
        heroes in play are randomly placed face up by rolling two dice
        and placing the jarl in the area indicated. (This is done every
        turn until all counters are used. "Dead" jarls may not be
        reused." */

        place_jarls();    // phase 5

        refreshcounters();

        /* 6. MARK TURN. One turn is marked off. */

        turn++;
        }
    } while (turn <= TURNS && !gameover);

    /* "At the end of the 20th turn the game is over and players total
    their glory to determine who has won. The turn should be marked off on
    each player's record sheet." */
 
    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   remove_hero(whichhero, FALSE);
    }
    for (whichjarl = 0; whichjarl <= JARL; whichjarl++)
    {   remove_jarl(whichjarl, FALSE);
    }
    for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
    {   remove_monster(whichmonster, FALSE);
    }
    for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
    {   remove_treasure(whichtreasure, FALSE);
    }
    for (whichsord = 0; whichsord <= SORDS; whichsord++)
    {   remove_sord(whichsord, FALSE);
    }
    refreshcounters();
    for (whichcountry = 0; whichcountry <= 65; whichcountry++)
    {   world[whichcountry].hero = -1;
    }

    if (!gameover)
    {   SetAPen(MainWindowPtr->RPort, BLACK);
        RectFill(MainWindowPtr->RPort, 0, 0, SCREENXPIXEL, SCREENYPIXEL);

        strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_GAME_OVER, "Game over"));
        strcat(saystring, "!");
        say(LOWER);                          

        SetDrMd(MainWindowPtr->RPort, JAM1);
        for (whichhero = 0; whichhero <= HEROES; whichhero++)
        {   if (hero[whichhero].control != NONE)
            {   hero[whichhero].glory += hero[whichhero].wealth / 10;
                hero[whichhero].glory += hero[whichhero].luck   /  3;
                if
                (   treasure[BROSUNGNECKLACE].possessortype == HERO
                 && treasure[BROSUNGNECKLACE].possessor == whichhero
                )
                {   hero[whichhero].wealth += 20;
                }
                for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
                {   if (jarl[whichjarl].alive && jarl[whichjarl].hero == whichhero)
                    {   hero[whichhero].glory += jarl[whichjarl].strength / 2;
                        if
                        (   treasure[BROSUNGNECKLACE].possessortype == JARL
                         && treasure[BROSUNGNECKLACE].possessor == whichjarl
                        )
                        {   hero[whichhero].wealth += 20;
            }   }   }   }
            if (hero[whichhero].control == NONE)
            {   SetAPen(MainWindowPtr->RPort, MEDIUMGREY);
            } elif (hero[whichhero].glory >= 15)
            {   SetAPen(MainWindowPtr->RPort, GREEN);
            } else
            {   SetAPen(MainWindowPtr->RPort, RED);
            }
            RectFill(MainWindowPtr->RPort, 320 - 70, 200 + (whichhero * SCOREDISTANCE), 320 + 70, 200 + 11 + (whichhero * SCOREDISTANCE));
        
            SetAPen(MainWindowPtr->RPort, BLACK);
            Move(MainWindowPtr->RPort, 320 - 70 + 4, 200 + 8 + (whichhero * SCOREDISTANCE));
            Text(MainWindowPtr->RPort, hero[whichhero].name, strlen(hero[whichhero].name));
        
            if (hero[whichhero].control == NONE)
            {   strcpy(numberstring, "-");
            } else
            {   stcl_d(numberstring, hero[whichhero].glory);
                Move(MainWindowPtr->RPort, 320 + 70 - (8 * 4) - 4 + (8 * (4 - strlen(numberstring))), 200 + 8 + (whichhero * SCOREDISTANCE));
                Text(MainWindowPtr->RPort, numberstring, strlen(numberstring));
        }   }
        SetAPen(MainWindowPtr->RPort, BLACK);
        Move(MainWindowPtr->RPort, 340, 200);
        Draw(MainWindowPtr->RPort, 340, 200 + ((HEROES + 1) * SCOREDISTANCE));
        
        clearkybd();
        waitkey();
}   }    

MODULE void callforaid(SLONG passedtype, SLONG passed)
{   SLONG passedhero, passedwhere, whichjarl;

    if (passedtype == HERO)
    {   passedhero = passed;
        passedwhere = hero[passed].where;
    } else
    {   // assert(passedtype == JARL);
        // assert(jarl[passed].hero != -1);
        passedhero = jarl[passed].hero;
        passedwhere = jarl[passed].where;
    }

    if (passedtype == JARL && hero[passedhero].where == passedwhere)
    {   hero[passedhero].defending = TRUE;
        select_hero(passedhero, FALSE);
    }

    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
    {   if
        (   jarl[whichjarl].hero == passedhero
         && jarl[whichjarl].where == passedwhere
         && !jarl[whichjarl].defending
        )
        {   jarl[whichjarl].defending = TRUE;
            select_jarl(whichjarl, FALSE);
    }   }

    refreshcounters();
}

MODULE void dobattle(SLONG defendtype, SLONG defender, SLONG attackhero)
{   SLONG decision,
          result,
          attackstrength = 0,
          attackluck     = 0,
          attacktype,
          attacker,
          defendstrength = 0,
          defendluck     = 0,
          defendhero,
          whichhero,
          whichjarl,
          whichsord;

    /* defendtype: type of defender, one of HERO, JARL, MONSTER or KINGDOM.
       defender: ordinal number of defender. */

    if (defendtype == HERO)
    {   defendhero = defender;
        hero[defender].defending = TRUE;
        select_hero(defender, FALSE);
        callforaid(HERO, defender);
    } elif (defendtype == JARL)
    {   defendhero = jarl[defender].hero;
        jarl[defender].defending = TRUE;
        if (defendhero != -1)
        {   select_jarl(defender, FALSE);
            callforaid(JARL, defender);
        } else
        {   select_jarl(defender, TRUE);
    }   }
    elif (defendtype == MONSTER)
    {   defendstrength = monster[defender].strength;
        defendhero = -1;
    } else
    {   // assert(defendtype == KINGDOM);
        defendstrength = world[defender].tax;
        defendhero = -1; // even if it already has a king it makes no difference to the combat
    }

    // "II. ROLL FOR DROW, WITCH, OR GHOST MAGIC SPELLS (IF APPLICABLE)."

    if (defendtype == MONSTER)
    {   if (monster[defender].species == GHOST)
        {   decision = d6();
            if (decision <= 3)
            {   cast(defender, decision);
        }   }
        elif (monster[defender].species == DROW)
        {   cast(defender, d6());
        } elif (monster[defender].species == WITCH)
        {   cast(defender, d6());
            if (attackersleft())
            {   cast(defender, d6());
    }   }   }

    if (!attackersleft())
    {   // no attackers, abort combat
        return;
    }

    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   if (hero[whichhero].attacking)
        {   attackstrength += hero[whichhero].strength;
        } elif (hero[whichhero].defending)
        {   defendstrength += hero[whichhero].strength;
    }   }
    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
    {   if (jarl[whichjarl].attacking)
        {   attackstrength += jarl[whichjarl].strength;
        } elif (jarl[whichjarl].defending)
        {   defendstrength += jarl[whichjarl].strength;
    }   }

    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   if (hero[whichhero].attacking && hero[whichhero].hagall)
        {   attackstrength--;
        } elif (hero[whichhero].defending && hero[whichhero].hagall)
        {   defendstrength--;
    }   }
    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
    {   if (jarl[whichjarl].attacking && jarl[whichjarl].hagall)
        {   attackstrength--;
        } elif (jarl[whichjarl].defending && jarl[whichjarl].hagall)
        {   defendstrength--;
    }   }
    if (defendtype == MONSTER && monster[defender].hagall)
    {   defendstrength--;
    }

    /* "III. MODIFY THE DIE ROLL WITH LUCK. Before the die is rolled,
    heroes who are involved in the battle (or who have jarls involved in
    the battle) may modify the die roll up or down one with each point of
    luck expended before the die is rolled. If there are two or more
    heroes involved in the battle they should each write how much luck
    they are using to modify the die roll and how before revealing the
    amounts simultaneously." */

    if (hero[attackhero].luck >= 1)
    {   if (hero[attackhero].control == HUMAN)
        {   strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_ATTACKING, "Attacking"));
            saywho(HERO, attackhero, FALSE, TRUE);
            strcat(saystring, ", ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_USE_LUCK, "use luck"));
            strcat(saystring, " (0-");
            if (hero[attackhero].luck >= 9)
            {   strcat(saystring, "9");
            } else
            {   stcl_d(numberstring, hero[attackhero].luck);
                strcat(saystring, numberstring);
            }
            strcat(saystring, ")?");
            say(LOWER);
            attackstrength += getluck(attackhero);
        } else
        {   // assert(hero[attackhero].control == AMIGA);
            attackluck = 0;
    }   }

    if (defendhero != -1)
    {   if (hero[defendhero].control == HUMAN)
        {   if (hero[defendhero].luck >= 1)
            {   strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_DEFENDING, "Defending"));
                saywho(defendtype, defender, FALSE, TRUE);
                strcat(saystring, ", ");
                strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_USE_LUCK, "use luck"));
                strcat(saystring, " (0-");
                if (hero[defendhero].luck >= 9)
                {   strcat(saystring, "9");
                } else
                {   stcl_d(numberstring, hero[defendhero].luck);
                    strcat(saystring, numberstring);
                }
                strcat(saystring, ")?");
                say(LOWER);
                defendstrength += getluck(defendhero);
        }   }
        else
        {   // assert(hero[defendhero].control == AMIGA);
            defendluck = 0;
    }   }

/*  if (hero[attackhero].control == AMIGA && attackluck > 0)
    {   strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_ATTACKING, "Attacking"));
        saywho(HERO, attackhero, FALSE, TRUE);
        strcat(saystring, " ");
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_USED, "used"));
        strcat(saystring, " ");
        stcl_d(numberstring, attackluck);
        strcat(saystring, numberstring);
        strcat(saystring, " ");
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_LUCK2, "luck"));
        strcat(saystring, ".");
        say(LOWER);
        anykey();
    }
    if (defendhero != -1)
    {   if (hero[defendhero].control == AMIGA && defendluck > 0)
        {   strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_DEFENDING, "Defending"));
            saywho(HERO, defendhero, FALSE, TRUE);
            strcat(saystring, ", ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_USED, "used"));
            strcat(saystring, " ");
            stcl_d(numberstring, defendluck);
            strcat(saystring, numberstring);
            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_LUCK2, "luck"));
            strcat(saystring, ".");
            say(LOWER);
            anykey();
    }   } */

    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   if (hero[whichhero].alive && hero[whichhero].rune == OGAL)
        {   if (hero[whichhero].attacking)
            {   attackstrength++;
            } elif (hero[whichhero].defending)
            {   defendstrength++;
    }   }   }

    for (whichsord = 0; whichsord <= SORDS; whichsord++)
    {   if
        (   (   sord[whichsord].possessortype == HERO
             && hero[sord[whichsord].possessor].attacking
            )
         || (   sord[whichsord].possessortype == JARL
             && jarl[sord[whichsord].possessor].attacking
        )   )
        {   if (whichsord == BALMUNG || whichsord == HRUNTING)
            {   attackstrength++;
            } elif (whichsord == DRAGVENDILL || whichsord == GRAM || whichsord == TYRFING)
            {   attackstrength += 2;
            } elif (whichsord == LOVI)
            {   attackstrength++;
                for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
                {   if (jarl[whichjarl].defending)
                    {   attackstrength += 2;
                        break;
        }   }   }   }
        elif
        (   (   sord[whichsord].possessortype == HERO
             && hero[sord[whichsord].possessor].defending
            )
         || (   sord[whichsord].possessortype == JARL
             && jarl[sord[whichsord].possessor].defending
        )   )
        {   if (whichsord == BALMUNG || whichsord == HRUNTING)
            {   defendstrength++;
            } elif (whichsord == DRAGVENDILL || whichsord == GRAM || whichsord == TYRFING)
            {   defendstrength += 2;
            } elif (whichsord == LOVI)
            {   defendstrength++;
                for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
                {   if (jarl[whichjarl].attacking)
                    {   defendstrength += 2;
                        break;
    }   }   }   }   }

    if (hero[attackhero].attacking)
    {   attackstrength += odin_tyr(attackhero, TRUE);
        if (attackstrength < 0)
        {   attackstrength = 0;
    }   }
    if (defendhero != -1 && hero[defendhero].defending)
    {   defendstrength += odin_tyr(defendhero, FALSE);
        if (defendstrength < 0)
        {   defendstrength = 0;
    }   }

    if
    (   (   sord[BALMUNG].possessortype == HERO
         && hero[sord[BALMUNG].possessor].attacking
        )
     || (   sord[BALMUNG].possessortype == JARL
         && jarl[sord[BALMUNG].possessor].attacking
    )   )
    {   ; // one of the attackers is wielding Balmung
        // assert(sord[BALMUNG].where == -1);
    } else
    {   if
        (   (   treasure[MAGICSHIRT].possessortype == HERO
             && hero[treasure[MAGICSHIRT].possessor].defending
            )
         || (   treasure[MAGICSHIRT].possessortype == JARL
             && jarl[treasure[MAGICSHIRT].possessor].defending
        )   )
        {   // one of the defenders is wearing the Magic Shirt
            // assert(treasure[MAGICSHIRT].where == -1);

            defendstrength++;
        }

        if
        (   (   treasure[MAILCOAT].possessortype == HERO
             && hero[treasure[MAILCOAT].possessor].defending
            )
         || (   treasure[MAILCOAT].possessortype == JARL
             && jarl[treasure[MAILCOAT].possessor].defending
        )   )
        {   // one of the defenders is wearing the Mail Coat
            // assert(treasure[MAILCOAT].where == -1);

            defendstrength += 2;
    }   }

    /* "V. ROLL ONE DIE AND CHECK THE COMBAT RESULTS TABLE TO DETERMINE
    THE OUTCOME OF THE BATTLE AFTER ADDING ALL MODIFIERS TO THE DIE ROLL.
    After all modifications to the combat strengths of both sides have
    been made, subtract the defender's strength from the attacker's and
    consult the COMBAT RESULTS TABLE below to determine the results
    according to a die roll and modifications due to luck." */

/*
Printf("Involved in the combat are:\n");
Printf(" Attackers:\n");
if (hero[attackhero].attacking)
{   Printf("  Hero %s!\n", hero[attackhero].name);
}
for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
{   if (jarl[whichjarl].attacking)
    {   Printf("  Jarl %s!\n", jarl[whichjarl].name);
}   }
Printf(" Defenders:\n");
if (defendhero != -1)
{   if (hero[defendhero].defending)
    {   Printf("  Hero %s!\n", hero[defendhero].name);
}   }
for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
{   if (jarl[whichjarl].defending)
    {   Printf("  Jarl %s!\n", jarl[whichjarl].name);
}   }
if (defendhero == -1)
{   if (defendtype == KINGDOM)
    {   Printf("  Kingdom %s!\n", world[defender].name);
    } elif (defendtype == MONSTER)
    {   Printf("  Monster %s!\n", monster[defender].name);
}   }
*/

    result = attackstrength - defendstrength + d6();

    if (result == 4) // attacker flees
    {   if (sord[HRUNTING].possessortype == HERO)
        {   if (hero[sord[HRUNTING].possessor].attacking)
            {   result = 6; // defender flees
        }   }
        elif (sord[HRUNTING].possessortype == JARL)
        {   if (jarl[sord[HRUNTING].possessor].attacking)
            {   result = 6; // defender flees
    }   }   }
    elif (result == 6) // defender flees
    {   if (sord[HRUNTING].possessortype == HERO)
        {   if (hero[sord[HRUNTING].possessor].defending)
            {   result = 4; // attacker flees
        }   }
        elif (sord[HRUNTING].possessortype == JARL)
        {   if (jarl[sord[HRUNTING].possessor].defending)
            {   result = 4; // attacker flees
    }   }   }

    /* "VI. APPLY THE COMBAT RESULT." */

    if (hero[attackhero].attacking)
    {   attacktype = HERO;
        attacker   = attackhero;
    } else
    {   attacktype = JARL; // uses the first jarl found
        for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
        {   if (jarl[whichjarl].attacking)
            {   attacker = whichjarl;
                break;
    }   }   }

    if (result <= 2) // attackers killed
    {   if (hero[attackhero].attacking)
        {   kill(defendtype, defender, defendhero, HERO, attackhero, attackhero);
        }
        for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
        {   if (jarl[whichjarl].attacking)
            {   kill(defendtype, defender, defendhero, JARL, whichjarl, attackhero);
    }   }   }
    elif (result == 3) // attackers wounded
    {   if (hero[attackhero].attacking)
        {   wound(defendtype, defender, defendhero, HERO, attackhero, attackhero);
        }
        for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
        {   if (jarl[whichjarl].attacking)
            {   wound(defendtype, defender, defendhero, JARL, whichjarl, attackhero);
    }   }   }
    elif (result == 4) // attackers flee
    {   if (hero[attackhero].attacking)
        {   flee(defendtype, defender, defendhero, HERO, attackhero, attackhero);
        }
        for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
        {   if (jarl[whichjarl].attacking)
            {   flee(defendtype, defender, defendhero, JARL, whichjarl, attackhero);
    }   }   }
    elif (result == 5) // no result
    {   strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_NO_RESULT, "No result"));
        strcat(saystring, ".");
        say(LOWER);
        anykey();
    } elif (result == 6) // defenders flee
    {   if (defendtype == MONSTER || defendtype == KINGDOM)
        {   flee(attacktype, attacker, attackhero, defendtype, defender, -1);
        } else
        {   assert(defendtype == HERO || defendtype == JARL);
            if (defendhero != -1 && hero[defendhero].defending)
            {   flee(attacktype, attacker, attackhero, HERO, defendhero, defendhero);
            }
            for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
            {   if (jarl[whichjarl].defending)
                {   flee(attacktype, attacker, attackhero, JARL, whichjarl, defendhero);
    }   }   }   }
    elif (result == 7) // defenders wounded
    {   if (defendtype == MONSTER || defendtype == KINGDOM)
        {   wound(attacktype, attacker, attackhero, defendtype, defender, -1);
        } else
        {   assert(defendtype == HERO || defendtype == JARL);
            if (defendhero != -1 && hero[defendhero].defending)
            {   wound(attacktype, attacker, attackhero, HERO, defendhero, defendhero);
            }
            for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
            {   if (jarl[whichjarl].defending)
                {   wound(attacktype, attacker, attackhero, JARL, whichjarl, defendhero);
    }   }   }   }
    else // defenders killed
    {   // assert(result >= 8);
        if (defendtype == MONSTER || defendtype == KINGDOM)
        {   kill(attacktype, attacker, attackhero, defendtype, defender, -1);
        } else
        {   assert(defendtype == HERO || defendtype == JARL);
            if (defendhero != -1 && hero[defendhero].defending)
            {   kill(attacktype, attacker, attackhero, HERO, defendhero, defendhero);
            }
            for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
            {   if (jarl[whichjarl].defending)
                {   kill(attacktype, attacker, attackhero, JARL, whichjarl, defendhero);
    }   }   }   }

    if (hero[attackhero].attacking)
    {   thor(attackhero);
    }
    if (defendhero != -1 && hero[defendhero].defending && hero[defendhero].alive)
    {   thor(defendhero);
    }

    if (hero[attackhero].attacking)
    {   pray(attackhero);
    }
    if (defendhero != -1 && hero[defendhero].defending && hero[defendhero].alive)
    {   pray(defendhero);
    }

    if (hero[attackhero].attacking)
    {   deselect_hero(attackhero, FALSE);
        hero[attackhero].attacking = FALSE;
    } elif (hero[defendhero].defending)
    {   deselect_hero(defendhero, FALSE);
        hero[defendhero].defending = FALSE;
    }
    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
    {   if (jarl[whichjarl].attacking)
        {   deselect_jarl(whichjarl, FALSE);
            jarl[whichjarl].attacking   =
            jarl[whichjarl].recruitable = FALSE;
        } elif (jarl[whichjarl].defending)
        {   deselect_jarl(whichjarl, FALSE);
            jarl[whichjarl].defending   =
            jarl[whichjarl].recruitable = FALSE;
    }   }
    refreshcounters();
}

MODULE void flee(SLONG routertype, SLONG router, SLONG routerhero, SLONG routedtype, SLONG routed, SLONG routedhero)
{   if (routedtype == HERO)
    {   hero[routed].glory -= 2;
        if (hero[routed].glory < 0)
        {   hero[routed].glory = 0;
    }   }

    if (routertype == HERO || routertype == JARL)
    {   if (routedtype == KINGDOM)
        {   world[routed].hero = routerhero;
            darken();
            saywho(routertype, router, FALSE, FALSE);
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_HAS_CONQUERED_KINGDOM, "has conquered kingdom"));
            strcat(saystring, " ");
            strcat(saystring, world[routed].name);
            strcat(saystring, " (");
            stcl_d(numberstring, world[routed].tax);
            strcat(saystring, numberstring);
            strcat(saystring, ").");
            say(LOWER);
            anykey();
        } elif (routedtype == JARL)
        {   if
            (   routerhero != -1
             && hero[routerhero].where == jarl[routed].where
             && !recruit(routed, routerhero)
            )
            {   saywho(JARL, routed, FALSE, FALSE);
                strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_IS_ROUTED, "is routed"));
                strcat(saystring, "!");
                say(LOWER);
                anykey();

                if (routertype == HERO)
                {   if (hero[router].control == AMIGA)
                    {   amiga_rout(JARL, routed);
                    } else
                    {   // assert(hero[router].control == HUMAN);
                        human_rout(JARL, routed, routerhero);
                }   }
                else
                {   // assert(routertype == JARL);
                    if (jarl[router].hero == -1 || hero[jarl[router].hero].control == AMIGA)
                    {   amiga_rout(JARL, routed);
                    } else
                    {   human_rout(JARL, routed, routerhero);
        }   }   }   }
        elif (routedtype == HERO)
        {   saywho(HERO, routed, FALSE, FALSE);
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_IS_ROUTED, "is routed"));
            strcat(saystring, "!");
            say(LOWER);
            anykey();

            if (routertype == HERO)
            {   if (hero[router].control == AMIGA)
                {   amiga_rout(HERO, routed);
                } else
                {   // assert(hero[router].control == HUMAN);
                    human_rout(HERO, routed, routerhero);
            }   }
            else
            {   // assert(routertype == JARL);
                if (jarl[router].hero == -1 || hero[jarl[router].hero].control == AMIGA)
                {   amiga_rout(HERO, routed);
                } else
                {   human_rout(HERO, routed, routerhero);
        }   }   }
        elif (routedtype == MONSTER)
        {   strcpy(saystring, monstertypes[monster[routed].species]);
            strcat(saystring, " ");
            strcat(saystring, monster[routed].name);
            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_IS_ROUTED, "is routed"));
            strcat(saystring, "!");
            say(LOWER);
            anykey();

            if (routertype == HERO)
            {   if (hero[router].control == AMIGA)
                {   amiga_rout(MONSTER, routed);
                } else
                {   // assert(hero[router].control == HUMAN);
                    human_rout(MONSTER, routed, routerhero);
            }   }
            else
            {   // assert(routertype == JARL);
                if (jarl[router].hero == -1 || hero[jarl[router].hero].control == AMIGA)
                {   amiga_rout(MONSTER, routed);
                } else
                {   human_rout(MONSTER, routed, routerhero);
    }   }   }   }
    else
    {   // assert(routertype == MONSTER || routertype == KINGDOM);
        if (routedtype == JARL)
        {   saywho(JARL, routed, FALSE, FALSE);
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_IS_ROUTED, "is routed"));
            strcat(saystring, "!");
            say(LOWER);
            anykey();

            amiga_rout(JARL, routed);
        } elif (routedtype == HERO)
        {   saywho(HERO, routed, FALSE, FALSE);
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_IS_ROUTED, "is routed"));
            strcat(saystring, "!");
            say(LOWER);
            anykey();

            amiga_rout(HERO, routed);
}   }   }

MODULE void wound(SLONG woundertype, SLONG wounder, SLONG wounderhero, SLONG woundedtype, SLONG wounded, SLONG woundedhero)
{   SLONG glory = 0, luck = 0, whichtreasure, whichsord;

    /* WOUNDED. Heroes on the wounded side are wounded.
    Jarls on the wounded side are removed from the board and placed,
    upside down, in their respective piles, from which they will reenter
    play normally. There is no further effect from being wounded, except
    that jarls that reenter play after being wounded are to be considered
    unrecruited jarls. */

    if (woundedtype == HERO)
    {   if (hero[wounded].wounded)
        {   kill(woundertype, wounder, wounderhero, woundedtype, wounded, woundedhero);
            return;
        }

        hero[wounded].wounded = TRUE;
        saywho(HERO, wounded, FALSE, FALSE);
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_IS_WOUNDED, "is wounded"));
        strcat(saystring, "!");
        say(LOWER);
        anykey();

        if (hero[wounded].maidens)
        {   hero[wounded].maidens--;
            hero[wounded].wounded = FALSE;

            strcpy(saystring, "Frey ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_SENDS_A_MAIDEN_TO_HEAL_HERO, "Frey sends a maiden to heal hero"));
            strcat(saystring, " ");
            strcat(saystring, hero[wounded].name);
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_S_WOUND, "'s wound"));
            strcat(saystring, ".");
            say(LOWER);
            anykey();
        }

        if (wounderhero != -1)
        {   gain(wounderhero, hero[woundedhero].strength / 2 / 2, hero[woundedhero].strength / 2 / 2);
    }   }
    elif (woundedtype == JARL)
    {   if
        (   wounderhero != -1
         && hero[wounderhero].where == jarl[wounded].where
         && recruit(wounded, wounderhero)
        )
        {   return;
        }

        jarl[wounded].alive  = FALSE;
        jarl[wounded].taken  = FALSE;
        jarl[wounded].hero   = -1;
        jarl[wounded].wealth = 0; // this is actually an ambiguity in the rules
        remove_jarl(wounded, TRUE);
         
        for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
        {   if
            (   treasure[whichtreasure].possessortype == JARL
             && treasure[whichtreasure].possessor == wounded
            )
            {   // drop the treasure
                treasure[whichtreasure].possessortype = KINGDOM;
                treasure[whichtreasure].possessor     = -1;
                treasure[whichtreasure].where         = jarl[wounded].where;
                move_treasure(whichtreasure, TRUE);
        }   }
        for (whichsord = 0; whichsord <= SORDS; whichsord++)
        {   if
            (   sord[whichsord].possessortype == JARL
             && sord[whichsord].possessor == wounded
            )
            {   // drop the sword
                sord[whichsord].possessortype = KINGDOM;
                sord[whichsord].possessor     = -1;
                sord[whichsord].where         = jarl[wounded].where;
                move_sord(whichsord, TRUE);
        }   }

        saywho(JARL, wounded, FALSE, FALSE);
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_IS_WOUNDED, "is wounded"));
        strcat(saystring, "!");
        say(LOWER);
        anykey();

        if (wounderhero != -1)
        {   gain(wounderhero, jarl[wounded].strength / 2 / 2, jarl[wounded].strength / 2 / 2); // not the same as / 4 due to rounding
    }   }
    elif (woundedtype == KINGDOM)
    {   world[wounded].hero = wounderhero;
        darken();

        saywho(woundertype, wounder, FALSE, FALSE);
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_HAS_CONQUERED_KINGDOM, "has conquered kingdom"));
        strcat(saystring, " ");
        strcat(saystring, world[wounded].name);
        strcat(saystring, " (");
        stcl_d(numberstring, world[wounded].tax);
        strcat(saystring, numberstring);
        strcat(saystring, ").");
        say(LOWER);
        anykey();
    } elif (woundedtype == MONSTER)
    {   monster[wounded].alive = FALSE;
        monster[wounded].taken = FALSE;
        remove_monster(wounded, TRUE);

        strcpy(saystring, monstertypes[monster[wounded].species]);
        strcat(saystring, " ");
        strcat(saystring, monster[wounded].name);
        strcat(saystring, " ");
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_IS_WOUNDED, "is wounded"));
        strcat(saystring, "!");
        say(LOWER);
        anykey();
       
        for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
        {   if
            (   treasure[whichtreasure].possessortype == MONSTER
             && treasure[whichtreasure].possessor == wounded
            )
            {   // give the treasure to the wounder of the dragon
                // assert(monster[wounded].species == DRAGON);
                treasure[whichtreasure].possessortype = woundertype;
                treasure[whichtreasure].possessor     = wounder;
                treasure[whichtreasure].where         = -1;

                saywho(woundertype, wounder, FALSE, FALSE);
                strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_FINDS_THE, "finds the"));
                strcat(saystring, " ");
                strcat(saystring, treasure[whichtreasure].name);
                strcat(saystring, ".");
                say(LOWER);
                anykey();
        }   }

        if (monster[wounded].wealth > 0)
        {   hero[wounderhero].wealth += monster[wounded].wealth;

            saywho(woundertype, wounder, FALSE, FALSE);
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_FINDS, "finds"));
            strcat(saystring, " ");
            stcl_d(numberstring, monster[wounded].wealth);
            strcat(saystring, numberstring);
            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_GOLDEN_MARKS, "golden marks"));
            strcat(saystring, ".");
            say(LOWER);
            anykey();
        }

        switch (monster[wounded].species)
        {
        case DRAGON:
            glory = 6;
            luck  = 5;
        break;
        case DROW:
            glory = 3;
            luck  = 2;
        break;
        case GHOST:
            glory = 2;
            luck  = 2;
        break;
        case GIANT:
            glory = 4;
            luck  = 3;
        break;
        case TROLL:
            glory = 3;
            luck  = 3;
        break;
        case WITCH:
            glory = 5;
            luck  = 4;
        break;
        default:
            // assert(0);
        break;
        }
        glory /= 2;
        luck  /= 2;

        // assert(wounderhero != -1);
        gain(wounderhero, glory, luck);
}   }
MODULE void kill(SLONG killertype, SLONG killer, SLONG killerhero, SLONG killedtype, SLONG killed, SLONG killedhero)
{   SLONG glory = 0, luck = 0, result, whichjarl, whichtreasure, whichsord;

    if (killedtype == HERO)
    {   hero[killed].alive     =
        hero[killed].attacking =
        hero[killed].defending = FALSE;
        remove_hero(killed, TRUE);

        for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
        {   if
            (   treasure[whichtreasure].possessortype == HERO
             && treasure[whichtreasure].possessor == killed
            )
            {   // drop the treasure
                treasure[whichtreasure].possessortype = KINGDOM;
                treasure[whichtreasure].possessor     = -1;
                treasure[whichtreasure].where         = hero[killed].where;
                move_treasure(whichtreasure, TRUE);
        }   }
        for (whichsord = 0; whichsord <= SORDS; whichsord++)
        {   if
            (   sord[whichsord].possessortype == HERO
             && sord[whichsord].possessor == killed
            )
            {   // drop the sword
                sord[whichsord].possessortype = KINGDOM;
                sord[whichsord].possessor     = -1;
                sord[whichsord].where         = hero[killed].where;
                move_sord(whichsord, TRUE);
        }   }

        saywho(HERO, killed, FALSE, FALSE);
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_IS_KILLED, "is killed"));
        strcat(saystring, "!");
        say(LOWER);
        anykey();

        if (killerhero != -1)
        {   gain(killerhero, hero[killedhero].strength / 2, hero[killedhero].strength / 2);
    }   }
    elif (killedtype == JARL)
    {   if
        (   killerhero == -1
         || hero[killerhero].where != jarl[killed].where
         || !recruit(killed, killerhero)
        )
        {   jarl[killed].alive     =
            jarl[killed].attacking =
            jarl[killed].defending = FALSE;
            remove_jarl(killed, TRUE);
            
            for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
            {   if
                (   treasure[whichtreasure].possessortype == JARL
                 && treasure[whichtreasure].possessor == killed
                )
                {   // drop the treasure
                    treasure[whichtreasure].possessortype = KINGDOM;
                    treasure[whichtreasure].possessor     = -1;
                    treasure[whichtreasure].where         = jarl[killed].where;
                    move_treasure(whichtreasure, TRUE);
            }   }
            for (whichsord = 0; whichsord <= SORDS; whichsord++)
            {   if
                (   sord[whichsord].possessortype == JARL
                 && sord[whichsord].possessor == killed
                )
                {   // drop the treasure
                    sord[whichsord].possessortype = KINGDOM;
                    sord[whichsord].possessor     = -1;
                    sord[whichsord].where         = jarl[killed].where;
                    move_sord(whichsord, TRUE);
            }   }

            saywho(JARL, killed, FALSE, FALSE);
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_IS_KILLED, "is killed"));
            strcat(saystring, "!");
            say(LOWER);
            anykey();

            if (killerhero != -1 && killedtype == JARL)
            {   if (hero[killerhero].where == jarl[killed].where)
                {   if (jarl[killed].wealth)
                    {   hero[killerhero].wealth += jarl[killed].wealth;
                        saywho(HERO, killerhero, FALSE, FALSE);
                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_TAKES, "takes"));
                        strcat(saystring, " ");
                        stcl_d(numberstring, jarl[killed].wealth);
                        strcat(saystring, " ");
                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_GOLDEN_MARKS, "golden marks"));
                        strcat(saystring, " ");
                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_FROM, "from"));
                        strcat(saystring, " ");
                        saywho(JARL, killed, FALSE, TRUE);
                        strcat(saystring, ".");
                        say(LOWER);
                        anykey();
                }   }
                else
                {   for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
                    {   if
                        (   jarl[whichjarl].alive
                         && jarl[whichjarl].hero == killerhero
                         && jarl[whichjarl].where == jarl[killed].where
                        )
                        {   assert(whichjarl != killed);

                            if (jarl[killed].wealth)
                            {   jarl[whichjarl].wealth += jarl[killed].wealth;
                                saywho(JARL, whichjarl, FALSE, FALSE);
                                strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_TAKES, "takes"));
                                strcat(saystring, " ");
                                stcl_d(numberstring, jarl[killed].wealth);
                                strcat(saystring, " ");
                                strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_GOLDEN_MARKS, "golden marks"));
                                strcat(saystring, " ");
                                strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_FROM, "from"));
                                strcat(saystring, " ");
                                saywho(JARL, killed, FALSE, TRUE);
                                strcat(saystring, ".");
                                say(LOWER);
                                anykey();
            }   }   }   }   }

            if (killedhero != -1)
            {   if (hero[killedhero].control == HUMAN)
                {   saywho(HERO, killedhero, TRUE, FALSE);
                    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_LOSE, "lose"));
                    strcat(saystring, " ");
                    stcl_d(numberstring, jarl[killed].strength / 2);
                    strcat(saystring, numberstring);
                    strcat(saystring, " (");
                    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_CHAR_GLORY, "G"));
                    strcat(saystring, ")");
                    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_UNCHAR_GLORY, "lory"));
                    strcat(saystring, " ");
                    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_OR, "or"));
                    strcat(saystring, " ");
                    stcl_d(numberstring, jarl[killed].strength / 2);
                    strcat(saystring, numberstring);
                    strcat(saystring, " (");
                    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_CHAR_LUCK, "L"));
                    strcat(saystring, ")");
                    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_UNCHAR_LUCK, "uck"));
                    strcat(saystring, "?");
                    say(LOWER);
                    do
                    {   result = getevent(KEYBOARD, NULL);
                    } while (result != onekey[ONEKEY_GLORY] && result != onekey[ONEKEY_LUCK]);
                    if (result == onekey[ONEKEY_GLORY])
                    {   hero[killedhero].glory -= jarl[killed].strength / 2;
                        if (hero[killedhero].glory < 0)
                        {   hero[killedhero].glory = 0;
                    }   }
                    else
                    {   // assert(result == onekey[ONEKEY_LUCK]);
                        hero[killedhero].luck  -= jarl[killed].strength / 2;
                        if (hero[killedhero].luck < 0)
                        {   hero[killedhero].luck = 0;
                }   }   }
                else
                {   // assert(hero[killedhero].control == AMIGA);
                    hero[killedhero].glory -= jarl[killed].strength / 2;
                    if (hero[killedhero].glory < 0)
                    {   hero[killedhero].glory = 0;
            }   }   }
            if (killerhero != -1)
            {   gain(killerhero, jarl[killed].strength / 2, jarl[killed].strength / 2);
    }   }   }
    elif (killedtype == KINGDOM)
    {   world[killed].hero = killerhero;
        darken();
        saywho(HERO, killerhero, FALSE, FALSE);
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_HAS_CONQUERED_KINGDOM, "has conquered kingdom"));
        strcat(saystring, " ");
        strcat(saystring, world[killed].name);
        strcat(saystring, " (");
        stcl_d(numberstring, world[killed].tax);
        strcat(saystring, numberstring);
        strcat(saystring, ").");
        say(LOWER);
        anykey();
    } elif (killedtype == MONSTER)
    {   monster[killed].alive = FALSE;
        remove_monster(killed, TRUE);

        strcpy(saystring, monstertypes[monster[killed].species]);
        strcat(saystring, " ");
        strcat(saystring, monster[killed].name);
        strcat(saystring, " ");
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_IS_KILLED, "is killed"));
        strcat(saystring, "!");
        say(LOWER);
        anykey();

        for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
        {   if
            (   treasure[whichtreasure].possessortype == MONSTER
             && treasure[whichtreasure].possessor == killed
            )
            {   // give the treasure to the killer of the dragon
                // assert(monster[killed].species == DRAGON);
                treasure[whichtreasure].possessortype = killertype;
                treasure[whichtreasure].possessor     = killer;
                treasure[whichtreasure].where         = -1;

                saywho(killertype, killer, FALSE, FALSE);
                strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_FINDS_THE, "finds the"));
                strcat(saystring, " ");
                strcat(saystring, treasure[whichtreasure].name);
                strcat(saystring, ".");
                say(LOWER);
                anykey();
        }   }

        if (monster[killed].wealth > 0)
        {   hero[killerhero].wealth += monster[killed].wealth;

            saywho(killertype, killer, FALSE, FALSE);
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_FINDS, "finds"));
            strcat(saystring, " ");
            stcl_d(numberstring, monster[killed].wealth);
            strcat(saystring, numberstring);
            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_GOLDEN_MARKS, "golden marks"));
            strcat(saystring, ".");
            say(LOWER);
            anykey();
        }

        switch (monster[killed].species)
        {
        case DRAGON:
            glory = 6;
            luck  = 5;
        break;
        case DROW:
            glory = 3;
            luck  = 2;
        break;
        case GHOST:
            glory = 2;
            luck  = 2;
        break;
        case GIANT:
            glory = 4;
            luck  = 3;
        break;
        case TROLL:
            glory = 3;
            luck  = 3;
        break;
        case WITCH:
            glory = 5;
            luck  = 4;
        break;
        default:
            // assert(0);
        break;
        }
        // assert(killerhero != -1);
        gain(killerhero, glory, luck);

        // check if hero was present at the combat
        if
        (   killerhero != -1
         && hero[killerhero].attacking
        )
        {   if
            (   (   monster[killed].species == DROW
                 || monster[killed].species == GHOST
                 || monster[killed].species == WITCH
                )
             && hero[killer].rune == -1
            )
            {   hero[killer].rune = rand() % (RUNES + 1);
                saywho(HERO, killer, FALSE, FALSE);
                strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_LEARNS_THE_RUNE, "learns the rune"));
                strcat(saystring, " ");
                strcat(saystring, runename[hero[killer].rune]);
                strcat(saystring, ", ");
                strcat(saystring, runedesc[hero[killer].rune]);
                strcat(saystring, ".");
                say(LOWER);
                anykey();
}   }   }   }

MODULE FLAG recruit(SLONG recruited, SLONG recruiterhero)
{   SLONG jarls = 0,
          result,
          whichjarl;

    if (jarl[recruited].hero == -1 && hero[recruiterhero].luck >= 1 && jarl[recruited].recruitable)
    {   jarl[recruited].recruitable = FALSE;
        for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
        {   if (jarl[whichjarl].alive && jarl[whichjarl].hero == recruiterhero)
            {   jarls++;
        }   }
        if (jarls <= 3)
        {   if (hero[recruiterhero].control == HUMAN)
            {   saywho(HERO, recruiterhero, TRUE, FALSE);
                strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_RECRUIT_JARL, "recruit jarl"));
                strcat(saystring, " ");
                strcat(saystring, jarl[recruited].name);
                strcat(saystring, " (");
                strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_CHAR_YES, "Y"));
                strcat(saystring, "/");
                strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_CHAR_NO, "N"));
                strcat(saystring, ")?");
                say(LOWER);
                do
                {   result = getevent(KEYBOARD, NULL);
                } while (result != onekey[ONEKEY_YES] && result != onekey[ONEKEY_NO]);
                if (result == onekey[ONEKEY_YES])
                {   hero[recruiterhero].luck--;
                    gain(recruiterhero, jarl[recruited].strength / 2, jarl[recruited].strength / 2);
                    jarl[recruited].hero = recruiterhero;
                    return(TRUE);
                } else
                {   // assert(result == onekey[ONEKEY_NO]);
            }   }
            else
            {   // assert(hero[recruiterhero].control == AMIGA);
                hero[recruiterhero].luck--;
                gain(recruiterhero, jarl[recruited].strength / 2, jarl[recruited].strength / 2);
                jarl[recruited].hero = recruiterhero;
                saywho(HERO, recruiterhero, FALSE, FALSE);
                strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_RECRUITS_JARL, "recruits jarl"));
                strcat(saystring, " ");
                strcat(saystring, jarl[recruited].name);
                strcat(saystring, ".");
                say(LOWER);
                anykey();
                return(TRUE);
    }   }   }

    return(FALSE);
}

MODULE SLONG d6(void)
{   return((rand() % 6) + 1);
}

AGLOBAL void cleanexit(SLONG rc)
{   BPTR  FileHandle /* = NULL */ ;
    SLONG whichhero;

    destroycounters();

    if (ASLRqPtr)
    {   FreeAslRequest(ASLRqPtr);
        ASLRqPtr = NULL;
    }
    if (OldWindowPtr)
    {   ProcessPtr->pr_WindowPtr = OldWindowPtr;
    }

    /* It does not matter whether there are outstanding messages for a
    window when it is closed, provided that the window does not use a
    shared IDCMP message port. */

    if (HelpWindowPtr)
    {   CloseWindow(HelpWindowPtr);
        HelpWindowPtr = NULL;
    }
    if (MainWindowPtr)
    {   ClearMenuStrip(MainWindowPtr);
        CloseWindow(MainWindowPtr);
        MainWindowPtr = NULL;
    }
    if (GListPtr)
    {   FreeGadgets(GListPtr);
        GListPtr = NULL;
    }
    if (MenuPtr)
    {   FreeMenus(MenuPtr);
        MenuPtr = NULL;
    }
    if (VisualInfoPtr)
    {   FreeVisualInfo(VisualInfoPtr);
        VisualInfoPtr = NULL;
    }
    if (ScreenPtr)
    {   CloseScreen(ScreenPtr);
        ScreenPtr = NULL;
    }
    if (ASLBase)
    {   CloseLibrary((struct Library *) ASLBase);
        ASLBase = NULL;
    }
    if (GadToolsBase)
    {   CloseLibrary((struct Library *) GadToolsBase);
        GadToolsBase = NULL;
    }
    if (GfxBase)
    {   CloseLibrary((struct Library *) GfxBase);
        GfxBase = NULL;
    }
    if (LocaleBase)
    {   CloseCatalog(li.li_Catalog);
        CloseLibrary((struct Library *) LocaleBase);
        LocaleBase = NULL;
    }
    if (IntuitionBase)
    {   OpenWorkBench();
        CloseLibrary((struct Library *) IntuitionBase);
        IntuitionBase = NULL;
    }
    if (ArgsPtr)
    {   FreeArgs(ArgsPtr);
        ArgsPtr = NULL;
    }

    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {    IOBuffer[whichhero] = (SBYTE) hero[whichhero].control;
    }
    IOBuffer[ 6] = (UBYTE)   (DisplayID     / 16777216);
    IOBuffer[ 7] = (UBYTE)  ((DisplayID     % 16777216) / 65536);
    IOBuffer[ 8] = (UBYTE) (((DisplayID     % 16777216) % 65536) / 256);
    IOBuffer[ 9] = (UBYTE) (((DisplayID     % 16777216) % 65536) % 256);
    IOBuffer[10] = (UBYTE)   (DisplayWidth  / 16777216);
    IOBuffer[11] = (UBYTE)  ((DisplayWidth  % 16777216) / 65536);
    IOBuffer[12] = (UBYTE) (((DisplayWidth  % 16777216) % 65536) / 256);
    IOBuffer[13] = (UBYTE) (((DisplayWidth  % 16777216) % 65536) % 256);
    IOBuffer[14] = (UBYTE)   (DisplayHeight / 16777216);
    IOBuffer[15] = (UBYTE)  ((DisplayHeight % 16777216) / 65536);
    IOBuffer[16] = (UBYTE) (((DisplayHeight % 16777216) % 65536) / 256);
    IOBuffer[17] = (UBYTE) (((DisplayHeight % 16777216) % 65536) % 256);
    IOBuffer[18] = (UBYTE)   (DisplayDepth  / 65536);
    IOBuffer[19] = (UBYTE)   (DisplayDepth  % 65536);
    IOBuffer[20] = (UBYTE)    speed;
    if (FileHandle = Open("PROGDIR:Saga.config", MODE_NEWFILE))
    {   Write(FileHandle, IOBuffer, 21);
        Close(FileHandle);
        // FileHandle = NULL;
    }

    exit(rc); // End of program.
}

MODULE void say(SLONG position)
{   SLONG length;

    length = strlen(saystring);

    SetAPen(MainWindowPtr->RPort, BLACK);
    if (position == UPPER)
    {   RectFill
        (   MainWindowPtr->RPort,
            0,   MESSAGEY,
            639, MESSAGEY + 7
        );
        Move(MainWindowPtr->RPort, 4, MESSAGEY + 6);
    }
    else
    {   // assert(position == LOWER);
        RectFill
        (   MainWindowPtr->RPort,
            0,   MESSAGEY + 10,
            639, MESSAGEY + 27
        );
        Move(MainWindowPtr->RPort, 4, MESSAGEY + 16);
    }

    SetAPen(MainWindowPtr->RPort, WHITE);
    if (position == LOWER && length > 79)
    {   Text(MainWindowPtr->RPort, saystring, 79);
        Move(MainWindowPtr->RPort, 4, MESSAGEY + 26);
        Text(MainWindowPtr->RPort, &saystring[79], length - 79);
    } else
    {   Text(MainWindowPtr->RPort, saystring, length);
}   }

MODULE void newhero(SLONG whichhero, FLAG givesord)
{   SLONG whichjarl, whichsord;

    hero[whichhero].where     =
    hero[whichhero].homewhere = rand() % 36;
    hero[whichhero].glory     =
    hero[whichhero].wealth    = 0;
    hero[whichhero].luck      = 3;
    hero[whichhero].alive     = TRUE;
    hero[whichhero].verydead  =
    hero[whichhero].wounded   =
    hero[whichhero].hagall    =
    hero[whichhero].loseturn  = FALSE;
    hero[whichhero].rune      =
    hero[whichhero].god       = -1;
    hero[whichhero].sea       = NORMAL;
    hero[whichhero].maidens   = 0;
    if (givesord)
    {   hero[whichhero].promoted = -1;
    }

    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
    {   if (jarl[whichjarl].hero == whichhero)
        {   jarl[whichjarl].hero = -1;
    }   }

    deselect_hero(whichhero, FALSE);
    move_hero(whichhero, TRUE);
    // we don't unslot newborn counters

    if (!givesord)
    {   return;
    }
    
    // at least one sword should should always be available
    do
    {   whichsord = rand() % 6;
    } while (sord[whichsord].taken);
    sord[whichsord].taken         = TRUE;
    sord[whichsord].possessortype = HERO;
    sord[whichsord].possessor     = whichhero;
    sord[whichsord].where         = -1;
}

MODULE SLONG getevent(SLONG mode, SLONG* countertype)
{   AUTO    UWORD                code,
                                 qual;
    AUTO    ULONG                class;
    AUTO    struct IntuiMessage* MsgPtr;
    AUTO    LONG                 country;
    AUTO    SLONG                counter,
                                 ticks = 0;
    AUTO    WORD                 mousex, mousey;
    AUTO    struct MenuItem*     ItemPtr;
    PERSIST SLONG                cheat = 0;

    /* return codes:
    -4: Escape
    -3: spacebar
    -2: backspace
    -1: invalid country */

    while(1)
    {   while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
        {   class  = MsgPtr->Class;
            code   = MsgPtr->Code;
            mousex = MsgPtr->MouseX;
            mousey = MsgPtr->MouseY;
            qual   = MsgPtr->Qualifier;
            if (class == IDCMP_MENUVERIFY && code == MENUHOT && mousey >= 0)
            {   code = MENUCANCEL;
                ReplyMsg(MsgPtr);
            } else
            {   GT_ReplyIMsg(MsgPtr); // seems that this doesn't work for menu verify messages
            }
            switch(class)
            {
            case IDCMP_CLOSEWINDOW:
                cleanexit(EXIT_SUCCESS);
            break;
            case IDCMP_REFRESHWINDOW:
                GT_BeginRefresh(MainWindowPtr);
                GT_EndRefresh(MainWindowPtr, TRUE);
            break;
            case IDCMP_MOUSEBUTTONS:
                if ((code == MIDDLEDOWN || code == MENUUP) && !(qual & IEQUALIFIER_REPEAT))
                {   if (mode == KEYBOARD)
                    {   return('0');
                    } elif (mode != ANYKEY || tickwait == -1)
                    {   return(-3);
                }   }
                elif (code == SELECTDOWN && !(qual & IEQUALIFIER_REPEAT))
                {   if (mode == KEYBOARD || (mode == ANYKEY && tickwait == -1))
                    {   if (mousey >= MESSAGEY)
                        {   return('0');
                        } else
                        {   return(-1);
                    }   }
                    elif (mode == COUNTER)
                    {   if (mousey >= MESSAGEY)
                        {   return(-3);
                        }
                        counter = checkcounters(mousex, mousey, countertype);
                        if (counter == -1)
                        {   country = checkcountry(mousex, mousey);
                            *(countertype) = KINGDOM;
                            flash(country);
                            return(country);
                        } else
                        {   return(counter);
                    }   }
                    elif (mode == COUNTRY)
                    {   if (mousey >= MESSAGEY)
                        {   return(-3);
                        }
                        counter = checkcounters(mousex, mousey, countertype);
                        if (counter == -1)
                        {   country = checkcountry(mousex, mousey);
                            *(countertype) = KINGDOM;
                            flash(country);
                            return(country);
                        } else
                        {   if (*(countertype) == HERO)
                            {   flash(hero[counter].where);
                                return(hero[counter].where);
                            } elif (*(countertype) == JARL)
                            {   flash(jarl[counter].where);
                                return(jarl[counter].where);
                            } elif (*(countertype) == MONSTER)
                            {   flash(monster[counter].where);
                                return(monster[counter].where);
                }   }   }   }
            break;
            case IDCMP_INTUITICKS:
                if (mode == ANYKEY && tickwait != -1)
                {   ticks++;
                    if (ticks >= tickwait)
                    {   return(-3);
                }   }
                counter = checkcounters(mousex, mousey, countertype);
                if (counter == -1)
                {   country = checkcountry(mousex, mousey);
                    *(countertype) = KINGDOM;
                    showcountry(country);
                } else
                {   if (*(countertype) == HERO)
                    {   saywho(HERO, counter, FALSE, FALSE);
                        strcat(saystring, "(");
                        stcl_d(numberstring, hero[counter].strength);
                        strcat(saystring, numberstring);
                        strcat(saystring, "-");
                        stcl_d(numberstring, hero[counter].moves);
                        strcat(saystring, numberstring);
                        strcat(saystring, ")");
                        say(UPPER);
                    } elif (*(countertype) == JARL)
                    {   if (jarl[counter].face == FACEDOWN)
                        {   strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_UNKNOWN_JARL, "Unknown jarl"));
                            strcat(saystring, " (?-?)");
                        } else
                        {   saywho(JARL, counter, FALSE, FALSE);
                            strcat(saystring, "(");
                            stcl_d(numberstring, jarl[counter].strength);
                            strcat(saystring, numberstring);
                            strcat(saystring, "-");
                            stcl_d(numberstring, jarl[counter].moves);
                            strcat(saystring, numberstring);
                            strcat(saystring, ")");
                        }
                        say(UPPER);
                    } elif (*(countertype) == MONSTER)
                    {   strcpy(saystring, monstertypes[monster[counter].species]);
                        strcat(saystring, " ");
                        strcat(saystring, monster[counter].name);
                        strcat(saystring, " (");
                        stcl_d(numberstring, monster[counter].strength);
                        strcat(saystring, numberstring);
                        strcat(saystring, "-");
                        stcl_d(numberstring, monster[counter].moves);
                        strcat(saystring, numberstring);
                        strcat(saystring, ")");
                        say(UPPER);
                    } elif (*(countertype) == TREASURE)
                    {   strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_THE, "The"));
                        strcat(saystring, " ");
                        strcat(saystring, treasure[counter].name);
                        strcat(saystring, " ");
                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_TREASURE2, "treasure"));
                        say(UPPER);
                    } elif (*(countertype) == SORD)
                    {   strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_SWORD, "Sword"));
                        strcat(saystring, " ");
                        strcat(saystring, sord[counter].name);
                        say(UPPER);
                }   }
            break;
            case IDCMP_VANILLAKEY:
                if (code == ' ' && (mode != ANYKEY || tickwait == -1))
                {   return(-3);
                } elif (code == 27) // Escape
                {   if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                    {   cleanexit(EXIT_SUCCESS);
                    } elif (mode != ANYKEY || tickwait == -1)
                    {   return(-4);
                }   }
                elif (mode == KEYBOARD || (mode == ANYKEY && tickwait == -1))
                {   code = toupper(code);
                    return((SLONG) code);
                }
                elif (code == 8) // backspace
                {   if (mode != ANYKEY || tickwait == -1)
                    {   return(-2);
                }   }
            break;
            case IDCMP_RAWKEY:
                switch(code)
                {
                case HELP:
                    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                    {   summarywindow();
                    } else
                    {   counter = checkcounters(mousex, mousey, countertype);
                        if (counter == -1)
                        {   country = checkcountry(mousex, mousey);
                            if (country >= 0)
                            {   infowindow(KINGDOM, country);
                            } else
                            {   summarywindow();
                        }   }
                        else
                        {   infowindow(*(countertype), counter);
                    }   }
                break;
                default:
                    if
                    (   (mode == KEYBOARD || (mode == ANYKEY && tickwait == -1))
                     && code < KEYUP && (code < FIRSTQUALIFIER || code > LASTQUALIFIER)
                    )
                    {   if (code == SCAN_F1 + cheat)
                        {   cheat++;
                            if (cheat == 5)
                            {   cheat = 0;
                                hero[BEOWULF].luck = 5000;
                                DisplayBeep(ScreenPtr);
                        }   }
                        else cheat = 0;
                    }
                break;
                }
            break;
            case IDCMP_MENUPICK:
                while (code != MENUNULL)
                {   ItemPtr = ItemAddress(MenuPtr, code);

                    switch (MENUNUM(code))
                    {
                    case MN_PROJECT:
                        switch (ITEMNUM(code))
                        {
                        case IN_NEW:
                            return(-4);
                        case IN_SAVE:
                            savegame(FALSE);
                        break;
                        case IN_SAVEAS:
                            savegame(TRUE);
                        break;
                        case IN_QUIT:
                            cleanexit(EXIT_SUCCESS);
                        break;
                        default:
                            // IN_OPEN
                        break;
                        }
                    break;
                    case MN_HELP:
                        switch(ITEMNUM(code))
                        {
                        case IN_GAME_SUMMARY:
                            summarywindow();
                        break;
                        case IN_ABOUT:
                            helpabout();
                        break;
                        default:
                        break;
                        }
                    break;
                    default:
                    break;
                    }
                    code = ItemPtr->NextSelect;
                }
            break;
            default:
            break;
}   }   }   }

MODULE void showcountry(SLONG country)
{   if (country >= 0 && country <= 65)
    {   strcpy(saystring, world[country].name);
        if (country <= 35)
        {   strcat(saystring, " (");
            stcl_d(numberstring, world[country].tax);
            strcat(saystring, numberstring);
            strcat(saystring, ")");
    }   }
    else
    {   strcpy(saystring, "-");
    }
    say(UPPER);
}

MODULE void phase1(void)
{   SLONG besthero = -1,
          glory,
          whichhero,
          whichjarl,
          whichmonster,
          whichorder;
    FLAG  done;

   /* "1. MOVEMENT. All heroes and jarls move. The hero with the most
        glory and his or her jarls move first. In cases of ties the heroes
        roll dice to see who goes first, with the highest roll going
        first.

        A counter may move as many areas as its movement factor. Each area
        is defined by colour or, in the case of sea areas, by dividing
        lines. Counters may move and remain in sea areas just as if they
        were on land. There is no difference between land movement and sea
        movement." */

    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   hero[whichhero].moved  =
        hero[whichhero].hagall =
        hero[whichhero].routed = FALSE;
    }
    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
    {   jarl[whichjarl].hagall =
        jarl[whichjarl].routed = FALSE;
    }
    for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
    {   monster[whichmonster].hagall = FALSE;
    }

    for (whichorder = 0; whichorder <= HEROES; whichorder++)
    {   glory = -1;
        done = TRUE;
        for (whichhero = 0; whichhero <= HEROES; whichhero++)
        {   if (hero[whichhero].alive && !hero[whichhero].moved)
            {   done = FALSE;
                if
                (   hero[whichhero].glory > glory
                 || (hero[whichhero].glory == glory && !(rand() % 2))
                )
                {   besthero = whichhero;
                    glory    = hero[whichhero].glory;
        }   }   }
        if (done)
        {   order[whichorder] = -1;
        } else
        {   order[whichorder] = besthero;
            hero[besthero].moved = TRUE;
    }   }

    for (whichorder = 0; whichorder <= HEROES; whichorder++)
    {   if (order[whichorder] == -1)
        {   break;
        } else
        {   move(order[whichorder]);
    }   }

    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   hero[whichhero].sea      = NORMAL;
        hero[whichhero].loseturn = FALSE;
    }
    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
    {   jarl[whichjarl].sea      = NORMAL;
        jarl[whichjarl].loseturn = FALSE;
    }
    for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
    {   monster[whichmonster].sea      = NORMAL;
}   }

MODULE void phase2(void)
{   SLONG whichorder;

    /* "2. COMBAT AND JARLS. Combat occurs in the same sequence as
        movement; jarls are recruited after combat.

        Heroes *must* attack at least one monster (if there is a monster)
        in the area they are in during the combat portion of the turn. If
        there is more than one monster they may choose which one they wish
        to fight. They may attack more than one monster in an area." */

    for (whichorder = 0; whichorder <= HEROES; whichorder++)
    {   if (order[whichorder] == -1)
        {   break;
        } else
        {   attack(order[whichorder]);
}   }   }

MODULE void attack(SLONG whichhero)
{   SLONG attackers,
          countertype = -1,
          country     = -1,
          totalstrength,
          weakestmonster,
          weakeststrength,
          whichattack,
          whichcountry,
          whichjarl,
          whichmonster,
          whichmonster2,
          whichrivalhero;
    FLAG  must        = FALSE;

    if (hero[whichhero].alive)
    {   for (whichattack = 0; whichattack <= ATTACKS; whichattack++)
        {   hero[whichhero].attacked[whichattack]   = -1;
            hero[whichhero].attacktype[whichattack] = -1;
        }
        for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
        {   if (jarl[whichjarl].alive && jarl[whichjarl].hero == whichhero)
            {   for (whichattack = 0; whichattack <= ATTACKS; whichattack++)
                {   jarl[whichjarl].attacked[whichattack]   = -1;
                    jarl[whichjarl].attacktype[whichattack] = -1;
        }   }   }

        for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
        {   if (monster[whichmonster].alive && monster[whichmonster].where == hero[whichhero].where)
            {   must = TRUE;
                weakeststrength = 99;
                for (whichmonster2 = 0; whichmonster2 <= MONSTERS; whichmonster2++)
                {   if (monster[whichmonster2].alive && monster[whichmonster2].where == hero[whichhero].where && monster[whichmonster2].strength < weakeststrength)
                    {   weakeststrength = monster[whichmonster2].strength;
                        weakestmonster  = whichmonster2;
                }   }
                break;
        }   }

        if (hero[whichhero].control == HUMAN)
        {   while(1)
            {   saywho(HERO, whichhero, TRUE, FALSE);
                strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_SELECT_ATTACKERS, "select attackers"));
                strcat(saystring, "?");
                say(LOWER);
                country = getevent(COUNTRY, &countertype);

                if (country >= 0)
                {   if (hero[whichhero].alive && hero[whichhero].where == country && !hero[whichhero].routed)
                    {   attackers = 1;
                        select_hero(whichhero, FALSE);
                        hero[whichhero].attacking = TRUE;
                    } else
                    {   attackers = 0;
                    }
                    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
                    {   if (jarl[whichjarl].alive && jarl[whichjarl].where == country && !jarl[whichjarl].routed && jarl[whichjarl].hero == whichhero)
                        {   attackers++;
                            select_jarl(whichjarl, FALSE);
                            jarl[whichjarl].attacking = TRUE;
                    }   }
                    if (attackers)
                    {   refreshcounters();
                        getdefender(whichhero, country);
                }   }
                elif (country == -3)
                {   if (must && hero[whichhero].alive && !hero[whichhero].routed)
                    {   // check whether the hero has fought a monster
                        for (whichattack = 0; whichattack <= ATTACKS; whichattack++)
                        {   if (hero[whichhero].attacktype[whichattack] == MONSTER)
                            {   return;
                        }   }
                        saywho(HERO, whichhero, TRUE, FALSE);
                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_YOU_MUST_FIGHT_A_MONSTER, "you must fight a monster"));
                        strcat(saystring, ".");
                        say(LOWER);
                        anykey();
                    } else
                    {   if (hero[whichhero].attacking)
                        {   deselect_hero(whichhero, FALSE);
                        }
                        for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
                        {   if (jarl[whichjarl].alive && jarl[whichjarl].attacking)
                            {   deselect_jarl(whichjarl, FALSE);
                        }   }
                        refreshcounters();
                        return;
        }   }   }   }
        elif (hero[whichhero].control == AMIGA)
        {   for (whichcountry = 0; whichcountry <= 65; whichcountry++)
            {   // check for possible enemies

                if (!(totalstrength = getattackers(whichhero, whichcountry)))
                {   continue;
                }
                for (whichrivalhero = 0; whichrivalhero <= HEROES; whichrivalhero++)
                {   if (whichhero != whichrivalhero && hero[whichrivalhero].alive && hero[whichrivalhero].where == whichcountry && totalstrength > hero[whichhero].strength + 3)
                    {   amiga_attack(whichhero, HERO, whichrivalhero);
                }   }

                if (!(totalstrength = getattackers(whichhero, whichcountry)))
                {   continue;
                }
                for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
                {   if (jarl[whichjarl].alive && jarl[whichjarl].hero != whichhero && jarl[whichjarl].where == whichcountry && (jarl[whichjarl].face == FACEDOWN || totalstrength > jarl[whichjarl].strength + 3))
                    {    amiga_attack(whichhero, JARL, whichjarl);
                }   }

                if (!(totalstrength = getattackers(whichhero, whichcountry)))
                {   continue;
                }
                for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
                {   if
                    (   monster[whichmonster].alive
                     && monster[whichmonster].where == whichcountry
                     && (   (must && weakestmonster == whichmonster)
                         || totalstrength > monster[whichmonster].strength + 1
                    )   )
                    {   amiga_attack(whichhero, MONSTER, whichmonster);
                }   }

                if (!(totalstrength = getattackers(whichhero, whichcountry)))
                {   continue;
                }
                if (whichcountry <= 35 && world[whichcountry].hero != whichhero && !world[whichcountry].is && totalstrength > world[whichcountry].tax + 2)
                {   amiga_attack(whichhero, KINGDOM, whichcountry);
}   }   }   }   }

MODULE void newgame(void)
{   SLONG whichhero, whichjarl, whichmonster, whichcountry, whichslot,
          whichtreasure, whichsord;

    OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_NEW,    NOSUB));
    OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_OPEN,   NOSUB));
    OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVE,   NOSUB));
    OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVEAS, NOSUB));
     OnMenu(MainWindowPtr, FULLMENUNUM(MN_HELP,    IN_GAME_SUMMARY, NOSUB));

    pathname[0] = 0;

    /* 0. SET UP

    "Divide the counters into four piles, keeping the heroes separate.
    The four piles, all face down, should be: monsters of all sorts,
    jarls, magic weapons [(swords)], and magic treasures.

    Each player picks a hero counter to represent him or her in the game.
    Players roll dice if two or more people want the same counter, and
    high roll chooses first." */

    reset_images();
    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   hero[whichhero].strength  = HERO_STRENGTH;
        hero[whichhero].moves     = HERO_MOVES;
        hero[whichhero].name      = trueheroname[whichhero];
        hero[whichhero].attacking =
        hero[whichhero].defending =
        hero[whichhero].alive     = FALSE;
        hero[whichhero].verydead  = TRUE;
        hero[whichhero].glory     =
        hero[whichhero].luck      =
        hero[whichhero].wealth    = 0;
        hero[whichhero].rune      = -1;
        remove_hero(whichhero, FALSE);
    }
    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
    {   jarl[whichjarl].hero      = -1;
        jarl[whichjarl].wealth    = 0;
        jarl[whichjarl].attacking =
        jarl[whichjarl].defending =
        jarl[whichjarl].alive     =
        jarl[whichjarl].taken     = FALSE;
        remove_jarl(whichjarl, FALSE);
    }
    for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
    {   monster[whichmonster].alive = FALSE;
        monster[whichmonster].taken = FALSE;
        remove_monster(whichmonster, FALSE);
    }
    for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
    {   remove_treasure(whichtreasure, FALSE);
        treasure[whichtreasure].taken         = FALSE;
        treasure[whichtreasure].possessor     =
        treasure[whichtreasure].possessortype =
        treasure[whichtreasure].where         = -1;
    }
    for (whichsord = 0; whichsord <= SORDS; whichsord++)
    {   remove_sord(whichsord, FALSE);
        sord[whichsord].taken         = FALSE;
        sord[whichsord].possessor     =
        sord[whichsord].possessortype =
        sord[whichsord].where         = -1;
    }

    for (whichcountry = 0; whichcountry <= 65; whichcountry++)
    {   world[whichcountry].hero = -1;
        world[whichcountry].is   = FALSE;
        for (whichslot = 0; whichslot <= SLOTS; whichslot++)
        {   world[whichcountry].slot[whichslot] = FALSE;
    }   }

    SetAPen(MainWindowPtr->RPort, BLACK);
    RectFill(MainWindowPtr->RPort, 0, 0, SCREENXPIXEL, SCREENYPIXEL);
    darken();
    drawmap();

    /* "Each player then picks a magic sword at random from the face-down
    pile. Magic swords will not be given out again in the game and so all
    of the left-over magic swords are put aside until the next game." */

    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   if (hero[whichhero].control != NONE)
        {   /* "Heroes begin the game in a randomly determined area (found in the
            same manner as monsters are placed). This area should be noted on the
            record sheet, as it is sometimes necessary to know a hero's home
            country." */
            newhero(whichhero, TRUE);
    }   }

    place_monsters();
    place_jarls();
    refreshcounters();

    turn = 1;
    faxirides = 3;
}

MODULE void clearkybd(void)
{   struct IntuiMessage* MsgPtr;

    while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
        GT_ReplyIMsg(MsgPtr);
}

MODULE void titlescreen(void)
{   AUTO    FLAG                 done;
    AUTO    SLONG                whichhero;
    AUTO    struct IntuiMessage* MsgPtr;
    AUTO    ULONG                class;
    AUTO    UWORD                code, qual;
    AUTO    struct Gadget*       addr;
    AUTO    struct MenuItem*     ItemPtr;

    loaded   =
    gameover = FALSE;

     OnMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_NEW,    NOSUB));
     OnMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_OPEN,   NOSUB));
    OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVE,   NOSUB));
    OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVEAS, NOSUB));
    OffMenu(MainWindowPtr, FULLMENUNUM(MN_HELP,    IN_GAME_SUMMARY, NOSUB));

    SetAPen(MainWindowPtr->RPort, BLACK);
    RectFill(MainWindowPtr->RPort, 0, 0, SCREENXPIXEL, SCREENYPIXEL);
    drawlogo();

    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   GT_SetGadgetAttrs(CycleGadgetPtr[whichhero], MainWindowPtr, NULL, GA_Disabled, FALSE, TAG_DONE);
    }
    GT_SetGadgetAttrs(SpeedGadgetPtr, MainWindowPtr, NULL, GA_Disabled, FALSE, TAG_DONE);
    RefreshGadgets(SpeedGadgetPtr, MainWindowPtr, NULL);
    if (speed == 2)
    {   GT_SetGadgetAttrs(SpeedGadgetPtr, MainWindowPtr, NULL, GTSL_Level, 0, TAG_DONE); // kludgy
    } else
    {   GT_SetGadgetAttrs(SpeedGadgetPtr, MainWindowPtr, NULL, GTSL_Level, 4 - speed, TAG_DONE); // kludgy
    }
    GT_SetGadgetAttrs(SpeedGadgetPtr, MainWindowPtr, NULL, GTSL_Level, speed, TAG_DONE); // kludgy

    SetAPen(MainWindowPtr->RPort, WHITE);
    SetDrMd(MainWindowPtr->RPort, JAM1);
    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   Move(MainWindowPtr->RPort, 212, 208 + (whichhero * 16)    );
        Text(MainWindowPtr->RPort, cycleheroname[whichhero], 10);
        Move(MainWindowPtr->RPort, 212 + (cycleheropos[whichhero] * 8), 208 + (whichhero * 16) + 1);
        Text(MainWindowPtr->RPort, "_", 1);
    }
    if (cliload)
    {   if (loadgame(FALSE))
        {   loaded = TRUE;
        } else
        {   cliload = FALSE;
    }   }

    if (!cliload)
    {   done = FALSE;
        do
        {   while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
            {   addr  = (struct Gadget *) MsgPtr->IAddress;
                class = MsgPtr->Class;
                code  = MsgPtr->Code;
                qual  = MsgPtr->Qualifier;
                GT_ReplyIMsg(MsgPtr);
                switch (class)
                {
                case IDCMP_RAWKEY:
                    if (!(qual & IEQUALIFIER_REPEAT))
                    {   switch (code)
                        {
                        case SCAN_F1:
                            if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                            {   if (hero[0].control == 0)
                                {   hero[0].control = 2;
                                } else
                                {   hero[0].control--;
                            }   }
                            else
                            {   if (hero[0].control == 2)
                                {   hero[0].control = 0;
                                } else
                                {   hero[0].control++;
                            }   }
                            GT_SetGadgetAttrs(CycleGadgetPtr[0], MainWindowPtr, NULL, GTCY_Active, hero[0].control, TAG_DONE);
                        break;
                        case SCAN_F2:
                            if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                            {   if (hero[1].control == 0)
                                {   hero[1].control = 2;
                                } else
                                {   hero[1].control--;
                            }   }
                            else
                            {   if (hero[1].control == 2)
                                {   hero[1].control = 0;
                                } else
                                {   hero[1].control++;
                            }   }
                            GT_SetGadgetAttrs(CycleGadgetPtr[1], MainWindowPtr, NULL, GTCY_Active, hero[1].control, TAG_DONE);
                        break;
                        case SCAN_F3:
                            if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                            {   if (hero[2].control == 0)
                                {   hero[2].control = 2;
                                } else
                                {   hero[2].control--;
                            }   }
                            else
                            {   if (hero[2].control == 2)
                                {   hero[2].control = 0;
                                } else
                                {   hero[2].control++;
                            }   }
                            GT_SetGadgetAttrs(CycleGadgetPtr[2], MainWindowPtr, NULL, GTCY_Active, hero[2].control, TAG_DONE);
                        break;
                        case SCAN_F4:
                            if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                            {   if (hero[3].control == 0)
                                {   hero[3].control = 2;
                                } else
                                {   hero[3].control--;
                            }   }
                            else
                            {   if (hero[3].control == 2)
                                {   hero[3].control = 0;
                                } else
                                {   hero[3].control++;
                            }   }
                            GT_SetGadgetAttrs(CycleGadgetPtr[3], MainWindowPtr, NULL, GTCY_Active, hero[3].control, TAG_DONE);
                        break;
                        case SCAN_F5:
                            if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                            {   if (hero[4].control == 0)
                                {   hero[4].control = 2;
                                } else
                                {   hero[4].control--;
                            }   }
                            else
                            {   if (hero[4].control == 2)
                                {   hero[4].control = 0;
                                } else
                                {   hero[4].control++;
                            }   }
                            GT_SetGadgetAttrs(CycleGadgetPtr[4], MainWindowPtr, NULL, GTCY_Active, hero[4].control, TAG_DONE);
                        break;
                        case SCAN_F6:
                            if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                            {   if (hero[5].control == 0)
                                {   hero[5].control = 2;
                                } else
                                {   hero[5].control--;
                            }   }
                            else
                            {   if (hero[5].control == 2)
                                {   hero[5].control = 0;
                                } else
                                {   hero[5].control++;
                            }   }
                            GT_SetGadgetAttrs(CycleGadgetPtr[5], MainWindowPtr, NULL, GTCY_Active, hero[5].control, TAG_DONE);
                        break;
                        case HELP:
                            helpabout();
                        break;
                        default:
                        break;
                    }   }
                break;
                case IDCMP_VANILLAKEY:
                    code = toupper(code);
                    switch(code)
                    {
                    case ' ':
                    case 13: // Return or Enter
                        done = TRUE;
                    break;
                    case 27: // Escape
                        cleanexit(EXIT_SUCCESS);
                    break;
                    case '1':
                    case 'B':
                        if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                        {   if (hero[0].control == 0)
                            {   hero[0].control = 2;
                            } else
                            {   hero[0].control--;
                        }   }
                        else
                        {   if (hero[0].control == 2)
                            {   hero[0].control = 0;
                            } else
                            {   hero[0].control++;
                        }   }
                        GT_SetGadgetAttrs(CycleGadgetPtr[0], MainWindowPtr, NULL, GTCY_Active, hero[0].control, TAG_DONE);
                    break;
                    case '!':
                        if (hero[0].control == 0)
                        {   hero[0].control = 2;
                        } else
                        {   hero[0].control--;
                        }
                        GT_SetGadgetAttrs(CycleGadgetPtr[0], MainWindowPtr, NULL, GTCY_Active, hero[0].control, TAG_DONE);
                    break;
                    case '2':
                    case 'U':
                        if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                        {   if (hero[1].control == 0)
                            {   hero[1].control = 2;
                            } else
                            {   hero[1].control--;
                        }   }
                        else
                        {   if (hero[1].control == 2)
                            {   hero[1].control = 0;
                            } else
                            {   hero[1].control++;
                        }   }
                        GT_SetGadgetAttrs(CycleGadgetPtr[1], MainWindowPtr, NULL, GTCY_Active, hero[1].control, TAG_DONE);
                    break;
                    case '@':
                        if (hero[1].control == 0)
                        {   hero[1].control = 2;
                        } else
                        {   hero[1].control--;
                        }
                        GT_SetGadgetAttrs(CycleGadgetPtr[1], MainWindowPtr, NULL, GTCY_Active, hero[1].control, TAG_DONE);
                    break;
                    case '3':
                    case 'E':
                        if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                        {   if (hero[2].control == 0)
                            {   hero[2].control = 2;
                            } else
                            {   hero[2].control--;
                        }   }
                        else
                        {   if (hero[2].control == 2)
                            {   hero[2].control = 0;
                            } else
                            {   hero[2].control++;
                        }   }
                        GT_SetGadgetAttrs(CycleGadgetPtr[2], MainWindowPtr, NULL, GTCY_Active, hero[2].control, TAG_DONE);
                    break;
                    case '#':
                        if (hero[2].control == 0)
                        {   hero[2].control = 2;
                        } else
                        {   hero[2].control--;
                        }
                        GT_SetGadgetAttrs(CycleGadgetPtr[2], MainWindowPtr, NULL, GTCY_Active, hero[2].control, TAG_DONE);
                    break;
                    case '4':
                    case 'R':
                        if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                        {   if (hero[3].control == 0)
                            {   hero[3].control = 2;
                            } else
                            {   hero[3].control--;
                        }   }
                        else
                        {   if (hero[3].control == 2)
                            {   hero[3].control = 0;
                            } else
                            {   hero[3].control++;
                        }   }
                        GT_SetGadgetAttrs(CycleGadgetPtr[3], MainWindowPtr, NULL, GTCY_Active, hero[3].control, TAG_DONE);
                    break;
                    case '$':
                        if (hero[3].control == 0)
                        {   hero[3].control = 2;
                        } else
                        {   hero[3].control--;
                        }
                        GT_SetGadgetAttrs(CycleGadgetPtr[3], MainWindowPtr, NULL, GTCY_Active, hero[3].control, TAG_DONE);
                    break;
                    case '5':
                    case 'S':
                        if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                        {   if (hero[4].control == 0)
                            {   hero[4].control = 2;
                            } else
                            {   hero[4].control--;
                        }   }
                        else
                        {   if (hero[4].control == 2)
                            {   hero[4].control = 0;
                            } else
                            {   hero[4].control++;
                        }   }
                        GT_SetGadgetAttrs(CycleGadgetPtr[4], MainWindowPtr, NULL, GTCY_Active, hero[4].control, TAG_DONE);
                    break;
                    case '%':
                        if (hero[4].control == 0)
                        {   hero[4].control = 2;
                        } else
                        {   hero[4].control--;
                        }
                        GT_SetGadgetAttrs(CycleGadgetPtr[4], MainWindowPtr, NULL, GTCY_Active, hero[4].control, TAG_DONE);
                    break;
                    case '6':
                    case 'T':
                        if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                        {   if (hero[5].control == 0)
                            {   hero[5].control = 2;
                            } else
                            {   hero[5].control--;
                        }   }
                        else
                        {   if (hero[5].control == 2)
                            {   hero[5].control = 0;
                            } else
                            {   hero[5].control++;
                        }   }
                        GT_SetGadgetAttrs(CycleGadgetPtr[5], MainWindowPtr, NULL, GTCY_Active, hero[5].control, TAG_DONE);
                    break;
                    case '^':
                        if (hero[5].control == 0)
                        {   hero[5].control = 2;
                        } else
                        {   hero[5].control--;
                        }
                        GT_SetGadgetAttrs(CycleGadgetPtr[5], MainWindowPtr, NULL, GTCY_Active, hero[5].control, TAG_DONE);
                    break;
                    default:
                    break;
                    }
                break;
                case IDCMP_MENUPICK:
                    while (code != MENUNULL)
                    {   ItemPtr = ItemAddress(MenuPtr, code);
    
                        switch (MENUNUM(code))
                        {
                        case MN_PROJECT:
                            switch (ITEMNUM(code))
                            {
                            case IN_NEW:
                                done = TRUE;
                            break;
                            case IN_OPEN:
                                if (loadgame(TRUE))
                                {   done = TRUE;
                                    loaded = TRUE;
                                }
                            break;
                            case IN_QUIT:
                                cleanexit(EXIT_SUCCESS);
                            break;
                            default:
                                // IN_SAVE, IN_SAVEAS
                            break;
                            }
                        break;
                        case MN_HELP:
                            switch(ITEMNUM(code))
                            {
                            case IN_ABOUT:
                                helpabout();
                            break;
                            default:
                            break;
                            }
                        break;
                        default:
                        break;
                        }
                        code = ItemPtr->NextSelect;
                    }
                break;
                case IDCMP_MOUSEBUTTONS:
                    if (code == SELECTDOWN && !(qual & IEQUALIFIER_REPEAT))
                    {   done = TRUE;
                    }
                break;
                case IDCMP_REFRESHWINDOW:
                    GT_BeginRefresh(MainWindowPtr);
                    GT_EndRefresh(MainWindowPtr, TRUE);
                break;
                case IDCMP_GADGETUP:
                    if (addr == SpeedGadgetPtr)
                    {   speed = code;
                    } else
                    {   for (whichhero = 0; whichhero <= HEROES; whichhero++)
                        {   if (addr == CycleGadgetPtr[whichhero])
                            {   hero[whichhero].control = code;
                                break;
                    }   }   }
                break;
                case IDCMP_CLOSEWINDOW:
                    cleanexit(EXIT_SUCCESS);
                break;
                default:
                    ; /* IDCMP_INTUITICKS */
                break;
            }   }
            if (done)
            {   done = FALSE;
                for (whichhero = 0; whichhero <= HEROES; whichhero++)
                {   if (hero[whichhero].control != NONE)
                    {   done = TRUE;
                        break;
                }   }
                if (!done)
                {   ; // DisplayBeep(ScreenPtr); // no heroes active
            }   }
        } while (!done);
    }

    cliload = FALSE;
    if (!loaded)
    {   for (whichhero = 0; whichhero <= HEROES; whichhero++)
        {   GT_SetGadgetAttrs(CycleGadgetPtr[whichhero], MainWindowPtr, NULL, GA_Disabled, TRUE, TAG_DONE);
        }
        GT_SetGadgetAttrs(SpeedGadgetPtr, MainWindowPtr, NULL, GA_Disabled, TRUE, TAG_DONE);
    }

    if (speed == 4)
    {   tickwait = -1;
    } else
    {   tickwait = speed * 8;
}   }

MODULE void gain(SLONG whichhero, SLONG glory, SLONG luck)
{   SLONG result;

    if (glory == 0 && luck == 0)
    {   return;
    }

    if (hero[whichhero].control == HUMAN)
    {   saywho(HERO, whichhero, TRUE, FALSE);
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_GAIN, "gain"));
        strcat(saystring, " ");
        stcl_d(numberstring, glory);
        strcat(saystring, numberstring);
        strcat(saystring, " (");
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_CHAR_GLORY, "G"));
        strcat(saystring, ")");
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_UNCHAR_GLORY, "lory"));
        strcat(saystring, " ");
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_OR, "or"));
        strcat(saystring, " ");
        stcl_d(numberstring, luck);
        strcat(saystring, numberstring);
        strcat(saystring, " (");
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_CHAR_LUCK, "L"));
        strcat(saystring, ")");
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_UNCHAR_LUCK, "uck"));
        strcat(saystring, "?");
        say(LOWER);
        do
        {   result = getevent(KEYBOARD, NULL);
        } while (result != onekey[ONEKEY_GLORY] && result != onekey[ONEKEY_LUCK]);
        if (result == onekey[ONEKEY_GLORY])
        {   hero[whichhero].glory += glory;
        } else
        {   // assert(result == onekey[ONEKEY_LUCK]);
            hero[whichhero].luck  += luck;
    }   }
    else
    {   hero[whichhero].luck += luck;
}   }

MODULE void move(SLONG whichhero)
{   SLONG country,
          decision,
          freemove,
          i,
          movearray[66],
          moves,
          oldcountry,
          stop,
          whichconnection,
          whichjarl,
          whichmove = -1,
          whichrealmove,
          whichtreasure,
          whichsord;
    FLAG  legal;

// HEROES

    if (hero[whichhero].alive)
    {   select_hero(whichhero, TRUE);
        moves = getmoves(HERO, whichhero, FALSE);

        if (hero[whichhero].control == HUMAN)
        {   if
            (   treasure[FREYFAXI].possessortype == HERO
             && treasure[FREYFAXI].possessor     == whichhero
            )
            {   // assert(treasure[FREYFAXI].where == -1);
                // assert(faxirides >= 1);

                if (ask_faxi(HERO, whichhero))
                {   moves = getmoves(HERO, whichhero, TRUE);
            }   }

            movearray[0] = hero[whichhero].where;
            whichrealmove = 1;
            if (moves >= 1)
            {   oldcountry = hero[whichhero].where;
                whichmove     =
                whichrealmove = 1;
                freemove = FALSE;
                do
                {   saywho(HERO, whichhero, FALSE, FALSE);
                    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_IN, "in"));
                    strcat(saystring, " ");
                    strcat(saystring, world[hero[whichhero].where].name);
                    strcat(saystring, ", ");
                    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_MOVE, "move"));
                    strcat(saystring, " ");
                    stcl_d(numberstring, whichmove);
                    strcat(saystring, numberstring);
                    strcat(saystring, " ");
                    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_OF, "of"));
                    strcat(saystring, " ");
                    stcl_d(numberstring, moves);
                    strcat(saystring, numberstring);
                    strcat(saystring, "?");
                    say(LOWER);
                    do
                    {   country = getevent(COUNTRY, NULL);
                    } while ((country < -3 || country > 65) || country == -1);
                    if (country == -3)
                    {   break;
                    } elif (country == -2)
                    {   whichmove     =
                        whichrealmove = 1;
                        unslot_hero(whichhero);
                        hero[whichhero].where = oldcountry;
                        move_hero(whichhero, TRUE);
                        freemove = FALSE;
                    } else
                    {   legal = FALSE;
                        for (whichconnection = 0; whichconnection <= CONNECTIONS; whichconnection++)
                        {   if (world[hero[whichhero].where].connection[whichconnection] == country)
                            {   legal = TRUE;
                                break; // for speed
                        }   }
                        if (legal)
                        {   if
                            (   hero[whichhero].sea == BAD
                             && (   world[country].type == SEA
                                 || world[country].type == ISLE
                            )   )
                            {   legal = FALSE;
                                saywho(HERO, whichhero, FALSE, FALSE);
                                strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_M_N_T_B_S_T_T, "may not travel by sea this turn"));
                                strcat(saystring, ".");
                                say(LOWER);
                                anykey();
                        }   }
                        if (legal)
                        {   unslot_hero(whichhero);
                            hero[whichhero].where = country;
                            move_hero(whichhero, TRUE);
                            if (whichrealmove <= 65)
                            {    movearray[whichrealmove++] = country;
                            }
                            if (hero[whichhero].sea == GOOD)
                            {   if (!freemove)
                                {   if
                                    (   world[hero[whichhero].where].type == SEA
                                     || world[hero[whichhero].where].type == ISLE
                                    )
                                    {   freemove = TRUE;
                                    }
                                    whichmove++;
                                } else
                                {   if
                                    (   world[hero[whichhero].where].type == LAND
                                    )
                                    {   freemove = FALSE;
                                        whichmove++;
                            }   }   }
                            else
                            {   whichmove++;
                        }   }
                        else
                        {   ; // DisplayBeep(ScreenPtr);
                    }   }
                } while (whichmove <= moves);
            }

/* We ask instead of automatically taking because theoretically a hero
might want to pass on the opportunity, so he can allow one of his jarls
in the same square to take the treasure. */

            for (i = 0; i < whichrealmove; i++)
            {   for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
                {   if (movearray[i] == jarl[whichjarl].where && jarl[whichjarl].hero == whichhero)
                    {   // hero moved past jarl during move
                        hero[whichhero].wealth += jarl[whichjarl].wealth;
                        jarl[whichjarl].wealth = 0;
            }   }   }

            for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
            {   if (treasure[whichtreasure].possessortype == KINGDOM && treasure[whichtreasure].where == hero[whichhero].where)
                {   // assert(treasure[whichtreasure].possessor = -1);

                    asktreasure(HERO, whichhero, whichtreasure);
            }   }

            if (needsord(HERO, whichhero))
            {   for (whichsord = 0; whichsord <= SORDS; whichsord++)
                {   if (sord[whichsord].possessortype == KINGDOM && sord[whichsord].where == hero[whichhero].where)
                    {   // assert(sord[whichsord].possessor = -1);
                        if (asksord(HERO, whichhero, whichsord))
                        {   break;
            }   }   }   }

            if
            (   treasure[BROSUNGNECKLACE].possessortype == HERO
             && treasure[BROSUNGNECKLACE].possessor == whichhero
            )
            {   brosung(HERO, whichhero);
        }   }
        else
        {   // assert(hero[whichhero].control == AMIGA);

            movearray[0] = hero[whichhero].where;
            whichrealmove = 1;
            if (moves >= 1)
            {   saywho(HERO, whichhero, FALSE, FALSE);
                strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_IS_MOVING, "is moving"));
                strcat(saystring, "...");
                say(LOWER);
                freemove = FALSE;

                if
                (   hero[whichhero].wounded
                 && (   hero[whichhero].rune == ING
                     || hero[whichhero].where == hero[whichhero].homewhere
                )   )
                {   stop = TRUE;
                } else
                {   stop = assess(HERO, hero[whichhero].where);
                }

                for (whichmove = 1; whichmove <= moves; whichmove++)
                {   if (!stop)
                    {   stop = assess(HERO, whichhero);
                    }
                    if (stop)
                    {   break;
                    }

                    do
                    {   decision = rand() % (CONNECTIONS + 1);
                    } while (world[hero[whichhero].where].connection[decision] == -1);

                    if
                    (   hero[whichhero].sea == BAD
                     && (   world[world[hero[whichhero].where].connection[decision]].type == SEA
                         || world[world[hero[whichhero].where].connection[decision]].type == ISLE
                    )   )
                    {   whichmove--;
                    } else
                    {   unslot_hero(whichhero);
                        hero[whichhero].where = world[hero[whichhero].where].connection[decision];
                        move_hero(whichhero, TRUE);
                        if (whichrealmove <= 65)
                        {   movearray[whichrealmove++] = hero[whichhero].where;
                        }

                        if (hero[whichhero].sea == GOOD)
                        {   if (!freemove)
                            {   if
                                (   world[hero[whichhero].where].type == SEA
                                 || world[hero[whichhero].where].type == ISLE
                                )
                                {   freemove = TRUE;
                            }   }
                            else
                            {   if
                                (   world[hero[whichhero].where].type == LAND
                                )
                                {   freemove = FALSE;
                                } else
                                {   whichmove--;
            }   }   }   }   }   }

            for (i = 0; i < whichrealmove; i++)
            {   for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
                {   if (movearray[i] == jarl[whichjarl].where && jarl[whichjarl].hero == whichhero)
                    {   // hero moved past jarl during move
                        hero[whichhero].wealth += jarl[whichjarl].wealth;
                        jarl[whichjarl].wealth = 0;
            }   }   }

            // Amiga always takes whatever it can.
            for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
            {   if (treasure[whichtreasure].possessortype == KINGDOM && treasure[whichtreasure].where == hero[whichhero].where)
                {   // assert(treasure[whichtreasure].possessor = -1);

                    remove_treasure(whichtreasure, TRUE);
                    treasure[whichtreasure].possessortype = HERO;
                    treasure[whichtreasure].possessor     = whichhero;
                    treasure[whichtreasure].where         = -1;

                    saywho(HERO, whichhero, FALSE, FALSE);
                    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_TAKES_THE, "takes the"));
                    strcat(saystring, " ");
                    strcat(saystring, treasure[whichtreasure].name);
                    strcat(saystring, ".");
                    say(LOWER);
                    anykey();
            }   }

            if (needsord(HERO, whichhero))
            {   for (whichsord = 0; whichsord <= SORDS; whichsord++)
                {   if (sord[whichsord].possessortype == KINGDOM && sord[whichsord].where == hero[whichhero].where)
                    {   // assert(sord[whichsord].possessor = -1);

                        remove_sord(whichsord, TRUE);
                        sord[whichsord].possessortype = HERO;
                        sord[whichsord].possessor     = whichhero;
                        sord[whichsord].where         = -1;

                        saywho(HERO, whichhero, FALSE, FALSE);
                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_TAKES_SWORD, "takes sword"));
                        strcat(saystring, " ");
                        strcat(saystring, sord[whichsord].name);
                        strcat(saystring, ".");
                        say(LOWER);
                        anykey();

                        break;
        }   }   }   }

        // check healing

        if
        (   whichmove == 1
         && hero[whichhero].wounded
         && (   hero[whichhero].where == hero[whichhero].homewhere
             || hero[whichhero].rune == ING
        )   )
        {   hero[whichhero].wounded = FALSE;
            saywho(HERO, whichhero, FALSE, FALSE);
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_HEALS, "heals"));
            strcat(saystring, ".");
            say(LOWER);
            anykey();
        }
        deselect_hero(whichhero, TRUE);

        // JARLS

        for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
        {   if (jarl[whichjarl].alive && jarl[whichjarl].hero == whichhero)
            {   select_jarl(whichjarl, TRUE);
                moves = getmoves(JARL, whichjarl, FALSE);
                if (hero[whichhero].control == HUMAN)
                {   if
                    (   treasure[FREYFAXI].possessortype == JARL
                     && treasure[FREYFAXI].possessor     == whichjarl
                    )
                    {   // assert(treasure[FREYFAXI].where == -1);
                        // assert(faxirides >= 1);

                        if (ask_faxi(JARL, whichjarl))
                        {   moves = getmoves(JARL, whichjarl, TRUE);
                    }   }

                    movearray[0] = jarl[whichjarl].where;
                    whichmove = 1;
                    if (moves >= 1)
                    {   oldcountry = jarl[whichjarl].where;
                        do
                        {   saywho(JARL, whichjarl, FALSE, FALSE);
                            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_IN, "in"));
                            strcat(saystring, " ");
                            strcat(saystring, world[jarl[whichjarl].where].name);
                            strcat(saystring, ", ");
                            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_MOVE, "move"));
                            strcat(saystring, " ");
                            stcl_d(numberstring, whichmove);
                            strcat(saystring, numberstring);
                            strcat(saystring, " ");
                            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_OF, "of"));
                            strcat(saystring, " ");
                            stcl_d(numberstring, moves);
                            strcat(saystring, numberstring);
                            strcat(saystring, "?");
                            say(LOWER);
                            do
                            {   country = getevent(COUNTRY, NULL);
                            } while ((country < -3 || country > 65) || country == -1);
                            if (country == -3)
                            {   break;
                            } elif (country == -2)
                            {   whichmove = 1;
                                unslot_jarl(whichjarl);
                                jarl[whichjarl].where = oldcountry;
                                move_jarl(whichjarl, TRUE);
                            } else
                            {   legal = FALSE;
                                for (whichconnection = 0; whichconnection <= CONNECTIONS; whichconnection++)
                                {   if (world[jarl[whichjarl].where].connection[whichconnection] == country)
                                    {   legal = TRUE;
                                        break; // for speed
                                }   }
                                if (legal)
                                {   if
                                    (   jarl[whichjarl].sea == BAD
                                     && (   world[country].type == SEA
                                         || world[country].type == ISLE
                                    )   )
                                    {   legal = FALSE;
                                        saywho(JARL, whichjarl, FALSE, FALSE);
                                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_M_N_T_B_S_T_T, "may not travel by sea this turn"));
                                        strcat(saystring, ".");
                                        say(LOWER);
                                        anykey();
                                }   }
                                if (legal)
                                {   unslot_jarl(whichjarl);
                                    jarl[whichjarl].where = country;
                                    move_jarl(whichjarl, TRUE);
                                    movearray[whichmove] = country;
                                    whichmove++;
                                } else
                                {   ; // DisplayBeep(ScreenPtr);
                            }   }
                        } while (whichmove <= moves);
                    }

                    for (i = 0; i < whichmove; i++)
                    {   if (movearray[i] == hero[whichhero].where)
                        {   // jarl moved past hero during move
                            hero[whichhero].wealth += jarl[whichjarl].wealth;
                            jarl[whichjarl].wealth = 0;
                    }   }

                    for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
                    {   if (treasure[whichtreasure].possessortype == KINGDOM && treasure[whichtreasure].where == jarl[whichjarl].where)
                        {   // assert(treasure[whichtreasure].possessor = -1);

                            asktreasure(JARL, whichjarl, whichtreasure);
                    }   }

                    if (needsord(JARL, whichjarl))
                    {   for (whichsord = 0; whichsord <= SORDS; whichsord++)
                        {   if (sord[whichsord].possessortype == KINGDOM && sord[whichsord].where == jarl[whichjarl].where)
                            {   // assert(sord[whichsord].possessor = -1);

                                if (asksord(JARL, whichjarl, whichsord))
                                {   break;
                    }   }   }   }
                    if
                    (   treasure[BROSUNGNECKLACE].possessortype == JARL
                     && treasure[BROSUNGNECKLACE].possessor == whichjarl
                    )
                    {   brosung(JARL, whichjarl);
                }   }
                elif (hero[whichhero].control == AMIGA)
                {   saywho(JARL, whichjarl, FALSE, FALSE);
                    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_IS_MOVING, "is moving"));
                    strcat(saystring, "...");
                    say(LOWER);

                    movearray[0] = jarl[whichjarl].where;
                    whichmove = 1;
                    if (moves >= 1)
                    {   for (whichmove = 1; whichmove <= moves; whichmove++)
                        {   stop = assess(JARL, whichjarl);
                            if (stop)
                            {   break;
                            }

                            do
                            {   decision = rand() % (CONNECTIONS + 1);
                            } while (world[jarl[whichjarl].where].connection[decision] == -1);

                            if
                            (   jarl[whichjarl].sea == BAD
                             && (   world[world[jarl[whichjarl].where].connection[decision]].type == SEA
                                 || world[world[jarl[whichjarl].where].connection[decision]].type == ISLE
                            )   )
                            {   whichmove--;
                            } else
                            {   unslot_jarl(whichjarl);
                                jarl[whichjarl].where = world[jarl[whichjarl].where].connection[decision];
                                move_jarl(whichjarl, TRUE);
                                movearray[whichmove] = jarl[whichjarl].where;
                    }   }   }

                    for (i = 0; i < whichmove; i++)
                    {   if (movearray[i] == hero[whichhero].where)
                        {   // jarl moved past hero during move
                            hero[whichhero].wealth += jarl[whichjarl].wealth;
                            jarl[whichjarl].wealth = 0;
                    }   }

                    // Amiga always takes whatever it can.
                    for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
                    {   if (treasure[whichtreasure].possessortype == KINGDOM && treasure[whichtreasure].where == jarl[whichjarl].where)
                        {   // assert(treasure[whichtreasure].possessor = -1);

                            remove_treasure(whichtreasure, TRUE);
                            treasure[whichtreasure].possessortype = JARL;
                            treasure[whichtreasure].possessor     = whichjarl;
                            treasure[whichtreasure].where         = -1;

                            saywho(JARL, whichjarl, FALSE, FALSE);
                            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_TAKES_THE, "takes the"));
                            strcat(saystring, " ");
                            strcat(saystring, treasure[whichtreasure].name);
                            strcat(saystring, ".");
                            say(LOWER);
                            anykey();
                    }   }

                    if (needsord(JARL, whichjarl))
                    {   for (whichsord = 0; whichsord <= SORDS; whichsord++)
                        {   if (sord[whichsord].possessortype == KINGDOM && sord[whichsord].where == jarl[whichjarl].where)
                            {   // assert(sord[whichsord].possessor = -1);
            
                                remove_sord(whichsord, TRUE);
                                sord[whichsord].possessortype = HERO;
                                sord[whichsord].possessor     = whichhero;
                                sord[whichsord].where         = -1;

                                saywho(JARL, whichjarl, FALSE, FALSE);
                                strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_TAKES_SWORD, "takes sword"));
                                strcat(saystring, " ");
                                strcat(saystring, sord[whichsord].name);
                                strcat(saystring, ".");
                                say(LOWER);
                                anykey();

                                break;
                }   }   }   }
                deselect_jarl(whichjarl, TRUE);
}   }   }   }

MODULE void helpabout(void)
{   SBYTE                line;
    FLAG                 done          = FALSE;
    ULONG                class;
    UWORD                code, qual;
    struct IntuiMessage* MsgPtr;

    if (!(HelpWindowPtr = (struct Window *) OpenWindowTags(NULL,
        WA_Left,          (SCREENXPIXEL / 2) - (ABOUTXPIXEL / 2),
        WA_Top,           (SCREENYPIXEL / 2) - (ABOUTYPIXEL / 2),
        WA_Width,         ABOUTXPIXEL,
        WA_Height,        ABOUTYPIXEL,
        WA_IDCMP,         IDCMP_CLOSEWINDOW | IDCMP_RAWKEY,
        WA_Title,         abouttitle,
        WA_Gadgets,       NULL,
        WA_CustomScreen,  ScreenPtr,
        WA_DragBar,       TRUE,
        WA_CloseGadget,   TRUE,
        WA_NoCareRefresh, TRUE,
        WA_Activate,      TRUE,
	TAG_DONE))
    )
    {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open About... window!\0", 24);
        cleanexit(EXIT_FAILURE);
    } else
    {   SetAPen(HelpWindowPtr->RPort, LIGHTGREY);
        RectFill(HelpWindowPtr->RPort, 8, 13, ABOUTXPIXEL - 10, ABOUTYPIXEL - 6);
        SetAPen(HelpWindowPtr->RPort, BLACK);
        SetDrMd(HelpWindowPtr->RPort, JAM1);
        for (line = 0; line <= ABOUTLINES; line++)
        {   Move(HelpWindowPtr->RPort, about[line].x, about[line].y);
            Text(HelpWindowPtr->RPort, about[line].text, (SBYTE) strlen(about[line].text));
        }

        DrawBevelBox(HelpWindowPtr->RPort, 16, 20, 44 + 4, 38 + 4, GT_VisualInfo, VisualInfoPtr, GTBB_Recessed, TRUE, TAG_END);

        drawabout();

        while(!done)
        {   Wait(1L << HelpWindowPtr->UserPort->mp_SigBit);
            while (MsgPtr = (struct IntuiMessage *) GetMsg(HelpWindowPtr->UserPort))
            {   class  = MsgPtr->Class;
                code   = MsgPtr->Code;
                qual   = MsgPtr->Qualifier;
                ReplyMsg((struct Message *) MsgPtr);
                switch(class)
                {
                case IDCMP_CLOSEWINDOW:
                    done = TRUE;
                break;
                case IDCMP_RAWKEY:
                    if (!(qual & IEQUALIFIER_REPEAT) && code < KEYUP && (code < FIRSTQUALIFIER || code > LASTQUALIFIER))
                    {   done = TRUE;
                    }
                break;
                default:
                break;
        }   }   }
        CloseWindow(HelpWindowPtr);
        HelpWindowPtr = NULL;
        clearkybd();
}   }

MODULE void resettime(void)
{   struct timerequest* TimerIORequestPtr;
    struct timeval      timeval;

    if (!(TimerIORequestPtr = (struct timerequest *) AllocVec(sizeof(struct timerequest), MEMF_PUBLIC | MEMF_CLEAR)))
    {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Out of memory!\0", 24);
        cleanexit(EXIT_FAILURE);
    }
    if (OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *) TimerIORequestPtr, 0))
    {   FreeVec(TimerIORequestPtr);
        DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open timer.device!\0", 24);
        cleanexit(EXIT_FAILURE);
    }
    TimerBase = (struct Library *) TimerIORequestPtr->tr_node.io_Device;
    GetSysTime(&timeval);
    srand((UWORD) timeval.tv_micro);
    // no need to abort timer I/O requests, as we never send any
    CloseDevice((struct IORequest *) TimerIORequestPtr);
    FreeVec(TimerIORequestPtr);
}

MODULE void anykey(void)
{   if (tickwait != 0)
    {   getevent(ANYKEY, NULL);
}   }
MODULE void waitkey(void)
{   SLONG realtickwait = tickwait;

    tickwait = -1;
    getevent(ANYKEY, NULL);
    tickwait = realtickwait;
}

MODULE SLONG getluck(SLONG whichhero)
{   SLONG result;

    while(1)
    {   do
        {   result = getevent(KEYBOARD, NULL);
        } while (result < '0' || result > '9');

        if (result == '0')
        {   return(0);
        } else
        {   result -= '0';
        }

        if (result > hero[whichhero].luck)
        {   ; // DisplayBeep(ScreenPtr);
        } else
        {   hero[whichhero].luck -= result;
            return(result);
}   }   }

MODULE void phase3(void)
{   FLAG  ok;
    SBYTE whichhero, whichcountry, whichjarl;

    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   if (hero[whichhero].control != NONE && !(hero[whichhero].verydead))
        /* Note that we even do this for dead heroes: they can keep their
           kingdoms (for now) where they have jarls, as they may be
           promoting a jarl, in which case they are allowed to keep their
           kingdoms. */
        {   for (whichcountry = 0; whichcountry <= 35; whichcountry++)
            {   if (world[whichcountry].hero == whichhero)
                {   // determine whether the hero or one of his jarls is there

                    ok = FALSE;
                    if (!world[whichcountry].is)
                    {   if (hero[whichhero].where == whichcountry)
                        {   ok = TRUE;
                            hero[whichhero].wealth += world[whichcountry].tax;
                            if (hero[whichhero].rune == GEOFU)
                            {   hero[whichhero].wealth++;
                        }   }
                        else
                        {   for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
                            {   if
                                (   jarl[whichjarl].alive
                                 && jarl[whichjarl].hero == whichhero
                                 && jarl[whichjarl].where == whichcountry
                                ) // taxes are given to the first friendly jarl found
                                {   ok = TRUE;
                                    jarl[whichjarl].wealth += world[whichcountry].tax;
                                    if (hero[whichhero].rune == GEOFU)
                                    {   jarl[whichjarl].wealth++;
                                    }
                                    break;
                    }   }   }   }

                    if (!ok)
                    {   world[whichcountry].hero = -1;
                        darken();

                        strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_HERO, "Hero"));
                        strcat(saystring, " ");
                        strcat(saystring, hero[whichhero].name);
                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_S_KINGDOM, "'s kingdom"));
                        strcat(saystring, " ");
                        strcat(saystring, world[whichcountry].name);
                        strcat(saystring, " (");
                        stcl_d(numberstring, world[whichcountry].tax);
                        strcat(saystring, numberstring);
                        strcat(saystring, ") ");
                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_HAS_BEEN_OVERRUN, "has been overrun"));
                        strcat(saystring, ".");
                        say(LOWER);
                        anykey();
}   }   }   }   }   }

MODULE void gods(SLONG whichhero)
{   SLONG whichgod, whichprayer, decision;
    FLAG  heard;

    whichgod    = rand() % 6;
    whichprayer = d6();

    switch(whichgod)
    {
    case FREY:
        strcpy(saystring, "Frey ");
        heard = FALSE;
        if (whichprayer <= 4)
        {   // assert(whichprayer >= 1);
            hero[whichhero].maidens++;

            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_W_S_A_M_T_H_H, "will send a maiden to heal hero"));
            strcat(saystring, " ");                                    
            strcat(saystring, hero[whichhero].name);
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_S_NEXT_WOUND, "'s next wound"));
            strcat(saystring, ".");
        } else
        {   // assert(whichprayer == 5 || whichprayer == 6);
            hero[whichhero].maidens += 2;

            strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_W_S_A_M_T_H_H, "will send a maiden to heal hero"));
            strcat(saystring, " ");
            strcat(saystring, hero[whichhero].name);
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_S_NEXT_TWO_WOUNDS, "'s next two wounds"));
            strcat(saystring, ".");
        }
    break;
    case LOKI:
        strcpy(saystring, "Loki ");
        heard = FALSE;
        if (whichprayer <= 3)
        {   // assert(whichprayer >= 0);

            hero[whichhero].luck--;
            if (hero[whichhero].luck < 0)
            {   hero[whichhero].luck = 0;
            }

            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_S_A_P_O_L_F_H, "steals a point of luck from hero"));
            strcat(saystring, " ");
            strcat(saystring, hero[whichhero].name);
            strcat(saystring, ".");
        } else
        {   // assert(whichprayer >= 4 && whichprayer <= 6);

            hero[whichhero].luck++;

            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_GRANTS_HERO, "grants hero"));
            strcat(saystring, " ");
            strcat(saystring, hero[whichhero].name);
            strcat(saystring, " ");                                                        
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_A_P_O_L_F_H_D, "a point of luck for his daring"));
            strcat(saystring, ".");
        }
    break;
    case NJORD:
        strcpy(saystring, "Njord ");
        heard = FALSE;
        if (whichprayer == 1 || whichprayer == 2)
        {   hero[whichhero].sea = GOOD;

            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_AIDS_HERO, "aids hero"));
            strcat(saystring, " ");
            strcat(saystring, hero[whichhero].name);
            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_TO_MOVE_BY_SEA_NEXT_TURN, "to move by sea next turn"));
            strcat(saystring, ".");
        } elif (whichprayer == 3 || whichprayer == 4)
        {   decision = d6();
            hero[whichhero].wealth += decision;

            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_GIVES, "gives"));
            strcat(saystring, " ");
            stcl_d(numberstring, decision);
            strcat(saystring, numberstring);
            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_GOLDEN_MARKS_TO_HERO, "golden marks to hero"));
            strcat(saystring, " ");
            strcat(saystring, hero[whichhero].name);
            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_AS_A_GIFT, "as a gift"));
            strcat(saystring, ".");
        } elif (whichprayer == 5)
        {   decision = d6();
            if (decision > hero[whichhero].wealth)
            {   decision = hero[whichhero].wealth;
            }
            hero[whichhero].wealth -= decision;

            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_TAKES, "takes"));
            strcat(saystring, " ");
            stcl_d(numberstring, decision);
            strcat(saystring, numberstring);
            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_GOLDEN_MARKS_FROM_HERO, "golden marks from hero"));
            strcat(saystring, " ");
            strcat(saystring, hero[whichhero].name);
            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_AS_DUE_TRIBUTE, "as due tribute"));
            strcat(saystring, ".");
        } else
        {   // assert(whichprayer == 6);
            hero[whichhero].sea = BAD;

            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_PREVENTS_HERO, "prevents hero"));
            strcat(saystring, " ");
            strcat(saystring, hero[whichhero].name);
            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_F_T_B_S_N_T, "from travelling by sea next turn"));
            strcat(saystring, ".");
        }
    break;
    case ODIN:
        hero[whichhero].god = ODIN;
        heard = TRUE;
        strcpy(saystring, "Odin ");
    break;
    case THOR:
        hero[whichhero].god = THOR;
        heard = TRUE;
        strcpy(saystring, "Thor ");
    break;
    case TYR:
        hero[whichhero].god = TYR;
        heard = TRUE;
        strcpy(saystring, "Tyr ");
    break;
    default:
    break;
    }
    if (heard)
    {   strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_HEARD_THE_PRAYER_OF_HERO, "heard the prayer of hero"));
        strcat(saystring, " ");
        strcat(saystring, hero[whichhero].name);
        strcat(saystring, ".");
    }
    say(LOWER);
    anykey();
}

MODULE FLAG loadgame(FLAG aslwindow)
{   SLONG offset = 12, whichhero, whichjarl, whichmonster, whichcountry,
          whichslot, whichtreasure, whichsord;
    TEXT  newpathname[255];
    BPTR  FileHandle /* = NULL */ ;
    FLAG  ok;

    if (aslwindow)
    {   if
        (   AslRequestTags
            (    ASLRqPtr,
                 ASL_Hail, GetCatalogStr(li.li_Catalog, MSG_LOAD_GAME, "Load Game"),
                 ASL_FuncFlags, FILF_PATGAD,
                 TAG_DONE
            )
         && *(ASLRqPtr->rf_File)
        )
        {   strcpy(newpathname, ASLRqPtr->rf_Dir);
            AddPart(newpathname, ASLRqPtr->rf_File, 254);
            ok = TRUE;
        } else
        {   ok = FALSE;
    }   }
    else
    {   ok = TRUE;
        strcpy(newpathname, pathname);
    }

    // 'SAGA 1.0' fieldsets are 544 bytes long, plus the version string.

    if (ok)
    {   strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_LOADING, "Loading"));
        strcat(saystring, " ");
        strcat(saystring, newpathname);
        strcat(saystring, "...");
        say(LOWER);

        if (!(FileHandle = Open(newpathname, MODE_OLDFILE)))
        {   strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_CANT_OPEN, "Can't open"));
            strcat(saystring, " ");
            strcat(saystring, newpathname);
            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_FOR_READING, "for reading"));
            strcat(saystring, "!");
            say(LOWER);
            return(FALSE);
        }

        // read file
        if (Read(FileHandle, IOBuffer, 544) != 544)
        {   Close(FileHandle);
            // FileHandle = NULL;
            strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_CANT_READ_FROM, "Can't read from"));
            strcat(saystring, " ");
            strcat(saystring, newpathname);
            strcat(saystring, "!");
            say(LOWER);
            return(FALSE);
        }

        if (strcmp(IOBuffer, "SAGA 1.0 "))
        {   Close(FileHandle);
            // FileHandle = NULL;
            strcpy(saystring, newpathname);
            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_I_N_A_V_S_G_F, "is not a valid saved game file"));
            strcat(saystring, "!");
            say(LOWER);
            return(FALSE);
        }
        turn      = (SLONG) ((SBYTE) IOBuffer[10]);
        faxirides = (SLONG) ((SBYTE) IOBuffer[11]);

        for (whichhero = 0; whichhero <= HEROES; whichhero++)
        {   hero[whichhero].control   = (SLONG) ((SBYTE) IOBuffer[offset++] );
            hero[whichhero].alive     = (FLAG)  ((SBYTE) IOBuffer[offset++] );
            hero[whichhero].verydead  = (FLAG)  ((SBYTE) IOBuffer[offset++] );
            hero[whichhero].moves     = (SLONG) ((SBYTE) IOBuffer[offset++] );
            hero[whichhero].god       = (SLONG) ((SBYTE) IOBuffer[offset++] );
            hero[whichhero].rune      = (SLONG) ((SBYTE) IOBuffer[offset++] );
            hero[whichhero].where     = (SLONG) ((SBYTE) IOBuffer[offset++] );
            hero[whichhero].homewhere = (SLONG) ((SBYTE) IOBuffer[offset++] );
            hero[whichhero].promoted  = (SLONG) ((SBYTE) IOBuffer[offset++] );
            hero[whichhero].wounded   = (FLAG)  ((SBYTE) IOBuffer[offset++] );
            hero[whichhero].wealth    = (SLONG) ((IOBuffer[offset++] * 256) + IOBuffer[offset++]);
            hero[whichhero].glory     = (SLONG) ((IOBuffer[offset++] * 256) + IOBuffer[offset++]);
            hero[whichhero].luck      = (SLONG) ((IOBuffer[offset++] * 256) + IOBuffer[offset++]);
            hero[whichhero].sea       = (SLONG) ((SBYTE) IOBuffer[offset++]);
            hero[whichhero].loseturn  = (FLAG)  ((SBYTE) IOBuffer[offset++]);
            hero[whichhero].maidens   = (SLONG) ((SBYTE) IOBuffer[offset++]);
        }
        for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
        {   jarl[whichjarl].where     = (SLONG) ((SBYTE) IOBuffer[offset++]);
            jarl[whichjarl].homewhere = (SLONG) ((SBYTE) IOBuffer[offset++]);
            jarl[whichjarl].face      = (SLONG) ((SBYTE) IOBuffer[offset++]);
            jarl[whichjarl].hero      = (SLONG) ((SBYTE) IOBuffer[offset++]);
            jarl[whichjarl].taken     = (FLAG)  ((SBYTE) IOBuffer[offset++]);
            jarl[whichjarl].sea       = (SLONG) ((SBYTE) IOBuffer[offset++]);
            jarl[whichjarl].loseturn  = (FLAG)  ((SBYTE) IOBuffer[offset++]);
            jarl[whichjarl].alive     = (FLAG)  ((SBYTE) IOBuffer[offset++]);
        }
        for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
        {   monster[whichmonster].taken    = (FLAG)  ((SBYTE) IOBuffer[offset++]);
            monster[whichmonster].alive    = (FLAG)  ((SBYTE) IOBuffer[offset++]);
            monster[whichmonster].where    = (SLONG) ((SBYTE) IOBuffer[offset++]);
            monster[whichmonster].wealth   = (SLONG) ((SBYTE) IOBuffer[offset++]);
            monster[whichmonster].sea      = (SLONG) ((SBYTE) IOBuffer[offset++]);
            offset++; // skip monster[].loseturn
        }
        for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
        {   treasure[whichtreasure].taken         = (FLAG)  ((SBYTE) IOBuffer[offset++]);
            treasure[whichtreasure].possessor     = (FLAG)  ((SBYTE) IOBuffer[offset++]);
            treasure[whichtreasure].possessortype = (SLONG) ((SBYTE) IOBuffer[offset++]);
            treasure[whichtreasure].where         = (SLONG) ((SBYTE) IOBuffer[offset++]);
        }
        for (whichsord = 0; whichsord <= SORDS; whichsord++)
        {   sord[whichsord].taken         = (FLAG)  ((SBYTE) IOBuffer[offset++]);
            sord[whichsord].possessor     = (FLAG)  ((SBYTE) IOBuffer[offset++]);
            sord[whichsord].possessortype = (SLONG) ((SBYTE) IOBuffer[offset++]);
            sord[whichsord].where         = (SLONG) ((SBYTE) IOBuffer[offset++]);
        }
        for (whichcountry = 0; whichcountry <= 35; whichcountry++)
        {   world[whichcountry].hero = (SLONG) ((SBYTE) IOBuffer[offset++]);
            world[whichcountry].is   = (FLAG)  ((SBYTE) IOBuffer[offset++]);
        }
        // no need to read version string
        Close(FileHandle);
        // FileHandle = NULL;

        strcpy(pathname, newpathname);

        for (whichhero = 0; whichhero <= HEROES; whichhero++)
        {   GT_SetGadgetAttrs(CycleGadgetPtr[whichhero], MainWindowPtr, NULL, GA_Disabled, TRUE, TAG_DONE);
        }
        GT_SetGadgetAttrs(SpeedGadgetPtr, MainWindowPtr, NULL, GA_Disabled, TRUE, TAG_DONE);

        for (whichcountry = 0; whichcountry <= 65; whichcountry++)
        {   for (whichslot = 0; whichslot <= SLOTS; whichslot++)
            {   world[whichcountry].slot[whichslot] = FALSE;
        }   }

        for (whichhero = 0; whichhero <= HEROES; whichhero++)
        {   if (hero[whichhero].promoted == -1)
            {   hero[whichhero].name     = trueheroname[whichhero];
                hero[whichhero].strength = HERO_STRENGTH;
                hero[whichhero].moves    = HERO_MOVES;
            } else
            {   hero[whichhero].name     = jarl[hero[whichhero].promoted].name;
                hero[whichhero].strength = jarl[hero[whichhero].promoted].strength;
                hero[whichhero].moves    = jarl[hero[whichhero].promoted].moves;
            }
            deselect_hero(whichhero, FALSE);
            if (hero[whichhero].alive)
            {   move_hero(whichhero, FALSE);
            } else
            {   remove_hero(whichhero, FALSE);
        }   }

        for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
        {   jarl[whichjarl].recruitable = FALSE;
            if (jarl[whichjarl].alive)
            {   if (jarl[whichjarl].face == FACEUP)
                {   revealjarl(whichjarl, FALSE);
                } else
                {   // assert(jarl[whichjarl].face == FACEDOWN);
                    hidejarl(whichjarl, FALSE);
                }
                move_jarl(whichjarl, FALSE);
            } else
            {   remove_jarl(whichjarl, FALSE);
        }   }

        for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
        {   if (monster[whichmonster].alive)
            {   move_monster(whichmonster, FALSE);
            } else
            {   remove_monster(whichmonster, FALSE);
        }   }

        for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
        {   if (treasure[whichtreasure].possessor == -1)
            {   move_treasure(whichtreasure, FALSE);
        }   }

        for (whichsord = 0; whichsord <= SORDS; whichsord++)
        {   if (sord[whichsord].possessor == -1)
            {   move_sord(whichsord, FALSE);
        }   }

        darken();
        drawmap();
        refreshcounters();

        if (faxirides == -1)
        {   faxirides = 0;
            faxi_disappear();
        }

        strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_LOADED, "Loaded"));
        strcat(saystring, " ");
        strcat(saystring, pathname);
        strcat(saystring, ".");
        say(LOWER);
        return(TRUE);
}   }

MODULE void savegame(FLAG saveas)
{   SLONG offset = 12, whichhero, whichjarl, whichmonster, whichcountry,
          whichtreasure, whichsord;
    FLAG  cont = TRUE;
    TEXT  newpathname[255];
    BPTR  FileHandle /* = NULL */ ;

    strcpy(newpathname, pathname);
    if (saveas || newpathname[0] == 0)
    {   if
        (   AslRequestTags
            (   ASLRqPtr,
                ASL_Hail, GetCatalogStr(li.li_Catalog, MSG_SAVE_GAME, "Save Game"),
                ASL_FuncFlags, FILF_PATGAD | FILF_SAVE,
                TAG_DONE
            )
         && *(ASLRqPtr->rf_File) != 0
        )
        {   strcpy(newpathname, ASLRqPtr->rf_Dir);
            AddPart(newpathname, ASLRqPtr->rf_File, 254);
        } else
        {   cont = FALSE;
    }   }
    if (!cont)
    {   return;
    }

    strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_SAVING, "Saving"));
    strcat(saystring, " ");
    strcat(saystring, newpathname);
    strcat(saystring, "...");
    say(LOWER);

    if (!(FileHandle = Open(newpathname, MODE_NEWFILE)))
    {   strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_CANT_OPEN, "Can't open"));
        strcat(saystring, " ");
        strcat(saystring, newpathname);
        strcat(saystring, " ");
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_FOR_WRITING, "for writing"));
        strcat(saystring, "!");
        say(LOWER);
        anykey();
        return;
    }

    /* write header
       SAGA 1.0 *#%
       012345678901
       where * is NULL byte and # is turn and % is faxi rides */

    strcpy(IOBuffer, "SAGA 1.0 ");
    IOBuffer[10] = (SBYTE) turn;
    IOBuffer[11] = (SBYTE) faxirides;

    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {    IOBuffer[offset++] = (SBYTE) hero[whichhero].control;
         IOBuffer[offset++] = (SBYTE) hero[whichhero].alive;
         IOBuffer[offset++] = (SBYTE) hero[whichhero].verydead;
         IOBuffer[offset++] = (SBYTE) hero[whichhero].moves;
         IOBuffer[offset++] = (SBYTE) hero[whichhero].god;
         IOBuffer[offset++] = (SBYTE) hero[whichhero].rune;
         IOBuffer[offset++] = (SBYTE) hero[whichhero].where;
         IOBuffer[offset++] = (SBYTE) hero[whichhero].homewhere;
         IOBuffer[offset++] = (SBYTE) hero[whichhero].promoted;
         IOBuffer[offset++] = (SBYTE) hero[whichhero].wounded;
         IOBuffer[offset++] = (UBYTE) (hero[whichhero].wealth / 256);
         IOBuffer[offset++] = (UBYTE) (hero[whichhero].wealth % 256);
         IOBuffer[offset++] = (UBYTE) (hero[whichhero].glory  / 256);
         IOBuffer[offset++] = (UBYTE) (hero[whichhero].glory  % 256);
         IOBuffer[offset++] = (UBYTE) (hero[whichhero].luck   / 256);
         IOBuffer[offset++] = (UBYTE) (hero[whichhero].luck   % 256);
         IOBuffer[offset++] = (SBYTE) hero[whichhero].sea;
         IOBuffer[offset++] = (SBYTE) hero[whichhero].loseturn;
         IOBuffer[offset++] = (SBYTE) hero[whichhero].maidens;
    }
    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
    {    IOBuffer[offset++] = (SBYTE) jarl[whichjarl].where;
         IOBuffer[offset++] = (SBYTE) jarl[whichjarl].homewhere;
         IOBuffer[offset++] = (SBYTE) jarl[whichjarl].face;
         IOBuffer[offset++] = (SBYTE) jarl[whichjarl].hero;
         IOBuffer[offset++] = (SBYTE) jarl[whichjarl].taken;
         IOBuffer[offset++] = (SBYTE) jarl[whichjarl].sea;
         IOBuffer[offset++] = (SBYTE) jarl[whichjarl].loseturn;
         IOBuffer[offset++] = (SBYTE) jarl[whichjarl].alive;
    }
    for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
    {    IOBuffer[offset++] = (SBYTE) monster[whichmonster].taken;
         IOBuffer[offset++] = (SBYTE) monster[whichmonster].alive;
         IOBuffer[offset++] = (SBYTE) monster[whichmonster].where;
         IOBuffer[offset++] = (SBYTE) monster[whichmonster].wealth;
         IOBuffer[offset++] = (SBYTE) monster[whichmonster].sea;
         IOBuffer[offset++] = (SBYTE) 0; // skip monster loseturn
    }
    for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
    {    IOBuffer[offset++] = (SBYTE) treasure[whichtreasure].taken;
         IOBuffer[offset++] = (SBYTE) treasure[whichtreasure].possessor;
         IOBuffer[offset++] = (SBYTE) treasure[whichtreasure].possessortype;
         IOBuffer[offset++] = (SBYTE) treasure[whichtreasure].where;
    }
    for (whichsord = 0; whichsord <= SORDS; whichsord++)
    {    IOBuffer[offset++] = (SBYTE) sord[whichsord].taken;
         IOBuffer[offset++] = (SBYTE) sord[whichsord].possessor;
         IOBuffer[offset++] = (SBYTE) sord[whichsord].possessortype;
         IOBuffer[offset++] = (SBYTE) sord[whichsord].where;
    }
    for (whichcountry = 0; whichcountry <= 35; whichcountry++)
    {   IOBuffer[offset++] = (SBYTE) world[whichcountry].hero;
        IOBuffer[offset++] = (SBYTE) world[whichcountry].is;
    }

    if (Write(FileHandle, IOBuffer, offset) != offset)
    {   Close(FileHandle);
        // FileHandle = NULL;
        strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_CANT_WRITE_TO, "Can't write to"));
        strcat(saystring, " ");
        strcat(saystring, newpathname);
        strcat(saystring, "!");
        say(LOWER);
        anykey();
        return;
    }

    /* write version string */
    Write(FileHandle, VERSION, strlen(VERSION));

    Close(FileHandle);
    // FileHandle = NULL;

    strcpy(pathname, newpathname);

    strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_SAVED, "Saved"));
    strcat(saystring, " ");
    strcat(saystring, pathname);
    strcat(saystring, ".");
    say(LOWER);
    // no need for anykey(), as there is one when we return anyway.
}

MODULE SLONG odin_tyr(SLONG whichhero, FLAG attacking)
{   SLONG whichjarl, whichprayer;
    SLONG adjustment = 0;

    if (hero[whichhero].god == ODIN)
    {   hero[whichhero].god = -1;
        whichprayer = d6();
        strcpy(saystring, "Odin");

        if (whichprayer == 1)
        {   adjustment = -3;

            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_AIDS_HERO, "aids hero"));
            strcat(saystring, " ");
            strcat(saystring, hero[whichhero].name);
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_S_E_B_A_3_T_T_S, "'s enemy by adding 3 to their strength"));
            strcat(saystring, ".");
        } elif (whichprayer == 2)
        {   adjustment = -1;

            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_SENDS_A_WOLF_TO_AID_HERO, "sends a wolf to aid hero"));
            strcat(saystring, " ");
            strcat(saystring, hero[whichhero].name);
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_S_ENEMY, "'s enemy"));
            strcat(saystring, ".");
        } elif (whichprayer == 3)
        {   strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_S_R_A_S_B_H_T_O_T_B, "'s ravens are sent by him to observe the battle"));
            strcat(saystring, ".");
        } elif (whichprayer == 4)
        {   adjustment = 1;

            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_SENDS_A_WOLF_TO_AID_HERO, "sends a wolf to aid hero"));
            strcat(saystring, " ");
            strcat(saystring, hero[whichhero].name);
            strcat(saystring, ".");
        } elif (whichprayer == 5)
        {   adjustment = 3;

            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_AIDS_HERO, "aids hero"));
            strcat(saystring, " ");
            strcat(saystring, hero[whichhero].name);
            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_BY_ADDING_3_TO_HIS_STRENGTH, "by adding 3 to his strength"));
            strcat(saystring, ".");
        } else
        {   // assert(whichprayer == 6);

            adjustment = 5;
            hero[whichhero].glory += 3;

            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_INTERVENES_PERSONALLY, "intervenes personally"));
            strcat(saystring, ".");
        }
        say(LOWER);
        anykey();
    } elif (hero[whichhero].god == TYR)
    {   hero[whichhero].god = -1;
        whichprayer = d6();
        strcpy(saystring, "Tyr ");

        if (whichprayer == 1)
        {   adjustment = -1;

            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_AIDS_HERO, "aids hero"));
            strcat(saystring, " ");
            strcat(saystring, hero[whichhero].name);
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_S_E_B_A_1_T_T_S, "'s enemy by adding 1 to their strength"));
            strcat(saystring, ".");
        } elif (whichprayer == 2 || whichprayer == 3)
        {   strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_D_T_T_F_I_B_F, "decides that the fight is balanced fairly"));
            strcat(saystring, ".");
        } elif (whichprayer == 4)
        {   adjustment = 1;

            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_AIDS_HERO, "aids hero"));
            strcat(saystring, " ");
            strcat(saystring, hero[whichhero].name);
            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_BY_ADDING_1_TO_HIS_STRENGTH, "by adding 1 to his strength"));
            strcat(saystring, ".");
        } elif (whichprayer == 5)
        {   adjustment = 2;

            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_AIDS_HERO, "aids hero"));
            strcat(saystring, " ");
            strcat(saystring, hero[whichhero].name);
            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_BY_ADDING_2_TO_HIS_STRENGTH, "by adding 2 to his strength"));
            strcat(saystring, ".");
        } else
        {   assert(whichprayer == 6);

            adjustment = 1; // for the hero himself
            if (attacking)
            {   for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
                {   if (jarl[whichjarl].attacking)
                    {   adjustment++;
            }   }   }
            else
            {   for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
                {   if (jarl[whichjarl].defending)
                    {   adjustment++;
            }   }   }

            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_AIDS_HERO, "aids hero"));
            strcat(saystring, " ");
            strcat(saystring, hero[whichhero].name);
            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_B_A_1_T_T_S_O_E_P_O_H_S, "by adding 1 to the strength of each person on his side"));
            strcat(saystring, ".");
        }
        say(LOWER);
        anykey();
    }
    return(adjustment);
}

MODULE void pray(SLONG whichhero)
{   SLONG decision;

    decision = d6();
    if (decision == 1 || (hero[whichhero].rune == AMSIR && decision == 2))
    {   gods(whichhero);
}   }

MODULE void amiga_rout(SLONG routedtype, SLONG routed)
{   SLONG decision, whichmove, moves;
    FLAG freemove;

    if (routedtype == HERO)
    {   hero[routed].routed = TRUE;
    } elif (routedtype == JARL)
    {   jarl[routed].routed = TRUE;
    }

    moves = getmoves(routedtype, routed, FALSE);
    if (moves < 1)
    {   return;
    }

    if (routedtype == HERO || routedtype == JARL)
    {   saywho(routedtype, routed, FALSE, FALSE);
    } else
    {   // assert(routedtype == MONSTER);
        strcpy(saystring, monstertypes[monster[routed].species]);
        strcat(saystring, " ");
        strcat(saystring, monster[routed].name);
        strcat(saystring, " ");
    }

    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_IS_BEING_ROUTED, "is being routed"));
    strcat(saystring, "...");
    say(LOWER);

    if (routedtype == HERO)
    {   freemove = FALSE;
        select_hero(routed, TRUE);
        for (whichmove = 1; whichmove <= moves; whichmove++)
        {   do
            {   decision = rand() % (CONNECTIONS + 1);
            } while (world[hero[routed].where].connection[decision] == -1);
            if
            (   hero[routed].sea == BAD
             && (   world[world[hero[routed].where].connection[decision]].type == SEA
                 || world[world[hero[routed].where].connection[decision]].type == ISLE
            )   )
            {   whichmove--;
            } else
            {   unslot_hero(routed);
                hero[routed].where = world[hero[routed].where].connection[decision];
                move_hero(routed, TRUE);
                if (hero[routed].sea == GOOD)
                {   if (!freemove)
                    {   if
                        (   world[hero[routed].where].type == SEA
                         || world[hero[routed].where].type == ISLE
                        )
                        {   freemove = TRUE;
                    }   }
                    else
                    {   if
                        (   world[hero[routed].where].type == LAND
                        )
                        {   freemove = FALSE;
                        } else
                        {   whichmove--;
        }   }   }   }   }
        deselect_hero(routed, TRUE);
    } elif (routedtype == JARL)
    {   select_jarl(routed, TRUE);
        for (whichmove = 1; whichmove <= moves; whichmove++)
        {   do
            {   decision = rand() % (CONNECTIONS + 1);
            } while (world[jarl[routed].where].connection[decision] == -1);
            if
            (   jarl[routed].sea == BAD
             && (   world[world[jarl[routed].where].connection[decision]].type == SEA
                 || world[world[jarl[routed].where].connection[decision]].type == ISLE
            )   )
            {   whichmove--;
            } else
            {   unslot_jarl(routed);
                jarl[routed].where = world[jarl[routed].where].connection[decision];
                move_jarl(routed, TRUE);
        }   }
        deselect_jarl(routed, TRUE);
    } elif (routedtype == MONSTER)
    {   // select_monster(routed);
        for (whichmove = 1; whichmove <= moves; whichmove++)
        {   do
            {   decision = rand() % (CONNECTIONS + 1);
            } while (world[monster[routed].where].connection[decision] == -1);
            if
            (   monster[routed].sea == BAD
             && (   world[world[monster[routed].where].connection[decision]].type == SEA
                 || world[world[monster[routed].where].connection[decision]].type == ISLE
            )   )
            {   whichmove--;
            } else
            {   unslot_monster(routed);
                monster[routed].where = world[monster[routed].where].connection[decision];
                move_monster(routed, TRUE);
        }   }
        // deselect_monster(routed);
}   }

MODULE void human_rout(SLONG routedtype, SLONG routed, SLONG routerhero)
{   SLONG country,
          oldcountry = -1,
          moves,
          whichconnection,
          whichmove;
    FLAG  legal, freemove;

    moves = getmoves(routedtype, routed, FALSE);

    if (moves == 0)
    {   return;
    }

    if (routedtype == HERO)
    {   select_hero(routed, TRUE);
        oldcountry = hero[routed].where;
    } elif (routedtype == JARL)
    {   select_jarl(routed, TRUE);
        oldcountry = jarl[routed].where;
    } elif (routedtype == MONSTER)
    {   // select_monster(routed);
        oldcountry = monster[routed].where;
    }

    whichmove = 1;
    freemove = FALSE;
    do
    {   saywho(HERO, routerhero, TRUE, FALSE);
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_ROUT, "rout"));
        strcat(saystring, " ");
        stcl_d(numberstring, whichmove);
        strcat(saystring, numberstring);
        strcat(saystring, " ");
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_OF, "of"));
        strcat(saystring, " ");
        stcl_d(numberstring, moves);
        strcat(saystring, numberstring);
        strcat(saystring, " ");
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_FOR, "for"));

        if (routedtype == HERO || routedtype == JARL)
        {   saywho(routedtype, routed, FALSE, TRUE);
        } else
        {   // assert(routedtype == MONSTER);
            strcat(saystring, " ");
            strcat(saystring, monstertypes[monster[routed].species]);
            strcat(saystring, " ");
            strcat(saystring, monster[routed].name);
        }
        strcat(saystring, "?");
        say(LOWER);

        do
        {   country = getevent(COUNTRY, NULL);
        } while ((country < -3 || country > 65) || country == -1);
        if (country == -3)
        {   break;
        } elif (country == -2)
        {   whichmove = 1;
            if (routedtype == HERO)
            {   unslot_hero(routed);
                hero[routed].where = oldcountry;
                move_hero(routed, TRUE);
                freemove = FALSE;
            } elif (routedtype == JARL)
            {   unslot_jarl(routed);
                jarl[routed].where = oldcountry;
                move_jarl(routed, TRUE);
            } else
            {   // assert(routedtype == MONSTER);
                unslot_monster(routed);
                monster[routed].where = oldcountry;
                move_monster(routed, TRUE);
        }   }
        else
        {   legal = FALSE;
            for (whichconnection = 0; whichconnection <= CONNECTIONS; whichconnection++)
            {   if
                (   (routedtype == HERO    && world[hero[routed].where].connection[whichconnection] == country)
                 || (routedtype == JARL    && world[jarl[routed].where].connection[whichconnection] == country)
                 || (routedtype == MONSTER && world[monster[routed].where].connection[whichconnection] == country)
                )
                {   legal = TRUE;
                    break; // for speed
            }   }
            if (legal)
            {   if (routedtype == HERO)
                {   if
                    (   hero[routed].sea == BAD
                     && (   world[country].type == SEA
                         || world[country].type == ISLE
                    )   )
                    {   legal = FALSE;
                        saywho(HERO, routed, FALSE, FALSE);
                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_M_N_T_B_S_T_T, "may not travel by sea this turn"));
                        strcat(saystring, ".");
                        say(LOWER);
                        anykey();
                }   }
                elif (routedtype == JARL)
                {   if
                    (   jarl[routed].sea == BAD
                     && (   world[country].type == SEA
                         || world[country].type == ISLE
                    )   )
                    {   legal = FALSE;
                        saywho(JARL, routed, FALSE, FALSE);
                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_M_N_T_B_S_T_T, "may not travel by sea this turn"));
                        strcat(saystring, ".");
                        say(LOWER);
                        anykey();
                }   }
                elif (routedtype == MONSTER)
                {   if
                    (   monster[routed].sea == BAD
                     && (   world[country].type == SEA
                         || world[country].type == ISLE
                    )   )
                    {   legal = FALSE;
                        strcat(saystring, monstertypes[monster[routed].species]);
                        strcat(saystring, " ");
                        strcat(saystring, monster[routed].name);
                        strcat(saystring, " ");
                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_M_N_T_B_S_T_T, "may not travel by sea this turn"));
                        strcat(saystring, ".");
                        say(LOWER);
                        anykey();
            }   }   }
            if (legal)
            {   if (routedtype == HERO)
                {   unslot_hero(routed);
                    hero[routed].where = country;
                    move_hero(routed, TRUE);

                    if (hero[routed].sea == GOOD)
                    {   if (!freemove)
                        {   if
                            (   world[hero[routed].where].type == SEA
                             || world[hero[routed].where].type == ISLE
                            )
                            {   freemove = TRUE;
                            }
                            whichmove++;
                        } else
                        {   if
                            (   world[hero[routed].where].type == LAND
                            )
                            {   freemove = FALSE;
                                whichmove++;
                }   }   }   }
                elif (routedtype == JARL)
                {   unslot_jarl(routed);
                    jarl[routed].where = country;
                    move_jarl(routed, TRUE);
                } else
                {   // assert(routedtype == MONSTER);
                    unslot_monster(routed);
                    monster[routed].where = country;
                    move_monster(routed, TRUE);
                }
                whichmove++;
            } else
            {   ; // DisplayBeep(ScreenPtr);
        }   }
    } while (whichmove <= moves);

    if (routedtype == HERO)
    {   deselect_hero(routed, TRUE);
    } elif (routedtype == JARL)
    {   deselect_jarl(routed, TRUE);
}   }

MODULE SLONG getmoves(SLONG countertype, SLONG whichcounter, FLAG freyfaxi)
{   SLONG moves;

    if (countertype == HERO)
    {   moves = hero[whichcounter].moves;
    } elif (countertype == MONSTER)
    {   // assert(!freyfaxi);
        moves = monster[whichcounter].moves;
    } else
    {   assert(countertype == JARL);
        moves = jarl[whichcounter].moves;
    }

    if (freyfaxi)
    {   moves *= 2;
    }

    if
    (   countertype != MONSTER // so dragon's don't use magic treasures
     && treasure[MAGICSHIRT].possessortype == countertype
     && treasure[MAGICSHIRT].possessor     == whichcounter
    )
    {   // assert(treasure[MAGICSHIRT].where == -1);
        moves++;
    }

    if (countertype == HERO && hero[whichcounter].rune == EON)
    {   moves++;
    }

    if
    (   (countertype == HERO && hero[whichcounter].loseturn)
     || (countertype == JARL && jarl[whichcounter].loseturn)
    )
    {   moves = 0;
    }

    /* If you are stuck at sea or on an island, and can't travel
       by sea, then you can't move at all that turn. */
    if
    (   countertype == HERO
     && hero[whichcounter].sea == BAD
     && (   world[hero[whichcounter].where].type == SEA
         || world[hero[whichcounter].where].type == ISLE
    )   )
    {   moves = 0;
    } elif
    (   countertype == JARL
     && jarl[whichcounter].sea == BAD
     && (   world[jarl[whichcounter].where].type == SEA
         || world[jarl[whichcounter].where].type == ISLE
    )   )
    {   moves = 0;
    } elif
    (   countertype == MONSTER
     && monster[whichcounter].sea == BAD
     && (   world[monster[whichcounter].where].type == SEA
         || world[monster[whichcounter].where].type == ISLE
    )   )
    {   moves = 0;
    }

    return(moves);
}

MODULE void faxi_disappear(void)
{   if (faxirides == 0) // faxi disappears
    {   treasure[FREYFAXI].possessortype = -1; // noone
        treasure[FREYFAXI].possessor     = -1; // noone
        treasure[FREYFAXI].where         = -1; // nowhere
        // frey faxi won't be on the board at the moment anyway
        faxirides = -1; // so it only disappears once
}   }

MODULE void thor(SLONG whichhero)
{   SLONG whichprayer;

    if (hero[whichhero].god == THOR)
    {   hero[whichhero].god = -1;
        whichprayer = d6();
        strcpy(saystring, "Thor ");

        if (whichprayer >= 1 && whichprayer <= 3)
        {   strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_DECIDES_THAT_HERO, "decides that hero"));
            strcat(saystring, " ");
            strcat(saystring, hero[whichhero].name);
            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_DESERVES_NO_REWARD, "deserves no reward"));
            strcat(saystring, ".");
        } elif (whichprayer == 4 || whichprayer == 5)
        {   hero[whichhero].glory++;

            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_REWARDS_HERO, "rewards hero"));
            strcat(saystring, " ");
            strcat(saystring, hero[whichhero].name);
            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_B_S_T_H_G_1_G, "by speaking to him, granting 1 glory"));
            strcat(saystring, ".");
        } else
        {   // assert(whichprayer == 6);

            hero[whichhero].glory += 2;

            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_HONOURS_HERO, "honours hero"));
            strcat(saystring, " ");
            strcat(saystring, hero[whichhero].name);
            strcat(saystring, " ");
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_B_E_W_H_G_2_G, "by eating with him, granting 2 glory"));
            strcat(saystring, ".");
        }
        say(LOWER);
        anykey();
}   }

MODULE void dospell(SLONG spell, SLONG caster)
{   SLONG whichhero, whichjarl, whichmonster;

    if (spell == HAGALL || spell == JARA || d6() <= 3) // if it's a spell which doesn't have a saving throw, or the saving throw is missed
    {   strcat(saystring, ".");
        say(LOWER);
        anykey();

        for (whichhero = 0; whichhero <= HEROES; whichhero++)
        {   if
            (   hero[whichhero].control != NONE
             && hero[whichhero].alive
             && hero[whichhero].where == monster[caster].where
            )
            {   if (hero[whichhero].rune == SYGIL && d6() <= 3)
                {   strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_HERO, "Hero"));
                    strcat(saystring, " ");
                    strcat(saystring, hero[whichhero].name);
                    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_S_RUNE_PROTECTS_HIM, "'s rune protects him"));
                    strcat(saystring, ".");
                    say(LOWER);
                    anykey();
                } else
                {   if (spell == HAGALL)
                    {   hero[whichhero].hagall = TRUE;
                        hero[whichhero].sea    = BAD;
                    } elif (spell == JARA)
                    {   hero[whichhero].loseturn = TRUE;
                    } elif (spell == NIED)
                    {   hero[whichhero].loseturn = TRUE;
                        hero[whichhero].attacking = FALSE;
                        deselect_hero(whichhero, TRUE);
                    } elif (spell == WYNN)
                    {   hero[whichhero].glory -= 2;
                        if (hero[whichhero].glory < 0)
                        {   hero[whichhero].glory = 0;
                        }
                        amiga_rout(HERO, whichhero);
                        hero[whichhero].attacking = FALSE;
                        deselect_hero(whichhero, TRUE);
                    } elif (spell == YR)
                    {   wound(MONSTER, caster, -1, HERO, whichhero, whichhero);
                        hero[whichhero].attacking = FALSE;
                        deselect_hero(whichhero, TRUE);
        }   }   }   }
        for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
        {   if
            (   jarl[whichjarl].alive
             && jarl[whichjarl].where == monster[caster].where
            )
            {   if (spell == HAGALL)
                {   jarl[whichjarl].hagall = TRUE;
                    jarl[whichjarl].sea    = BAD;
                } elif (spell == JARA)
                {   jarl[whichjarl].loseturn = TRUE;
                } elif (spell == NIED)
                {   jarl[whichjarl].loseturn = TRUE;
                    jarl[whichjarl].attacking = FALSE;
                    deselect_jarl(whichjarl, TRUE);
                } elif (spell == WYNN)
                {   amiga_rout(JARL, whichjarl);
                    jarl[whichjarl].attacking = FALSE;
                    deselect_jarl(whichjarl, TRUE);
                } elif (spell == YR)
                {   if (jarl[whichjarl].face == FACEUP)
                    {   wound(MONSTER, caster, -1, JARL, whichjarl, jarl[whichjarl].hero);
                        jarl[whichjarl].attacking = FALSE;
                        deselect_jarl(whichjarl, TRUE);
        }   }   }   }
        
        if (spell == HAGALL)
        {   for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
            {   if
                (   monster[whichmonster].alive
                 && monster[whichmonster].where == monster[caster].where
                )
                {   monster[whichmonster].hagall = TRUE;
                    monster[whichmonster].sea    = BAD;
    }   }   }   }
    else
    {   strcat(saystring, ", ");
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_BUT_IT_FIZZLES, "but it fizzles"));
        strcat(saystring, "!");
        say(LOWER);
        anykey();
}   }

MODULE void cast(SLONG caster, SLONG whichspell)
{   strcpy(saystring, monstertypes[monster[caster].species]);
    strcat(saystring, " ");
    strcat(saystring, monster[caster].name);
    strcat(saystring, " ");
    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_CASTS, "casts"));
    strcat(saystring, " ");

    switch(whichspell)
    {
    case HAGALL:
        strcat(saystring, "Hagall (");
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_HAIL_SLOW, "hail/slow"));
        strcat(saystring, ")");

        dospell(HAGALL, caster);
    break;
    case IS:
        world[monster[caster].where].is = TRUE;
        darken();

        strcat(saystring, "Is (");
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_ICE, "ice"));
        strcat(saystring, ").");
        say(LOWER);
        anykey();
    break;
    case JARA:
        strcat(saystring, "Jara (");
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_LOSE_NEXT_TURN, "lose next turn"));
        strcat(saystring, ")");

        dospell(JARA, caster);
    break;
    case NIED:
        strcat(saystring, "Nied (");
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_N_R_A_L_N_T, "no result and lose next turn"));
        strcat(saystring, ")");

        dospell(NIED, caster);
    break;
    case WYNN:
        strcat(saystring, "Wynn (");
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_FLEEING, "fleeing"));
        strcat(saystring, ")");

        dospell(WYNN, caster);
    break;
    case YR:
        strcat(saystring, "Yr (");
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_WOUNDING, "wounding"));
        strcat(saystring, ")");

        dospell(YR, caster);
    break;
    default:
        // assert(0);
    break;
}   }

MODULE void darken(void)
{   SLONG whichcountry, colour;

    for (whichcountry = 0; whichcountry <= 35; whichcountry++)
    {   if (whichcountry >= 9 && whichcountry <= 11)
        {   colour = whichcountry + 80;
        } else
        {   colour = whichcountry + 8;
        }
        if (world[whichcountry].is)
        {   SetRGB4(&ScreenPtr->ViewPort, colour, 12, 12, 12); // light grey ice
        } elif (world[whichcountry].hero != -1)
        {   SetRGB4
            (   &ScreenPtr->ViewPort,
                colour,
                herocolour[world[whichcountry].hero].red,
                herocolour[world[whichcountry].hero].green,
                herocolour[world[whichcountry].hero].blue
            );
        } else
        {   SetRGB4
            (   &ScreenPtr->ViewPort,
                colour,
                taxcolours[world[whichcountry].tax].red,
                taxcolours[world[whichcountry].tax].green,
                taxcolours[world[whichcountry].tax].blue
            );
}   }   }

MODULE SLONG checkcountry(WORD mousex, WORD mousey)
{   SLONG country;

    country = ReadPixel(MainWindowPtr->RPort, mousex, mousey);
    if (country == 80 || country == 81 || country == 91)
    {   country = 11; // Scandia
    } elif (country == 82 || country == 83)
    {   country = 30; // Pictland
    } elif (country == 84 || country == 85)
    {   country = 31; // Hebrides
    } elif (country == 89)
    {   country =  9; // Suder Gotland
    } elif (country == 90)
    {   country = 10; // Juteland
    } else
    {   country -= 8;
    }

    return(country);
}

MODULE void infowindow(SLONG countertype, SLONG whichcounter)
{   SLONG                lines,
                         leftlines     = 0,
                         rightlines    = 0,
                         oldwhichline,
                         whichline,
                         whichcountry,
                         whichjarl,
                         whichhero,
                         whichtreasure,
                         whichsord,
                         wide,
                         whichmonster;
    FLAG                 counterrow = FALSE,
                         done       = FALSE,
                         ok;
    ULONG                class;
    UWORD                code, qual;
    struct IntuiMessage* MsgPtr;

    if (countertype == HERO)
    {   strcpy(line[LEFTSIDE][0], GetCatalogStr(li.li_Catalog, MSG_HERO_NAME, "Hero Name"));
        strcat(line[LEFTSIDE][0], ":");
        pad(line[LEFTSIDE][0]);
        strcat(line[LEFTSIDE][0], hero[whichcounter].name);

        strcpy(line[LEFTSIDE][1], GetCatalogStr(li.li_Catalog, MSG_CONTROL, "Control"));
        strcat(line[LEFTSIDE][1], ":");
        pad(line[LEFTSIDE][1]);
        if (hero[whichcounter].control == HUMAN)
        {   strcat(line[LEFTSIDE][1], GetCatalogStr(li.li_Catalog, MSG_HUMAN, "Human"));
        } else
        {   // assert(hero[whichcounter].control == AMIGA);
            strcat(line[LEFTSIDE][1], "Amiga");
        }
        
        strcpy(line[LEFTSIDE][2], GetCatalogStr(li.li_Catalog, MSG_COMBAT_STRENGTH, "Combat Strength"));
        strcat(line[LEFTSIDE][2], ":");
        pad(line[LEFTSIDE][2]);
        stcl_d(numberstring, hero[whichcounter].strength);
        strcat(line[LEFTSIDE][2], numberstring);
        
        strcpy(line[LEFTSIDE][3], GetCatalogStr(li.li_Catalog, MSG_MOVEMENT_FACTOR, "Movement Factor"));
        strcat(line[LEFTSIDE][3], ":");
        pad(line[LEFTSIDE][3]);
        stcl_d(numberstring, hero[whichcounter].moves);
        strcat(line[LEFTSIDE][3], numberstring);
        
        strcpy(line[LEFTSIDE][4], GetCatalogStr(li.li_Catalog, MSG_GLORY, "Glory"));
        strcat(line[LEFTSIDE][4], ":");
        pad(line[LEFTSIDE][4]);
        stcl_d(numberstring, hero[whichcounter].glory);
        strcat(line[LEFTSIDE][4], numberstring);
        
        strcpy(line[LEFTSIDE][5], GetCatalogStr(li.li_Catalog, MSG_LUCK, "Luck"));
        strcat(line[LEFTSIDE][5], ":");
        pad(line[LEFTSIDE][5]);
        stcl_d(numberstring, hero[whichcounter].luck);
        strcat(line[LEFTSIDE][5], numberstring);
        
        strcpy(line[LEFTSIDE][6], GetCatalogStr(li.li_Catalog, MSG_WEALTH, "Wealth"));
        strcat(line[LEFTSIDE][6], ":");
        pad(line[LEFTSIDE][6]);
        stcl_d(numberstring, hero[whichcounter].wealth);
        strcat(line[LEFTSIDE][6], numberstring);

        print_location(hero[whichcounter].where, 7);

        strcpy(line[LEFTSIDE][8], GetCatalogStr(li.li_Catalog, MSG_HOMELAND, "Homeland"));
        strcat(line[LEFTSIDE][8], ":");
        pad(line[LEFTSIDE][8]);
        strcat(line[LEFTSIDE][8], world[hero[whichcounter].homewhere].name);
        strcat(line[LEFTSIDE][8], " (");
        stcl_d(numberstring, world[hero[whichcounter].homewhere].tax);
        strcat(line[LEFTSIDE][8], numberstring);
        strcat(line[LEFTSIDE][8], ")");
        
        strcpy(line[LEFTSIDE][9], GetCatalogStr(li.li_Catalog, MSG_MAIDENS, "Maidens"));
        strcat(line[LEFTSIDE][9], ":");
        pad(line[LEFTSIDE][9]);
        stcl_d(numberstring, hero[whichcounter].maidens);
        strcat(line[LEFTSIDE][9], numberstring);
      
        strcpy(line[LEFTSIDE][10], GetCatalogStr(li.li_Catalog, MSG_RUNE, "Rune"));
        strcat(line[LEFTSIDE][10], ":");
        pad(line[LEFTSIDE][10]);
        if (hero[whichcounter].rune == -1)
        {   strcat(line[LEFTSIDE][10], GetCatalogStr(li.li_Catalog, MSG_NONE, "None"));
        } else
        {   strcat(line[LEFTSIDE][10], runename[hero[whichcounter].rune]);
        }

        strcpy(line[LEFTSIDE][11], GetCatalogStr(li.li_Catalog, MSG_SWORD, "Sword"));
        strcat(line[LEFTSIDE][11], ":");
        pad(line[LEFTSIDE][11]);
        ok = FALSE;
        for (whichsord = 0; whichsord <= SORDS; whichsord++)
        {   if
            (   sord[whichsord].possessortype == HERO
             && sord[whichsord].possessor == whichcounter
            )
            {   ok = TRUE;
                counterrow = TRUE;
                strcat(line[LEFTSIDE][11], sord[whichsord].name);
                break; // for speed
        }   }
        if (!ok)
        {   strcat(line[LEFTSIDE][11], GetCatalogStr(li.li_Catalog, MSG_NONE, "None"));
        }

        strcpy(line[LEFTSIDE][12], GetCatalogStr(li.li_Catalog, MSG_WOUNDED, "Wounded"));
        strcat(line[LEFTSIDE][12], "?");
        pad(line[LEFTSIDE][12]);
        if (hero[whichcounter].wounded)
        {   strcat(line[LEFTSIDE][12], GetCatalogStr(li.li_Catalog, MSG_YES, "Yes"));
        } else
        {   strcat(line[LEFTSIDE][12], GetCatalogStr(li.li_Catalog, MSG_NO, "No"));
        }

        print_paralyzed(hero[whichcounter].loseturn, 13);

        print_hagall(hero[whichcounter].hagall, 14);

        print_sea(hero[whichcounter].sea, 15);

        print_routed(hero[whichcounter].routed, 16);

        leftlines = 17; // counting from 1

        strcpy(line[RIGHTSIDE][0], GetCatalogStr(li.li_Catalog, MSG_RECRUITED_JARLS, "Recruited Jarls"));
        strcat(line[RIGHTSIDE][0], ":");

        whichline = oldwhichline = 1; // whichline always points to the NEXT line.
        for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
        {   if (jarl[whichjarl].alive && jarl[whichjarl].hero == whichcounter)
            {   strcpy(line[RIGHTSIDE][whichline], " ");
                strcat(line[RIGHTSIDE][whichline], jarl[whichjarl].name);
                strcat(line[RIGHTSIDE][whichline], " (");
                stcl_d(numberstring, jarl[whichjarl].strength);
                strcat(line[RIGHTSIDE][whichline], numberstring);
                strcat(line[RIGHTSIDE][whichline], "-");
                stcl_d(numberstring, jarl[whichjarl].moves);
                strcat(line[RIGHTSIDE][whichline], numberstring);
                strcat(line[RIGHTSIDE][whichline], ")");
                whichline++;
        }   }
        if (whichline == oldwhichline)
        {   strcpy(line[RIGHTSIDE][whichline], " ");
            strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_NONE, "None"));
            whichline++;
        }

        strcpy(line[RIGHTSIDE][whichline], "");
        whichline++;
        strcpy(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_CONQUERED_KINGDOMS, "Conquered Kingdoms"));
        strcat(line[RIGHTSIDE][whichline], ":");
        whichline++;

        oldwhichline = whichline;
        for (whichcountry = 0; whichcountry <= 35; whichcountry++)
        {   if (world[whichcountry].hero == whichcounter)
            {   strcpy(line[RIGHTSIDE][whichline], " ");
                strcat(line[RIGHTSIDE][whichline], world[whichcountry].name);
                strcat(line[RIGHTSIDE][whichline], " (");
                stcl_d(numberstring, world[whichcountry].tax);
                strcat(line[RIGHTSIDE][whichline], numberstring);
                strcat(line[RIGHTSIDE][whichline], ")");
                whichline++;
        }   }
        if (whichline == oldwhichline)
        {   strcpy(line[RIGHTSIDE][whichline], " ");
            strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_NONE, "None"));
            whichline++;
        }

        strcpy(line[RIGHTSIDE][whichline], "");
        whichline++;
        strcpy(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_MAGIC_TREASURES, "Magic Treasures"));
        strcat(line[RIGHTSIDE][whichline], ":");
        whichline++;

        oldwhichline = whichline;
        for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
        {   if (treasure[whichtreasure].possessortype == HERO
             && treasure[whichtreasure].possessor     == whichcounter
            )
            {   counterrow = TRUE;
                strcpy(line[RIGHTSIDE][whichline], " ");
                strcat(line[RIGHTSIDE][whichline], treasure[whichtreasure].name);
                if (whichtreasure == FREYFAXI)
                {   strcat(line[RIGHTSIDE][whichline], " (");
                    stcl_d(numberstring, faxirides);
                    strcat(line[RIGHTSIDE][whichline], numberstring);
                    strcat(line[RIGHTSIDE][whichline], " ");
                    strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_RIDES2, "rides"));
                    strcat(line[RIGHTSIDE][whichline], ")");
                }
                whichline++;
        }   }
        if (whichline == oldwhichline)
        {   strcpy(line[RIGHTSIDE][whichline], " ");
            strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_NONE, "None"));
            whichline++;
        }

        rightlines = whichline;
    } elif (countertype == MONSTER)
    {   strcpy(line[LEFTSIDE][0], GetCatalogStr(li.li_Catalog, MSG_MONSTER_NAME, "Monster Name"));
        strcat(line[LEFTSIDE][0], ":");
        pad(line[LEFTSIDE][0]);
        strcat(line[LEFTSIDE][0], monster[whichcounter].name);

        strcpy(line[LEFTSIDE][1], GetCatalogStr(li.li_Catalog, MSG_MONSTER_SPECIES, "Monster Species"));
        strcat(line[LEFTSIDE][1], ":");
        pad(line[LEFTSIDE][1]);
        strcat(line[LEFTSIDE][1], monstertypes[monster[whichcounter].species]);

        strcpy(line[LEFTSIDE][2], GetCatalogStr(li.li_Catalog, MSG_COMBAT_STRENGTH, "Combat Strength"));
        strcat(line[LEFTSIDE][2], ":");
        pad(line[LEFTSIDE][2]);
        stcl_d(numberstring, monster[whichcounter].strength);
        strcat(line[LEFTSIDE][2], numberstring);
        
        strcpy(line[LEFTSIDE][3], GetCatalogStr(li.li_Catalog, MSG_MOVEMENT_FACTOR, "Movement Factor"));
        strcat(line[LEFTSIDE][3], ":");
        pad(line[LEFTSIDE][3]);
        stcl_d(numberstring, monster[whichcounter].moves);
        strcat(line[LEFTSIDE][3], numberstring);
        
        strcpy(line[LEFTSIDE][4], GetCatalogStr(li.li_Catalog, MSG_WEALTH, "Wealth"));
        strcat(line[LEFTSIDE][4], ":");
        pad(line[LEFTSIDE][4]);
        stcl_d(numberstring, monster[whichcounter].wealth);
        strcat(line[LEFTSIDE][4], numberstring);

        print_location(monster[whichcounter].where, 5);

        print_hagall(monster[whichcounter].hagall, 6);

        print_sea(monster[whichcounter].sea, 7);

        strcpy(line[LEFTSIDE][8], GetCatalogStr(li.li_Catalog, MSG_TREASURE, "Treasure"));
        strcat(line[LEFTSIDE][8], "?");
        pad(line[LEFTSIDE][8]);
        ok = FALSE;
        for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
        {   if
            (   treasure[whichtreasure].possessortype == MONSTER
             && treasure[whichtreasure].possessor == whichcounter
            )
            {   ok = TRUE;
                break;
        }   }
        if (ok)
        {   strcat(line[LEFTSIDE][8], GetCatalogStr(li.li_Catalog, MSG_YES, "Yes"));
        } else
        {   strcat(line[LEFTSIDE][8], GetCatalogStr(li.li_Catalog, MSG_NO, "No"));
        }

        leftlines = 9; // counting from 1
        rightlines = 0;
    } elif (countertype == JARL)
    {   strcpy(line[LEFTSIDE][0], GetCatalogStr(li.li_Catalog, MSG_JARL_NAME, "Jarl Name"));
        strcat(line[LEFTSIDE][0], ":");
        pad(line[LEFTSIDE][0]);
        if (jarl[whichcounter].face == FACEUP)
        {   strcat(line[LEFTSIDE][0], jarl[whichcounter].name);
        } else
        {   strcat(line[LEFTSIDE][0], GetCatalogStr(li.li_Catalog, MSG_UNKNOWN, "Unknown"));
        }

        strcpy(line[LEFTSIDE][1], GetCatalogStr(li.li_Catalog, MSG_HERO, "Hero"));
        strcat(line[LEFTSIDE][1], ":");
        pad(line[LEFTSIDE][1]);
        if (jarl[whichcounter].hero == -1)
        {   strcat(line[LEFTSIDE][1], GetCatalogStr(li.li_Catalog, MSG_KING_NONE, "None"));
        } else
        {   strcat(line[LEFTSIDE][1], hero[jarl[whichcounter].hero].name);
        }

        strcpy(line[LEFTSIDE][2], GetCatalogStr(li.li_Catalog, MSG_COMBAT_STRENGTH, "Combat Strength"));
        strcat(line[LEFTSIDE][2], ":");
        pad(line[LEFTSIDE][2]);
        if (jarl[whichcounter].face == FACEUP)
        {   stcl_d(numberstring, jarl[whichcounter].strength);
            strcat(line[LEFTSIDE][2], numberstring);
        } else
        {   // assert(jarl[whichcounter].face == FACEDOWN);
            strcat(line[LEFTSIDE][2], GetCatalogStr(li.li_Catalog, MSG_UNKNOWN, "Unknown"));
        }

        strcpy(line[LEFTSIDE][3], GetCatalogStr(li.li_Catalog, MSG_MOVEMENT_FACTOR, "Movement Factor"));
        strcat(line[LEFTSIDE][3], ":");
        pad(line[LEFTSIDE][3]);
        if (jarl[whichcounter].face == FACEUP)
        {   stcl_d(numberstring, jarl[whichcounter].moves);
            strcat(line[LEFTSIDE][3], numberstring);
        } else
        {   // assert(jarl[whichcounter].face == FACEDOWN);
            strcat(line[LEFTSIDE][3], GetCatalogStr(li.li_Catalog, MSG_UNKNOWN, "Unknown"));
        }

        strcpy(line[LEFTSIDE][4], GetCatalogStr(li.li_Catalog, MSG_WEALTH, "Wealth"));
        strcat(line[LEFTSIDE][4], ":");
        pad(line[LEFTSIDE][4]);
        stcl_d(numberstring, jarl[whichcounter].wealth);
        strcat(line[LEFTSIDE][4], numberstring);

        print_location(jarl[whichcounter].where, 5);

        strcpy(line[LEFTSIDE][6], GetCatalogStr(li.li_Catalog, MSG_HOMELAND, "Homeland"));
        strcat(line[LEFTSIDE][6], ":");
        pad(line[LEFTSIDE][6]);
        strcat(line[LEFTSIDE][6], world[jarl[whichcounter].homewhere].name);
        strcat(line[LEFTSIDE][6], " (");
        stcl_d(numberstring, world[jarl[whichcounter].homewhere].tax);
        strcat(line[LEFTSIDE][6], numberstring);
        strcat(line[LEFTSIDE][6], ")");
        
        strcpy(line[LEFTSIDE][7], GetCatalogStr(li.li_Catalog, MSG_SWORD, "Sword"));
        strcat(line[LEFTSIDE][7], ":");
        pad(line[LEFTSIDE][7]);
        ok = FALSE;
        for (whichsord = 0; whichsord <= SORDS; whichsord++)
        {   if
            (   sord[whichsord].possessortype == JARL
             && sord[whichsord].possessor == whichcounter
            )
            {   ok = TRUE;
                counterrow = TRUE;
                strcat(line[LEFTSIDE][7], sord[whichsord].name);
                break; // for speed
        }   }
        if (!ok)
        {   strcat(line[LEFTSIDE][7], GetCatalogStr(li.li_Catalog, MSG_NONE, "None"));
        }

        print_paralyzed(jarl[whichcounter].loseturn, 8);

        print_hagall(jarl[whichcounter].hagall, 9);

        print_sea(jarl[whichcounter].sea, 10);

        print_routed(jarl[whichcounter].routed, 11);

        leftlines = 12; // counting from 1

        strcpy(line[RIGHTSIDE][0], GetCatalogStr(li.li_Catalog, MSG_MAGIC_TREASURES, "Magic Treasures"));
        strcat(line[RIGHTSIDE][0], ":");
        whichline = oldwhichline = 1; // whichline always points to the NEXT line.
        for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
        {   if (treasure[whichtreasure].possessortype == JARL
             && treasure[whichtreasure].possessor     == whichcounter
            )
            {   counterrow = TRUE;
                strcpy(line[RIGHTSIDE][whichline], " ");
                strcat(line[RIGHTSIDE][whichline], treasure[whichtreasure].name);
                if (whichtreasure == FREYFAXI)
                {   strcat(line[RIGHTSIDE][whichline], " (");
                    stcl_d(numberstring, faxirides);
                    strcat(line[RIGHTSIDE][whichline], numberstring);
                    strcat(line[RIGHTSIDE][whichline], " ");
                    strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_RIDES2, "rides"));
                    strcat(line[RIGHTSIDE][whichline], ")");
                }
                whichline++;
        }   }
        if (whichline == oldwhichline)
        {   strcpy(line[RIGHTSIDE][whichline], " ");
            strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_NONE, "None"));
            whichline++;
        }

        rightlines = whichline;
    } elif (countertype == TREASURE)
    {   strcpy(line[LEFTSIDE][0], GetCatalogStr(li.li_Catalog, MSG_TREASURE_NAME, "Treasure Name"));
        strcat(line[LEFTSIDE][0], ":");
        pad(line[LEFTSIDE][0]);
        strcat(line[LEFTSIDE][0], treasure[whichcounter].name);

        print_location(treasure[whichcounter].where, 1);

        strcpy(line[LEFTSIDE][2], GetCatalogStr(li.li_Catalog, MSG_RIDES, "Rides"));
        strcat(line[LEFTSIDE][2], ":");
        if (whichcounter == FREYFAXI)
        {   // assert(faxirides != -1);
            stcl_d(numberstring, faxirides);
            strcat(line[LEFTSIDE][2], numberstring);
        } else
        {   strcat(line[LEFTSIDE][2], GetCatalogStr(li.li_Catalog, MSG_N_A, "n/a"));
        }

        leftlines = 3;
        rightlines = 0;
    } elif (countertype == KINGDOM)
    {   strcpy(line[LEFTSIDE][0], GetCatalogStr(li.li_Catalog, MSG_KINGDOM_NAME, "Kingdom Name"));
        strcat(line[LEFTSIDE][0], ":");
        pad(line[LEFTSIDE][0]);
        strcat(line[LEFTSIDE][0], world[whichcounter].name);

        strcpy(line[LEFTSIDE][1], GetCatalogStr(li.li_Catalog, MSG_KING, "King"));
        strcat(line[LEFTSIDE][1], ":");
        pad(line[LEFTSIDE][1]);
        if (world[whichcounter].hero == -1)
        {   strcat(line[LEFTSIDE][1], GetCatalogStr(li.li_Catalog, MSG_KING_NONE, "None"));
        } else
        {   strcat(line[LEFTSIDE][1], hero[world[whichcounter].hero].name);
        }

        strcpy(line[LEFTSIDE][2], GetCatalogStr(li.li_Catalog, MSG_TAXATION_FACTOR, "Taxation Factor"));
        strcat(line[LEFTSIDE][2], ":");
        pad(line[LEFTSIDE][2]);
        stcl_d(numberstring, world[whichcounter].tax);
        strcat(line[LEFTSIDE][2], numberstring);

        strcpy(line[LEFTSIDE][3], GetCatalogStr(li.li_Catalog, MSG_TYPE, "Type"));
        strcat(line[LEFTSIDE][3], ":");
        pad(line[LEFTSIDE][3]);
        if (world[whichcounter].type == LAND)
        {   strcat(line[LEFTSIDE][3], GetCatalogStr(li.li_Catalog, MSG_LAND, "Land"));
        } elif (world[whichcounter].type == ISLE)
        {   strcat(line[LEFTSIDE][3], GetCatalogStr(li.li_Catalog, MSG_ISLAND, "Island"));
        } elif (world[whichcounter].type == SEA)
        {   strcat(line[LEFTSIDE][3], GetCatalogStr(li.li_Catalog, MSG_SEA, "Sea"));
        } else
        {   // assert(world[whichcounter].type == PENINSULA);
            strcat(line[LEFTSIDE][3], GetCatalogStr(li.li_Catalog, MSG_PENINSULA, "Peninsula"));
        }

        strcpy(line[LEFTSIDE][4], "Is (");
        strcat(line[LEFTSIDE][4], GetCatalogStr(li.li_Catalog, MSG_ICE, "ice"));
        strcat(line[LEFTSIDE][4], ")?");
        pad(line[LEFTSIDE][4]);
        if (world[whichcounter].is)
        {   strcat(line[LEFTSIDE][4], GetCatalogStr(li.li_Catalog, MSG_YES, "Yes"));
        } else
        {   strcat(line[LEFTSIDE][4], GetCatalogStr(li.li_Catalog, MSG_NO, "No"));
        }
                                   
        leftlines = 5; // counting from 1

        strcpy(line[RIGHTSIDE][0], GetCatalogStr(li.li_Catalog, MSG_CONTENTS, "Contents"));
        strcat(line[RIGHTSIDE][0], ":");

        whichline = oldwhichline = 1; // whichline always points to the NEXT line.
        for (whichhero = 0; whichhero <= HEROES; whichhero++)
        {   if (hero[whichhero].alive && hero[whichhero].where == whichcounter)
            {   strcpy(line[RIGHTSIDE][whichline], " ");
                strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_HERO, "Hero"));
                strcat(line[RIGHTSIDE][whichline], " ");
                strcat(line[RIGHTSIDE][whichline], hero[whichhero].name);
                strcat(line[RIGHTSIDE][whichline], " (");
                stcl_d(numberstring, hero[whichhero].strength);
                strcat(line[RIGHTSIDE][whichline], numberstring);
                strcat(line[RIGHTSIDE][whichline], "-");
                stcl_d(numberstring, hero[whichhero].moves);
                strcat(line[RIGHTSIDE][whichline], numberstring);
                strcat(line[RIGHTSIDE][whichline], ")");
                whichline++;
        }   }
        for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
        {   if (jarl[whichjarl].alive && jarl[whichjarl].where == whichcounter)
            {   strcpy(line[RIGHTSIDE][whichline], " ");
                if (jarl[whichjarl].face == FACEUP)
                {   strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_JARL, "Jarl"));
                    strcat(line[RIGHTSIDE][whichline], " ");
                    strcat(line[RIGHTSIDE][whichline], jarl[whichjarl].name);
                    strcat(line[RIGHTSIDE][whichline], " (");
                    stcl_d(numberstring, jarl[whichjarl].strength);
                    strcat(line[RIGHTSIDE][whichline], numberstring);
                    strcat(line[RIGHTSIDE][whichline], "-");
                    stcl_d(numberstring, jarl[whichjarl].moves);
                    strcat(line[RIGHTSIDE][whichline], numberstring);
                    strcat(line[RIGHTSIDE][whichline], ")");
                } else
                {   strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_UNKNOWN_JARL, "Unknown jarl"));
                    strcat(line[RIGHTSIDE][whichline], " (?-?)");
                }
                whichline++;
        }   }
        for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
        {   if (monster[whichmonster].alive && monster[whichmonster].where == whichcounter)
            {   strcpy(line[RIGHTSIDE][whichline], " ");
                strcat(line[RIGHTSIDE][whichline], monstertypes[monster[whichmonster].species]);
                strcat(line[RIGHTSIDE][whichline], " ");
                strcat(line[RIGHTSIDE][whichline], monster[whichmonster].name);
                strcat(line[RIGHTSIDE][whichline], " (");
                stcl_d(numberstring, monster[whichmonster].strength);
                strcat(line[RIGHTSIDE][whichline], numberstring);
                strcat(line[RIGHTSIDE][whichline], "-");
                stcl_d(numberstring, monster[whichmonster].moves);
                strcat(line[RIGHTSIDE][whichline], numberstring);
                strcat(line[RIGHTSIDE][whichline], ")");
                whichline++;
        }   }
        for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
        {   if
            (   treasure[whichtreasure].possessortype == KINGDOM
             && treasure[whichtreasure].where == whichcounter
            )
            {   strcpy(line[RIGHTSIDE][whichline], " ");
                strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_THE, "The"));
                strcat(line[RIGHTSIDE][whichline], " ");
                strcat(line[RIGHTSIDE][whichline], treasure[whichtreasure].name);
                whichline++;
        }   }
        for (whichsord = 0; whichsord <= SORDS; whichsord++)
        {   if
            (   sord[whichsord].possessortype == KINGDOM
             && sord[whichsord].where == whichcounter
            )
            {   strcpy(line[RIGHTSIDE][whichline], " ");
                strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_SWORD, "Sword"));
                strcat(line[RIGHTSIDE][whichline], " ");
                strcat(line[RIGHTSIDE][whichline], sord[whichsord].name);
                whichline++;
        }   }

        if (whichline == oldwhichline)
        {   strcpy(line[RIGHTSIDE][whichline], " ");
            strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_NONE, "None"));
            whichline++;
        }

        rightlines = whichline;
    } elif (countertype == SORD)
    {   strcpy(line[LEFTSIDE][0], GetCatalogStr(li.li_Catalog, MSG_SWORD_NAME, "Sword Name"));
        strcat(line[LEFTSIDE][0], ":");
        pad(line[LEFTSIDE][0]);
        strcat(line[LEFTSIDE][0], sord[whichcounter].name);

        print_location(sord[whichcounter].where, 1);

        leftlines = 2; // counting from 1
        rightlines = 0;
    }

    if (leftlines >= rightlines)
    {   lines = leftlines;
    } else
    {   lines = rightlines;
    }
    if (rightlines > 0)
    {   wide = 1;
    } else
    {   wide = 0;
    }

    if (!(InfoWindowPtr = (struct Window *) OpenWindowTags(NULL,
        WA_Left,          (SCREENXPIXEL / 2) - ((360 + (280 * wide )) / 2),
        WA_Top,           (SCREENYPIXEL / 2) - ( (30 + ( 10 * lines)) / 2),
        WA_Width,         360 + (280 * wide ),
        WA_Height,         30 + ( 10 * lines),
        WA_IDCMP,         IDCMP_CLOSEWINDOW | IDCMP_RAWKEY,
        WA_Title,         GetCatalogStr(li.li_Catalog, MSG_INFORMATION, "Information"),
        WA_Gadgets,       NULL,
        WA_CustomScreen,  ScreenPtr,
        WA_DragBar,       TRUE,
        WA_CloseGadget,   TRUE,
        WA_NoCareRefresh, TRUE,
        WA_Activate,      TRUE,
	TAG_DONE))
    )
    {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open information window!\0", 24);
        cleanexit(EXIT_FAILURE);
    }
    /* if (countertype == HERO)
    {   SetAPen(InfoWindowPtr->RPort, herocolour[whichcounter]);
    } elif (countertype == JARL && jarl[counter].hero != -1)
    {   SetAPen(InfoWindowPtr->RPort, herocolour[jarl[whichcounter].hero]);
    } elif (countertype == KINGDOM && world[counter].hero != -1)
    {   SetAPen(InfoWindowPtr->RPort, herocolour[world[whichcounter].hero]);
    } if we had a free pen, we could do this... else
    {   */ SetAPen(InfoWindowPtr->RPort, LIGHTGREY);
 /* } */
    RectFill(InfoWindowPtr->RPort, 8, 13, 360 + (280 * wide) - 10, 30 + (10 * lines) - 6);
    SetAPen(InfoWindowPtr->RPort, BLACK);
    SetDrMd(InfoWindowPtr->RPort, JAM1);

    for (whichline = 0; whichline < leftlines; whichline++)
    {   Move(InfoWindowPtr->RPort, 16, 26 + (whichline * 10));
        Text(InfoWindowPtr->RPort, line[LEFTSIDE][whichline], strlen(line[LEFTSIDE][whichline]));
    }
    if (wide)
    {   for (whichline = 0; whichline < rightlines; whichline++)
        {   Move(InfoWindowPtr->RPort, 320 + 16, 26 + (whichline * 10));
            Text(InfoWindowPtr->RPort, line[RIGHTSIDE][whichline], strlen(line[RIGHTSIDE][whichline]));
    }   }

    if (counterrow)
    {   if (countertype == HERO)
        {   hero_info(whichcounter);
        } else
        {   assert(countertype == JARL);
            jarl_info(whichcounter);
    }   }

    while(!done)
    {   Wait(1L << InfoWindowPtr->UserPort->mp_SigBit);
        while (MsgPtr = (struct IntuiMessage *) GetMsg(InfoWindowPtr->UserPort))
        {   class  = MsgPtr->Class;
            code   = MsgPtr->Code;
            qual   = MsgPtr->Qualifier;
            ReplyMsg((struct Message *) MsgPtr);
            switch(class)
            {
            case IDCMP_CLOSEWINDOW:
                done = TRUE;
            break;
            case IDCMP_RAWKEY:
                if (!(qual & IEQUALIFIER_REPEAT) && code < KEYUP && (code < FIRSTQUALIFIER || code > LASTQUALIFIER))
                {   done = TRUE;
                }
            break;
            default:
            break;
    }   }   }

    if (counterrow)
    {   uninfo();
    }
    CloseWindow(InfoWindowPtr);
    InfoWindowPtr = NULL;
    clearkybd();
}

MODULE void getdefender(SLONG attackhero, SLONG here)
{   FLAG  done = FALSE;
    SLONG counter, countertype, defendtype, defender, whichattack,
          whichjarl;

    do
    {   saywho(HERO, attackhero, TRUE, FALSE);
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_SELECT_DEFENDER, "select defender"));
        strcat(saystring, "?");
        say(LOWER);

        counter = getevent(COUNTER, &countertype);
        if (counter == -2 || counter == -3)
        {   // user wants to quit (back to `select attacker')
            if (hero[attackhero].attacking)
            {   deselect_hero(attackhero, TRUE);
            }
            for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
            {   if (jarl[whichjarl].alive && jarl[whichjarl].attacking)
                {   deselect_jarl(whichjarl, TRUE);
            }   }
            return;
        } elif (countertype == HERO) // if an enemy hero
        {   if (counter != attackhero && hero[counter].where == here)
            {   defendtype = HERO;
                defender = counter;
                done = TRUE;
        }   }
        elif (countertype == JARL) // if an enemy jarl
        {   if (jarl[counter].hero != attackhero && jarl[counter].where == here)
            {   defendtype = JARL;
                defender = counter;
                done = TRUE;
        }   }
        elif (countertype == MONSTER) // if a monster
        {   if (monster[counter].where == here)
            {   defendtype = MONSTER;
                defender = counter;
                done = TRUE;
        }   }
        elif (countertype == KINGDOM)
        {   if
            (    world[counter].hero != attackhero
              && counter <= 35
              && counter == here
            )
            {   defendtype = KINGDOM;
                defender = counter;
                done = TRUE;
        }   }

        if (done)
        {   if (hero[attackhero].attacking)
            {   // check if the hero has already fought this
                for (whichattack = 0; whichattack <= ATTACKS; whichattack++)
                {   if
                    (   hero[attackhero].attacktype[whichattack] == countertype
                     && hero[attackhero].attacked[whichattack]   == counter
                    )
                    {   done = FALSE;

                        saywho(HERO, attackhero, FALSE, FALSE);
                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_H_A_F_T_T_T, "has already fought that this turn"));
                        strcat(saystring, ".");
                        say(LOWER);
                        anykey();
                        break; // for speed
            }   }   }
            for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
            {   if (jarl[whichjarl].attacking)
                {   for (whichattack = 0; whichattack <= ATTACKS; whichattack++)
                    {   if
                        (   jarl[whichjarl].attacktype[whichattack] == countertype
                         && jarl[whichjarl].attacked[whichattack]   == counter
                        )
                        {   done = FALSE;

                            saywho(JARL, whichjarl, FALSE, FALSE);
                            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_H_A_F_T_T_T, "has already fought that this turn"));
                            strcat(saystring, ".");
                            say(LOWER);
                            anykey();
                            break; // for speed
        }   }   }   }   }
        else
        {   ; // DisplayBeep(ScreenPtr);
    }   }
    while (!done);

    // ok, going ahead with the battle
    if (countertype == JARL && jarl[counter].face == FACEDOWN)
    {   revealjarl(counter, TRUE);
    }
    if (hero[attackhero].attacking)
    {   for (whichattack = 0; whichattack <= ATTACKS; whichattack++)
        {   if (hero[attackhero].attacktype[whichattack] == -1)
            {   hero[attackhero].attacktype[whichattack] = countertype;
                hero[attackhero].attacked[whichattack]   = counter;
                break;
    }   }   }
    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
    {   if (jarl[whichjarl].attacking)
        {   for (whichattack = 0; whichattack <= ATTACKS; whichattack++)
            {   if (jarl[whichjarl].attacktype[whichattack] == -1)
                {   jarl[whichjarl].attacktype[whichattack] = countertype;
                    jarl[whichjarl].attacked[whichattack]   = counter;
                    break;
    }   }   }   }

    dobattle(countertype, counter, attackhero);
}

MODULE FLAG needsord(SLONG countertype, SLONG counter)
{   SLONG whichsord;

    for (whichsord = 0; whichsord <= SORDS; whichsord++)
    {   if
        (   sord[whichsord].possessortype == countertype
         && sord[whichsord].possessor == counter
        )
        {   return(FALSE);
    }   }
    return(TRUE);
}

MODULE void brosung(SLONG countertype, SLONG whichcounter)
{   SLONG result, whichconnection, whichmonster, whichtreasure, where;
   
    for (whichconnection = 0; whichconnection <= CONNECTIONS; whichconnection++)
    {   if (countertype == HERO)
        {   where = world[hero[whichcounter].where].connection[whichconnection];
        } else
        {   assert(countertype == JARL);
            where = world[jarl[whichcounter].where].connection[whichconnection];
        }
        if (where == -1)
        {   break;
        }
        for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
        {   if
            (   monster[whichmonster].alive
             && monster[whichmonster].species == DRAGON
             && monster[whichmonster].where == where
            )
            {   // there is a dragon here
                for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
                {   if
                    (   treasure[whichtreasure].possessortype == MONSTER
                     && treasure[whichtreasure].possessor == whichmonster
                    )
                    {   /* We know it is human control because we
                           don't call this function for Amiga heroes/jarls */

                        saywho(countertype, whichcounter, TRUE, FALSE);
                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_EXCHANGE_THE, "exchange the"));
                        strcat(saystring, " ");
                        strcat(saystring, treasure[BROSUNGNECKLACE].name);
                        strcat(saystring, " ");
                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_WITH, "with"));
                        strcat(saystring, " ");
                        strcat(saystring, monstertypes[DRAGON]);
                        strcat(saystring, " ");
                        strcat(saystring, monster[whichmonster].name);
                        strcat(saystring, " (");
                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_CHAR_YES, "Y"));
                        strcat(saystring, "/");
                        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_CHAR_NO, "N"));
                        strcat(saystring, ")?");
                        say(LOWER);
                        do
                        {   result = getevent(KEYBOARD, NULL);
                        } while (result != onekey[ONEKEY_YES] && result != onekey[ONEKEY_NO]);
                        if (result == onekey[ONEKEY_YES])
                        {   // give the dragon's treasure to the hero/jarl
                            treasure[whichtreasure].possessortype   = countertype;
                            treasure[whichtreasure].possessor       = whichcounter;

                            saywho(countertype, whichcounter, TRUE, FALSE);
                            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_TAKES_THE, "takes the"));
                            strcat(saystring, " ");
                            strcat(saystring, treasure[whichtreasure].name);
                            strcat(saystring, ".");
                            say(LOWER);

                            // give the hero/jarl's treasure to the dragon
                            treasure[BROSUNGNECKLACE].possessortype = MONSTER;
                            treasure[BROSUNGNECKLACE].possessor     = whichmonster;
                            break;
}   }   }   }   }   }   }

MODULE void flash(SLONG country)
{   SLONG colour;

    if (country < 0 || country > 65)
    {   return;
    }

    if (country == 9)
    {   colour = 89; // Suder Gotland
    } elif (country == 10)
    {   colour = 90; // Juteland
    } elif (country == 11)
    {   colour = 91; // Scandia
    } else
    {   colour = country + 8;
    }

    SetRGB4(&ScreenPtr->ViewPort, colour, 15, 15, 15); // white flash
    Delay(2); // hold the flash

    if (country >= 36)
    {   SetRGB4(&ScreenPtr->ViewPort, colour,  0,  0,  9); // dark blue
    } elif (world[country].hero != -1)
    {   SetRGB4
        (   &ScreenPtr->ViewPort,
            colour,
            herocolour[world[country].hero].red,
            herocolour[world[country].hero].green,
            herocolour[world[country].hero].blue
        );
    } elif (world[country].is)
    {   SetRGB4(&ScreenPtr->ViewPort, colour, 12, 12, 12); // light grey ice
    } else
    {   SetRGB4
        (   &ScreenPtr->ViewPort,
            colour,
            taxcolours[world[country].tax].red,
            taxcolours[world[country].tax].green,
            taxcolours[world[country].tax].blue
        );
}   }

MODULE FLAG assess(SLONG countertype, SLONG counter)
{   return(FALSE);
}

MODULE void promote(SLONG whichhero, SLONG whichjarl)
{   remove_jarl(whichjarl, TRUE);
    jarl[whichjarl].alive     = FALSE;
    hero[whichhero].alive     = TRUE;
    hero[whichhero].promoted  = whichjarl;
    hero[whichhero].name      = jarl[whichjarl].name;
    hero[whichhero].moves     = jarl[whichjarl].moves;
    hero[whichhero].strength  = jarl[whichjarl].strength;
    hero[whichhero].where     = jarl[whichjarl].where;
    hero[whichhero].homewhere = jarl[whichjarl].homewhere;
    hero[whichhero].god       =
    hero[whichhero].rune      = -1;
    hero[whichhero].maidens   =
    hero[whichhero].glory     = 0;
    hero[whichhero].hagall    = jarl[whichjarl].hagall;
    hero[whichhero].loseturn  = jarl[whichjarl].loseturn;
    hero[whichhero].wealth    = jarl[whichjarl].wealth;
    hero[whichhero].wounded   = FALSE;
    deselect_hero(whichhero, TRUE);
    move_hero(whichhero, TRUE);
}

MODULE void withdraw(SLONG whichhero)
{   SLONG whichcountry, whichjarl;

    hero[whichhero].verydead = TRUE;

    // all the jarls of the dead hero are freed
    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
    {   if (jarl[whichjarl].alive && jarl[whichjarl].hero == whichhero)
        {   jarl[whichjarl].hero = -1;
    }   }

    // all the kingdoms of the dead hero declare independence
    for (whichcountry = 0; whichcountry <= 35; whichcountry++)
    {   if (world[whichcountry].hero == whichhero)
        {   world[whichcountry].hero = -1;
    }   }

    darken();
}

MODULE FLAG asksord(SLONG countertype, SLONG counter, SLONG whichsord)
{   SLONG result, whichcountry;

    if (countertype == JARL)
    {   whichcountry = jarl[counter].where;
    } else
    {   whichcountry = hero[counter].where;
    }

    saywho(countertype, counter, FALSE, FALSE);
    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_IN, "in"));
    strcat(saystring, " ");
    strcat(saystring, world[whichcountry].name);
    strcat(saystring, ", ");
    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_TAKE_SWORD, "take sword"));
    strcat(saystring, " ");
    strcat(saystring, sord[whichsord].name);
    strcat(saystring, " (");
    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_CHAR_YES, "Y"));
    strcat(saystring, "/");
    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_CHAR_NO, "N"));
    strcat(saystring, ")?");
    say(LOWER);
    do
    {   result = getevent(KEYBOARD, NULL);
    } while (result != onekey[ONEKEY_YES] && result != onekey[ONEKEY_NO]);
    if (result == onekey[ONEKEY_YES])
    {   remove_sord(whichsord, TRUE);
        sord[whichsord].possessortype = countertype;
        sord[whichsord].possessor     = counter;
        sord[whichsord].where         = -1;
        return(TRUE);
    }
    // assert(result == onekey[ONEKEY_NO]);
    return(FALSE);
}


MODULE void asktreasure(SLONG countertype, SLONG counter, SLONG whichtreasure)
{   SLONG result, whichcountry;

    if (countertype == JARL)
    {   whichcountry = jarl[counter].where;
    } else
    {   whichcountry = hero[counter].where;
    }

    saywho(countertype, counter, FALSE, FALSE);
    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_IN, "in"));
    strcat(saystring, " ");
    strcat(saystring, world[whichcountry].name);
    strcat(saystring, ", ");
    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_TAKE_THE, "take the"));
    strcat(saystring, " ");
    strcat(saystring, treasure[whichtreasure].name);
    strcat(saystring, " (");
    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_CHAR_YES, "Y"));
    strcat(saystring, "/");
    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_CHAR_NO, "N"));
    strcat(saystring, ")?");
    say(LOWER);
    do
    {   result = getevent(KEYBOARD, NULL);
    } while (result != onekey[ONEKEY_YES] && result != onekey[ONEKEY_NO]);
    if (result == onekey[ONEKEY_YES])
    {   remove_treasure(whichtreasure, TRUE);
        treasure[whichtreasure].possessortype = countertype;
        treasure[whichtreasure].possessor     = counter;
        treasure[whichtreasure].where         = -1;
}   }

MODULE void pad(STRPTR thestring)
{   SLONG i, length;

    length = strlen(thestring);

    if (length < 21)
    {   for (i = length; i <= 21; i++)
        {   strcat(thestring, " ");
}   }   }

MODULE void print_location(SLONG whichcountry, SLONG index)
{   strcpy(line[LEFTSIDE][index], GetCatalogStr(li.li_Catalog, MSG_LOCATION, "Location"));
    strcat(line[LEFTSIDE][index], ":");
    pad(line[LEFTSIDE][index]);
    strcat(line[LEFTSIDE][index], world[whichcountry].name);
    strcat(line[LEFTSIDE][index], " (");
    stcl_d(numberstring, world[whichcountry].tax);
    strcat(line[LEFTSIDE][index], numberstring);
    strcat(line[LEFTSIDE][index], ")");
}

MODULE void print_sea(SLONG sea_value, SLONG index)
{   strcpy(line[LEFTSIDE][index], GetCatalogStr(li.li_Catalog, MSG_MOVE_BY_SEA, "Move by sea"));
    strcat(line[LEFTSIDE][index], "?");
    pad(line[LEFTSIDE][index]);
    if (sea_value == NORMAL)
    {   strcat(line[LEFTSIDE][index], GetCatalogStr(li.li_Catalog, MSG_YES, "Yes"));
    } elif (sea_value == BAD)
    {   strcat(line[LEFTSIDE][index], GetCatalogStr(li.li_Catalog, MSG_NO, "No"));
    } else
    {   // assert(sea_value == GOOD);
        strcat(line[LEFTSIDE][index], GetCatalogStr(li.li_Catalog, MSG_SPECIAL, "Special"));
}   }

MODULE void print_hagall(SLONG hagall_value, SLONG index)
{   strcpy(line[LEFTSIDE][index], "Hagall (");
    strcat(line[LEFTSIDE][index], GetCatalogStr(li.li_Catalog, MSG_SLOWED, "slowed"));
    strcat(line[LEFTSIDE][index], ")?");
    pad(line[LEFTSIDE][index]);
    if (hagall_value)
    {   strcat(line[LEFTSIDE][index], GetCatalogStr(li.li_Catalog, MSG_YES, "Yes"));
    } else
    {   strcat(line[LEFTSIDE][index], GetCatalogStr(li.li_Catalog, MSG_NO, "No"));
}   }

MODULE void print_paralyzed(SLONG loseturn_value, SLONG index)
{   strcpy(line[LEFTSIDE][index], GetCatalogStr(li.li_Catalog, MSG_PARALYZED, "Paralyzed"));
    strcat(line[LEFTSIDE][index], "?");
    pad(line[LEFTSIDE][index]);
    if (loseturn_value)
    {   strcat(line[LEFTSIDE][index], GetCatalogStr(li.li_Catalog, MSG_YES, "Yes"));
    } else
    {   strcat(line[LEFTSIDE][index], GetCatalogStr(li.li_Catalog, MSG_NO, "No"));
}   }

MODULE void print_routed(SLONG routed_value, SLONG index)
{   strcpy(line[LEFTSIDE][index], GetCatalogStr(li.li_Catalog, MSG_ROUTED, "Routed"));

    strcat(line[LEFTSIDE][index], "?");
    pad(line[LEFTSIDE][index]);
    if (routed_value)
    {   strcat(line[LEFTSIDE][index], GetCatalogStr(li.li_Catalog, MSG_YES, "Yes"));
    } else
    {   strcat(line[LEFTSIDE][index], GetCatalogStr(li.li_Catalog, MSG_NO, "No"));
}   }

MODULE void amiga_attack(SLONG attackhero, SLONG defendtype, SLONG defender)
{   SLONG whichattack, whichjarl;

    // ok, going ahead with the battle
    if (defendtype == JARL && jarl[defender].face == FACEDOWN)
    {   revealjarl(defender, TRUE);
    }
    if (hero[attackhero].attacking)
    {   for (whichattack = 0; whichattack <= ATTACKS; whichattack++)
        {   if (hero[attackhero].attacktype[whichattack] == -1)
            {   hero[attackhero].attacktype[whichattack] = defendtype;
                hero[attackhero].attacked[whichattack]   = defender;
                break;
    }   }   }
    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
    {   if (jarl[whichjarl].attacking)
        {   for (whichattack = 0; whichattack <= ATTACKS; whichattack++)
            {   if (jarl[whichjarl].attacktype[whichattack] == -1)
                {   jarl[whichjarl].attacktype[whichattack] = defendtype;
                    jarl[whichjarl].attacked[whichattack]   = defender;
                    break;
    }   }   }   }

    saywho(HERO, attackhero, FALSE, FALSE);
    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_ATTACKS, "attacks"));

    if (defendtype == HERO || defendtype == JARL)
    {   saywho(defendtype, defender, FALSE, TRUE);
    } elif (defendtype == MONSTER)
    {   strcat(saystring, " ");
        strcat(saystring, monstertypes[monster[defender].species]);
        strcat(saystring, " ");
        strcat(saystring, monster[defender].name);
    } else
    {   // assert(defendtype == KINGDOM);
        strcat(saystring, " ");
        if (world[defender].hero != -1)
        {   strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_HERO2, "hero"));
            strcat(saystring, " ");
            strcat(saystring, hero[world[defender].hero].name);
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_S, "'s"));
            strcat(saystring, " ");
        }
        strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_KINGDOM, "kingdom"));
        strcat(saystring, " ");
        strcat(saystring, world[defender].name);
        strcat(saystring, " (");
        stcl_d(numberstring, world[defender].tax);
        strcat(saystring, numberstring);
        strcat(saystring, ")");
    }

    strcat(saystring, ".");
    say(LOWER);
    anykey();
    dobattle(defendtype, defender, attackhero);
}

MODULE FLAG ask_faxi(SLONG countertype, SLONG whichcounter)
{   SLONG result;

    saywho(countertype, whichcounter, TRUE, FALSE);
    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_RIDE_THE, "ride the"));
    strcat(saystring, " ");
    strcat(saystring, treasure[FREYFAXI].name);
    strcat(saystring, " (");
    stcl_d(numberstring, faxirides);
    strcat(saystring, numberstring);
    strcat(saystring, " ");
    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_RIDES2, "rides"));
    strcat(saystring, ") (");
    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_CHAR_YES, "Y"));
    strcat(saystring, "/");
    strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_CHAR_NO, "N"));
    strcat(saystring, ")?");
    say(LOWER);

    do
    {    result = getevent(KEYBOARD, NULL);
    } while (result != onekey[ONEKEY_YES] && result != onekey[ONEKEY_NO]);
    if (result == onekey[ONEKEY_YES])
    {   faxirides--;
        faxi_disappear();
        return(TRUE);
    }
    return(FALSE);
}

MODULE void saywho(SLONG countertype, SLONG counter, FLAG comma, FLAG lowercase)
{   if (!lowercase)
    {   saystring[0] = 0;
    } else
    {   strcat(saystring, " ");
    }
    if (countertype == HERO)
    {   if (!lowercase)
        {   strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_HERO, "Hero"));
        } else
        {   strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_HERO2, "hero"));
        }
        strcat(saystring, " ");
        strcat(saystring, hero[counter].name);
    } else
    {   // assert(countertype == JARL);
        if (jarl[counter].hero != -1)
        {   if (!lowercase)
            {   strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_HERO, "Hero"));
            } else
            {   strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_HERO2, "hero"));
            }
            strcat(saystring, " ");
            strcat(saystring, hero[jarl[counter].hero].name);
            strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_S_JARL, "'s jarl"));
        } else
        {   if (!lowercase)
            {   strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_JARL, "Jarl"));
            } else
            {   strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_JARL2, "jarl"));
        }   }
        strcat(saystring, " ");
        strcat(saystring, jarl[counter].name);
    }
    if (!lowercase)
    {   if (comma)
        {   strcat(saystring, ",");
        }
        strcat(saystring, " ");
}   }

MODULE FLAG attackersleft(void)
{   SLONG whichhero, whichjarl;

    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   if (hero[whichhero].attacking)
        {   return(TRUE);
    }   }
    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
    {   if (jarl[whichjarl].attacking)
        {   return(TRUE);
    }   }
    return(FALSE);
}

MODULE void summarywindow(void)
{   SLONG                i,
                         jarls,
                         kingdoms,
                         length,
                         treasures,
                         wealth,
                         whichcountry,
                         whichjarl,
                         whichhero,
                         whichtreasure,
                         whichsord;
    FLAG                 done = FALSE,
                         ok;
    ULONG                class;
    UWORD                code, qual;
    struct IntuiMessage* MsgPtr;

    strcpy(line[0][0], GetCatalogStr(li.li_Catalog, MSG_SUMMARYLINE, "Hero Name  C-M J K S T C S R Glry Luck $$$$"));

                     /* Hero Name  C-M J K S T C S R Glry Luck $$$$
                                   o o a i w r o t u
                                   m v r n o e n a n
                                   b e l g r a t t e
                                   a m s d d s r u s
                                   t e   o   u o s
                                     n   m   r l
                                     t   s   e
                                             s

                        Heldenname K-B J K S S K S @ Ruhm Glck $$$$
                                   a e a ö c c o t @
                                   m w r n h h n a @
                                   p e l i w ä t t @
                                   f g s g e t r u @
                                     u   r r z o s @
                                     n   e t e l
                                     g   i     l
                                     s   c     e
                                         h
                                         e */

    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   strcpy(line[0][whichhero + 1], hero[whichhero].name);

        length = strlen(hero[whichhero].name);
        for (i = length; i < 11; i++)
        {   strcat(line[0][whichhero + 1], " ");
        }

        stcl_d(numberstring, hero[whichhero].strength);
        strcat(line[0][whichhero + 1], numberstring);
        strcat(line[0][whichhero + 1], "-");

        stcl_d(numberstring, hero[whichhero].moves);
        strcat(line[0][whichhero + 1], numberstring);
        strcat(line[0][whichhero + 1], " ");

        jarls = 0;
        for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
        {   if (jarl[whichjarl].alive && jarl[whichjarl].hero == whichhero)
            {   jarls++;
        }   }
        stcl_d(numberstring, jarls);
        strcat(line[0][whichhero + 1], numberstring);
        strcat(line[0][whichhero + 1], " ");

        kingdoms = 0;
        for (whichcountry = 0; whichcountry <= 35; whichcountry++)
        {   if (world[whichcountry].hero == whichhero)
            {   kingdoms++;
        }   }
        stcl_d(numberstring, kingdoms);
        strcat(line[0][whichhero + 1], numberstring);
        strcat(line[0][whichhero + 1], " ");

        ok = FALSE;
        for (whichsord = 0; whichsord <= SORDS; whichsord++)
        {   if
            (   sord[whichsord].possessortype == HERO
             && sord[whichsord].possessor     == whichhero
            )
            {   numberstring[0] = sord[whichsord].name[0];
                numberstring[1] = 0;
                strcat(line[0][whichhero + 1], numberstring);
                ok = TRUE;
                break;
        }   }
        if (!ok)
        {   strcat(line[0][whichhero + 1], "-");
        }
        strcat(line[0][whichhero + 1], " ");

        treasures = 0;
        for (whichtreasure = 0; whichtreasure <= SORDS; whichtreasure++)
        {   if
            (   (   treasure[whichtreasure].possessortype == HERO
                 && treasure[whichtreasure].possessor     == whichhero
                )
             || (   treasure[whichtreasure].possessortype == JARL
                 && jarl[treasure[whichtreasure].possessor].hero == whichhero
            )   )
            {   treasures++;
        }   }
        stcl_d(numberstring, treasures);
        strcat(line[0][whichhero + 1], numberstring);
        strcat(line[0][whichhero + 1], " ");

        if (hero[whichhero].control == HUMAN)
        {   strcat(line[0][whichhero + 1], GetCatalogStr(li.li_Catalog, MSG_CHAR_HUMAN, "H"));
        } elif (hero[whichhero].control == AMIGA)
        {   strcat(line[0][whichhero + 1], "A");
        } else
        {   // assert(hero[whichhero].control == NONE);
            strcat(line[0][whichhero + 1], "-");
        }
        strcat(line[0][whichhero + 1], " ");

        if (!hero[whichhero].alive)
        {   strcat(line[0][whichhero + 1], GetCatalogStr(li.li_Catalog, MSG_CHAR_DEAD,    "D"));
        } elif (hero[whichhero].wounded)
        {   strcat(line[0][whichhero + 1], GetCatalogStr(li.li_Catalog, MSG_CHAR_WOUNDED, "W"));
        } else
        {   strcat(line[0][whichhero + 1], GetCatalogStr(li.li_Catalog, MSG_CHAR_GOOD,    "G"));
        }

        strcat(line[0][whichhero + 1], " ");
        if (hero[whichhero].rune == -1)
        {   strcat(line[0][whichhero + 1], "-");
        } else
        {   numberstring[0] = runename[hero[whichhero].rune][0];
            numberstring[1] = 0;
            strcat(line[0][whichhero + 1], numberstring);
        }

        stcl_d(numberstring, hero[whichhero].glory);
        length = strlen(numberstring);
        for (i = length; i < 5; i++)
        {   strcat(line[0][whichhero + 1], " ");
        }
        strcat(line[0][whichhero + 1], numberstring);

        stcl_d(numberstring, hero[whichhero].luck);
        length = strlen(numberstring);
        for (i = length; i < 5; i++)
        {   strcat(line[0][whichhero + 1], " ");
        }
        strcat(line[0][whichhero + 1], numberstring);

        wealth = hero[whichhero].wealth;
        for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
        {   if (jarl[whichjarl].alive && jarl[whichjarl].hero == whichhero)
            {   wealth += jarl[whichjarl].wealth;
        }   }
        stcl_d(numberstring, wealth);
        length = strlen(numberstring);
        for (i = length; i < 5; i++)
        {   strcat(line[0][whichhero + 1], " ");
        }
        strcat(line[0][whichhero + 1], numberstring);
    }

    if (!(InfoWindowPtr = (struct Window *) OpenWindowTags(NULL,
        WA_Left,          (SCREENXPIXEL / 2) - (378 / 2),
        WA_Top,           (SCREENYPIXEL / 2) - (102 / 2),
        WA_Width,         378,
        WA_Height,        102,
        WA_IDCMP,         IDCMP_CLOSEWINDOW | IDCMP_RAWKEY,
        WA_Title,         GetCatalogStr(li.li_Catalog, MSG_GAME_SUMMARY, "Game Summary"),
        WA_Gadgets,       NULL,
        WA_CustomScreen,  ScreenPtr,
        WA_DragBar,       TRUE,
        WA_CloseGadget,   TRUE,
        WA_NoCareRefresh, TRUE,
        WA_Activate,      TRUE,
	TAG_DONE))
    )
    {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open summary window!\0", 24);
        cleanexit(EXIT_FAILURE);
    }
    RectFill(InfoWindowPtr->RPort, 8, 13, 378 - 10, 102 - 6);
    SetAPen(InfoWindowPtr->RPort, BLACK);
    SetDrMd(InfoWindowPtr->RPort, JAM1);

    Move(InfoWindowPtr->RPort, 16, 26);
    Text(InfoWindowPtr->RPort, line[0][0], strlen(line[0][0]));
    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   Move(InfoWindowPtr->RPort, 16, 38 + (whichhero * 10));
        Text(InfoWindowPtr->RPort, line[0][whichhero + 1], strlen(line[0][whichhero + 1]));
    }
    Move(InfoWindowPtr->RPort, 16, 29);
    Draw(InfoWindowPtr->RPort, 368 - 10, 29);

    while(!done)
    {   Wait(1L << InfoWindowPtr->UserPort->mp_SigBit);
        while (MsgPtr = (struct IntuiMessage *) GetMsg(InfoWindowPtr->UserPort))
        {   class  = MsgPtr->Class;
            code   = MsgPtr->Code;
            qual   = MsgPtr->Qualifier;
            ReplyMsg((struct Message *) MsgPtr);
            switch(class)
            {
            case IDCMP_CLOSEWINDOW:
                done = TRUE;
            break;
            case IDCMP_RAWKEY:
                if (!(qual & IEQUALIFIER_REPEAT) && code < KEYUP && (code < FIRSTQUALIFIER || code > LASTQUALIFIER))
                {   done = TRUE;
                }
            break;
            default:
            break;
    }   }   }

    CloseWindow(InfoWindowPtr);
    InfoWindowPtr = NULL;
    clearkybd();
}

MODULE SLONG getattackers(SLONG whichhero, SLONG whichcountry)
{   SLONG whichjarl,
          totalstrength = 0;
    FLAG  ok            = FALSE;

    if (hero[whichhero].alive && !hero[whichhero].routed && hero[whichhero].where == whichcountry)
    {   hero[whichhero].attacking = TRUE;
        select_hero(whichhero, FALSE);
        ok = TRUE;
        totalstrength += hero[whichhero].strength;
    }
    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
    {   if (jarl[whichjarl].alive && jarl[whichjarl].hero == whichhero && !jarl[whichjarl].routed && jarl[whichjarl].where == whichcountry)
        {   jarl[whichjarl].attacking = TRUE;
            select_jarl(whichjarl, FALSE);
            ok = TRUE;
            totalstrength += jarl[whichjarl].strength;
    }   }
    if (ok)
    {   refreshcounters();
    }
    return(totalstrength);
}
