Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!utgpu!utfyzx!sq!hobie From: hobie@sq.UUCP Newsgroups: comp.sys.amiga Subject: Amiga Ogre (Part 2/2) Message-ID: <1987Feb22.121205.9387@sq.uucp> Date: Sun, 22-Feb-87 12:12:05 EST Article-I.D.: sq.1987Feb22.121205.9387 Posted: Sun Feb 22 12:12:05 1987 Date-Received: Sun, 22-Feb-87 23:37:14 EST Reply-To: hobie@sq.uucp (Hobie Orris) Organization: SoftQuad Inc., Toronto Lines: 3125 Checksum: 01662 # Amiga Ogre Part 2: The source # This file contains: # README # linkfile - Alink WITH file # ogre.h ext.h # termcap.c initround.c main.c init.c help.c map.c move.c # attack.c resolve.c ogrecom.c ogrestat.c : To unbundle, sh this file echo x - README 1>&2 cat >README <<'@@@End of README' This file describes the programs comprising the Ogre game, and instructions for making it. For instructions on how to play it, read the file `Instructions'. Building the Ogre program: Compile the individual files, making sure that the compiler can find ext.h and ogre.h in the current directory. Link the files to form ogre by typing: 'lc:c/alink with linkfile', assuming your linker is on volume lc: and the modules to be linked are in the current directory. Type `ogre' to run the game, or use the icon. The Instructions menu will not work unless the Instructions file is on the volume `Ogre:'. The Files: ext.h - external variables such as the ogre and the friendly units. ogre.h - typedefs and defines of the global structures and constants. main.c - the main() routine. termcap.c - all console I/O routines for the Amiga. map.c - all the map handling routines for displaying units and craters, and stuff. Also contains the range calculating routine. attack.c - collect attack orders and display odds. Doesn't actually execute the attacks. init.c - initializes all the units and executes the initial deployment orders. A notable deviation from the original program is that I used the K&R shell sort, where the original used the Unix qsort(), for which I had no source. initround.c - does the initializations required every game turn, such as updating hexes, calculating ranges to the ogre and more. move.c - does the player's movements. ogrecom.c - the routines behind the ogre's "strategy". See below. ogrestat.c - handles the status display at the bottom of the screen. resolve.c - resolve all attacks and rammings. The Ogre's Strategy Movement: Weights are assigned to all the directions in which the ogre can move. The primary consideration is the distance to the CP; in the absence of other factors the Ogre will take the fastest route to it. However, it will crush any unit it can (best attacker first) and moves towards units that are in range of its missiles and batteries. It tries to weight so that dangerous, immobile units (howitzers) are attacked first. Fire: The basic strategy here is to fire at the next unit in range. Since the units are sorted by value, this will usually resuly in reasonable choices for targets, although the Ogre tends to overkill. Suggested improvements: ----------------------- Some things you may like to add to the game are additional units. The following are units from the game GEV: Mobile Howitzer (6/6 M1 D2) Ogre Mark IV ------------ Main Batteries: 1 (4/3 D4) Missile Racks: 3 (D4) Each contains 5 missiles and can be attacked instead of the missiles themselves Missiles: 15 (6/5) Only one missile per rack can be fired per turn Secondary Bats: 2 (3/2 D3) Anti-personnel: 8 (1/1 D1) Treads: 60 These treads are in groups of 4 instead of 3. The initial movement is 4, and is reduced by 1 per 15 treads destroyed. ----------------------------------------------------------------------------- Any comments, suggestions or enhancements are welcome. Hobie Orris 9 Ferrier Ave. Toronto, Ont., M4K 3H5 @@@End of README echo x - attack.c 1>&2 cat >attack.c <<'@@@End of attack.c' #include "ext.h" static OGRE allocated; #define PASS 'p' #define NOPASS '\0' #define RESOLVE 'r' #define MISSILE 'm' #define MAIN 'b' #define SECONDARY 's' #define AP 'a' #define TREAD 't' attack_def() { char moreunits; int i; moreunits = TRUE; zero(&allocated, sizeof(allocated)); init_def_attack(); while (moreunits) { moreunits = FALSE; for (i = 0; i < n_units; i++) { /* * Don't bother attacking if Ogre is immobile - H.O. */ if (ogre.movement == 0) check_over(); if (unit[i].status == OK && !unit[i].fired && unit[i].attack > 0 && unit[i].range_to_ogre <= unit[i].range) { describe_action("Fire",i); if (get_target(i) == PASS) moreunits = TRUE; else unit[i].fired = TRUE; } } } ogre_resolve(&allocated); } get_target(i) int i; { char action, invalid; movecur_unit(i); do { invalid = FALSE; action = Amiga_getchar(); switch (action) { case PASS: return(PASS); case MISSILE: if (ogre.missiles > 0) { allocated.missiles += unit[i].attack; update_odds(action); } else invalid = TRUE; break; case MAIN: if (ogre.main_bats > 0) { allocated.main_bats +=unit[i].attack; update_odds(action); } else invalid = TRUE; break; case SECONDARY: if (ogre.sec_bats > 0) { allocated.sec_bats +=unit[i].attack; update_odds(action); } else invalid = TRUE; break; case AP: if (ogre.ap > 0) { allocated.ap += unit[i].attack; update_odds(action); } else invalid = TRUE; break; case TREAD: if (ogre.treads > 0) { allocated.treads += unit[i].attack; update_odds(action); } else invalid = TRUE; if (invalid) break; ogre_resolve(&allocated); zero(&allocated,sizeof(allocated)); break; case RESOLVE: ogre_resolve(&allocated); zero(&allocated, sizeof(allocated)); return(PASS); break; default: invalid = TRUE; break; } } while (invalid); return(NOPASS); } zero(area, size) char *area; int size; { int i; for (i = 0; i < size; i++) area[i] = '\0'; } update_odds(weapon) char weapon; { char c[80]; static char blanks[10] = {" "}; char *odd_str(); switch (weapon) { case MAIN: movecur(18, 40); Amiga_puts(blanks); movecur(18, 40); sprintf(c,"%d %d (%s)",allocated.main_bats, DEF_MAIN, odd_str(allocated.main_bats, DEF_MAIN)); Amiga_puts(c); break; case SECONDARY: movecur(19, 40); Amiga_puts(blanks); movecur(19,40); sprintf(c,"%d %d (%s)",allocated.sec_bats, DEF_SECONDARY, odd_str(allocated.sec_bats, DEF_SECONDARY)); Amiga_puts(c); break; case MISSILE: movecur(20, 40); Amiga_puts(blanks); movecur(20,40); sprintf(c,"%s", odd_str(allocated.missiles, DEF_MISSILES)); Amiga_puts(c); break; case AP: movecur(21, 40); Amiga_puts(blanks); movecur(21,40); sprintf(c,"%s",odd_str(allocated.ap,DEF_AP)); Amiga_puts(c); break; case TREAD: movecur(22, 40); Amiga_puts(blanks); movecur(22,40); sprintf(c,"1/1 (%d) ", allocated.treads); Amiga_puts(c); break; } } @@@End of attack.c echo x - ext.h 1>&2 cat >ext.h <<'@@@End of ext.h' #include "ogre.h" #ifdef MAIN UNIT unit[N_UNITS]; OGRE ogre; int n_units; #else extern UNIT unit[N_UNITS]; extern OGRE ogre; extern int n_units; #endif @@@End of ext.h echo x - help.c 1>&2 cat >help.c <<'@@@End of help.c' #include #include #include #include #include #include #include #include #include struct NewWindow hw = { 0, 0, 640, 200, 3, 1, NULL, ACTIVATE, 0, NULL,"Ogre Help", NULL, NULL, 100, 45, 640, 200, CUSTOMSCREEN }; #define FULLPAGE 21 #define NUMCHAR 100 extern struct Screen *scrn; struct IOStdReq *HelpMsg, *MoreMsg; struct MsgPort *HelpPort, *MorePort; struct Window *helpwin; char fname[] = "Ogre:Instructions"; char buf[NUMCHAR]; UBYTE response; /* Open a window and a console for printing game instructions, and * open the instructions file. Note that the game volume name MUST * be "Ogre" for this to work. */ get_help() { FILE *fp, *fopen(); int error; /* read, write ports for the help window */ /* Can't open it. Complain. */ HelpPort = CreatePort("con2.write",0); if (HelpPort == NULL) return(-1); HelpMsg = CreateStdIO(HelpPort); if (HelpMsg == NULL) return(-1); MorePort = CreatePort("con2.read",0); if (MorePort == NULL) return(-2); MoreMsg = CreateStdIO(MorePort); if (MoreMsg == NULL) return(-2); hw.Screen = scrn; helpwin = (struct Window *) OpenWindow(&hw); if (helpwin == NULL) return(-1); error = OpenConsole(HelpMsg, MoreMsg, helpwin); if (error != 0) { end_help(); return(-3); } QueueRead(MoreMsg, &response); /* open the instructions file */ if (Lock(fname, ACCESS_READ) == NULL) { ConPutStr(HelpMsg, "\nCan't open Ogre:Instructions. Check your volume name.\n"); Delay(250); error = end_help(); return(-4); } fp = fopen(fname,"r"); if (fp == NULL) { return(-4); } put_help(fp); error = end_help(); close(fp); return(error); } /* cleanup and exit */ int end_help() { int error; DeletePort(HelpPort); DeleteStdIO(HelpMsg); DeletePort(MorePort); DeleteStdIO(MoreMsg); error = CloseWindow(helpwin); return(error); } /* write help file to window and read for more */ put_help(fp) FILE *fp; { int nomore = 0, numlines = 0; while ((nomore = fgets(&buf[0], NUMCHAR, fp)) != NULL) { ConPutStr(HelpMsg, buf); numlines += 1; /* when a full page has been written, pause for a keystroke */ if (numlines == FULLPAGE) { response = ConGetChar(MorePort, MoreMsg, &response); numlines = 0; } } /* get one last key to clear the remaining text from the screen */ response = ConGetChar(MorePort, MoreMsg, &response); } @@@End of help.c echo x - init.c 1>&2 cat >init.c <<'@@@End of init.c' #include "ext.h" static char a,b; static int cp_set; static int infantry_points, armor_points; init_units(mark) { char s[80]; int i,j; int unitcmp(); a = b = 10; switch (mark) { case 3: armor_points = 16; infantry_points = 18; break; case 5: armor_points = 22; infantry_points = 27; break; } n_units = 0; cp_set = FALSE; while (armor_points > 0 || infantry_points > 0 || !cp_set) { sprintf(s, "left to place: %d armor, %d infantry%s", armor_points, infantry_points, (cp_set) ? "." : ", CP"); movecur(16,0); eeol(16); Amiga_puts(s); getunit(); } sort(&unit[0], n_units, sizeof(UNIT), unitcmp); } sort(unit, n, size, comp) UNIT *unit; int n, size; int (*comp)(); { int gap, i, j; UNIT tmp; for (gap = n/2; gap > 0; gap /= 2) for (i = gap; i < n; ++i) for (j = i - gap; j >= 0; j -= gap) { if ((*comp)(unit[j], unit[j + gap]) <= 0) break; tmp = unit[j]; unit[j] = unit[j + gap]; unit[j + gap] = tmp; } } getunit() { char no_new, bad_char; char olda, oldb; char dir; no_new = TRUE; bad_char = FALSE; movecur_hex(a, b); while (no_new) { olda = a; oldb = b; dir = Amiga_getchar(); switch (dir) { case RIGHT: --a; --b; break; case UPRIGHT: --a; break; case DOWNRIGHT: --b; break; case LEFT: ++a; ++b; break; case UPLEFT: ++b; break; case DOWNLEFT: ++a; break; case SIT: break; case CP: if (cp_set) bad_char = TRUE; else { add_unit(a, b, dir); no_new = FALSE; cp_set = TRUE; } break; case HVYTANK: case MSLTANK: case GEV: if (occupied(a,b) || blocked(a,b) || armor_points == 0) { bad_char = TRUE; break; } add_unit(a,b,dir); no_new = FALSE; --armor_points; break; case '1': case '2': case '3': if (occupied(a,b) || blocked(a,b) || infantry_points < (dir - '0')) { bad_char = TRUE; break; } add_unit(a, b, dir); no_new = FALSE; infantry_points -= (dir - '0'); break; case INFANTRY: if (occupied(a,b) || blocked(a,b) || infantry_points < 3) { bad_char = TRUE; break; } add_unit(a, b, '3'); no_new = FALSE; infantry_points -= 3; break; case HOWITZER: if (occupied(a,b) || blocked(a,b) || armor_points <= 1) { bad_char = TRUE; break; } add_unit(a,b,dir); no_new = FALSE; armor_points -= 2; break; default: bad_char = TRUE; break; } if (off_obstructed(a,b) || bad_char) { a = olda; b = oldb; bad_char = FALSE; } else movecur_hex(a,b); } /* while */ } add_unit(a, b, c) char a, b, c; { int i; i = n_units; ++n_units; switch (c) { case CP: unit[i].type = CP; unit[i].attack = 0; unit[i].range = 0; unit[i].defend = 0; unit[i].movement = 0; break; case HVYTANK: unit[i].type = HVYTANK; unit[i].attack = 4; unit[i].range = 2; unit[i].defend = 3; unit[i].movement = 3; break; case MSLTANK: unit[i].type = MSLTANK; unit[i].attack = 3; unit[i].range = 4; unit[i].defend = 2; unit[i].movement = 2; break; case GEV: unit[i].type = GEV; unit[i].attack = 2; unit[i].range = 2; unit[i].defend = 2; unit[i].movement = 4; break; case HOWITZER: unit[i].type = HOWITZER; unit[i].attack = 6; unit[i].range = 8; unit[i].defend = 1; unit[i].movement = 0; break; case INFANTRY: case '3': unit[i].type = INFANTRY; unit[i].attack = 3; unit[i].range = 1; unit[i].defend = 1; unit[i].movement = 2; break; case '1': unit[i].type = INFANTRY; unit[i].attack = 1; unit[i].range = 1; unit[i].defend = 1; unit[i].movement = 2; break; case '2': unit[i].type = INFANTRY; unit[i].attack = 2; unit[i].range = 1; unit[i].defend = 1; unit[i].movement = 2; break; } unit[i].range_to_ogre = 0; unit[i].fired = 0; unit[i].status = OK; unit[i].moves_left = 0; unit[i].l_hex = a; unit[i].r_hex = b; disp_unit(i); } occupied(a,b) char a,b; { int i; for (i = 0; i < n_units; ++i) if (unit[i].status != DESTROYED && unit[i].l_hex == a && unit[i].r_hex == b) return(TRUE); return(FALSE); } init_ogre(mark) int mark; { long lrand48(); ogre.l_hex = (char) lrand48() % 7 + 22; ogre.r_hex = 50 - ogre.l_hex; switch (mark) { case 3: ogre.treads = 45; ogre.init_treads = 45; ogre.movement = 3; ogre.missiles = 2; ogre.main_bats = 1; ogre.sec_bats = 4; ogre.ap = 8; break; case 5: ogre.treads = 60; ogre.init_treads = 60; ogre.movement = 3; ogre.missiles = 5; ogre.main_bats = 2; ogre.sec_bats = 6; ogre.ap = 10; break; } disp_ogre(); } unitcmp(u1, u2) UNIT *u1, *u2; { int cmp; switch(u1->type) { case CP: switch (u2->type) { case CP: cmp = 0; break; default: cmp = -1; break; } break; case HOWITZER: switch(u2->type) { case CP: cmp = 1; break; case HOWITZER: cmp = 0; break; default: cmp = -1; break; } break; case HVYTANK: switch (u2->type) { case CP: case HOWITZER: cmp = 1; break; case HVYTANK: cmp = 0; break; default: cmp = -1; break; } break; case MSLTANK: switch(u2->type) { case CP: case HOWITZER: case HVYTANK: cmp = 1; break; case MSLTANK: cmp = 0; break; default: cmp = -1; break; } break; case GEV: switch (u2->type) { case INFANTRY: cmp = -1; break; case GEV: cmp = 0; break; default: cmp = -1; break; } break; case INFANTRY: switch (u2->type) { case INFANTRY: cmp = 0; break; default: cmp = -1; break; } break; } return(cmp); } @@@End of init.c echo x - initround.c 1>&2 cat >initround.c <<'@@@End of initround.c' #include "ext.h" init_round() { int i; for (i = 0; i < n_units; ++i) { unit[i].moves_left = unit[i].movement; if (unit[i].status == DISABLED) { unit[i].status = OK; update_hex(unit[i].l_hex, unit[i].r_hex); } unit[i].range_to_ogre = range(ogre.l_hex, ogre.r_hex, unit[i].l_hex, unit[i].r_hex); } } init_move_ogre() { int i; for (i = 0; i < n_units; ++i) { unit[i].range_to_ogre = range(ogre.l_hex, ogre.r_hex, unit[i].l_hex, unit[i].r_hex); } } init_def_attack() { int i; for (i = 0; i < n_units; ++i) { if (unit[i].status == OK) { unit[i].fired = FALSE; unit[i].range_to_ogre = range(ogre.l_hex, ogre.r_hex, unit[i].l_hex, unit[i].r_hex); } } } init_ogre_attack() { int i; for (i = 0; i < n_units; ++i) { unit[i].fired = 0; unit[i].range_to_ogre = range(ogre.l_hex, ogre.r_hex, unit[i].l_hex, unit[i].r_hex); } } init_gev2() { int i; for (i = 0; i < n_units; ++i) if (unit[i].status == OK && unit[i].type == GEV) unit[i].moves_left = 3; } display_range(i) int i; { char c[80]; movecur(18,0); eeol(18); sprintf(c,"range from unit %d to Ogre %d.",i,unit[i].range_to_ogre); Amiga_puts(c); cycle(); } @@@End of initround.c echo x - main.c 1>&2 cat >main.c <<'@@@End of main.c' /* * OGRE - a tactical ground combat game set in 2086. * * Written by Michael Caplinger of Rice University 1982 * based on the Steve Jackson Microgame (c) 1977. * * Ported to Amiga from Unix by Hobie Orris, 1986 * (who was too lazy to type in all the comments. Sorry) */ #define MAIN 1 #include "ext.h" main(argc, argv) int argc; char **argv; { int mark; /* The original program set a trap here: signal(SIGINT, handler) * For Amiga, I've chosen to handle close window events instead * of breaks; see Amiga_getchar() in termcap.c - H.O. */ init_screen(); mark = get_mark(); init_units(mark); init_ogre(mark); disp_ogre_status(TRUE); while (1) { init_round(); /* the Ogre fires */ assign_fire_ogre(); check_over(); /* player moves and fires */ move_def(); attack_def(); check_over(); /* 2nd GEV move */ init_gev2(); move_def(); /* Ogre moves */ move_ogre(); check_over(); } } check_over() { char *message, c; int over,i; static char drawstring[] = "The Ogre self-destructs and destroys the CP. Draw!"; static char youstring[] = "You win!"; static char ogrestring[] = "The Ogre wins!"; over = FALSE; if (unit[0].status == DESTROYED) { message = &ogrestring[0]; over = TRUE; } /* if the Ogre is immobilized it is beaten */ else if (ogre.movement == 0 && unit[0].range_to_ogre < 5) { /* * Optional rule 8.05 - the Ogre can self-destruct, destroying * everything within 4 hexes, and armor at 5 hexes is disabled. * So, if CP is within 4 hexes, blow up - H.O. */ for (i = 0; i < n_units; ++i) { if (unit[i].range_to_ogre < 5) { unit[i].status = DESTROYED; disp_unit(i); } else if (unit[i].range_to_ogre == 5 && unit[i].status == OK && unit[i].type != CP && unit[i].type != INFANTRY) { unit[i].status = DISABLED; disp_unit(i); } } disp_hex(ogre.l_hex, ogre.r_hex, '*'); message = &drawstring[0]; over = TRUE; } else if (ogre.movement == 0 && unit[0].range_to_ogre > 4) { message = &youstring[0]; over = TRUE; } if (over) { puts(message); for (i = 16; i < 23; ++i) { movecur(i,1); eeol(i); } eeol(16); movecur(16,1); Amiga_puts(message); c = Amiga_getchar(); reset_term(); } } @@@End of main.c echo x - map.c 1>&2 cat >map.c <<'@@@End of map.c' #include "ext.h" #include init_screen() { int a, b; char row, col; tc_setup(); for (a = 1; a <= 28; ++a) { for (b = 1; b <= 28; ++b) if (!off_map(a,b)) disp_hex(a, b, '7'); } disp_craters(); /* refresh the screen */ refresh(); } to_xy(lhex, rhex, row, col) char lhex, rhex, *row, *col; { *row = (lhex - rhex) + 7; *col = 50 - (lhex + rhex); } off_map(a, b) char a, b; { char row, col; to_xy(a, b, &row, &col); if (col < 0 || col > 38 || row < 0 || row > 14) return(TRUE); else return(FALSE); } off_obstructed(a, b) char a, b; { char row, col; to_xy(a, b, &row, &col); if (col < 10 || col > 38 || row < 0 || row > 14) return(TRUE); else return(FALSE); } disp_hex(a, b, c) char a, b, c; { char row, col; to_xy(a, b, &row, &col); movecur(row, col * 2 + 1); Amiga_putchar(c); } update_hex(a, b) char a, b; { int i; if (ogre.l_hex == a && ogre.r_hex == b) { disp_ogre(); return; } for (i = 0; i < n_units; ++i) if (unit[i].l_hex == a && unit[i].r_hex == b && unit[i].status != DESTROYED) { disp_unit(i); return; } if (blocked(a, b)) { disp_hex(a, b, '*'); return; } disp_hex(a, b, '7'); } disp_unit(i) int i; { char a, b; a = unit[i].l_hex; b = unit[i].r_hex; switch(unit[i].status) { case OK: switch (unit[i].type) { case INFANTRY: disp_hex(a, b, '0' + unit[i].attack); break; default: disp_hex(a, b, unit[i].type); break; } break; case DISABLED: disp_hex(a, b, tolower(unit[i].type)); break; case DESTROYED: disp_hex(a, b, '7'); break; } } disp_ogre(i) int i; { /* these are Amiga console control strings for changing colour */ static char black_on[] = { 0x9b, '1', ';', '3', '2', ';', '4', '0', 'm', '\0' }; static char black_off[] = { 0x9b, '0', ';', '3', '1', ';', '4', '0', 'm', '\0' }; char a, b; a = ogre.l_hex; b = ogre.r_hex; Amiga_puts(black_on); disp_hex(a, b, 'O'); Amiga_puts(black_off); } movecur_hex(a, b) char a, b; { char row, col; to_xy(a, b, &row, &col); movecur(row, col * 2 + 1); } movecur_unit(i) int i; { movecur_hex(unit[i].l_hex, unit[i].r_hex); } #define ABS(i) (((i) < 0) ? -(i) : (i)) #define BIGINT 32767 range(a1, b1, a2, b2) char a1, a2, b1, b2; { char diff1, diff2, temp; int subrange[3], min, i, rangesum; diff1 = a1 - b1; diff2 = a2 - b2; subrange[0] = ABS(a1 - a2); subrange[1] = ABS(b1 - b2); subrange[2] = ABS(diff1 - diff2); min = 0; for (i = 1; i < 3; ++i) if (subrange[i] < subrange[min]) min = i; rangesum = subrange[min]; temp = subrange[min]; subrange[min] = subrange[2]; subrange[2] = temp; min = 0; for (i = 1; i < 2; ++i) if (subrange[i] < subrange[min]) min = i; rangesum += subrange[min]; return(rangesum); } static struct { char l_hex, r_hex; } craters[] = { 17, 16, 19, 13, 13, 18, 14, 15, 13, 15, 15, 10, 9, 15, 10, 12, 7, 14, 11, 10, 14, 7, 12, 6, 7, 10, 8, 6, 4, 9, 9, 4, 9, 3, }; #define NCRATERS (sizeof(craters) / 2 * sizeof(char)) blocked(a, b) char a, b; { int i; for (i = 0; i < NCRATERS; ++i) if (craters[i].l_hex == a && craters[i].r_hex == b) return(TRUE); return(FALSE); } disp_craters() { int i; for (i = 0; i < NCRATERS; ++i) disp_hex(craters[i].l_hex, craters[i].r_hex, '*'); } describe_action(action, i) char *action; int i; { char c[80]; switch(unit[i].type) { case HOWITZER: movecur(16, 1); eeol(16); sprintf(c, "%s howitzer (%d/%d D%d M%d)", action, unit[i].attack, unit[i].range, unit[i].defend, unit[i].moves_left); Amiga_puts(c); break; case MSLTANK: movecur(16, 1); eeol(16); sprintf(c, "%s missile tank (%d/%d D%d M%d)", action, unit[i].attack, unit[i].range, unit[i].defend, unit[i].moves_left); Amiga_puts(c); break; case GEV: movecur(16, 1); eeol(16); sprintf(c, "%s GEV (%d/%d D%d M%d)", action, unit[i].attack, unit[i].range, unit[i].defend, unit[i].moves_left); Amiga_puts(c); break; case HVYTANK: movecur(16, 1); eeol(16); sprintf(c, "%s heavy tank (%d/%d D%d M%d)", action, unit[i].attack, unit[i].range, unit[i].defend, unit[i].moves_left); Amiga_puts(c); break; case INFANTRY: movecur(16, 1); eeol(16); sprintf(c, "%s infantry (%d/%d D%d M%d)", action, unit[i].attack, unit[i].range, unit[i].defend, unit[i].moves_left); Amiga_puts(c); break; } } /* routines display() and display_xy() have been removed */ @@@End of map.c echo x - move.c 1>&2 cat >move.c <<'@@@End of move.c' #include "ext.h" move_def() { int i; for (i = 0; i < n_units; ++i) if (unit[i].status == OK) { if (unit[i].moves_left > 0) describe_action("Move",i); while (unit[i].moves_left > 0 && unit[i].status == OK) getmove(i); } } getmove(i) int i; { char nomove, bad_char, a, b, dir, olda, oldb; nomove = TRUE; while (nomove) { a = unit[i].l_hex; b = unit[i].r_hex; movecur_hex(a, b); bad_char = FALSE; dir = Amiga_getchar(); switch (dir) { case RIGHT: --a; --b; break; case UPRIGHT: --a; break; case DOWNRIGHT: --b; break; case LEFT: ++a; ++b; break; case UPLEFT: ++b; break; case DOWNLEFT: ++a; break; case SIT: case ' ': unit[i].moves_left = 0; return(0); default: bad_char = TRUE; break; } if (off_map(a, b) || (occupied(a, b) && unit[i].moves_left == 1) || blocked(a, b) || bad_char) { bad_char = FALSE; } else { olda = unit[i].l_hex; oldb = unit[i].r_hex; unit[i].l_hex = a; unit[i].r_hex = b; update_hex(olda, oldb); nomove = FALSE; unit[i].moves_left -= 1; def_ram(i); update_hex(unit[i].l_hex, unit[i].r_hex); } } } @@@End of move.c echo x - ogre.h 1>&2 cat >ogre.h <<'@@@End of ogre.h' /* * ogre.h */ typedef struct { char type; char attack; char range; char defend; char movement; char range_to_ogre; char fired; char moves_left; char status; char l_hex; char r_hex; } UNIT; typedef struct { char missiles; char main_bats; char sec_bats; char ap; char treads; char movement; char moves_left; char l_hex; char r_hex; char init_treads; } OGRE; /* unit types */ #define CP 'C' #define HVYTANK 'T' #define MSLTANK 'M' #define GEV 'G' #define HOWITZER 'H' #define INFANTRY 'I' /* unit statuses */ #define OK 1 #define DISABLED 2 #define DESTROYED 3 /*directions */ #define RIGHT 'd' #define UPRIGHT 'e' #define DOWNRIGHT 'x' #define LEFT 'a' #define UPLEFT 'w' #define DOWNLEFT 'z' #define SIT 's' #define HELPKEY '?' #define TRUE 1 #define FALSE 0 #define N_UNITS 30 /* ogre weapon stats */ #define DEF_MISSILES 3 #define DEF_MAIN 4 #define DEF_SECONDARY 3 #define DEF_AP 1 #define ATK_MISSILES 6 #define ATK_MAIN 4 #define ATK_SECONDARY 3 #define ATK_AP 1 #define RANGE_MISSILES 5 #define RANGE_MAIN 3 #define RANGE_SECONDARY 2 #define RANGE_AP 1 @@@End of ogre.h echo x - ogrecom.c 1>&2 cat >ogrecom.c <<'@@@End of ogrecom.c' #include "ext.h" move_ogre() { init_move_ogre(); ogre.moves_left = ogre.movement; while (ogre.moves_left > 0) { move_ogre1(); ogre_ram(); cycle(); } } #define INFINITY 32767 move_ogre1() { int weight[7]; int i, max; char a, b, olda, oldb; a = ogre.l_hex; b = ogre.r_hex; weight[0] = - INFINITY; weight[1] = getweight(a - 1, b - 1); weight[2] = getweight(a - 1, b); weight[3] = getweight(a, b + 1); weight[4] = getweight(a + 1, b + 1); weight[5] = getweight(a + 1, b); weight[6] = getweight(a, b - 1); max = 0; for (i = 1; i < 7; ++i) if (weight[i] > weight[max]) max = i; switch (max) { case 0: break; case 1: --a; --b; break; case 2: --a; break; case 3: ++b; break; case 4: ++a; ++b; break; case 5: ++a; break; case 6: --b; break; } olda = ogre.l_hex; oldb = ogre.r_hex; ogre.l_hex = a; ogre.r_hex = b; update_hex(olda, oldb); disp_ogre(); ogre.moves_left -= 1; } getweight(a, b) char a, b; { int weight, total_attacks, to_target, i; weight = - range(a, b, unit[0].l_hex, unit[0].r_hex); total_attacks = ogre.missiles + ogre.main_bats + ogre.sec_bats; for (i = 0; i < n_units; ++i) { if (unit[i].status == DESTROYED) continue; to_target = range(a, b, unit[i].l_hex, unit[i].r_hex); if (to_target == 0) { if (unit[i].type == CP) weight = 50; else weight = 10 * unit[i].attack; break; } if (total_attacks <= 0) continue; if (to_target <= RANGE_MISSILES && ogre.missiles > 0) { weight += unit[i].attack; weight += 4 - unit[i].movement; total_attacks -= 1; continue; } if (to_target <= RANGE_MAIN && ogre.main_bats > 0) { weight += unit[i].attack; weight += 4 - unit[i].movement; total_attacks -= 1; continue; } if (to_target <= RANGE_SECONDARY && ogre.sec_bats > 0) { weight += unit[i].attack; weight += 4 - unit[i].movement; total_attacks -= 1; continue; } if (to_target <= RANGE_AP && ogre.ap > 0 && unit[i].type == INFANTRY || unit[i].type == CP) { weight += unit[i].attack; weight += 4 - unit[i].movement; total_attacks -= 1; continue; } } if (off_map(a, b) || blocked(a, b)) weight = - INFINITY; return(weight); } #define INCR(i) i = (i == n_units - 1) ? 0 : i + 1 #define MIN(a, b) (((a) > (b)) ? (a) : (b)) assign_fire_ogre() { int i, unitno, nmissiles; init_ogre_attack(); unitno = nextunit(RANGE_AP, 0); for (i = 0; i < ogre.ap; ++i) { if (unit[unitno].range_to_ogre <= RANGE_AP && (unit[unitno].type == CP || unit[unitno].type == INFANTRY)) { unit[unitno].fired += ATK_AP; display_attack("AP", unitno); } unitno = nextunit(RANGE_AP, unitno); } unitno = nextunit(RANGE_SECONDARY, unitno); for (i = 0; i < ogre.sec_bats; ++i) { if (unit[unitno].range_to_ogre <= RANGE_SECONDARY) { unit[unitno].fired += ATK_SECONDARY; display_attack("secondary battery", unitno); } unitno = nextunit(RANGE_SECONDARY, unitno); } unitno = nextunit(RANGE_MAIN, unitno); for (i = 0; i < ogre.main_bats; ++i) { if (unit[unitno].range_to_ogre <= RANGE_MAIN) { unit[unitno].fired += ATK_MAIN; display_attack("main battery", unitno); } unitno = nextunit(RANGE_MAIN, unitno); } unitno = nextunit(RANGE_MISSILES, unitno); nmissiles = ogre.missiles; for (i = 0; i < nmissiles; ++i) { if (unit[unitno].status != DESTROYED && unit[unitno].type != INFANTRY && unit[unitno].range_to_ogre <= RANGE_MISSILES) { unit[unitno].fired += ATK_MISSILES; ogre.missiles -= 1; display_attack("missile", unitno); disp_ogre_status(FALSE); } unitno = nextunit(RANGE_MISSILES, unitno); } } cycle() { Delay(60); } display_attack(weapon, target) char *weapon; int target; { char c[80]; if (unit[target].status == DESTROYED) return; sprintf(c, "Ogre fires %s at unit at hex %d%d ", weapon, unit[target].l_hex, unit[target].r_hex); movecur(16, 0); Amiga_puts(c); movecur_hex(unit[target].l_hex, unit[target].r_hex); cycle(); def_resolve(target); } nextunit(range, unitno) int range, unitno; { int start; start = unitno; INCR(unitno); while (unitno != start) { if (range == 1) { if (unit[unitno].status != DESTROYED && (unit[unitno].type == CP || unit[unitno].type == INFANTRY) && unit[unitno].range_to_ogre <= range) return(unitno); } else { if (unit[unitno].status != DESTROYED && unit[unitno].range_to_ogre <= range) return(unitno); } INCR(unitno); } return(unitno); } @@@End of ogrecom.c echo x - ogrestat.c 1>&2 cat >ogrestat.c <<'@@@End of ogrestat.c' #include "ext.h" disp_ogre_status(redraw) int redraw; { static OGRE last; char s[80]; if (redraw || last.main_bats != ogre.main_bats) if (ogre.main_bats > 0) { sprintf(s, "Main Batteries: %d (4/3 D4)", ogre.main_bats); movecur(18, 0); eeol(18); Amiga_puts(s); } else { movecur(18, 0); eeol(18); Amiga_puts(" "); } if (redraw || last.sec_bats != ogre.sec_bats) if (ogre.sec_bats > 0) { sprintf(s, "Secondary Batteries: %d (3/2 D3)", ogre.sec_bats); movecur(19, 0); eeol(19); Amiga_puts(s); } else { movecur(19, 0); eeol(19); Amiga_puts(" "); } if (redraw || last.missiles != ogre.missiles) if (ogre.missiles > 0) { sprintf(s, "Missiles: %d (6/5 D3)", ogre.missiles); movecur(20, 0); eeol(20); Amiga_puts(s); } else { movecur(20, 0); eeol(20); Amiga_puts(" "); } if (redraw || last.ap != ogre.ap) if (ogre.ap > 0) { sprintf(s, "Anti-Personnel: %d (1/1 D1)", ogre.ap); movecur(21, 0); eeol(21); Amiga_puts(s); } else { movecur(21, 0); eeol(21); Amiga_puts(" "); } if (redraw || last.treads != ogre.treads) if (ogre.treads > 0) { sprintf(s, "Treads: %d (1/* D1)", ogre.treads); movecur(22, 0); eeol(22); Amiga_puts(s); movecur(22, 40); sprintf(s, "Movement: %d",ogre.movement); Amiga_puts(s); } else { movecur(22, 0); eeol(22); Amiga_puts(" "); } /* if (redraw || last.movement != ogre.movement) { sprintf(s, "Movement: %d", ogre.movement); movecur(23, 0); eeol(23); Amiga_puts(s); } */ /* Lattice allows structure copying! */ last = ogre; } @@@End of ogrestat.c echo x - resolve.c 1>&2 cat >resolve.c <<'@@@End of resolve.c' #include "ext.h" static char *odd_names[] = { "0/1", "1/2", "1/1", "2/1", "3/1", "4/1", "+", }; static char crt[6][7] = { OK, OK, OK, OK, DISABLED, DISABLED, DESTROYED, OK, OK, OK, DISABLED, DISABLED, DESTROYED, DESTROYED, OK, OK, DISABLED, DISABLED, DESTROYED, DESTROYED, DESTROYED, OK, OK, DISABLED, DESTROYED, DESTROYED, DESTROYED, DESTROYED, OK, DISABLED, DESTROYED, DESTROYED, DESTROYED, DESTROYED, DESTROYED, OK, DESTROYED, DESTROYED, DESTROYED, DESTROYED, DESTROYED, DESTROYED, }; odds(attack, defend) int attack, defend; { int result; result = (defend > 0) ? attack / defend + 1 : 6; if (result > 6) result = 6; if (result == 1) result = (2 * attack < defend) ? 0 : 1; return(result); } char *odd_str(attack, defend) int attack, defend; { return(odd_names[odds(attack, defend)]); } ogre_resolve(allocations) OGRE *allocations; { static char blanks[12] = {" "}; eeol(16); Amiga_puts("Resolving..."); cycle(); if (allocations->missiles > 0) { if (crt[roll()][odds(allocations->missiles, DEF_MISSILES)] == DESTROYED) ogre.missiles -= 1; } if (allocations->main_bats > 0) { if (crt[roll()][odds(allocations->main_bats, DEF_MAIN)] == DESTROYED) ogre.main_bats -= 1; } if (allocations->sec_bats > 0) { if (crt[roll()][odds(allocations->sec_bats, DEF_SECONDARY)] == DESTROYED) ogre.sec_bats -= 1; } if (allocations->ap > 0) { if (crt[roll()][odds(allocations->ap, DEF_AP)] == DESTROYED) ogre.ap -= 1; } if (allocations->treads > 0) { if (crt[roll()][odds(1,1)] == DESTROYED) decrease_treads(allocations->treads); } movecur(18, 40); Amiga_puts(blanks); movecur(19, 40); Amiga_puts(blanks); movecur(19, 40); Amiga_puts(blanks); movecur(20, 40); Amiga_puts(blanks); movecur(21, 40); Amiga_puts(blanks); movecur(22, 40); Amiga_puts(blanks); disp_ogre_status(FALSE); } def_resolve(i) int i; { char result; if (unit[i].status != DESTROYED && unit[i].fired > 0) { result = crt[roll()][odds(unit[i].fired, unit[i].defend)]; if (unit[i].type == INFANTRY) if (result == DISABLED) { unit[i].attack -= 1; if (unit[i].attack == 0) unit[i].status = DESTROYED; update_hex(unit[i].l_hex, unit[i].r_hex); return; } switch (unit[i].status) { case OK: unit[i].status = result; break; case DISABLED: if (result != OK) unit[i].status = DESTROYED; break; } if (unit[i].status != OK) update_hex(unit[i].l_hex, unit[i].r_hex); } } roll() { long lrand48(), k = 0; while (k == 0) k = (lrand48()) % 6; return(k); } ogre_ram() { int i; for (i = 0; i < n_units; ++i) if (unit[i].l_hex == ogre.l_hex && unit[i].r_hex == ogre.r_hex && unit[i].status != DESTROYED) switch (unit[i].type) { case INFANTRY: if (ogre.ap > 0) { unit[i].attack -= 1; if (unit[i].attack == 0) unit[i].status = DESTROYED; } break; default: if (unit[i].movement == 0 || unit[i].status == DISABLED) { unit[i].status = DESTROYED; decrease_treads((unit[i].type == HVYTANK) ? 2 : 1); disp_ogre_status(FALSE); } else { unit[i].status = (roll() > 3) ? DESTROYED : DISABLED; decrease_treads((unit[i].type == HVYTANK) ? 2 : 1); disp_ogre_status(FALSE); } break; } } def_ram(i) int i; { if (unit[i].l_hex == ogre.l_hex && unit[i].r_hex == ogre.r_hex && unit[i].type != INFANTRY) { if (unit[i].type == HVYTANK) decrease_treads(2); else decrease_treads(1); unit[i].status = DESTROYED; disp_ogre_status(FALSE); } } decrease_treads(attack) int attack; { ogre.treads -= attack; ogre.movement = 0; if (ogre.treads > 0) ogre.movement = 1; if (ogre.treads > ogre.init_treads / 3) ogre.movement = 2; if (ogre.treads > 2 * ogre.init_treads / 3) ogre.movement = 3; } @@@End of resolve.c echo x - termcap.c 1>&2 cat >termcap.c <<'@@@End of termcap.c' /* * This file contains all the console I/O stuff, most of which is cribbed * from the ROM Kernel Manual. Some of the routines here are not used, like * clear_screen() and the cursor movement defines. The idea behind the * apparently redundant routines Amiga_putchar(), Amiga_getchar(), etc, is * to avoid having external pointers to windows and message ports in all the * other files. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define HELPKEY '?' struct TextAttr MyFont = { "topaz.font", TOPAZ_EIGHTY, FS_NORMAL,FPF_ROMFONT }; struct NewWindow nw = { 0, 0, 640, 200, 3, 1, CLOSEWINDOW|MENUPICK|GADGETUP|GADGETDOWN, WINDOWCLOSE|SMART_REFRESH|ACTIVATE|GIMMEZEROZERO|BORDERLESS, 0, NULL,"Ogre 2.0 by Hobie Orris", NULL, NULL, 100, 45, 640, 200, CUSTOMSCREEN }; struct NewScreen ns = { 0, 0, 640, 200, 2, 0, 1, HIRES, CUSTOMSCREEN, &MyFont, NULL, 0, 0 }; extern struct MsgPort *CreatePort(); extern struct IOStdReq *CreateStdIO(); struct Screen *scrn; struct Window *w; struct RastPort *rp; struct IOStdReq *WriteMsg, *ReadMsg; struct MsgPort *WritePort, *ReadPort; struct IntuiMessage *Imsg; ULONG DosBase, GfxBase, IntuitionBase; /************************************************************************/ /* */ /* Gadget Stuff */ /* */ /************************************************************************/ /* The gadgets look like this: * * Gadget0 Gadget1 * Gadget2 Gadget6 Gadget3 * Gadget4 Gadget5 * * All have plane 0 as below, and plane 1 as zeroes. */ /* offsets of gadget 0 from the window top left */ #define BASEPTX 450 /* x offset */ #define BASEPTY 123 /* y offset */ /* the pictures themselves */ USHORT Imgadget0[36] = { 0xffff, 0xf000, 0x8000, 0x1000, 0xbff0, 0x1000, 0xbfe0, 0x1000, 0xbfc0, 0x1000, 0xbf80, 0x1000, 0xbfc0, 0x1000, 0xbfe0, 0x1000, 0xbbf0, 0x1000, 0xb1f8, 0x1000, 0xa0fc, 0x1000, 0x807e, 0x1000, 0x803f, 0x1000, 0x801f, 0x9000, 0x800f, 0x1000, 0x8006, 0x1000, 0x8000, 0x1000, 0xffff, 0xf000 }; USHORT Imgadget1[36] = { 0xffff, 0xf000, 0x8000, 0x1000, 0x80ff, 0xd000, 0x807f, 0xd000, 0x803f, 0xd000, 0x801f, 0xd000, 0x803f, 0xd000, 0x807f, 0xd000, 0x80fd, 0xd000, 0x81f8, 0xd000, 0x83f0, 0x5000, 0x87e0, 0x1000, 0x8fc0, 0x1000, 0x9f80, 0x1000, 0x8f00, 0x1000, 0x8600, 0x1000, 0x8000, 0x1000, 0xffff, 0xf000 }; USHORT Imgadget2[36] = { 0xffff, 0xf000, 0x8000, 0x1000, 0x8080, 0x1000, 0x8180, 0x1000, 0x8380, 0x1000, 0x8700, 0x1000, 0x8fff, 0xd000, 0x9fff, 0xd000, 0xbfff, 0xd000, 0x9fff, 0xd000, 0x8fff, 0xd000, 0x8700, 0x1000, 0x8380, 0x1000, 0x8180, 0x1000, 0x8080, 0x1000, 0x8000, 0x1000, 0x8000, 0x1000, 0xffff, 0xf000 }; USHORT Imgadget3[36] = { 0xffff, 0xf000, 0x8000, 0x1000, 0x8010, 0x1000, 0x8018, 0x1000, 0x801c, 0x1000, 0x801e, 0x1000, 0xbfff, 0x1000, 0xbfff, 0x9000, 0xbfff, 0xd000, 0xbfff, 0x9000, 0xbfff, 0x1000, 0x801e, 0x1000, 0x801c, 0x1000, 0x8018, 0x1000, 0x8010, 0x1000, 0x8000, 0x1000, 0x8000, 0x1000, 0xffff, 0xf000, }; USHORT Imgadget4[36] = { 0xffff, 0xf000, 0x8000, 0x1000, 0x8006, 0x1000, 0x800f, 0x1000, 0x801f, 0x9000, 0x803f, 0x1000, 0x807e, 0x1000, 0xa0fc, 0x1000, 0xb1f8, 0x1000, 0xbbf0, 0x1000, 0xbfe0, 0x1000, 0xbfc0, 0x1000, 0xbf80, 0x1000, 0xbfc0, 0x1000, 0xbfe0, 0x1000, 0xbff0, 0x1000, 0x8000, 0x1000, 0xffff, 0xf000 }; USHORT Imgadget5[36] = { 0xffff, 0xf000, 0x8000, 0x1000, 0x8600, 0x1000, 0x8f00, 0x1000, 0x9f80, 0x1000, 0x8fc0, 0x1000, 0x87e0, 0x1000, 0x83f0, 0x5000, 0x81f8, 0xd000, 0x80fd, 0xd000, 0x807f, 0xd000, 0x803f, 0xd000, 0x801f, 0xd000, 0x803f, 0xd000, 0x807f, 0xd000, 0x80ff, 0xd000, 0x8000, 0x1000, 0xffff, 0xf000 }; USHORT Imgadget6[36] = { 0xffff, 0xf000, 0x8000, 0x1000, 0x81fc, 0x1000, 0x83fe, 0x1000, 0x8706, 0x1000, 0x8e00, 0x1000, 0x8c00, 0x1000, 0x8e00, 0x1000, 0x87fc, 0x1000, 0x83fe, 0x1000, 0x8007, 0x1000, 0x8003, 0x1000, 0x8007, 0x1000, 0x860e, 0x1000, 0x87fc, 0x1000, 0x83f8, 0x1000, 0x8000, 0x1000, 0xffff, 0xf000 }; #define PLNUM 0x01 /* number of planes in image */ #define PLPICK 0x02 /* display in plane 1 */ #define PLOFF 0x01 /* plane 0 turned on */ struct Image Gadgpic[7] = { /* image 0 */ 0, 0, 20, 18, PLNUM, &Imgadget0[0], PLPICK, PLOFF, NULL, /* image 1 */ 0, 0, 20, 18, PLNUM, &Imgadget1[0], PLPICK, PLOFF, NULL, /* image 2 */ 0, 0, 20, 18, PLNUM, &Imgadget2[0], PLPICK, PLOFF, NULL, /* image 3 */ 0, 0 , 20, 18, PLNUM, &Imgadget3[0], PLPICK, PLOFF, NULL, /* image 4 */ 0, 0, 20, 18, PLNUM, &Imgadget4[0], PLPICK, PLOFF, NULL, /* image 5 */ 0, 0, 20, 18, PLNUM, &Imgadget5[0], PLPICK, PLOFF, NULL, /* image 6 */ 0, 0, 20, 18, PLNUM, &Imgadget6[0], PLPICK, PLOFF, NULL }; struct Gadget Arrow[7] = { /* Up left arrow 0 */ NULL, BASEPTX, BASEPTY, 20, 18, GADGHCOMP|GADGIMAGE, GADGIMMEDIATE|RELVERIFY, BOOLGADGET, &Gadgpic[0], NULL, NULL, NULL, NULL, NULL, NULL, /* Up right arrow 1 */ NULL, BASEPTX + 20, BASEPTY, 20, 18, GADGHCOMP|GADGIMAGE, RELVERIFY|GADGIMMEDIATE, BOOLGADGET, &Gadgpic[1], NULL, NULL, NULL, NULL, NULL, NULL, /* left arrow 2 */ NULL, BASEPTX - 10, BASEPTY + 18, 20, 18, GADGHCOMP|GADGIMAGE, RELVERIFY|GADGIMMEDIATE, BOOLGADGET, &Gadgpic[2], NULL, NULL, NULL, NULL, NULL, NULL, /* right arrow 3 */ NULL, BASEPTX + 30, BASEPTY + 18, 20, 18, GADGHCOMP|GADGIMAGE, RELVERIFY|GADGIMMEDIATE, BOOLGADGET, &Gadgpic[3], NULL, NULL, NULL, NULL, NULL, NULL, /* down left arrow 4 */ NULL, BASEPTX, BASEPTY + 36, 20, 18, GADGHCOMP|GADGIMAGE, RELVERIFY|GADGIMMEDIATE, BOOLGADGET, &Gadgpic[4], NULL, NULL, NULL, NULL, NULL, NULL, /* down right arrow 5 */ NULL, BASEPTX + 20, BASEPTY + 36, 20, 18, GADGHCOMP|GADGIMAGE, RELVERIFY|GADGIMMEDIATE, BOOLGADGET, &Gadgpic[5], NULL, NULL, NULL, NULL, NULL, NULL, /* sit 6 */ NULL, BASEPTX + 10, BASEPTY + 18, 20, 18, GADGHCOMP|GADGIMAGE, RELVERIFY|GADGIMMEDIATE, BOOLGADGET, &Gadgpic[6], NULL, NULL, NULL, NULL, NULL, NULL, }; /* These are the command characters returned to Amiga_getchar() * when a gadget is selected. */ char Gadtbl[] = { 'w', 'e', 'a', 'd', 'z', 'x', 's', '\0' }; /*************************************************************************/ /* */ /* Menu Stuff */ /* */ /*************************************************************************/ /* Main menu structure which has three entries: Deploy, Target and Help */ #define WID 112 #define WID2 130 struct Menu mymenu[3] = { NULL, 1, 0, WID, 0, MENUENABLED, NULL, NULL, 0, 0, 0, 0, NULL, WID + 1, 0, WID, 0, MENUENABLED, NULL, NULL, 0, 0, 0, 0, NULL, WID * 2 + 2, 0, WID, 0, MENUENABLED, NULL, NULL, 0, 0, 0, 0 }; /* Menu entries for the Deploy menu */ struct MenuItem Menu1[6] = { /* 1st item */ NULL, 0, 0, WID, 8, ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0, 0, /* 2nd item */ NULL, 0, 10, WID, 8, ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0, 0, /* 3rd item */ NULL, 0, 20, WID, 8, ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0,0, /* 4th item */ NULL, 0, 30, WID, 8, ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0, 0, /* 5th item */ NULL, 0, 40, WID, 8, ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0,0, /* 6th item */ NULL, 0, 50, WID, 8, ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0, 0 }; struct MenuItem Menu2[7] = { NULL, 0, 0, WID2, 8, ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0, 0, /* 2nd item */ NULL, 0, 10, WID2, 8, ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0,0,0, /* 3rd item */ NULL, 0, 20, WID2, 8, ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0, 0, /* 4th item */ NULL, 0, 30, WID2, 8, ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0,0, /* 5th item */ NULL, 0, 40, WID2, 8, ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0,0, /* 6th item */ NULL, 0, 50, WID2, 8, ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0,0, /* 7th item */ NULL, 0, 60, WID2, 8, ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0, 0 }; struct MenuItem Menu3[1] = { /* 1st item */ NULL, 0, 0, WID2, 8, ITEMENABLED|HIGHCOMP|ITEMTEXT, 0, 0, 0, 0, 0, 0 }; /* deploy menu titles */ UBYTE *Depstr[6] = { "C Command Post", "H Howitzer", "T Heavy Tank", "M Missile Tank", "G GEV", "I Infantry" }; /* target menu titles */ UBYTE *Tarstr[7] = { "t Treads", "b Main Battery", "s Secondary Batt", "m Missile", "a Anti-Personnel", "p Pass now", "r Resolve now" }; /* help menu title */ UBYTE *Helpstr = "? Instructions"; /* Menu strip titles */ UBYTE *Titles[] = { "Deploy", "Target", "Help" }; /* Menu item text message descriptors */ struct IntuiText MenuText[14] = {3, 0, JAM1, 0, 0, &MyFont, 0, 0, 3, 0, JAM1, 0, 0, &MyFont, 0, 0, 3, 0, JAM1, 0, 0, &MyFont, 0, 0, 3, 0, JAM1, 0, 0, &MyFont, 0, 0, 3, 0, JAM1, 0, 0, &MyFont, 0, 0, 3, 0, JAM1, 0, 0, &MyFont, 0, 0, 3, 0, JAM1, 0, 0, &MyFont, 0, 0, 3, 0, JAM1, 0, 0, &MyFont, 0, 0, 3, 0, JAM1, 0, 0, &MyFont, 0, 0, 3, 0, JAM1, 0, 0, &MyFont, 0, 0, 3, 0, JAM1, 0, 0, &MyFont, 0, 0, 3, 0, JAM1, 0, 0, &MyFont, 0, 0, 3, 0, JAM1, 0, 0, &MyFont, 0, 0, 3, 0, JAM1, 0, 0, &MyFont, 0, 0 }; /* These are the command characters associated with menu selections */ char Mentbl[3][7] = { {'C', 'H', 'T', 'M', 'G', 'I', '\0'}, /* deploy cmds */ {'t', 'b', 's', 'm', 'a', 'p', 'r'}, /* target cmds */ {'?', '\0', '\0', '\0', '\0', '\0', '\0'} /* help */ }; /***********************************************************************/ /* */ /* Requester Stuff */ /* */ /***********************************************************************/ char BodyText[] = "Choose an Ogre type"; char PosText[] = "Mark III"; char NegText[] = "Mark V"; struct IntuiText Body = { 3, 1, JAM1, 60, 10, NULL, &BodyText[0], NULL }; struct IntuiText Pos = { 3, 1, JAM1, 7, 4, NULL, &PosText[0], NULL }; struct IntuiText Neg = { 3, 1, JAM1, 7, 4, NULL, &NegText[0], NULL }; /***********************************************************************/ /* */ /* Toys Code */ /* */ /***********************************************************************/ /* getevent pulls a message off the program's message queue and checks if * it's a menu-related or gadget-related message. If it is, the appropriate * handler is called. */ char getevent() { char GadgetServe(), MenuServe(), result; struct IntuiMessage *GetMsg(), Tmpmsg; /* check queue for incoming messages */ Imsg = GetMsg(w->UserPort); if (Imsg == NULL) return('\0'); else Tmpmsg = *Imsg; ReplyMsg(Imsg); /* if message available, decode it */ if (Tmpmsg.Class != 0) { switch (Tmpmsg.Class) { /* could be a close window event */ case CLOSEWINDOW: endit(); break; /* or a menu selection */ case MENUPICK: result = MenuServe(&Tmpmsg); return(result); break; case GADGETUP: result = GadgetServe(&Tmpmsg); return (result); break; /* if no selection was made, return a null */ default: return('\0'); break; } } } /* checkmenu */ /* This routine invokes the requester that asks for Ogre type */ int get_mark() { int x; x = AutoRequest(w, &Body, &Pos, &Neg, 0L, 0L, 300L, 60L); if (x) x = 3; else x = 5; return(x); } /* Initmenu sets up the menus at the start of the program. * Nobody said this would be easy. */ InitMenu() { int i; /* link the three menus */ mymenu[0].NextMenu = &mymenu[1]; mymenu[1].NextMenu = &mymenu[2]; mymenu[2].NextMenu = NULL; /* point to first items on the menus */ mymenu[0].FirstItem = &Menu1[0]; mymenu[1].FirstItem = &Menu2[0]; mymenu[2].FirstItem = &Menu3[0]; /* initialize titles */ mymenu[0].MenuName = Titles[0]; mymenu[1].MenuName = Titles[1]; mymenu[2].MenuName = Titles[2]; /* link menu items */ for (i = 0; i < 6; ++i) Menu1[i].NextItem = &Menu1[i + 1]; Menu1[5].NextItem = NULL; for (i = 0; i < 7; ++i) Menu2[i].NextItem = &Menu2[i + 1]; Menu2[6].NextItem = NULL; Menu3[0].NextItem = NULL; /* link item names to text descriptors */ for (i = 0; i < 6; ++i) MenuText[i].IText = Depstr[i]; for (i = 0; i < 7; ++i) MenuText[6 + i].IText = Tarstr[i]; MenuText[13].IText = Helpstr; /* link text descriptors to item structures */ for (i = 0; i < 6; ++i) Menu1[i].ItemFill = &MenuText[i]; for (i = 0; i < 7; ++i) Menu2[i].ItemFill = &MenuText[6 + i]; Menu3[0].ItemFill = &MenuText[13]; SetMenuStrip(w, &mymenu[0]); } /* InitGad sets up the gadgets before the game starts */ InitGad() { int i; /* link Image structures to Gadget structures */ for (i = 0; i < 6; ++i) Arrow[i].GadgetRender = (APTR) &Gadgpic[i]; /* link image data to Image structures */ Gadgpic[0].ImageData = &Imgadget0[0]; Gadgpic[1].ImageData = &Imgadget1[0]; Gadgpic[2].ImageData = &Imgadget2[0]; Gadgpic[3].ImageData = &Imgadget3[0]; Gadgpic[4].ImageData = &Imgadget4[0]; Gadgpic[5].ImageData = &Imgadget5[0]; Gadgpic[6].ImageData = &Imgadget6[0]; Arrow[6].NextGadget = NULL; } refresh() { int i; RefreshGadgets(&Arrow[0], w, NULL); /* Add the gadgets to the window's gadget list and activate them */ for (i = 0; i < 7; ++i) { AddGadget(w, &Arrow[i], -1); OnGadget(&Arrow[i], w, NULL); } } /* MenuServe decodes menu request messages and translates them into the * proper character to hand to main program. */ char MenuServe(Menmsg) struct IntuiMessage *Menmsg; { USHORT menusel, itemsel; /* menu and item selected */ char selection; /* extract the menu and item numbers */ menusel = MENUNUM(Menmsg->Code); itemsel = ITEMNUM(Menmsg->Code); if (menusel == MENUNULL) return(NULL); /* get the command character from the table */ selection = Mentbl[menusel][itemsel]; return(selection); } /* GadgetServe translates a gadget selection into a command character * and returns that character. */ char GadgetServe(GadMsg) struct IntuiMessage *GadMsg; { int i; for (i = 0; i < 7; ++i) if (GadMsg->IAddress == (APTR) &Arrow[i]) break; return (Gadtbl[i]); } /* * These are the calls known to the rest of the Ogre program */ tc_setup() { make_console(); } /* This is not a true erase to end of line routine, since we want * to preserve the gadget display. It erases to column 55. */ eeol(row) int row; { static char s[55] = {" "}; movecur(row,0); Amiga_puts(s); movecur(row,0); } clear_screen() { static char ff = 0x0c; ConPutChar(WriteMsg,&ff); } /* * Move the cursor to row, col by building a CSI sequence */ movecur(row, col) int row, col; { char seq[8]; int n,i; row += 1; /* Kludge city! The Amiga display is shorter than a terminal */ /* CSI character */ seq[0] = 0x9b; /* convert row to ASCII */ n = stci_d(&seq[1], row, 4); i = n + 1; /* field separator */ seq[i] = 0x3b; i++; /* convert column to ASCII */ n = stci_d(&seq[i], col, 4); i += n; /* terminator */ seq[i] = 0x48; seq[i+1] = '\0'; ConPutStr(WriteMsg, &seq[0]); } set_term() { cursoff(WriteMsg); } reset_term() { endit(); } /* * These are mine. They insulate the rest of the files from knowing anything * about message ports and other messy stuff. */ Amiga_puts(s) char *s; { ConPutStr(WriteMsg, s); } /* Put a single char out. This is weird: take away the static, and it no * longer works! */ Amiga_putchar(c) char c; { static char x; x = c; ConPutChar(WriteMsg, &x); } /* Get a character from the keyboard or a close window event from the * mouse. A close window event ends the program. * If you want to add menus then this is the place to do it. */ char Amiga_getchar() { static char c; BYTE MayGetChar(); struct IntuiMessage *GetMsg(); char checkmenu(), event; BYTE ret; FOREVER { ret = 0; /* first, check for keyboard input */ ret = MayGetChar(ReadPort, ReadMsg, &c); if (ret != -1) { /* Trap help requests here, so that help can be obtained * from anywhere in the program. */ if (ret == HELPKEY) ret = get_help(); else return((char) ret); } /* if no keyboard chars are ready, check our message port for * menus and gadgets. */ if ((event = getevent()) != '\0') { if (event == HELPKEY) ret = get_help(); else return(event); } } } endit() { err(7); exit(0); } /* * This stuff is from the ROM Kernel Manual */ make_console() { int error; UBYTE c; if ((DosBase = OpenLibrary("dos.library", 0)) == NULL) err(1); if ((IntuitionBase = OpenLibrary("intuition.library", 0)) == NULL) err(2); if ((GfxBase = OpenLibrary("graphics.library", 0)) == NULL) err(3); WritePort = CreatePort("con1.write", 0); if (WritePort == 0) err(4); WriteMsg = CreateStdIO(WritePort); if (WriteMsg == 0) err(19); ReadPort = CreatePort("con1.read", 0); if (ReadPort == 0) err(5); ReadMsg = CreateStdIO(ReadPort); if (ReadMsg == 0) err(12); scrn = (struct Screen *) OpenScreen(&ns); if (scrn == NULL) { printf("Can't open window"); exit(20); } nw.Screen = scrn; w = (struct Window *) OpenWindow(&nw); if (w == NULL) err(6); /* link gadgets into window */ InitGad(); /* link menus into window */ InitMenu(); error = OpenConsole(WriteMsg, ReadMsg, w); if (error != 0) err(7); QueueRead(ReadMsg, &c); c = CheckIO(ReadMsg); if (c == FALSE) AbortIO(ReadMsg); else GetMsg(ReadPort); } /* * This routine is ugly. Please fix it. */ static err(n) int n; { switch (n) { case 7: CloseDevice(WriteMsg); case 6: CloseWindow(w); case 10: CloseScreen(scrn); case 5: DeletePort(ReadPort); case 12: DeleteStdIO(ReadMsg); case 4: DeletePort(WritePort); case 19: DeleteStdIO(WriteMsg); case 3: CloseLibrary(GfxBase); case 2: CloseLibrary(IntuitionBase); case 1: CloseLibrary(DosBase); } exit(n); /* return error code to CLI */ } OpenConsole(wreq, rreq, win) struct IOStdReq *wreq, *rreq; struct Window *win; { int error; wreq->io_Data = (APTR) win; wreq->io_Length = sizeof(*win); error = OpenDevice("console.device", 0, wreq, 0); rreq->io_Device = wreq->io_Device; rreq->io_Unit = wreq->io_Unit; return(error); } ConPutChar(request, ch) struct IOStdReq *request; char *ch; { request->io_Command = CMD_WRITE; request->io_Data = ch; request->io_Length = 1; DoIO(request); return(0); } ConWrite(request, string, len) struct IOStdReq *request; char *string; int len; { request->io_Command = CMD_WRITE; request->io_Data = (APTR) string; request->io_Length = len; DoIO(request); return(0); } ConPutStr(request, string) struct IOStdReq *request; char *string; { request->io_Command = CMD_WRITE; request->io_Data = (APTR) string; request->io_Length = -1; DoIO(request); return(0); } QueueRead(request, buf) struct IOStdReq *request; UBYTE *buf; { request->io_Command = CMD_READ; request->io_Data = (APTR)buf; request->io_Length = 1; SendIO(request); return(0); } char ConGetChar(console, request, buf) struct IOStdReq *request; struct MsgPort *console; char *buf; { char temp; while ((GetMsg(console) == NULL)) WaitPort(console); QueueRead(request, buf); temp = *buf; return(temp); } BYTE MayGetChar(console,rreq, buf) struct IOStdReq *rreq; struct MsgPort *console; char *buf; { register BYTE *temp; if (GetMsg(console) == NULL) return(-1); temp = (char *) rreq->io_Data; QueueRead(rreq, buf); return(*temp); } @@@End of termcap.c echo x - linkfile 1>&2 cat >linkfile <<'@@@End of linkfile' from lc:lib/Lstartup.obj termcap.o map.o resolve.o attack.o move.o * help.o init.o ogrecom.o initround.o ogrestat.o main.o to ogre library lc:lib/lc.lib lc:lib/amiga.lib @@@End of linkfile -- Hobie Orris | SoftQuad Inc., Toronto, Ont. |"There'll be no more giant leeches {ihnp4 | decvax | ? }!utzoo!sq!hobie | When you find the good Lord Jesus"