[net.sources] Ogre for System V, Release 2

spear@ihopb.UUCP (Steven Spearman) (01/09/85)

Here is a hacked version of 'ogre' which has been changed from
termcap to terminfo support.  Also I made a few other cosmetic
enhancements - it could be done much better.  I am posting the
whole thing here.  Author credits and such are contained in the
files.

Steve Spearman  AT&T Bell Labs   ihnp4!ihopb!spear

#--------cut here-----------
# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# Makefile attack.c ext.h init.c initround.c main.c map.c move.c ogre.6 ogre.h ogrecom.c ogrestat.c resolve.c terminfo.c

echo x - Makefile
cat > "Makefile" << '//E*O*F Makefile//'
OBJ = init.o terminfo.o map.o main.o move.o initround.o ogrecom.o ogrestat.o \
	  attack.o resolve.o

#This CC inserts real time checks
#CC = $(TOOLS)/bin/bcc
CC = cc
CCFLAG = -g

ogre: $(OBJ)
	$(CC) $(CCFLAG) -o ogre $(OBJ) -lcurses

init.o: init.c ogre.h
	$(CC) $(CCFLAG) -c init.c

main.o: main.c ogre.h
	$(CC) $(CCFLAG) -c main.c

move.o: move.c ogre.h
	$(CC) $(CCFLAG) -c move.c

attack.o: attack.c ogre.h
	$(CC) $(CCFLAG) -c attack.c

resolve.o: resolve.c ogre.h
	$(CC) $(CCFLAG) -c resolve.c

initround.o: initround.c ogre.h
	$(CC) $(CCFLAG) -c initround.c

terminfo.o: terminfo.c
	$(CC) $(CCFLAG) -c terminfo.c

ogrecom.o: ogrecom.c ogre.h
	$(CC) $(CCFLAG) -c ogrecom.c

ogrestat.o: ogrestat.c ogre.h
	$(CC) $(CCFLAG) -c ogrestat.c

map.o: map.c ogre.h
	$(CC) $(CCFLAG) -c map.c
//E*O*F Makefile//

echo x - attack.c
cat > "attack.c" << '//E*O*F attack.c//'
/*
    This file contains routines to collect attack orders from the player,
    and display his odds of success for each target.  It calls the
    routines in "resolve.c" to determine the outcomes of the attacks.

    Michael Caplinger, Rice University, March 1982.
*/

#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()
{
    int moreunits;
    int  i;

    moreunits = TRUE;
    zero(&allocated, sizeof(allocated));
    init_def_attack();

    /*
        The "fired" element of each unit description is here used as a
        Boolean to keep track of who has fired.
    */

    while(moreunits) {

        moreunits = FALSE;

        for(i = 0; i < n_units; i++) {

            if(unit[i].status == ISOK &&
                !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;
{

    int    action, invalid;

    movecur_unit(i);

    do {

        invalid = FALSE;
	refresh();
        action = getch();
    
        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;

                /* TREAD has to be resolved immediately. */
                ogre_resolve(&allocated);
                zero(&allocated, sizeof(allocated));
                break;

            case RESOLVE:
                ogre_resolve(&allocated);
                zero(&allocated, sizeof(allocated));
                return(PASS);

            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)
int weapon;
{

    extern char *odd_str();

    switch(weapon) {

        case MAIN:

            mvwprintw(stdscr,18, 40, "%d/%d (%s)", allocated.main_bats, DEF_MAIN,
                odd_str(allocated.main_bats, DEF_MAIN));
            break;

        case SECONDARY:

            mvwprintw(stdscr,19, 40, "%d/%d (%s)", allocated.sec_bats, DEF_SECONDARY,
                odd_str(allocated.sec_bats, DEF_SECONDARY));
            break;

        case MISSILE:

            mvwprintw(stdscr,20, 40, "%s", odd_str(allocated.missiles, DEF_MISSILES));
            break;

        case AP:

            mvwprintw(stdscr,21, 40, "%s", odd_str(allocated.ap, DEF_AP));
            break;

        case TREAD:
            mvwprintw(stdscr,22, 40, "1/1 (%d)", allocated.treads);
            break;
default:
    error("Bad weapons value in update_odds");
    }

}
//E*O*F attack.c//

echo x - ext.h
cat > "ext.h" << '//E*O*F 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

//E*O*F ext.h//

echo x - init.c
cat > "init.c" << '//E*O*F init.c//'
#include "ext.h"

static int a, b;
static int cp_set;
static int infantry_points, armor_points;

init_units(mark)
{
    int unitcmp();

	init_screen();

    a = 10;
    b = 10;

    switch(mark) {

        case 3:
            armor_points = 10;
            infantry_points = 18;
            break;

        case 5: 
            armor_points = 18;
            infantry_points = 27;
            break;
    }

    n_units = 0;
    cp_set = FALSE;

    while(armor_points > 0 || infantry_points > 0 || !cp_set) {
        mvwprintw(stdscr,16,0, "left to place: %d armor, %d infantry%s",
            armor_points, infantry_points,
            (cp_set) ? "." : ", CP");
        getunit();
    }

    /* sort the units so lower the i, the more valuable the unit. */
    qsort( (int *) unit, (unsigned) n_units, sizeof(UNIT), unitcmp);


}

getunit()
{
    int    no_new, bad_int;
    int    olda, oldb;
    int    dir;

    no_new = TRUE;
    bad_int = FALSE;

    movecurhex(a, b);

    while(no_new) {

        olda = a;
        oldb = b;

	refresh();
        dir = getch();
    
        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_int = 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_int = TRUE;
                    break;
                }
                add_unit(a, b, dir);
                no_new = FALSE;
                armor_points--;
                break;
    
    	    case '1':
                if(occupied(a, b) || blocked(a, b) || infantry_points < 1) {
                    bad_int = TRUE;
                    break;
                }
                add_unit(a, b, dir);
                no_new = FALSE;
                infantry_points -= 1;
                break;

	    case '2':
                if(occupied(a, b) || blocked(a, b) || infantry_points < 2) {
                    bad_int = TRUE;
                    break;
                }
                add_unit(a, b, dir);
                no_new = FALSE;
                infantry_points -= 2;
                break;

            case INFANTRY:
	    case '3':
                if(occupied(a, b) || blocked(a, b) || infantry_points < 3) {
                    bad_int = TRUE;
                    break;
                }
                add_unit(a, b, dir);
                no_new = FALSE;
                infantry_points -= 3;
                break;
    
            case HOWITZER:
                if(occupied(a, b) || blocked(a, b) || armor_points <= 1) {
                    bad_int = TRUE;
                    break;
                }
                add_unit(a, b, dir);
                no_new = FALSE;
                armor_points -= 2;
                break;
    
            default:
                bad_int = TRUE;
                break;
    
        }
    
        if(off_obstructed(a, b)  || 
            bad_int)
        {

            a = olda;
            b = oldb;
            bad_int = FALSE;
    
        }

        else {

            movecurhex(a, b);

        }

    }

}

add_unit(a, b, c)
int 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 = ISOK;
    unit[i].moves_left = 0;
    unit[i].l_hex = a;
    unit[i].r_hex = b;

    disp_unit(i);

}

occupied(a, b)
int 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)
{

    ogre.l_hex = rand() % 7 + 22; /* 22 - 28 */
    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);

}
//E*O*F init.c//

echo x - initround.c
cat > "initround.c" << '//E*O*F 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 = ISOK;
            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 == ISOK) {
            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 == ISOK && unit[i].type == GEV)
            unit[i].moves_left = 3;

}

display_range(i)
{

    movecur(18, 0); clrtoeol();
    printw("range from unit %d to Ogre %d.", i, unit[i].range_to_ogre);
    refresh();
    cycle();

}
//E*O*F initround.c//

echo x - main.c
cat > "main.c" << '//E*O*F main.c//'

/*
    OGRE: a tactical ground combat game set in 2085.

    Adapted from the Metagaming Microgame by Steve Jackson.

    This version was written for a Vax 11/780 under Unix
    by Michael Caplinger, Rice University, February-March 1982.

	Modifications:
	  1/8/85 - terminfo conversion by Steven Spearman

    Paper game (c) 1977 by Steve Jackson
    This implementation (c) 1982, 1984 by Michael Caplinger
*/

#include <signal.h>

#define MAIN
#include "ext.h"

main(argc, argv)
char **argv;
{

    int handler();
    int mark;

    signal(SIGINT, handler);

    if(argc > 1)
        switch(argv[1][0]) {

            case '3':
                mark = 3;
                break;

            case '5':
                mark = 5;
                break;

            default:
                mark = 3;
                break;
        }

    else mark = 3;

    set_term();
    srand((unsigned) time((long *) 0));
    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();

        /* Let the GEVs move their extra 3 turns. */
        init_gev2();
        move_def();

        /* The Ogre moves. */
        move_ogre();
        check_over(); 

    }

}

handler() {

    clear_screen();
    reset_term();
    exit(0);

}

/*
    See if the game is over, and die if it is.
*/
check_over()
{
    char *message;
    int over;

    over = FALSE;

    if(unit[0].status == DESTROYED) {
        message = "The Ogre wins!!";
        over = TRUE;
    }
    if(ogre.movement == 0) {
        message = "You win!!";
        over = TRUE;
    }

    if(over) {
        clear_screen();
        reset_term();
        printf("%s\n", message);
        exit(0);
    }

}
//E*O*F main.c//

echo x - map.c
cat > "map.c" << '//E*O*F map.c//'
/*
    These routines implement all functions associated with the map and display
    thereof.

    (Thanks to Bob Hood of Rice for coming up with 
     the x-y and range algorithms.)

    Michael Caplinger, Rice University, March 1982.
*/

#include "ext.h"
#include <stdio.h>
#include <ctype.h>
#include <varargs.h>


/* Initialize the map display, at the beginning of the game. */
init_screen() {

    int a, b;

    clear_screen();

    for(a = 1; a <= 28; a++) {
        for(b = 1; b <= 28; b++) {
            if(!off_map(a, b)) {
                disp_hex(a, b, '.');
            }
        }
    }
    disp_craters();
}


/* 
    Convert a left and right hex pair (eg, the hex 2015 has an l_hex of 20 and
    an r_hex of 15) to x-y screen coordinates.
*/
to_xy(lhex, rhex, row, col)
int lhex, rhex;
int *row, *col;
{

    *row = (lhex - rhex) + 7;
    *col = 50 - (lhex + rhex);

}

/* Check to see if an lr pair is off the map. */
off_map(a, b)
int a, b;
{
    int row, col;

    to_xy((int)a, (int)b, &row, &col);
    if(col < 0 || col > 38 || row < 0 || row > 14) return(TRUE);
    else return(FALSE);

}

/* Check to see if an lr pair is off the obstructed area of the map. */
off_obstructed(a, b)
int a, b;
{
    int row, col;

    to_xy((int)a, (int)b, &row, &col);
    if(col < 10 || col > 38 || row < 0 || row > 14) return(TRUE);
    else return(FALSE);

}

/* Display a character at a given hex. */
disp_hex(a, b, c)
int a, b, c;
{
    int row, col;
/* fprintf(stderr, "Use %d, %d\n", (int)a, (int)b); */
    to_xy(a, b, &row, &col);
/* fprintf(stderr, "Move cursor to (%d,%d) (%d,%d)\n",
(int)row,(int)col,(int)row,(int)col*2+1);*/

    movecur((int)row, (int)col * 2 + 1);
    addch(c);
}

/* 
    Display the contents of a hex.  If more than one item is in a hex,
    the following precedence applies:
        1) Ogre
        2) Defending units (by value)
        3) Craters (not that anything can be in a crater hex.)
*/
update_hex(a, b)
int 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, '.');

}

/* Display the ith unit. */
disp_unit(i)
int i;
{
    int a, b;

    a = unit[i].l_hex;
    b = unit[i].r_hex;

    switch(unit[i].status) {

        case ISOK:

            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, '.');
            break;

    }

}

/* Display the Ogre. */
disp_ogre()
{
    int a, b;

    a = ogre.l_hex;
    b = ogre.r_hex;

    disp_hex(a, b, 'O');

}


/* Move the cursor to the specified hex on the screen. */
movecurhex(a, b)
int a, b;
{
    int row, col;

    to_xy((int)a, (int)b, &row, &col);

    movecur((int)row, (int)col * 2 + 1);

}

/* Point at the ith unit with the cursor. */
movecur_unit(i)
int i;
{

    movecurhex(unit[i].l_hex, unit[i].r_hex);

}

#define ABS(i) (((i) < 0) ? -(i) : (i))
#define BIGINT 32767

/* Calculate the range between 2 hexes. */
range(a1, b1, a2, b2)
int a1, b1, a2, b2;
{

    int    diff1, diff2, temp;
    int     subrange[3];
    int     min, i;
    int     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);

}

/*
    This is a hardwired set of craters, taken from the paper game's map.
*/
static struct {
    int l_hex;
    int 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) / (sizeof craters[0]))

/* Determine if a hex has a crater. */
blocked(a, b)
int 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);

}

/* Display the craters. */
disp_craters()
{
    int i;

    for(i = 0; i < NCRATERS; i++) 
        disp_hex(craters[i].l_hex, craters[i].r_hex, '*');

}

#include <stdio.h>

describe_action(action, i)
char *action;
int i;
{
move(16,0);
clrtoeol();

    switch(unit[i].type) {

        case HOWITZER:
            mvwprintw(stdscr,16,0, "%s howitzer (%d/%d D%d M%d)", action,
                unit[i].attack, unit[i].range, 
                unit[i].defend, unit[i].moves_left);
            break;

        case MSLTANK:
            mvwprintw(stdscr,16,0, "%s missile tank (%d/%d D%d M%d)", action,
                unit[i].attack, unit[i].range, 
                unit[i].defend, unit[i].moves_left);
            break;

        case GEV:
            mvwprintw(stdscr,16,0, "%s GEV (%d/%d D%d M%d)", action,
                unit[i].attack, unit[i].range, 
                unit[i].defend, unit[i].moves_left);
            break;

        case HVYTANK:
            mvwprintw(stdscr,16,0, "%s heavy tank (%d/%d D%d M%d)", action,
                unit[i].attack, unit[i].range, 
                unit[i].defend, unit[i].moves_left);
            break;

        case INFANTRY:
            mvwprintw(stdscr,16,0, "%s infantry (%d/%d D%d M%d)", action,
                unit[i].attack, unit[i].range, 
                unit[i].defend, unit[i].moves_left);
            break;

    }

}

//E*O*F map.c//

echo x - move.c
cat > "move.c" << '//E*O*F move.c//'
/*
    Move the defender's units.

    Michael Caplinger, Rice University, March 1982.
*/

#include "ext.h"

move_def()
{
    int i, j;

    for(i = 0; i < n_units; i++)
        if(unit[i].status == ISOK) {
            if(unit[i].moves_left > 0) describe_action("Move", i);
            while(unit[i].moves_left > 0 && unit[i].status == ISOK) 
                getmove(i);
        }

}

getmove(i)
int i;
{

    int    nomove, bad_int;
    int    a, b, dir;
    int    olda, oldb;

    nomove = TRUE;

    while(nomove) {
    
        a = unit[i].l_hex;
        b = unit[i].r_hex;

        movecurhex(a, b);

        bad_int = FALSE;
    
	refresh();
        dir = getch();
    
        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;
    
            default:
                bad_int = TRUE;
                break;
    
        }

        /* Rule 5.02 */
        /*
            Note that the no-stacking rule can be violated by SITting on an
            occupied hex, and that the enforcement of no-stacking below is
            TOO stringent.
        */

        if(off_map(a, b) || 
            (occupied(a, b) && unit[i].moves_left == 1) ||
            blocked(a, b) ||
            bad_int)
        {

            bad_int = FALSE;
    
        }
    
        else {
            /* display move */

            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);

        }

    }

}
//E*O*F move.c//

echo x - ogre.6
cat > "ogre.6" << '//E*O*F ogre.6//'
.TH OGRE 6
.UC 4
.SH NAME
Ogre - a game of tank warfare in the 21st century.
.SH SYNOPSIS
/usr/local/games/ogre [ogre type (3 or 5)]
.SH DESCRIPTION
.PP
Ogre is a game of tank warfare in the 21st century.  You command a force of
infantry, armor, and howitzers pitted against a gian cybernetic tank, the
Ogre.  Your mission is to destroy the Ogre, or at least render it immobile,
before it reaches and destroys your command post.
.PP
A more complete reference on how to play can be found in the Ogre rule book
for the Metagaming MicroGame, now distributed by Steve Jackson's company.
Here's some very sketchy and incomplete documentation for Ogre players:
.PP
The game has the following phases:
.PP
1) Initialization.  The player's armor units, infantry, and command post
are placed on the map.  Nothing can be placed on the leftmost 7
columns of hexes, or on craters (*'s), or on any unit already placed.
Valid commands are:
.nf

           y   u

        h         l    (hex movement keys)

           b   n

            place a:

        H   howitzer
        T   heavy tank
        M   missile tank
        G   GEV
        I   Infantry unit (attack strength 3)
        C   Command Post
.fi

on the space currently pointed at by the cursor.  Note that these
are capital letters.
.PP
Units are displayed as these characters, except infantry, which appear
as '1', '2', or '3' depending on their attack strength.
.PP
2) The Ogre (an O) now appears.
.PP
3) You are given the opportunity to move all your vehicles and infantry
that can move.  The cursor motion keys are used to move the unit
indicated by the cursor.  Additionally, 's' or ' ' can be used to
let a vehicle stay motionless.  No vehicle can move through a crater
hex, or into a hex occupied by another friendly unit on its last turn,
although it can move through a friendly hex on its way elsewhere.
Moving through the hex occupied by the Ogre is an attempt to ram the
Ogre.  This reduces the Ogre's treads by some amount, and destroys the
unit.
.PP
4) You now fire all your vehicles in range at designated targets on the
Ogre.  The following commands are used:
.TP     
.B m  
fire at missiles
.TP
.B b   
fire at main batteries
.TP
.B s   
fire at secondary batteries
.TP        
.B a   
fire at anti-personnel guns
.TP        
.B t   
fire at treads
.PP
The odds of destroying the target are displayed, but no action
is taken until 'r' is used, or until you run out of attack points.
(except for attacks on treads - see below.)
(in the odds display, '+' means a sure thing.)
.TP 
.B p   
Pass. The unit is passed over, and given the opportunity to fire
later.
.TP        
.B r   
resolve all allocations so far, and display the results.  This
is implied by 't', as tread attacks cannot be grouped.  A resolve
is done automatically when you run out of attacking units.
.PP
5) Second movement phase for GEVs.  Just like step 3, except that only GEVs
can move.
.PP
6) The Ogre moves.  If it runs over any of your units, they are damaged
or destroyed.
.PP
7) The Ogre fires at all units in range.  Destroyed units are removed from
the map.  Disabled units are displayed in lower case, and may not
move or fire until the end of the NEXT Ogre attack.
.PP
Steps 3 through 7 are repeated until either
a) the Ogre has no movement points left, in which case you win, or
b) your command post is destroyed, in which case the Ogre wins.
.SH MISCELLANEOUS
.PP
The display "a/r Dd Mm" means the unit concerned attacks at a, at range r,
defends at d, and moves m hexes per turn.
.PP
The Ogre by default is a Mark III.  An argument of '5' on the command line
makes it a Mark V, and gives you more armor points.
.PP
The game can be interrupted at any point with a control-C.  There's now
no way to restart.
.PP
The paper game is copyright (c) 1977 by Steve Jackson.  This computer
implementation is copyright (c) 1984 by Michael Caplinger.
.SH AUTHOR
Michael Caplinger, Rice University (mike@rice.ARPA), from a Microgame of the
same name published by Metagaming of Austin, Texas, and written by Steve
Jackson.  This implementation is not authorized in any way by Mr. Jackson,
and should not be sold for profit.
.SH SEE ALSO
termcap(5)
.SH BUGS
.PP
The Ogre sometimes gets confused and doesn't know where to go, so it
oscillates from one hex to another, and then back.
//E*O*F ogre.6//

echo x - ogre.h
cat > "ogre.h" << '//E*O*F ogre.h//'
#include <curses.h>

typedef struct {

    int    type;
    int    attack;
    int    range;
    int    defend;
    int    movement;
    int    range_to_ogre;
    int    fired;
    int    moves_left;
    int    status;
    int    l_hex;
    int    r_hex;

} UNIT;

typedef struct {

    int    missiles;
    int    main_bats;
    int    sec_bats;
    int    ap;
    int    treads;
    int    movement;
    int    moves_left;
    int    l_hex;
    int    r_hex;
    int    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 ISOK          1
#define DISABLED    2
#define DESTROYED   3

/* directions */
#define RIGHT       'l'
#define UPRIGHT     'u'
#define DOWNRIGHT   'n'
#define LEFT        'h'
#define UPLEFT      'y'
#define DOWNLEFT    'b'
#define SIT         '.'



#define N_UNITS     30

#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

//E*O*F ogre.h//

echo x - ogrecom.c
cat > "ogrecom.c" << '//E*O*F ogrecom.c//'
/*
    These routines define the Ogre's stategy (such as it is).
    There's lots of room for improvement here.
*/

#include "ext.h"

move_ogre()
{

    init_move_ogre();

    ogre.moves_left = ogre.movement;

    while(ogre.moves_left > 0) {
        moveogre1();
        ogre_ram();
        cycle();
    }

}

#define INFINITY 32767

/* Move the Ogre one hex. */
moveogre1()
{

    int weight[7];
    int i, max;
    int a, b;
    int olda, oldb;

    a = ogre.l_hex;
    b = ogre.r_hex;

    /* Collect weights for each possible move. These will be maximized. */

    weight[0] = - INFINITY; /* temp patch: getweight(a, b); */
    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;

}

/*
    The weight for each hex is a measure of how desirable it is to be in that
    hex; the weights of the six possible directions are maximized.

    The primary consideration is distance to the CP; in the absence of other
    factors, the Ogre will take the fastest course to the CP.
    However, the Ogre will crush any unit it can (units with higher attacks
    chosen first) and moves towards units that are within range of its missiles
    or batteries.  It attempts to weight so that a concentration of dangerous,
    immobile units (like howitzers) is attacked first.

    Testing indicates that this isn't a bad strategy.
*/
getweight(a, b)
int a, b;
{
    int weight;
    int total_attacks;
    int to_target;
    int 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 = 1; i < n_units; i++) {

        if(unit[i].status == DESTROYED) continue;

        to_target = range(a, b, unit[i].l_hex, unit[i].r_hex);

        /*
             If you can crush somebody, do it.
             More dangerous units get crushed first.
        */
        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;
/*
mvwprintw(stdscr,17,0, "%d %d weight %d", a, b, weight); cycle();
*/

    return(weight);

}

#define INCR(i) i = (i == n_units - 1) ? 0 : i + 1

#define MIN(a, b) (((a) > (b)) ? (a) : (b))

/* 
    Figure out who the Ogre will fire at. In this code, the "fired" element
    of the unit description is the number of hit points assigned against that
    unit.
*/
assign_fire_ogre()
{

    int i, unitno, nmissiles;

    init_ogre_attack();

    /*
        The basic strategy here is to fire at the next unit in range. Since
        the units are sorted by value, this will hopefully (although not 
        always) result in reasonable choices for targets.
        Experience indicates that the Ogre often overkills (which is OK)
        but fails to attack some valuable possibility (not OK).  Some
        work needs to be done here.
    */

    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 &&
	    /* don't fire at infantry... 27 Oct 83 */
	    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()
{

    refresh();
    sleep(1);

}

/*
    Display and resolve an attack on a single defending unit.
*/
display_attack(weapon, target)
char *weapon;
int  target;
{

    /* No point if the unit is already destroyed. */
    if(unit[target].status == DESTROYED) return;

    mvwprintw(stdscr,16,0, "Ogre fires %s at unit at hex %d%d", weapon,
        unit[target].l_hex, unit[target].r_hex);

    movecurhex(unit[target].l_hex, unit[target].r_hex);

    cycle();

    def_resolve(target);

}

nextunit(range, unitno)
int range;
int 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);

}
//E*O*F ogrecom.c//

echo x - ogrestat.c
cat > "ogrestat.c" << '//E*O*F ogrestat.c//'
/*
    Handle the Ogre status display.
*/

#include "ext.h"

disp_ogre_status(redraw)

/* If redraw is false, the display is not touched if nothing has changed. */
int redraw;
{
    static OGRE last;

    /*
        The Ogre status display occupies the bottom 6 lines of the display.
    */

    /*               0        1         2         3         4
                     1234567890123456789012345678901234567890       */

    if(redraw || last.main_bats != ogre.main_bats)
        if(ogre.main_bats > 0)
        mvwprintw(stdscr,18,0, "Main Batteries:      %d (4/3 D4)", ogre.main_bats);
        else mvaddstr(18,0,    "Main Batteries       GONE         ");

    if(redraw || last.sec_bats != ogre.sec_bats)
        if(ogre.sec_bats > 0)
        mvwprintw(stdscr,19,0, "Secondary Batteries: %d (3/2 D3)", ogre.sec_bats);
        else mvaddstr(19,0,    "Secondary Batteries  GONE         ");

    if(redraw || last.missiles != ogre.missiles)
        if(ogre.missiles > 0)
        mvwprintw(stdscr,20,0, "Missiles:            %d (6/5 D3)", ogre.missiles);
        else mvaddstr(20,0,    "Missiles             GONE         ");

    if(redraw || last.ap != ogre.ap)
        if(ogre.ap > 0)
        mvwprintw(stdscr,21,0, "Anti-personnel:     %2d (1/1 D1)", ogre.ap);
        else mvaddstr(21,0,    "Anti-personnel       GONE          ");

    if(redraw || last.treads != ogre.treads)
        if(ogre.treads > 0)
        mvwprintw(stdscr,22,0, "Treads:             %2d (1/* D1)", ogre.treads);
        else mvaddstr(22,0, "Treads GONE               ");

    if(redraw || last.movement != ogre.movement)
        mvwprintw(stdscr,23,0, "Movement:            %d", ogre.movement);

    copy(&last, &ogre, sizeof(last));

}

copy(to, from, size)
char *to, *from;
int size;
{
    int i;

    for(i = 0; i < size; i++) to[i] = from[i];

}
//E*O*F ogrestat.c//

echo x - resolve.c
cat > "resolve.c" << '//E*O*F resolve.c//'
/*
    Resolve all attacks and rams from both directions.

    Michael Caplinger, Rice University, March 1982.
*/

#include "ext.h"

static char *odd_names[] = {
    "0/1",
    "1/2",
    "1/1",
    "2/1",
    "3/1",
    "4/1",
    "+",
};

static char crt[6][7] = {

    ISOK, ISOK,      ISOK,      ISOK,      DISABLED,  DISABLED,  DESTROYED,
    ISOK, ISOK,      ISOK,      DISABLED,  DISABLED,  DESTROYED, DESTROYED,
    ISOK, ISOK,      DISABLED,  DISABLED,  DESTROYED, DESTROYED, DESTROYED,
    ISOK, ISOK,      DISABLED,  DESTROYED, DESTROYED, DESTROYED, DESTROYED,
    ISOK, DISABLED,  DESTROYED, DESTROYED, DESTROYED, DESTROYED, DESTROYED,
    ISOK, 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;
    if (result < 0)
		error("bad value - odds");

    return(result);

}

char *odd_str(attack, defend)
int attack, defend;
{

    return(odd_names[odds(attack, defend)]);

}


/* Resolve all attacks on the Ogre. */
ogre_resolve(allocations)
OGRE *allocations;
{

    move(16,0);
    clrtoeol();
    mvwprintw(stdscr,16,0, "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);

    }

    /* erase the odds. */
    movecur(18, 40); clrtoeol();
    movecur(19, 40); clrtoeol();
    movecur(20, 40); clrtoeol();
    movecur(21, 40); clrtoeol();
    movecur(22, 40); clrtoeol();

    /* update the Ogre status display. */
    disp_ogre_status(FALSE);

}

/* Resolve an Ogre attack on a defending unit. */
def_resolve(i)
{
    char result;

    if(unit[i].status != DESTROYED && unit[i].fired > 0) {

        result = crt[roll()][odds(unit[i].fired, unit[i].defend)];

        /* Infantry is a special case. */
        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 ISOK:
                unit[i].status = result;
                break;

            case DISABLED:
                if(result != ISOK) unit[i].status = DESTROYED;
                break;

        }

        if(unit[i].status != ISOK) 
            update_hex(unit[i].l_hex, unit[i].r_hex);

    }

}

roll()
{

    return(rand() % 6);

}

/* Routine called for each hex the Ogre moves through, to handle rams. */
ogre_ram()
{
    int i;

    /* Rule 5.03 */
    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:

                    /* Rule 5.04 */
                    if(ogre.ap > 0) {
                        unit[i].attack -= 1;
			if(unit[i].attack == 0) 
			    unit[i].status = DESTROYED;
                    }
                    break;

                default:

                    /* Rule 5.031 */
                    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;

            }


}

/* See if a defender has rammed the Ogre. */
def_ram(i)
int i;
{
    if(unit[i].l_hex == ogre.l_hex &&
       unit[i].r_hex == ogre.r_hex &&
       unit[i].type != INFANTRY) {

        /* Rule 5.036 */

        decrease_treads(1);
        unit[i].status = DESTROYED;
        disp_ogre_status(FALSE);

    }

}

decrease_treads(attack)
int attack;
{

    /* Rule 6.05 */

    /* Now, where is the movement factor going? */

    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;

}

//E*O*F resolve.c//

echo x - terminfo.c
cat > "terminfo.c" << '//E*O*F terminfo.c//'
#include <curses.h>
/*
    Interface to terminfo library.
	This is a hack conversion from a termcap interface
		- by sgs 1/1/85
*/

clear_screen() {
	clear();
	refresh();
}

movecur(row, col)
int row, col;
{
	move(row,col);
}

/*
    Set terminal to CBREAK and NOECHO.
*/
set_term() {
	initscr();
	cbreak();
	noecho();
}

/*
    Reset the terminal to normal mode.
*/
reset_term() {
    resetty();
}

error(s)
char s[];
{
	mvwprintw(stdscr,23,0,"Fatal Game error: %s",s);
	reset_term();
	exit(1);
}
//E*O*F terminfo.c//

echo Possible errors detected by \'wc\' [hopefully none]:
temp=/tmp/shar$$
trap "rm -f $temp; exit" 0 1 2 3 15
cat > $temp <<\!!!
     40    105    787 Makefile
    198    372   4379 attack.c
     16     21    158 ext.h
    443    793   8737 init.c
     86    145   1381 initround.c
    113    212   1865 main.c
    326    821   6155 map.c
    121    203   2202 move.c
    128    765   4313 ogre.6
     76    152   1293 ogre.h
    326    871   7268 ogrecom.c
     61    187   1831 ogrestat.c
    225    546   5126 resolve.c
     41     71    498 terminfo.c
   2200   5264  45993 total
!!!
wc  Makefile attack.c ext.h init.c initround.c main.c map.c move.c ogre.6 ogre.h ogrecom.c ogrestat.c resolve.c terminfo.c | sed 's=[^ ]*/==' | diff -b $temp -
exit 0