home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Die Multimedia Power-CD
/
MULTIMEDIA.bin
/
demos_os
/
explosiv
/
explod.c
< prev
next >
Wrap
Text File
|
1990-01-20
|
31KB
|
965 lines
/****************************************************************************
* EXPLOD.C - simple fireworks for Hercules/CGA/EGA
*
* This program was developed with Datalight C 2.20 and Arrowsoft ASM 1.00d.
* (It also works with Turbo C 1.5/MASM 5.0 with one EQU change in EXPA.ASM).
* The code should be compilable by most other C compilers. However, the
* segment names in EXPA.ASM will have to be changed to suit the compiler.
*
* To compile:
* asm expa ; OR masm /mx expa ;
* dlc explod.c expa.obj (don't forget the /mx !!!)
* tcc explod.c expa.obj
* (C) 1989 Dennis Lo
* You are free to use and distribute this source code, provided that the
* authors' names remain in the code, and that both the source and executables
* of modified versions are clearly distinguished from the originals with
* descriptive messages.
*
* Change Log
* 89/06/24 Dennis Lo V1.0 Initial release.
* 89/07/03 Dennis Lo V1.1 Added cmd line options. Code cleanups.
* 89/07/26 Erik Liljencrantz Added EGA support with autodetection
* Restores previous CRT textmode on exit
* 89/08/19 Dennis Lo V1.2 Code cleanups. Changed references to frames
* table to use segment and offsets so that multiple
* frames tables can be supported in the future
* without switching to a large data memory model.
* 89/09/03 Erik Liljencrantz Added VGA support with autodetection
* 90/01/20 Dennis Lo V2.0 Allow multiple explosion frame tables.
* Read in explosion shape tables from data files.
* Added -f and keypress options. Split part of
* functionality into expgen.c. Keyboard control.
* -n option.
****************************************************************************/
#include <stdio.h>
#include <ctype.h>
#ifndef DLC
# include <dir.h>
#endif
#include <dos.h>
#include "explod.h"
#define PUT(s) fputs(s,stdout)
/*=====================================================================
* External assembler routines.
*=====================================================================
*/
/* Datalight C does not prepend underscores to external names */
#ifdef DLC
# define DosAlloc _DosAlloc
# define DosFree _DosFree
# define DosMemLeft _DosMemLeft
# define ChkKey _ChkKey
# define gr_card _gr_card
# define gr_setcard _gr_setcard
# define gr_gmode _gr_gmode
# define gr_tmode _gr_tmode
# define gr_addr _gr_addr
# define gr_store_pt _gr_store_pt
# define gr_frplot _gr_frplot
#endif
extern unsigned short DosAlloc();
extern unsigned short DosFree();
extern unsigned short DosMemLeft();
extern int ChkKey();
extern int gr_card();
extern gr_setcard();
extern gr_gmode();
extern gr_tmode();
extern int gr_addr();
extern gr_store_pt();
extern gr_frplot();
#define DEADPOINT 32767 /* this must match the definition in expa.asm */
/*=====================================================================
* Configuration Parameters
*=====================================================================
*/
/* Video parameters */
static int Interlace_factor;
static int Screen_xsize;
static int Screen_ysize;
/* Animation parameters */
static int Simul_exps = -1; /* # of simultaneous explosions */
static int Delay_factor = 0; /* amount to delay after each frame */
/* Explosion parameters */
static int Gravity = 0; /* Gravity override */
static int Wind = 0; /* Wind override */
static int Centre_x; /* Coords of centre of screen */
static int Centre_y;
static unsigned int Centre_y_mask;
/* Explosion control parameters */
static int Leave_trail = 0; /* If non-0 then don't erase explosions */
static int Event_limit = 0; /* # of exp events before exiting */
static int Total_frames = 0; /* used to find avg #frames per explosion */
/*=====================================================================
* Explosion Creation table:
* Temporarily keeps track of the parameters and points of an explosion
* while its frames are being calculated.
*=====================================================================
*/
/* 16.16 fixed point type: overlays a 32-bit long with its 16-bit
whole number part and its 16-bit fractional part */
typedef union
{
long l;
struct /* Note: this is endian dependent */
{
unsigned short ls;
short ms;
} s;
} fixed;
/* Structure of an explosion point at explosion creation */
typedef struct
{
fixed x, y; /* location */
fixed xv, yv; /* velocity */
fixed xa, ya; /* acceleration */
int alive; /* liveness: 0=dead */
} exp_pt_type;
/* Explosion creation table */
exp_pt_type Pt_table [MAX_POINTS+1];
/*=====================================================================
* Explosion type descriptor - contains all information in a ready-to-
* playback explosion, including a pointer to its frames table. The
* frames table contains an array of MAX_FRAMES frames. Each frame is
* one frame in the animation of the explosion, and consists of
* MAX_POINTS structures of the form {offset (2 bytes), value (1 byte)}.
* The frame table structure treated only as a block of memory by the
* C code, so it is not explicitly declared. (It cannot be declared
* in C in a portable way due to structure alignment padding.)
*=====================================================================
*/
#define FRAME_PT_SIZE 3 /* size of one point in the frame table */
#define MAX_EXP_DESC 30 /* Max # of explosion types */
/* Explosion descriptor type */
typedef struct
{
int nframes;
int npoints;
int xsize;
int ysize;
int gravity;
int wind;
int trail_len;
unsigned short frame_seg;
unsigned short frame_ofs;
} exp_desc_type;
/* Array of explosion descriptors for the explosions read in from disk */
static exp_desc_type Exp_desc [MAX_EXP_DESC];/* Explosion descriptors */
static int Num_exp_desc; /* # of explosions read in */
/*=====================================================================
* Explosion Event Table - each entry controls one instance of an
* active explosion event during playback.
*=====================================================================
*/
#define MAX_EXPS 48 /* max # of simultaneously active explosion events */
/* Explosion events table */
typedef struct
{
int centre; /* addr of centre of explosion */
int frame_num; /* frame #. Dead if -1 */
exp_desc_type *exp_desc; /* explosion type */
} exp_event_type;
static exp_event_type Exp_ev_tab [MAX_EXPS];
/*====================================================================
* Return a random number between 0..maxval
*====================================================================
*/
int
rnd (maxval)
int maxval;
{
# define MAX_RAND 32767 /* max val returned by rand() */
long l;
l = (long) maxval * rand() / MAX_RAND;
return ((int) l);
}
/*====================================================================
* Read a number from a string - replaces the need for sscanf() which
* reduces the size of the executable by about 2.5K.
* Returns a ptr to the next word in the string.
*====================================================================
*/
char *
str_to_num (str, num)
char *str; /* IN: ptr to string containing the number */
int *num; /* OUT: the number read */
{
/* Skip leading spaces */
while (*str && *str == ' ') str++;
*num = atoi (str);
/* Skip non spaces (skip past the number) */
while (*str && *str != ' ') str++;
return (str);
}
/*====================================================================
* Local memory allocator:
* MemInit() - allocates as much memory from DOS as possible.
* Return 1 if successful, 0 if not.
* MemAlloc() - allocates a block of memory to the caller.
* Returns segment addr of block, or 0 if failed.
* MemCleanup() - returns all memory to DOS.
*
* Why a local memory allocator? malloc() won't work in the small
* memory model because we need >64K of memory. DOS's malloc()
* (int21 ah=48h) seems to waste a lot of memory when called several
* times in a row -- it was leaving ~5K gaps between each allocated
* block for reasons that I don't understand. I tried a DOS realloc()
* (int21 ah=4ah) but that didn't help. After a month of playing with
* it I gave up in disgust and wrote these routines instead.
*====================================================================
*/
unsigned mem_start;
unsigned mem_curr;
unsigned mem_left;
int
MemInit()
{
/*
* Allocate all available memory from DOS:
* Try to allocate 640K at first so DOS will return the actual
* amount available.
*/
mem_left = DosMemLeft ();
if (mem_left == 0)
{
PUT ("DosMemLeft failed!\n");
return (0);
}
mem_start = DosAlloc (mem_left);
if (mem_start == 0)
{
PUT ("MemInit: DosAlloc failed!\n");
return (0);
}
mem_curr = mem_start;
return (1);
}
int
MemAlloc (size)
unsigned size; /* size in bytes */
{
int addr;
/* Convert the requested size to # of paragraphs */
size = (size + 15) >> 4;
if (size > mem_left)
return (0);
addr = mem_curr;
mem_curr += size;
mem_left -= size;
return (addr);
}
MemCleanup()
{
if (DosFree (mem_start) != 0)
PUT ("DosFree failed!\n");
}
/************************ User Interface ***************************/
/*=====================================================================
* Return the path name portion of a filename.
*=====================================================================
*/
void
GetPathName (filename, pathname)
char *filename; /* in */
char *pathname; /* out */
{
char *path_end;
char path_len = 0;
/* Scan backwards in the filename for the end of the path */
path_end = filename + strlen (filename);
while (path_end >= filename && *path_end != ':' &&
*path_end != '/' && *path_end != '\\')
path_end--;
/* Copy the path to the output string */
if (path_end >= filename)
{
path_len = path_end - filename;
strncpy (pathname, filename, path_len);
pathname [path_len++] = '\\';
}
pathname [path_len] = '\0';
}
/*=====================================================================
* Process command line arguments.
* Returns 1 if successful, 0 if not.
* Also sets up explosion parameters according to video card type.
*=====================================================================
*/
int
GetArgs (argc, argv)
int argc;
char *argv[];
{
int video_type;
static char name [80]; /* Current data file name */
static char path [80]; /* Current path */
/* Set video params */
video_type = gr_card (); /* guess video card type */
SetVideoParams (video_type);
/* Print instructions if no command line parameters are given */
if (argc == 1)
Instructions();
/*
* Loop to parse each command line parameter
*/
while (--argc > 0)
{
if (**++argv == '-')
{
switch ((*argv)[1])
{
case 'v': /* -v: video card type (c, h)*/
video_type = (*argv)[2];
SetVideoParams (video_type);
break;
case 's': /* -s: # of simultaneous explosions */
Simul_exps = atoi ((*argv) + 2);
break;
case 'd': /* -d: delay factor */
Delay_factor = atoi ((*argv) + 2);
break;
case 'g': /* -g: gravity override */
Gravity = atoi ((*argv) + 2);
break;
case 'w': /* -w: wind override */
Wind = atoi ((*argv) + 2);
break;
case 'f': /* -f: fill screen with trails */
Leave_trail = 1;
break;
case 'n': /* -n: total number of explosions */
Event_limit = atoi ((*argv) + 2);
break;
default:
PUT ("*** Invalid option: "); PUT (*argv); PUT ("\n");
Instructions();
return (0);
}
}
/*
* Else a filename argument:
* Wildcard expand the filename and read in each of the resulting
* explosion data files.
*/
else
{
#ifdef DLC
struct FIND *blk;
# define FFNAME blk->name
GetPathName (*argv, path);
blk = findfirst (*argv, 0);
while (blk != NULL)
{
strcpy (name, path);
strcat (name, FFNAME);
PUT ("Reading "); PUT (name); PUT ("\n");
if (ReadDatFile (name, &Exp_desc[Num_exp_desc], Pt_table))
Num_exp_desc++;
blk = findnext ();
}
#else /* TURBOC */
struct ffblk blk;
# define FFNAME blk.ff_name
int more_files;
GetPathName (*argv, path);
more_files = findfirst (*argv, &blk, 0);
while (more_files == 0)
{
strcpy (name, path);
strcat (name, FFNAME);
PUT ("Reading "); PUT (name); PUT ("\n");
if (ReadDatFile (name, &Exp_desc[Num_exp_desc], Pt_table))
Num_exp_desc++;
more_files = findnext (&blk);
}
#endif
}
}
return (1);
}
/*=====================================================================
* Set video card-related parameters
*=====================================================================
*/
SetVideoParams (video_mode)
char video_mode;
{
# define NUM_VIDEO_MODES 4
/*
* Default parameters for each video mode
*/
static struct defaults_struct {
char video_mode;
int interlace_factor;
int screen_xsize;
int screen_ysize;
int simul_exps;
} defaults [NUM_VIDEO_MODES] = {
'c', 2, 640, 200, 8, /* cga */
'h', 4, 720, 348, 10, /* hgc */
'e', 1, 640, 350, 10, /* ega */
'v', 1, 640, 480, 12 /* vga */
};
int i;
/*
* Find the defaults table entry for the given video mode and set
* the video configuration parameters to the values in that entry.
*/
for (i=0; i<NUM_VIDEO_MODES; i++)
{
if (video_mode == defaults[i].video_mode)
{
Interlace_factor = defaults [i].interlace_factor;
Screen_xsize = defaults [i].screen_xsize;
Screen_ysize = defaults [i].screen_ysize;
/* If not specified on the command line then set to default */
if (Simul_exps == -1)
Simul_exps = defaults [i].simul_exps;
break;
}
}
Centre_y_mask = (0xffff - (Interlace_factor - 1));
Centre_x = (Screen_xsize / 2);
Centre_y = (Screen_ysize / 2) & Centre_y_mask;
gr_setcard (video_mode);
}
/*=====================================================================
* Print instructions
*=====================================================================
*/
Instructions ()
{
PUT ("EXPLOD 2.0 by Dennis Lo 90/01/20\n");
PUT ("Usage: explod [optional parameters] <data files>\n");
PUT ("Parameters can be one of\n");
PUT (" -vC :C=video type. CGA:'-vc' HGC:'-vh' EGA:'-ve' VGA:'-vv'\n");
PUT (" Default is auto-detect\n");
PUT (" -sN :N = # of simultaneous explosions. Default: 10 (8 for CGA)\n");
PUT (" -dN :N = Delay factor. Default: 0\n");
PUT (" -gN :N = Gravity. Default: CGA=15 HGC=20 EGA=20\n");
PUT (" -wN :N = Wind. Default: 0\n");
PUT (" -k : Keyboard control - start explosions with keypresses.\n");
PUT (" -f : Fill screen with explosion trails.\n");
PUT (" -nN :N = # of explosions before exiting. Default: 0 (infinite)\n");
PUT ("eg. (for 12Mhz AT with VGA, in EGA mode): explod -ve -d6 *.dat\n");
PUT ("Press ESCAPE to return to DOS\n");
}
/********************* Explosion event handling *************************/
/*=====================================================================
* Initialize the explosion events table
*=====================================================================
*/
InitExpEvents ()
{
int i;
/* Set all events inactive */
for (i=0; i<MAX_EXPS; i++)
Exp_ev_tab[i].frame_num = -1;
}
/*=====================================================================
* Add an explosion to the events table
*=====================================================================
*/
StartExpEvent (x, y)
int x, y;
{
int i;
exp_desc_type *e;
y &= Centre_y_mask;
/* Find the first free entry in the table */
for (i=0; i<MAX_EXPS; i++)
if (Exp_ev_tab[i].frame_num == -1)
break;
/* don't do anything if table is full */
if (i >= MAX_EXPS)
return;
Exp_ev_tab[i].centre = gr_addr (x, y);
Exp_ev_tab[i].frame_num = 0;
e = &Exp_desc [rnd (Num_exp_desc)];
Exp_ev_tab[i].exp_desc = e;
/* Display the first frame */
gr_frplot (e->npoints, e->frame_seg, e->frame_ofs,
Exp_ev_tab[i].centre, 1);
}
/*=====================================================================
* Play back 1 frame of each event in the explosion events table
*=====================================================================
*/
PlayExpEvents ()
{
int i, j;
unsigned short frame_seg;
unsigned short frame_ofs;
unsigned short frame_i_addr;
exp_event_type *event;
exp_desc_type *e;
/*
* Loop once for each event in the events table:
*/
for (i=0; i < MAX_EXPS; i++)
{
event = &Exp_ev_tab[i];
e = event->exp_desc;
if (event->frame_num != -1) /* if the event is active */
{
frame_seg = e->frame_seg;
frame_ofs = e->frame_ofs;
/* if finished last frame of this explosion event */
if (++event->frame_num == (e->nframes + e->trail_len))
{
/* turn off the final frame's points */
if (!Leave_trail)
gr_frplot (e->npoints, frame_seg,
frame_ofs + (event->frame_num - e->trail_len-1) *
e->npoints * FRAME_PT_SIZE, Exp_ev_tab[i].centre, 0);
/* free the current event's in the explosion events table */
event->frame_num = -1;
}
else
{
/* Turn off previous frame's points (unless no prev frame) */
if (event->frame_num - e->trail_len - 1 >= 0 &&
!Leave_trail)
gr_frplot (e->npoints, frame_seg,
frame_ofs + (event->frame_num - e->trail_len-1) *
e->npoints * FRAME_PT_SIZE, Exp_ev_tab[i].centre, 0);
/* Turn on current frame's points */
if (event->frame_num < e->nframes)
gr_frplot (e->npoints, frame_seg,
frame_ofs + event->frame_num *
e->npoints * FRAME_PT_SIZE, Exp_ev_tab[i].centre, 1);
}
}
}
}
/*********************** Explosion Creation ************************/
/*====================================================================
* Generate the frames of an explosion, storing them in a frame table
* at the given address.
*====================================================================
*/
FrameInit (e, pt_table)
exp_desc_type *e;
exp_pt_type pt_table[];
{
exp_pt_type *curr_pt; /* current explosion point */
unsigned frame_i, i; /* loop counters */
unsigned short frame_i_addr; /* addr of current frame */
int fade_window = 0; /* fade counter (can fade if 0) */
unsigned short centre_addr = gr_addr (Centre_x, Centre_y);
unsigned short frame_seg = e->frame_seg;
unsigned short frame_ofs = e->frame_ofs;
/*
* Loop once to create each frame of the explosion
*/
for (frame_i = 0; frame_i < e->nframes; frame_i++)
{
/* Find the address of this frame in the frame table */
frame_i_addr = frame_ofs + (frame_i * e->npoints * FRAME_PT_SIZE);
/*
* Loop once for each point in the explosion
*/
for (i=0; i<e->npoints; i++)
{
curr_pt = &(pt_table[i]);
/* If the point is dead, mark it as dead and go on to the next */
if (!curr_pt->alive)
{
gr_store_pt (DEADPOINT, 0, frame_seg,
/* below is &frame table [frame_i] [i] */
frame_i_addr + (i * FRAME_PT_SIZE), 0);
continue;
}
/* calculate the next position of the point */
curr_pt->x.l += curr_pt->xv.l;
curr_pt->y.l += curr_pt->yv.l;
curr_pt->xv.l += curr_pt->xa.l;
curr_pt->yv.l += curr_pt->ya.l;
/* Store the point in the frame */
gr_store_pt (curr_pt->x.s.ms, curr_pt->y.s.ms, frame_seg,
/* below is &frame table [frame_i] [i] */
frame_i_addr + (i * FRAME_PT_SIZE),
centre_addr);
/*
* Do point fadeout - one point dies 1 out of 8 times here,
* starting at 60% of the way through the explosion.
*/
fade_window = (fade_window + 1) & 7;
if (frame_i > (e->nframes * 3 / 5) && fade_window == 0)
curr_pt->alive = 0;
}
}
}
/*====================================================================
* Read in an explosion description from the given disk file.
* Returns 1 if successful, 0 if not.
*====================================================================
*/
int
ReadDatFile (filename, e, pt_table)
char *filename;
exp_desc_type *e;
exp_pt_type pt_table[];
{
int x1, y1, x2, y2;
long src_x, src_y, dest_x, dest_y;
long accel, vel;
int cx = Centre_x;
int cy = Centre_y;
int i;
FILE *fp;
# define LINELEN 80
char linebuf [LINELEN];
char *lineptr;
unsigned short frame_buf_size;
/*
* Read in the explosion description file header information
*/
if ((fp = fopen (filename, "r")) == NULL)
{
PUT ("Error reading file "); PUT (filename); PUT ("\n");
return (0);
}
fgets (linebuf, LINELEN, fp);
str_to_num (linebuf, &e->npoints);
fgets (linebuf, LINELEN, fp);
str_to_num (linebuf, &e->nframes);
fgets (linebuf, LINELEN, fp);
str_to_num (linebuf, &e->gravity);
fgets (linebuf, LINELEN, fp);
str_to_num (linebuf, &e->wind);
fgets (linebuf, LINELEN, fp);
str_to_num (linebuf, &e->trail_len);
/*
* Perform any user-specified command-line parameter overrides
*/
if (Gravity != 0)
e->gravity = Gravity;
if (Wind != 0)
e->wind = Wind;
/*
* Allocate memory for the explosion's frames
*/
e->frame_ofs = 0;
frame_buf_size = (unsigned short) e->nframes * e->npoints * FRAME_PT_SIZE;
if ((e->frame_seg = MemAlloc (frame_buf_size)) == 0)
{
PUT ("Not enough memory for file ");
PUT (filename);
PUT ("\n");
return (1);
}
/*
* Read in the points for the explosion
*/
for (i=0; i<e->npoints; i++)
{
/* read in a (srcx, srcy), (destx, desty) coordinate pair */
fgets (linebuf, LINELEN, fp);
lineptr = str_to_num (linebuf, &x1);
lineptr = str_to_num (lineptr, &y1);
lineptr = str_to_num (lineptr, &x2);
lineptr = str_to_num (lineptr, &y2);
/* Convert to fixed pt. (Can't use shifts because they are unsigned) */
src_x = (x1 + cx) * 65536;
src_y = (y1 + cy) * 65536;
dest_x = (x2 + cx) * 65536;
dest_y = (y2 + cy) * 65536;
/* Store src coordinate in explosion table's current position field */
pt_table [i].x.s.ms = (int) (src_x >> 16);
pt_table [i].x.s.ls = 0;
pt_table [i].y.s.ms = (int) (src_y >> 16);
pt_table [i].y.s.ls = 0;
/*
* Calculate velocity and acceleration.
* accel = 2 * distance / #steps^2 (#steps is equivalent to time)
* vel = accel * #steps
*/
accel = (2 * (dest_x - src_x)) / ((long) e->nframes*e->nframes);
vel = (2 * (dest_x - src_x)) / (long) e->nframes;
pt_table [i].xa.l = -accel + (e->wind * 100);
pt_table [i].xv.l = vel;
accel = (2 * (dest_y - src_y)) / ((long) e->nframes*e->nframes);
vel = (2 * (dest_y - src_y)) / (long) e->nframes;
pt_table [i].ya.l = -accel + (e->gravity * 100);
pt_table [i].yv.l = vel;
pt_table [i].alive = 1;
}
/* Generate the frame table for the explosion */
FrameInit (e, pt_table);
/* Update stats used for calculating # of simultaneous explosions */
Total_frames += e->nframes;
return (1);
}
/****************************** Main *******************************/
/*=====================================================================
* Given a keyboard key, return an explosion x-y starting point
* roughly equivalent to the key's location on the keyboard.
*=====================================================================
*/
KeyToScreenPos (key, xsize, ysize, xpos, ypos)
int key; /* in: key's ascii value */
int xsize; /* in: x size of screen */
int ysize; /* in: y size of screen */
int *xpos; /* out: screen x position */
int *ypos; /* out: screen y position */
{
int x, y;
static unsigned char key_xpos [] =
{
/*spc*/ 8, /*!*/ 1, /*"*/ 11, /*#*/ 3, /*$*/ 4, /*%*/ 5, /*&*/ 6,
/*'*/ 11, /*(*/ 9, /*)*/ 10, /***/ 8, /*+*/ 12, /*,*/ 8,
/*-*/ 11, /*.*/ 9, /*slash*/ 10, /*0*/ 10, /*1*/ 1, /*2*/ 2,
/*3*/ 3, /*4*/ 4, /*5*/ 5, /*6*/ 6, /*7*/ 7, /*8*/ 8, /*9*/ 9,
/*:*/ 10, /*;*/ 10, /*<*/ 8, /*=*/ 12, /*>*/ 9, /*?*/ 10,
/*@*/ 2, /*A*/ 1, /*B*/ 5, /*C*/ 3, /*D*/ 3, /*E*/ 3, /*F*/ 4,
/*G*/ 5, /*H*/ 6, /*I*/ 8, /*J*/ 7, /*K*/ 8, /*L*/ 9, /*M*/ 7,
/*N*/ 6, /*O*/ 9, /*P*/ 10, /*Q*/ 1, /*R*/ 4, /*S*/ 2, /*T*/ 5,
/*U*/ 7, /*V*/ 4, /*W*/ 2, /*X*/ 2, /*Y*/ 6, /*Z*/ 1, /*[*/ 11,
/*\*/ 11, /*]*/12, /*^*/ 6, /*_*/ 10, /*`*/ 0
};
static unsigned char key_ypos [] =
{
/*spc*/ 5, /*!*/ 1, /*"*/ 3, /*#*/ 1, /*$*/ 1, /*%*/ 1, /*&*/ 1,
/*'*/ 3, /*(*/ 1, /*)*/ 1, /***/ 1, /*+*/ 1, /*,*/ 4,
/*-*/ 1, /*.*/ 4, /*slash*/ 4, /*0*/ 1, /*1*/ 1, /*2*/ 1,
/*3*/ 1, /*4*/ 1, /*5*/ 1, /*6*/ 1, /*7*/ 1, /*8*/ 1, /*9*/ 1,
/*:*/ 3, /*;*/ 3, /*<*/ 4, /*=*/ 1, /*>*/ 4, /*?*/ 4,
/*@*/ 1, /*A*/ 3, /*B*/ 4, /*C*/ 4, /*D*/ 3, /*E*/ 2, /*F*/ 3,
/*G*/ 3, /*H*/ 3, /*I*/ 2, /*J*/ 3, /*K*/ 3, /*L*/ 3, /*M*/ 4,
/*N*/ 4, /*O*/ 2, /*P*/ 20, /*Q*/ 2, /*R*/ 2, /*S*/ 3, /*T*/ 2,
/*U*/ 2, /*V*/ 4, /*W*/ 2, /*X*/ 4, /*Y*/ 2, /*Z*/ 4, /*[*/ 2,
/*\*/ 5, /*]*/ 2, /*^*/ 1, /*_*/ 1, /*`*/ 1
};
# define MAX_KEYX 13
# define MAX_KEYY 5
/* Special case: if space bar then make it random */
if (key == 32)
{
*xpos = rnd (xsize);
*ypos = rnd (ysize);
return;
}
if (key > 96) key -= 32;
if (key > 96) key &= 63;
key -= 32;
if (key < 0) key =- key;
x = key_xpos [key];
if (x >= MAX_KEYX)
x = MAX_KEYX - 1;
x = (long) x * xsize / MAX_KEYX;
*xpos = x;
y = key_ypos [key];
if (y >= MAX_KEYY)
y = MAX_KEYY - 1;
y = (long) y * ysize / MAX_KEYY;
*ypos = y;
}
/*=====================================================================
* Main - loop to check input and animate explosion events
*=====================================================================
*/
main (argc, argv)
int argc;
char *argv[];
{
int key;
int start_count;
int start_interval;
int avg_num_frames;
int event_count = 0;
int last_event_frame_count = 0;
int i, j;
int xpos, ypos;
/* Initialize the local memory allocator */
if (!MemInit())
exit (1);
/* Read in the command line arguments and explosion files */
Num_exp_desc = 0;
if (!GetArgs (argc, argv))
goto exit;
if (Num_exp_desc == 0)
{
PUT ("\nERROR: no data files specified or all files are invalid.\n");
goto exit;
}
/* Calculate the number of frames to wait between starting explosions */
avg_num_frames = Total_frames / Num_exp_desc;
if (Simul_exps > 0)
{
start_interval = avg_num_frames / Simul_exps;
start_count = start_interval;
}
InitExpEvents();
gr_gmode(); /* enter graphics mode */
/*
* Main loop: animate one explosion frame once each loop
* Exit loop when ESC pressed or when Event_limit explosions are done.
*/
while ((key = ChkKey()) != 27)
{
/*
* Start a new explosion event every start_interval loops or
* when a key is pressed.
*/
if ((Simul_exps != 0 && start_count++ == start_interval) || key)
{
/* Start only if event limit hasn't been reached */
if (Event_limit == 0 || event_count++ < Event_limit)
{
if (key)
KeyToScreenPos (key, Screen_xsize, Screen_ysize,
&xpos, &ypos);
else
{
xpos = Screen_xsize/7 + rnd (Screen_xsize*5/7);
ypos = Screen_ysize/7 + rnd (Screen_ysize*5/7);
}
StartExpEvent (xpos, ypos);
start_count = 0;
}
}
/* Play back one frame of each explosion event */
PlayExpEvents ();
/* Exit if the event limit has been reached and the last explosion
has ended. */
if (Event_limit && event_count >= Event_limit &&
++last_event_frame_count > avg_num_frames)
break;
/*
* Optional delay for machines that are too fast.
* The function call in the inner loop prevents optimizing
* compilers from optimizing away the loop.
*/
if (Delay_factor > 0)
for (i=0; i < Delay_factor; i++)
for (j=0; j<100; j++)
DummyDelay (i*j);
}
gr_tmode ();
exit:
MemCleanup(); /* Release memory used by the local mem allocator */
}
/*
* Dummy function used for delays
*/
DummyDelay (i)
int i;
{
return (i * i);
}