[net.sources] Ogre, a computer game

Mike Caplinger <mike@rice.ARPA> (11/10/84)

Cut on the dotted line and extract with sh.  See ogre.6 for documentation.
------------------------------------
echo 'Start of distribution file ogre.sh:'
echo 'Extracting Makefile...'
sed 's/^X//' > Makefile << '/'
XOBJ = init.o termcap.o map.o main.o move.o initround.o ogrecom.o ogrestat.o \
X	  attack.o resolve.o
X
Xogre: $(OBJ)
X	cc -o ogre $(OBJ) -ltermcap
X
Xinit.o: init.c ogre.h
X	cc -c init.c
X
Xmain.o: main.c ogre.h
X	cc -c main.c
X
Xmove.o: move.c ogre.h
X	cc -c move.c
X
Xattack.o: attack.c ogre.h
X	cc -c attack.c
X
Xresolve.o: resolve.c ogre.h
X	cc -c resolve.c
X
Xinitround.o: initround.c ogre.h
X	cc -c initround.c
X
Xtermcap.o: termcap.c
X	cc -c termcap.c
X
Xogrecom.o: ogrecom.c ogre.h
X	cc -c ogrecom.c
X
Xogrestat.o: ogrestat.c ogre.h
X	cc -c ogrestat.c
X
Xmap.o: map.c ogre.h
X	cc -c map.c
X
Xbackup:
X	tar cvf /arch/mike/ogre.tar *
/
echo 'Extracting attack.c...'
sed 's/^X//' > attack.c << '/'
X/*
X    This file contains routines to collect attack orders from the player,
X    and display his odds of success for each target.  It calls the
X    routines in "resolve.c" to determine the outcomes of the attacks.
X
X    Michael Caplinger, Rice University, March 1982.
X*/
X
X#include "ext.h"
X
Xstatic OGRE allocated;
X
X#define PASS        'p'
X#define NOPASS      '\0'
X#define RESOLVE     'r'
X#define MISSILE     'm'
X#define MAIN        'b'
X#define SECONDARY   's'
X#define AP          'a'
X#define TREAD       't'
X
Xattack_def()
X{
X    char moreunits;
X    int  i;
X
X    moreunits = TRUE;
X    zero(&allocated, sizeof(allocated));
X    init_def_attack();
X
X    /*
X        The "fired" element of each unit description is here used as a
X        Boolean to keep track of who has fired.
X    */
X
X    while(moreunits) {
X
X        moreunits = FALSE;
X
X        for(i = 0; i < n_units; i++) {
X
X            if(unit[i].status == OK &&
X                !unit[i].fired &&
X                unit[i].attack > 0  &&
X                unit[i].range_to_ogre <= unit[i].range) {
X
X                    describe_action("Fire", i);
X
X                    if(get_target(i) == PASS) moreunits = TRUE;
X                    else unit[i].fired = TRUE;
X
X            }
X        }
X    }
X    ogre_resolve(&allocated);
X}
X
Xget_target(i)
Xint i;
X{
X
X    char    action, invalid;
X
X    movecur_unit(i);
X
X    do {
X
X        invalid = FALSE;
X        action = getchar();
X    
X        switch(action) {
X    
X            case PASS:
X                return(PASS);
X    
X            case MISSILE:
X                if(ogre.missiles > 0) {
X                    allocated.missiles += unit[i].attack;
X                    update_odds(action);
X                }
X                else {
X                    invalid = TRUE;
X                }
X                break;
X    
X            case MAIN:
X                if(ogre.main_bats > 0) {
X                    allocated.main_bats += unit[i].attack;
X                    update_odds(action);
X                }
X                else {
X                    invalid = TRUE;
X                }
X                break;
X    
X            case SECONDARY:
X                if(ogre.sec_bats > 0) {
X                    allocated.sec_bats += unit[i].attack;
X                    update_odds(action);
X                }
X                else {
X                    invalid = TRUE;
X                }
X                break;
X    
X            case AP:
X                if(ogre.ap > 0) {
X                    allocated.ap += unit[i].attack;
X                    update_odds(action);
X                }
X                else {
X                    invalid = TRUE;
X                }
X                break;
X    
X            case TREAD:
X                if(ogre.treads > 0) {
X                    allocated.treads += unit[i].attack;
X                    update_odds(action);
X                }
X                else {
X                    invalid = TRUE;
X                }
X                if(invalid) break;
X
X                /* TREAD has to be resolved immediately. */
X                ogre_resolve(&allocated);
X                zero(&allocated, sizeof(allocated));
X                break;
X
X            case RESOLVE:
X                ogre_resolve(&allocated);
X                zero(&allocated, sizeof(allocated));
X                return(PASS);
X                break;
X
X            default:
X                invalid = TRUE;
X                break;
X    
X        }
X
X    } while(invalid);
X
X    return(NOPASS);
X
X}
X
X
Xzero(area, size)
Xchar *area;
Xint  size;
X{
X
X    int i;
X
X    for(i = 0; i < size; i++) area[i] = '\0';
X
X}
X
Xupdate_odds(weapon)
Xchar weapon;
X{
X
X    char *odd_str();
X
X    switch(weapon) {
X
X        case MAIN:
X
X            display_xy(18, 40, "%d/%d (%s)", allocated.main_bats, DEF_MAIN,
X                odd_str(allocated.main_bats, DEF_MAIN));
X            break;
X
X        case SECONDARY:
X
X            display_xy(19, 40, "%d/%d (%s)", allocated.sec_bats, DEF_SECONDARY,
X                odd_str(allocated.sec_bats, DEF_SECONDARY));
X            break;
X
X        case MISSILE:
X
X            display_xy(20, 40, "%s", odd_str(allocated.missiles, DEF_MISSILES));
X            break;
X
X        case AP:
X
X            display_xy(21, 40, "%s", odd_str(allocated.ap, DEF_AP));
X            break;
X
X        case TREAD:
X            display_xy(22, 40, "1/1 (%d)", allocated.treads);
X            break;
X
X    }
X
X}
/
echo 'Extracting ext.h...'
sed 's/^X//' > ext.h << '/'
X#include "ogre.h"
X
X#ifdef MAIN
X
XUNIT unit[N_UNITS];
XOGRE ogre;
Xint n_units;
X
X#else
X
Xextern UNIT unit[N_UNITS];
Xextern OGRE ogre;
Xextern int n_units;
X
X#endif
X
/
echo 'Extracting init.c...'
sed 's/^X//' > init.c << '/'
X#include "ext.h"
X
Xstatic char a, b;
Xstatic int cp_set;
Xstatic int infantry_points, armor_points;
X
Xinit_units(mark)
X{
X    int i, j;
X    int unitcmp();
X
X	init_screen();
X
X    a = 10;
X    b = 10;
X
X    switch(mark) {
X
X        case 3:
X            armor_points = 10;
X            infantry_points = 18;
X            break;
X
X        case 5: 
X            armor_points = 18;
X            infantry_points = 27;
X            break;
X    }
X
X    n_units = 0;
X    cp_set = FALSE;
X
X    while(armor_points > 0 || infantry_points > 0 || !cp_set) {
X        display(16, "left to place: %d armor, %d infantry%s",
X            armor_points, infantry_points,
X            (cp_set) ? "." : ", CP");
X        getunit();
X    }
X
X    /* sort the units so lower the i, the more valuable the unit. */
X    qsort( (char *) unit, n_units, sizeof(UNIT), unitcmp);
X
X
X}
X
Xgetunit()
X{
X    char    no_new, bad_char;
X    char    olda, oldb;
X    char    dir;
X
X    no_new = TRUE;
X    bad_char = FALSE;
X
X    movecur_hex(a, b);
X
X    while(no_new) {
X
X        olda = a;
X        oldb = b;
X
X        dir = getchar();
X    
X        switch(dir) {
X    
X            case RIGHT:
X                a--;
X                b--;
X                break;
X    
X            case UPRIGHT:
X                a--;
X                break;
X    
X            case DOWNRIGHT:
X                b--;
X                break;
X    
X            case LEFT:
X                a++;
X                b++;
X                break;
X    
X            case UPLEFT:
X                b++;
X                break;
X    
X            case DOWNLEFT:
X                a++;
X                break;
X    
X            case SIT:
X                break;
X
X            case CP:
X                if(cp_set) {
X                    bad_char = TRUE;
X                }
X                else {
X                    add_unit(a, b, dir);
X                    no_new = FALSE;
X                    cp_set = TRUE;
X                }
X                break;
X
X            case HVYTANK:
X            case MSLTANK:
X            case GEV:
X                if(occupied(a, b) || blocked(a, b) || armor_points == 0) {
X                    bad_char = TRUE;
X                    break;
X                }
X                add_unit(a, b, dir);
X                no_new = FALSE;
X                armor_points--;
X                break;
X    
X    	    case '1':
X                if(occupied(a, b) || blocked(a, b) || infantry_points < 1) {
X                    bad_char = TRUE;
X                    break;
X                }
X                add_unit(a, b, dir);
X                no_new = FALSE;
X                infantry_points -= 1;
X                break;
X
X	    case '2':
X                if(occupied(a, b) || blocked(a, b) || infantry_points < 2) {
X                    bad_char = TRUE;
X                    break;
X                }
X                add_unit(a, b, dir);
X                no_new = FALSE;
X                infantry_points -= 2;
X                break;
X
X            case INFANTRY:
X	    case '3':
X                if(occupied(a, b) || blocked(a, b) || infantry_points < 3) {
X                    bad_char = TRUE;
X                    break;
X                }
X                add_unit(a, b, dir);
X                no_new = FALSE;
X                infantry_points -= 3;
X                break;
X    
X            case HOWITZER:
X                if(occupied(a, b) || blocked(a, b) || armor_points <= 1) {
X                    bad_char = TRUE;
X                    break;
X                }
X                add_unit(a, b, dir);
X                no_new = FALSE;
X                armor_points -= 2;
X                break;
X    
X            default:
X                bad_char = TRUE;
X                break;
X    
X        }
X    
X        if(off_obstructed(a, b)  || 
X            bad_char)
X        {
X
X            a = olda;
X            b = oldb;
X            bad_char = FALSE;
X    
X        }
X
X        else {
X
X            movecur_hex(a, b);
X
X        }
X
X    }
X
X}
X
Xadd_unit(a, b, c)
Xchar a, b, c;
X{
X    int i;
X
X    i = n_units;
X    n_units++;
X
X    switch(c) {
X
X        case CP:
X            unit[i].type = CP;
X            unit[i].attack = 0;
X            unit[i].range = 0;
X            unit[i].defend = 0;
X            unit[i].movement = 0;
X            break; 
X
X        case HVYTANK:
X            unit[i].type = HVYTANK;
X            unit[i].attack = 4;
X            unit[i].range = 2;
X            unit[i].defend = 3;
X            unit[i].movement = 3;
X            break; 
X
X        case MSLTANK:
X            unit[i].type = MSLTANK;
X            unit[i].attack = 3;
X            unit[i].range = 4;
X            unit[i].defend = 2;
X            unit[i].movement = 2;
X            break; 
X
X        case GEV:
X            unit[i].type = GEV;
X            unit[i].attack = 2;
X            unit[i].range = 2;
X            unit[i].defend = 2;
X            unit[i].movement = 4;
X            break; 
X
X        case HOWITZER:
X            unit[i].type = HOWITZER;
X            unit[i].attack = 6;
X            unit[i].range = 8;
X            unit[i].defend = 1;
X            unit[i].movement = 0;
X            break; 
X
X        case INFANTRY:
X	case '3':
X            unit[i].type = INFANTRY;
X            unit[i].attack = 3;
X            unit[i].range = 1;
X            unit[i].defend = 1;
X            unit[i].movement = 2;
X            break; 
X
X	case '1':
X            unit[i].type = INFANTRY;
X            unit[i].attack = 1;
X            unit[i].range = 1;
X            unit[i].defend = 1;
X            unit[i].movement = 2;
X            break; 
X
X	case '2':
X            unit[i].type = INFANTRY;
X            unit[i].attack = 2;
X            unit[i].range = 1;
X            unit[i].defend = 1;
X            unit[i].movement = 2;
X            break; 
X
X    }
X
X    unit[i].range_to_ogre = 0;
X    unit[i].fired = 0;
X    unit[i].status = OK;
X    unit[i].moves_left = 0;
X    unit[i].l_hex = a;
X    unit[i].r_hex = b;
X
X    disp_unit(i);
X
X}
X
Xoccupied(a, b)
Xchar a,b;
X{
X    int i;
X
X    for(i = 0; i < n_units; i++)
X        if(unit[i].status != DESTROYED &&
X           unit[i].l_hex == a &&
X           unit[i].r_hex == b) return(TRUE);
X
X    return(FALSE);
X
X}
X
Xinit_ogre(mark)
X{
X
X    ogre.l_hex = rand() % 7 + 22; /* 22 - 28 */
X    ogre.r_hex = 50 - ogre.l_hex;
X
X    switch(mark) {
X
X        case 3:
X            ogre.treads = 45;
X            ogre.init_treads = 45;
X            ogre.movement = 3;
X            ogre.missiles = 2;
X            ogre.main_bats = 1;
X            ogre.sec_bats  = 4;
X            ogre.ap = 8;
X            break;
X
X        case 5:
X            ogre.treads = 60;
X            ogre.init_treads = 60;
X            ogre.movement = 3;
X            ogre.missiles = 5;
X            ogre.main_bats = 2;
X            ogre.sec_bats  = 6;
X            ogre.ap = 10;
X            break;
X
X    }
X
X
X    disp_ogre();
X
X}
X
Xunitcmp(u1, u2)
XUNIT *u1, *u2;
X{
X    int cmp;
X
X    switch(u1 -> type) {
X
X        case CP:
X
X            switch(u2 -> type) {
X
X                case CP: 
X                    cmp = 0;
X                    break;
X
X                default:
X                    cmp = -1;
X                    break;
X
X            }
X
X            break;
X
X        case HOWITZER:
X            switch(u2 -> type) {
X
X                case CP: 
X                    cmp = 1;
X                    break;
X
X                case HOWITZER:
X                    cmp = 0;
X                    break;
X
X                default:
X                    cmp = -1;
X                    break;
X
X            }
X
X            break;
X
X        case HVYTANK:
X            switch(u2 -> type) {
X
X                case CP:
X                case HOWITZER:
X                    cmp = 1;
X                    break;
X
X                case HVYTANK:
X                    cmp = 0;
X                    break;
X
X                default:
X                    cmp = -1;
X                    break;
X
X            }
X
X            break;
X
X        case MSLTANK:
X            switch(u2 -> type) {
X
X                case CP:
X                case HOWITZER:
X                case HVYTANK:
X                    cmp = 1;
X                    break;
X
X                case MSLTANK:
X                    cmp = 0;
X                    break;
X
X                default:
X                    cmp = -1;
X                    break;
X
X            }
X
X            break;
X
X        case GEV:
X            switch(u2 -> type) {
X
X                case INFANTRY:
X                    cmp = -1;
X                    break;
X
X                case GEV:
X                    cmp = 0;
X                    break;
X
X                default:
X                    cmp = 1;
X                    break;
X
X            }
X
X            break;
X
X        case INFANTRY:
X            switch(u2 -> type) {
X
X                case INFANTRY: 
X                    cmp = 0;
X                    break;
X
X                default:
X                    cmp = 1;
X                    break;
X
X            }
X
X            break;
X
X        }
X
X    return(cmp);
X
X}
/
echo 'Extracting initround.c...'
sed 's/^X//' > initround.c << '/'
X#include "ext.h"
X
Xinit_round()
X{
X
X    int i;
X
X    for(i = 0; i < n_units; i++) {
X
X        unit[i].moves_left = unit[i].movement;
X        if(unit[i].status == DISABLED) {
X            unit[i].status = OK;
X            update_hex(unit[i].l_hex, unit[i].r_hex);
X        }
X        unit[i].range_to_ogre =
X            range(ogre.l_hex, ogre.r_hex, unit[i].l_hex, unit[i].r_hex);
X
X    }
X
X}
X
Xinit_move_ogre()
X{
X
X    int i;
X
X    for(i = 0; i < n_units; i++) {
X
X        unit[i].range_to_ogre =
X            range(ogre.l_hex, ogre.r_hex, unit[i].l_hex, unit[i].r_hex);
X
X    }
X
X}
X
Xinit_def_attack()
X{
X
X    int i;
X
X    for(i = 0; i < n_units; i++) {
X
X        if(unit[i].status == OK) {
X            unit[i].fired = FALSE;
X            unit[i].range_to_ogre =
X                range(ogre.l_hex, ogre.r_hex, unit[i].l_hex, unit[i].r_hex);
X        }
X
X    }
X
X}
X
Xinit_ogre_attack()
X{
X
X    int i;
X
X    for(i = 0; i < n_units; i++) {
X
X            unit[i].fired = 0;
X            unit[i].range_to_ogre =
X                range(ogre.l_hex, ogre.r_hex, unit[i].l_hex, unit[i].r_hex);
X
X    }
X
X}
X
Xinit_gev2()
X{
X    int i;
X
X    for(i = 0; i < n_units; i++)
X        if(unit[i].status == OK && unit[i].type == GEV)
X            unit[i].moves_left = 3;
X
X}
X
Xdisplay_range(i)
X{
X
X    movecur(18, 0); eeol();
X    printf("range from unit %d to Ogre %d.", i, unit[i].range_to_ogre);
X    cycle();
X
X}
/
echo 'Extracting main.c...'
sed 's/^X//' > main.c << '/'
X
X/*
X    OGRE: a tactical ground combat game set in 2085.
X
X    Adapted from the Metagaming Microgame by Steve Jackson.
X
X    This version was written for a Vax 11/780 under Unix
X    by Michael Caplinger, Rice University, February-March 1982.
X
X    Paper game (c) 1977 by Steve Jackson
X    This implementation (c) 1982, 1984 by Michael Caplinger
X*/
X
X#include <signal.h>
X
X#define MAIN
X#include "ext.h"
X
Xmain(argc, argv)
Xchar **argv;
X{
X
X    int handler();
X    int mark;
X
X    signal(SIGINT, handler);
X
X    if(argc > 1)
X        switch(argv[1][0]) {
X
X            case '3':
X                mark = 3;
X                break;
X
X            case '5':
X                mark = 5;
X                break;
X
X            default:
X                mark = 3;
X                break;
X        }
X
X    else mark = 3;
X
X    set_term();
X    srand(time(0));
X    init_units(mark);
X    init_ogre(mark);
X    disp_ogre_status(TRUE);
X
X    while(1) {
X
X        init_round();
X
X        /* The Ogre fires. */
X        assign_fire_ogre();
X        check_over(); 
X
X        /* Player moves, and fires. */
X        move_def();
X        attack_def();
X
X        /* Let the GEVs move their extra 3 turns. */
X        init_gev2();
X        move_def();
X
X        /* The Ogre moves. */
X        move_ogre();
X        check_over(); 
X
X    }
X
X}
X
Xhandler() {
X
X    clear_screen();
X    reset_term();
X    exit(0);
X
X}
X
X/*
X    See if the game is over, and die if it is.
X*/
Xcheck_over()
X{
X    char *message;
X    int over;
X
X    over = FALSE;
X
X    if(unit[0].status == DESTROYED) {
X        message = "The Ogre wins!!";
X        over = TRUE;
X    }
X    if(ogre.movement == 0) {
X        message = "You win!!";
X        over = TRUE;
X    }
X
X    if(over) {
X        clear_screen();
X        reset_term();
X        printf("%s\n", message);
X        exit(0);
X    }
X
X}
/
echo 'Extracting map.c...'
sed 's/^X//' > map.c << '/'
X/*
X    These routines implement all functions associated with the map and display
X    thereof.
X
X    (Thanks to Bob Hood of Rice for coming up with 
X     the x-y and range algorithms.)
X
X    Michael Caplinger, Rice University, March 1982.
X*/
X
X#include "ext.h"
X#include <ctype.h>
X
X
X/* Initialize the map display, at the beginning of the game. */
Xinit_screen() {
X
X    int a, b;
X    char row, col;
X
X    tc_setup();
X    clear_screen();
X
X    for(a = 1; a <= 28; a++) {
X        for(b = 1; b <= 28; b++) {
X            if(!off_map(a, b)) {
X                disp_hex(a, b, '.');
X            }
X        }
X    }
X    disp_craters();
X}
X
X
X/* 
X    Convert a left and right hex pair (eg, the hex 2015 has an l_hex of 20 and
X    an r_hex of 15) to x-y screen coordinates.
X*/
Xto_xy(lhex, rhex, row, col)
Xchar lhex, rhex, *row, *col;
X{
X
X    *row = (lhex - rhex) + 7;
X    *col = 50 - (lhex + rhex);
X
X}
X
X/* Check to see if an lr pair is off the map. */
Xoff_map(a, b)
Xchar a, b;
X{
X    char row, col;
X
X    to_xy(a, b, &row, &col);
X    if(col < 0 || col > 38 || row < 0 || row > 14) return(TRUE);
X    else return(FALSE);
X
X}
X
X/* Check to see if an lr pair is off the obstructed area of the map. */
Xoff_obstructed(a, b)
Xchar a, b;
X{
X    char row, col;
X
X    to_xy(a, b, &row, &col);
X    if(col < 10 || col > 38 || row < 0 || row > 14) return(TRUE);
X    else return(FALSE);
X
X}
X
X/* Display a character at a given hex. */
Xdisp_hex(a, b, c)
Xchar a, b, c;
X{
X    char row, col;
X
X    to_xy(a, b, &row, &col);
X
X    movecur(row, col * 2 + 1);
X    putchar(c);
X
X}
X
X/* 
X    Display the contents of a hex.  If more than one item is in a hex,
X    the following precedence applies:
X        1) Ogre
X        2) Defending units (by value)
X        3) Craters (not that anything can be in a crater hex.)
X*/
Xupdate_hex(a, b)
Xchar a, b;
X{
X
X    int i;
X
X    if(ogre.l_hex == a && ogre.r_hex == b) {
X        disp_ogre();
X        return;
X    }
X
X    for(i = 0; i < n_units; i++)
X        if(unit[i].l_hex == a && unit[i].r_hex == b &&
X            unit[i].status != DESTROYED) {
X            disp_unit(i);
X            return;
X        }
X
X    if(blocked(a, b)) {
X        disp_hex(a, b, '*');
X        return;
X    }
X
X    disp_hex(a, b, '.');
X
X}
X
X/* Display the ith unit. */
Xdisp_unit(i)
Xint i;
X{
X    char a, b;
X
X    a = unit[i].l_hex;
X    b = unit[i].r_hex;
X
X    switch(unit[i].status) {
X
X        case OK:
X
X            switch(unit[i].type) {
X
X                case INFANTRY:
X                    disp_hex(a, b, '0' + unit[i].attack);
X                    break;
X
X                default:
X                    disp_hex(a, b, unit[i].type);
X                    break;
X
X            }
X            break;
X
X        case DISABLED:
X            disp_hex(a, b, tolower(unit[i].type));
X            break;
X
X        case DESTROYED:
X            disp_hex(a, b, '.');
X            break;
X
X    }
X
X}
X
X/* Display the Ogre. */
Xdisp_ogre(i)
Xint i;
X{
X    char a, b;
X
X    a = ogre.l_hex;
X    b = ogre.r_hex;
X
X    disp_hex(a, b, 'O');
X
X}
X
X
X/* Move the cursor to the specified hex on the screen. */
Xmovecur_hex(a, b)
Xchar a, b;
X{
X    char row, col;
X
X    to_xy(a, b, &row, &col);
X
X    movecur(row, col * 2 + 1);
X
X}
X
X/* Point at the ith unit with the cursor. */
Xmovecur_unit(i)
Xint i;
X{
X
X    movecur_hex(unit[i].l_hex, unit[i].r_hex);
X
X}
X
X#define ABS(i) (((i) < 0) ? -(i) : (i))
X#define BIGINT 32767
X
X/* Calculate the range between 2 hexes. */
Xrange(a1, b1, a2, b2)
Xchar a1, b1, a2, b2;
X{
X
X    char    diff1, diff2, temp;
X    int     subrange[3];
X    int     min, i;
X    int     rangesum;
X
X    diff1 = a1 - b1;
X    diff2 = a2 - b2;
X
X    subrange[0] = ABS(a1 - a2);
X    subrange[1] = ABS(b1 - b2);
X    subrange[2] = ABS(diff1 - diff2);
X
X    min = 0;
X    for(i = 1; i < 3; i++)
X        if(subrange[i] < subrange[min]) min = i;
X
X    rangesum = subrange[min];
X
X    temp = subrange[min]; subrange[min] = subrange[2]; subrange[2] = temp;
X
X    min = 0;
X    for(i = 1; i < 2; i++)
X        if(subrange[i] < subrange[min]) min = i;
X
X    rangesum += subrange[min];
X
X    return(rangesum);
X
X}
X
X/*
X    This is a hardwired set of craters, taken from the paper game's map.
X*/
Xstatic struct {
X    char l_hex;
X    char r_hex;
X} craters[] = {
X    17, 16,
X    19, 13,
X    13, 18,
X    14, 15,
X    13, 15,
X    15, 10,
X    9,  15,
X    10, 12,
X    7,  14,
X    11, 10,
X    14, 7,
X    12, 6,
X    7,  10,
X    8,  6,
X    4,  9,
X    9,  4,
X    9,  3,
X};
X
X#define NCRATERS    (sizeof(craters) / 2 * sizeof(char))
X
X/* Determine if a hex has a crater. */
Xblocked(a, b)
Xchar a, b;
X{
X    int i;
X
X    for(i = 0; i < NCRATERS; i++) 
X        if(craters[i].l_hex == a && craters[i].r_hex == b) return(TRUE);
X
X    return(FALSE);
X
X}
X
X/* Display the craters. */
Xdisp_craters()
X{
X    int i;
X
X    for(i = 0; i < NCRATERS; i++) 
X        disp_hex(craters[i].l_hex, craters[i].r_hex, '*');
X
X}
X
X#include <stdio.h>
X
Xdescribe_action(action, i)
Xchar *action;
Xint i;
X{
X
X    switch(unit[i].type) {
X
X        case HOWITZER:
X            display(16, "%s howitzer (%d/%d D%d M%d)", action,
X                unit[i].attack, unit[i].range, 
X                unit[i].defend, unit[i].moves_left);
X            break;
X
X        case MSLTANK:
X            display(16, "%s missile tank (%d/%d D%d M%d)", action,
X                unit[i].attack, unit[i].range, 
X                unit[i].defend, unit[i].moves_left);
X            break;
X
X        case GEV:
X            display(16, "%s GEV (%d/%d D%d M%d)", action,
X                unit[i].attack, unit[i].range, 
X                unit[i].defend, unit[i].moves_left);
X            break;
X
X        case HVYTANK:
X            display(16, "%s heavy tank (%d/%d D%d M%d)", action,
X                unit[i].attack, unit[i].range, 
X                unit[i].defend, unit[i].moves_left);
X            break;
X
X        case INFANTRY:
X            display(16, "%s infantry (%d/%d D%d M%d)", action,
X                unit[i].attack, unit[i].range, 
X                unit[i].defend, unit[i].moves_left);
X            break;
X
X    }
X
X}
X
Xdisplay(line, format, args)
Xint line;
Xchar *format;
Xint args;
X{
X
X    movecur(line, 0);
X    eeol();
X    _doprnt(format, &args, stdout);
X
X}
X
Xdisplay_xy(line, col, format, args)
Xint line, col;
Xchar *format;
Xint args;
X{
X
X    movecur(line, col);
X    eeol();
X    _doprnt(format, &args, stdout);
X
X}
X
X
/
echo 'Extracting move.c...'
sed 's/^X//' > move.c << '/'
X/*
X    Move the defender's units.
X
X    Michael Caplinger, Rice University, March 1982.
X*/
X
X#include "ext.h"
X
Xmove_def()
X{
X    int i, j;
X
X    for(i = 0; i < n_units; i++)
X        if(unit[i].status == OK) {
X            if(unit[i].moves_left > 0) describe_action("Move", i);
X            while(unit[i].moves_left > 0 && unit[i].status == OK) 
X                getmove(i);
X        }
X
X}
X
Xgetmove(i)
Xint i;
X{
X
X    char    nomove, bad_char;
X    char    a, b, dir;
X    char    olda, oldb;
X
X    nomove = TRUE;
X
X    while(nomove) {
X    
X        a = unit[i].l_hex;
X        b = unit[i].r_hex;
X
X        movecur_hex(a, b);
X
X        bad_char = FALSE;
X    
X        dir = getchar();
X    
X        switch(dir) {
X    
X            case RIGHT:
X                a--;
X                b--;
X                break;
X    
X            case UPRIGHT:
X                a--;
X                break;
X    
X            case DOWNRIGHT:
X                b--;
X                break;
X    
X            case LEFT:
X                a++;
X                b++;
X                break;
X    
X            case UPLEFT:
X                b++;
X                break;
X    
X            case DOWNLEFT:
X                a++;
X                break;
X    
X            case SIT:
X            case ' ':
X                unit[i].moves_left = 0;
X                return;
X    
X            default:
X                bad_char = TRUE;
X                break;
X    
X        }
X
X        /* Rule 5.02 */
X        /*
X            Note that the no-stacking rule can be violated by SITting on an
X            occupied hex, and that the enforcement of no-stacking below is
X            TOO stringent.
X        */
X
X        if(off_map(a, b) || 
X            (occupied(a, b) && unit[i].moves_left == 1) ||
X            blocked(a, b) ||
X            bad_char)
X        {
X
X            bad_char = FALSE;
X    
X        }
X    
X        else {
X            /* display move */
X
X            olda = unit[i].l_hex;
X            oldb = unit[i].r_hex;
X            unit[i].l_hex = a;
X            unit[i].r_hex = b;
X
X            update_hex(olda, oldb);
X
X            nomove = FALSE;
X            unit[i].moves_left -= 1;
X
X            def_ram(i);
X
X            update_hex(unit[i].l_hex, unit[i].r_hex);
X
X        }
X
X    }
X
X}
/
echo 'Extracting ogre.6...'
sed 's/^X//' > ogre.6 << '/'
X.TH OGRE 6
X.UC 4
X.SH NAME
XOgre - a game of tank warfare in the 21st century.
X.SH SYNOPSIS
X/usr/games/ogre [ogre type (3 or 5)]
X.SH DESCRIPTION
X.PP
XOgre is a game of tank warfare in the 21st century.  You command a force of
Xinfantry, armor, and howitzers pitted against a gian cybernetic tank, the
XOgre.  Your mission is to destroy the Ogre, or at least render it immobile,
Xbefore it reaches and destroys your command post.
X.PP
XA more complete reference on how to play can be found in the Ogre rule book
Xfor the Metagaming MicroGame, now distributed by Steve Jackson's company.
XHere's some very sketchy and incomplete documentation for Ogre players:
X.PP
XThe game has the following phases:
X.PP
X1) Initialization.  The player's armor units, infantry, and command post
Xare placed on the map.  Nothing can be placed on the leftmost 7
Xcolumns of hexes, or on craters (*'s), or on any unit already placed.
XValid commands are:
X.nf
X
X           w   e
X
X        a         d    (hex movement keys)
X
X           z   x
X
X            place a:
X
X        H   howitzer
X        T   heavy tank
X        M   missile tank
X        G   GEV
X        I   Infantry unit (attack strength 3)
X        C   Command Post
X.fi
X
Xon the space currently pointed at by the cursor.  Note that these
Xare capital letters.
X.PP
XUnits are displayed as these characters, except infantry, which appear
Xas '1', '2', or '3' depending on their attack strength.
X.PP
X2) The Ogre (an O) now appears.
X.PP
X3) You are given the opportunity to move all your vehicles and infantry
Xthat can move.  The cursor motion keys are used to move the unit
Xindicated by the cursor.  Additionally, 's' or ' ' can be used to
Xlet a vehicle stay motionless.  No vehicle can move through a crater
Xhex, or into a hex occupied by another friendly unit on its last turn,
Xalthough it can move through a friendly hex on its way elsewhere.
XMoving through the hex occupied by the Ogre is an attempt to ram the
XOgre.  This reduces the Ogre's treads by some amount, and destroys the
Xunit.
X.PP
X4) You now fire all your vehicles in range at designated targets on the
XOgre.  The following commands are used:
X.TP     
X.B m  
Xfire at missiles
X.TP
X.B b   
Xfire at main batteries
X.TP
X.B s   
Xfire at secondary batteries
X.TP        
X.B a   
Xfire at anti-personnel guns
X.TP        
X.B t   
Xfire at treads
X.PP
XThe odds of destroying the target are displayed, but no action
Xis taken until 'r' is used, or until you run out of attack points.
X(except for attacks on treads - see below.)
X(in the odds display, '+' means a sure thing.)
X.TP 
X.B p   
XPass. The unit is passed over, and given the opportunity to fire
Xlater.
X.TP        
X.B r   
Xresolve all allocations so far, and display the results.  This
Xis implied by 't', as tread attacks cannot be grouped.  A resolve
Xis done automatically when you run out of attacking units.
X.PP
X5) Second movement phase for GEVs.  Just like step 3, except that only GEVs
Xcan move.
X.PP
X6) The Ogre moves.  If it runs over any of your units, they are damaged
Xor destroyed.
X.PP
X7) The Ogre fires at all units in range.  Destroyed units are removed from
Xthe map.  Disabled units are displayed in lower case, and may not
Xmove or fire until the end of the NEXT Ogre attack.
X.PP
XSteps 3 through 7 are repeated until either
Xa) the Ogre has no movement points left, in which case you win, or
Xb) your command post is destroyed, in which case the Ogre wins.
X.SH MISCELLANEOUS
X.PP
XThe display "a/r Dd Mm" means the unit concerned attacks at a, at range r,
Xdefends at d, and moves m hexes per turn.
X.PP
XThe Ogre by default is a Mark III.  An argument of '5' on the command line
Xmakes it a Mark V, and gives you more armor points.
X.PP
XThe game can be interrupted at any point with a control-C.  There's now
Xno way to restart.
X.PP
XThe paper game is copyright (c) 1977 by Steve Jackson.  This computer
Ximplementation is copyright (c) 1984 by Michael Caplinger.
X.SH AUTHOR
XMichael Caplinger, Rice University (mike@rice.ARPA), from a Microgame of the
Xsame name published by Metagaming of Austin, Texas, and written by Steve
XJackson.  This implementation is not authorized in any way by Mr. Jackson,
Xand should not be sold for profit.
X.SH SEE ALSO
Xtermcap(5)
X.SH BUGS
X.PP
XThe Ogre sometimes gets confused and doesn't know where to go, so it
Xoscillates from one hex to another, and then back.
/
echo 'Extracting ogre.h...'
sed 's/^X//' > ogre.h << '/'
Xtypedef struct {
X
X    char    type;
X    char    attack;
X    char    range;
X    char    defend;
X    char    movement;
X    char    range_to_ogre;
X    char    fired;
X    char    moves_left;
X    char    status;
X    char    l_hex;
X    char    r_hex;
X
X} UNIT;
X
Xtypedef struct {
X
X    char    missiles;
X    char    main_bats;
X    char    sec_bats;
X    char    ap;
X    char    treads;
X    char    movement;
X    char    moves_left;
X    char    l_hex;
X    char    r_hex;
X    char    init_treads;
X
X} OGRE;
X
X/* unit types */
X
X#define CP          'C'
X#define HVYTANK     'T'
X#define MSLTANK     'M'
X#define GEV         'G'
X#define HOWITZER    'H'
X#define INFANTRY    'I'
X
X
X/* unit statuses */
X#define OK          1
X#define DISABLED    2
X#define DESTROYED   3
X
X/* directions */
X#define RIGHT       'd'
X#define UPRIGHT     'e'
X#define DOWNRIGHT   'x'
X#define LEFT        'a'
X#define UPLEFT      'w'
X#define DOWNLEFT    'z'
X#define SIT         's'
X
X
X#define TRUE        1
X#define FALSE       0
X
X#define N_UNITS     30
X
X#define DEF_MISSILES    3
X#define DEF_MAIN        4
X#define DEF_SECONDARY   3
X#define DEF_AP          1
X
X#define ATK_MISSILES    6
X#define ATK_MAIN        4
X#define ATK_SECONDARY   3
X#define ATK_AP          1
X
X#define RANGE_MISSILES      5  
X#define RANGE_MAIN          3
X#define RANGE_SECONDARY     2
X#define RANGE_AP            1
X
/
echo 'Extracting ogrecom.c...'
sed 's/^X//' > ogrecom.c << '/'
X/*
X    These routines define the Ogre's stategy (such as it is).
X    There's lots of room for improvement here.
X*/
X
X#include "ext.h"
X
Xmove_ogre()
X{
X
X    init_move_ogre();
X
X    ogre.moves_left = ogre.movement;
X
X    while(ogre.moves_left > 0) {
X        move_ogre1();
X        ogre_ram();
X        cycle();
X    }
X
X}
X
X#define INFINITY 32767
X
X/* Move the Ogre one hex. */
Xmove_ogre1()
X{
X
X    int weight[7];
X    int i, max;
X    char a, b;
X    char olda, oldb;
X
X    a = ogre.l_hex;
X    b = ogre.r_hex;
X
X    /* Collect weights for each possible move. These will be maximized. */
X
X    weight[0] = - INFINITY; /* temp patch: getweight(a, b); */
X    weight[1] = getweight(a - 1, b - 1);
X    weight[2] = getweight(a - 1, b);
X    weight[3] = getweight(a, b + 1);
X    weight[4] = getweight(a + 1, b + 1);
X    weight[5] = getweight(a + 1, b);
X    weight[6] = getweight(a, b - 1);
X
X    max = 0;
X    for(i = 1; i < 7; i++)
X        if(weight[i] > weight[max]) max = i;
X
X    switch(max) {
X
X        case 0:
X            break;
X
X        case 1:
X            a--;
X            b--;
X            break;
X
X        case 2:
X            a--;
X            break;
X
X        case 3:
X            b++;
X            break;
X
X        case 4:
X            a++;
X            b++;
X            break;
X
X        case 5:
X            a++;
X            break;
X
X        case 6:
X            b--;
X            break;
X
X    }
X
X    olda = ogre.l_hex;
X    oldb =  ogre.r_hex;
X
X    ogre.l_hex = a;
X    ogre.r_hex = b;
X
X    update_hex(olda, oldb);
X
X    disp_ogre();
X    ogre.moves_left -= 1;
X
X}
X
X/*
X    The weight for each hex is a measure of how desirable it is to be in that
X    hex; the weights of the six possible directions are maximized.
X
X    The primary consideration is distance to the CP; in the absence of other
X    factors, the Ogre will take the fastest course to the CP.
X    However, the Ogre will crush any unit it can (units with higher attacks
X    chosen first) and moves towards units that are within range of its missiles
X    or batteries.  It attempts to weight so that a concentration of dangerous,
X    immobile units (like howitzers) is attacked first.
X
X    Testing indicates that this isn't a bad strategy.
X*/
Xgetweight(a, b)
Xchar a, b;
X{
X    int weight;
X    int total_attacks;
X    int to_target;
X    int i;
X
X    weight = - range(a, b, unit[0].l_hex, unit[0].r_hex);
X
X    total_attacks = ogre.missiles + ogre.main_bats + ogre.sec_bats;
X
X    for(i = 1; i < n_units; i++) {
X
X        if(unit[i].status == DESTROYED) continue;
X
X        to_target = range(a, b, unit[i].l_hex, unit[i].r_hex);
X
X        /*
X             If you can crush somebody, do it.
X             More dangerous units get crushed first.
X        */
X        if(to_target == 0) {
X	    if(unit[i].type == CP) weight = 50;
X            else weight = 10 * unit[i].attack;
X            break;
X        }
X
X        if(total_attacks <= 0) continue;
X
X        if(to_target <= RANGE_MISSILES && ogre.missiles > 0) {
X            weight += unit[i].attack;
X            weight += 4 - unit[i].movement;
X            total_attacks -= 1;
X            continue;
X        }
X
X        if(to_target <= RANGE_MAIN && ogre.main_bats > 0) {
X            weight += unit[i].attack;
X            weight += 4 - unit[i].movement;
X            total_attacks -= 1;
X            continue;
X        }
X
X        if(to_target <= RANGE_SECONDARY && ogre.sec_bats > 0) {
X            weight += unit[i].attack;
X            weight += 4 - unit[i].movement;
X            total_attacks -= 1;
X            continue;
X        }
X
X        if(to_target <= RANGE_AP && ogre.ap > 0 && 
X	    (unit[i].type == INFANTRY || unit[i].type == CP)) {
X            weight += unit[i].attack;
X            weight += 4 - unit[i].movement;
X            total_attacks -= 1;
X            continue;
X        }
X
X    }
X
X    if(off_map(a, b) || blocked(a, b)) weight = - INFINITY;
X/*
Xdisplay(17, "%d %d weight %d", a, b, weight); cycle();
X*/
X
X    return(weight);
X
X}
X
X#define INCR(i) i = (i == n_units - 1) ? 0 : i + 1
X
X#define MIN(a, b) (((a) > (b)) ? (a) : (b))
X
X/* 
X    Figure out who the Ogre will fire at. In this code, the "fired" element
X    of the unit description is the number of hit points assigned against that
X    unit.
X*/
Xassign_fire_ogre()
X{
X
X    int i, unitno, nmissiles;
X
X    init_ogre_attack();
X
X    /*
X        The basic strategy here is to fire at the next unit in range. Since
X        the units are sorted by value, this will hopefully (although not 
X        always) result in reasonable choices for targets.
X        Experience indicates that the Ogre often overkills (which is OK)
X        but fails to attack some valuable possibility (not OK).  Some
X        work needs to be done here.
X    */
X
X    unitno = nextunit(RANGE_AP, 0);
X
X    for(i = 0; i < ogre.ap; i++) {
X
X        if(unit[unitno].range_to_ogre <= RANGE_AP &&
X          (unit[unitno].type == CP || unit[unitno].type == INFANTRY)) {
X
X            unit[unitno].fired += ATK_AP;
X            display_attack("AP", unitno);
X
X        }
X        unitno = nextunit(RANGE_AP, unitno);
X
X    }
X
X    unitno = nextunit(RANGE_SECONDARY, unitno);
X
X    for(i = 0; i < ogre.sec_bats; i++) {
X
X        if(unit[unitno].range_to_ogre <= RANGE_SECONDARY) {
X
X            unit[unitno].fired += ATK_SECONDARY;
X            display_attack("secondary battery", unitno);
X
X        }
X        unitno = nextunit(RANGE_SECONDARY, unitno);
X
X    }
X
X    unitno = nextunit(RANGE_MAIN, unitno);
X
X    for(i = 0; i < ogre.main_bats; i++) {
X
X        if(unit[unitno].range_to_ogre <= RANGE_MAIN) {
X
X            unit[unitno].fired += ATK_MAIN;
X            display_attack("main battery", unitno);
X
X        }
X        unitno = nextunit(RANGE_MAIN, unitno);
X
X    }
X
X    unitno = nextunit(RANGE_MISSILES, unitno);
X
X    nmissiles = ogre.missiles;
X
X    for(i = 0; i < nmissiles; i++) {
X
X        if(unit[unitno].status != DESTROYED &&
X	    /* don't fire at infantry... 27 Oct 83 */
X	    unit[unitno].type != INFANTRY && 
X            unit[unitno].range_to_ogre <= RANGE_MISSILES) {
X
X            unit[unitno].fired += ATK_MISSILES;
X            ogre.missiles -= 1;
X            display_attack("missile", unitno);
X            disp_ogre_status(FALSE);
X
X        }
X        unitno = nextunit(RANGE_MISSILES, unitno);
X
X    }
X
X}
X
X#include <stdio.h>
X 
Xcycle()
X{
X
X    fflush(stdout);
X    sleep(1);
X
X}
X
X/*
X    Display and resolve an attack on a single defending unit.
X*/
Xdisplay_attack(weapon, target)
Xchar *weapon;
Xint  target;
X{
X
X    /* No point if the unit is already destroyed. */
X    if(unit[target].status == DESTROYED) return;
X
X    display(16, "Ogre fires %s at unit at hex %d%d", weapon,
X        unit[target].l_hex, unit[target].r_hex);
X
X    movecur_hex(unit[target].l_hex, unit[target].r_hex);
X
X    cycle();
X
X    def_resolve(target);
X
X}
X
Xnextunit(range, unitno)
Xint range;
Xint unitno;
X{
X    int start;
X
X    start = unitno;
X    INCR(unitno);
X    while(unitno != start) {
X        if(range == 1) {
X            if(unit[unitno].status != DESTROYED &&
X                (unit[unitno].type == CP || unit[unitno].type == INFANTRY) &&
X                unit[unitno].range_to_ogre <= range)
X                return(unitno);
X        }
X        else {
X            if(unit[unitno].status != DESTROYED &&
X                unit[unitno].range_to_ogre <= range)
X                return(unitno);
X        }
X        INCR(unitno);
X    }
X
X    return(unitno);
X
X}
/
echo 'Extracting ogrestat.c...'
sed 's/^X//' > ogrestat.c << '/'
X/*
X    Handle the Ogre status display.
X*/
X
X#include "ext.h"
X
Xdisp_ogre_status(redraw)
X
X/* If redraw is false, the display is not touched if nothing has changed. */
Xint redraw;
X{
X    static OGRE last;
X
X    /*
X        The Ogre status display occupies the bottom 6 lines of the display.
X    */
X
X    /*               0        1         2         3         4
X                     1234567890123456789012345678901234567890       */
X
X    if(redraw || last.main_bats != ogre.main_bats)
X        if(ogre.main_bats > 0)
X        display(18, "Main Batteries:      %d (4/3 D4)", ogre.main_bats);
X        else display(18, " ");
X
X    if(redraw || last.sec_bats != ogre.sec_bats)
X        if(ogre.sec_bats > 0)
X        display(19, "Secondary Batteries: %d (3/2 D3)", ogre.sec_bats);
X        else display(19, " ");
X
X    if(redraw || last.missiles != ogre.missiles)
X        if(ogre.missiles > 0)
X        display(20, "Missiles:            %d (6/5 D3)", ogre.missiles);
X        else display(20, " ");
X
X    if(redraw || last.ap != ogre.ap)
X        if(ogre.ap > 0)
X        display(21, "Anti-personnel:     %2d (1/1 D1)", ogre.ap);
X        else display(21, " ");
X
X    if(redraw || last.treads != ogre.treads)
X        if(ogre.treads > 0)
X        display(22, "Treads:             %2d (1/* D1)", ogre.treads);
X        else display(22, " ");
X
X    if(redraw || last.movement != ogre.movement)
X        display(23, "Movement:            %d", ogre.movement);
X
X    copy(&last, &ogre, sizeof(last));
X
X}
X
Xcopy(to, from, size)
Xchar *to, *from;
Xint size;
X{
X    int i;
X
X    for(i = 0; i < size; i++) to[i] = from[i];
X
X}
/
echo 'Extracting resolve.c...'
sed 's/^X//' > resolve.c << '/'
X/*
X    Resolve all attacks and rams from both directions.
X
X    Michael Caplinger, Rice University, March 1982.
X*/
X
X#include "ext.h"
X
Xstatic char *odd_names[] = {
X    "0/1",
X    "1/2",
X    "1/1",
X    "2/1",
X    "3/1",
X    "4/1",
X    "+",
X};
X
Xstatic char crt[6][7] = {
X
X    OK, OK,        OK,        OK,        DISABLED,  DISABLED,  DESTROYED,
X    OK, OK,        OK,        DISABLED,  DISABLED,  DESTROYED, DESTROYED,
X    OK, OK,        DISABLED,  DISABLED,  DESTROYED, DESTROYED, DESTROYED,
X    OK, OK,        DISABLED,  DESTROYED, DESTROYED, DESTROYED, DESTROYED,
X    OK, DISABLED,  DESTROYED, DESTROYED, DESTROYED, DESTROYED, DESTROYED,
X    OK, DESTROYED, DESTROYED, DESTROYED, DESTROYED, DESTROYED, DESTROYED,
X
X};
X
Xodds(attack, defend)
Xint attack, defend;
X{
X    int result;
X
X    result = (defend > 0) ? attack / defend + 1 : 6;
X
X    if(result > 6) result = 6;
X
X    if(result == 1)
X        result = (2 * attack < defend) ? 0 : 1;
X
X    return(result);
X
X}
X
Xchar *odd_str(attack, defend)
Xint attack, defend;
X{
X
X    return(odd_names[odds(attack, defend)]);
X
X}
X
X
X/* Resolve all attacks on the Ogre. */
Xogre_resolve(allocations)
XOGRE *allocations;
X{
X
X    display(16, "Resolving..."); cycle();
X
X    if(allocations -> missiles > 0) {
X        if(crt[roll()][odds(allocations -> missiles, DEF_MISSILES)] ==
X            DESTROYED) ogre.missiles -= 1;
X    }
X
X    if(allocations -> main_bats > 0) {
X        if(crt[roll()][odds(allocations -> main_bats, DEF_MAIN)] ==
X            DESTROYED) ogre.main_bats -= 1;
X    }
X
X    if(allocations -> sec_bats > 0) {
X        if(crt[roll()][odds(allocations -> sec_bats, DEF_SECONDARY)] ==
X            DESTROYED) ogre.sec_bats -= 1;
X    }
X
X    if(allocations -> ap > 0) {
X        if(crt[roll()][odds(allocations -> ap, DEF_AP)] ==
X            DESTROYED) ogre.ap -= 1;
X    }
X
X    if(allocations -> treads > 0) {
X        if(crt[roll()][odds(1, 1)] == DESTROYED)
X            decrease_treads(allocations -> treads);
X
X    }
X
X    /* erase the odds. */
X    movecur(18, 40); eeol();
X    movecur(19, 40); eeol();
X    movecur(20, 40); eeol();
X    movecur(21, 40); eeol();
X    movecur(22, 40); eeol();
X
X    /* update the Ogre status display. */
X    disp_ogre_status(FALSE);
X
X}
X
X/* Resolve an Ogre attack on a defending unit. */
Xdef_resolve(i)
X{
X    char result;
X
X    if(unit[i].status != DESTROYED && unit[i].fired > 0) {
X
X        result = crt[roll()][odds(unit[i].fired, unit[i].defend)];
X
X        /* Infantry is a special case. */
X        if(unit[i].type == INFANTRY)
X            if(result == DISABLED) {
X                unit[i].attack -= 1;
X                if(unit[i].attack == 0) unit[i].status = DESTROYED;
X                update_hex(unit[i].l_hex, unit[i].r_hex);
X                return;
X            }
X
X        switch(unit[i].status) {
X
X            case OK:
X                unit[i].status = result;
X                break;
X
X            case DISABLED:
X                if(result != OK) unit[i].status = DESTROYED;
X                break;
X
X        }
X
X        if(unit[i].status != OK) 
X            update_hex(unit[i].l_hex, unit[i].r_hex);
X
X    }
X
X}
X
Xroll()
X{
X
X    return(rand() % 6);
X
X}
X
X/* Routine called for each hex the Ogre moves through, to handle rams. */
Xogre_ram()
X{
X    int i;
X
X    /* Rule 5.03 */
X    for(i = 0; i < n_units; i++)
X        if(unit[i].l_hex == ogre.l_hex &&
X           unit[i].r_hex == ogre.r_hex &&
X           unit[i].status != DESTROYED)
X
X            switch(unit[i].type) {
X
X                case INFANTRY:
X
X                    /* Rule 5.04 */
X                    if(ogre.ap > 0) {
X                        unit[i].attack -= 1;
X			if(unit[i].attack == 0) 
X			    unit[i].status = DESTROYED;
X                    }
X                    break;
X
X                default:
X
X                    /* Rule 5.031 */
X                    if(unit[i].movement == 0 || 
X                       unit[i].status == DISABLED) {
X                        unit[i].status = DESTROYED;
X                        decrease_treads( (unit[i].type == HVYTANK) ? 2 : 1);
X                        disp_ogre_status(FALSE);
X                    }
X                    else {
X                        unit[i].status = (roll() > 3) ? DESTROYED : DISABLED;
X                        decrease_treads( (unit[i].type == HVYTANK) ? 2 : 1);
X                        disp_ogre_status(FALSE);
X                    }
X                    break;
X
X            }
X
X
X}
X
X/* See if a defender has rammed the Ogre. */
Xdef_ram(i)
Xint i;
X{
X    if(unit[i].l_hex == ogre.l_hex &&
X       unit[i].r_hex == ogre.r_hex &&
X       unit[i].type != INFANTRY) {
X
X        /* Rule 5.036 */
X
X        decrease_treads(1);
X        unit[i].status = DESTROYED;
X        disp_ogre_status(FALSE);
X
X    }
X
X}
X
Xdecrease_treads(attack)
Xint attack;
X{
X
X    /* Rule 6.05 */
X
X    /* Now, where is the movement factor going? */
X
X    ogre.treads  -= attack;
X    ogre.movement = 0;
X    if(ogre.treads > 0)  ogre.movement = 1;
X    if(ogre.treads > ogre.init_treads / 3) ogre.movement = 2;
X    if(ogre.treads > 2 * ogre.init_treads / 3) ogre.movement = 3;
X
X}
X
/
echo 'Extracting termcap.c...'
sed 's/^X//' > termcap.c << '/'
X#include <sgtty.h>
X
X/*
X    Interface to termcap library.
X*/
X
Xchar    PC;
Xchar    *BC, *UP;
Xchar    *eeolseq, *cmseq;
Xchar    *clearseq;
Xshort   ospeed;
Xint     putchar();
X
Xtc_setup() {
X
X    static  char    bp[1024];
X    static  char    buffer[1024];
X    char    *area = buffer;
X    char    *getenv();
X    char    *tgetstr();
X    char    *name;
X    int     retcode;
X
X    name = getenv("TERM");
X
X    retcode = tgetent(bp, name);
X
X    switch(retcode) {
X
X        case -1:
X            printf("can't open termcap file.\n");
X            exit(1);
X            break;
X
X        case 0:
X            printf("No termcap entry for %s.\n", name);
X            exit(1);
X            break;
X
X    }
X
X    eeolseq = tgetstr("ce", &area);
X    cmseq   = tgetstr("cm", &area);
X    clearseq = tgetstr("cl", &area);
X    BC   = tgetstr("bc", &area);
X    UP   = tgetstr("up", &area);
X
X}
X
Xeeol() {
X
X    tputs(eeolseq, 0, putchar);
X
X}
X
Xclear_screen() {
X
X    tputs(clearseq, 0, putchar);
X
X}
X
Xmovecur(row, col)
Xint row, col;
X{
X
X    tputs(tgoto(cmseq, col, row), 0, putchar);
X
X}
X
Xstruct sgttyb old_term;
Xstruct sgttyb new_term;
X
X/*
X    Set terminal to CBREAK and NOECHO.
X*/
Xset_term() {
X    static int  first = 1;
X
X    if(first) {
X        gtty(0, &old_term);
X        gtty(0, &new_term);
X
X        new_term.sg_flags &= ~(ECHO); /* | CRMOD); */
X        new_term.sg_flags |= CBREAK;
X	
X	ospeed = new_term.sg_ospeed;
X
X        first = 0;
X    }
X
X    stty(0, &new_term);
X
X}
X
X/*
X    Reset the terminal to normal mode.
X*/
Xreset_term() {
X
X    stty(0, &old_term);
X
X}
/
echo 'Distribution file ogre.sh complete.'