Category : C Source Code
Archive   : EXPLOD.ZIP
Filename : EXPLOD.C
Output of file : EXPLOD.C contained in archive : EXPLOD.ZIP
* EXPLOD.C - simple fireworks for Hercules card or CGA
*
* This has been developed with Datalight C 2.20 and Arrowsoft ASM 1.00d.
* This file is also compilable with Quick C 1.0 and Turbo C 1.5. However,
* the EXPLOD.OBJ file generated by Quick C and Turbo C will not link
* properly with EXPA.OBJ because the segment names in EXPA.ASM are defined
* according to Datalight C requirements. They must be redefined to suit
* your C compiler.
*
* To compile
* asm expa ;
* dlc explod.c expa.obj
*
* (C) 1989 Dennis Lo
* This source code may be freely distributed and used, provided that my
* name remains in the source code, and that modified versions are clearly
* distinguished from the original.
*
* Change Log
* 89/06/24 Dennis Lo V1.0 Initial release. "Trails" idea from Dave Lo.
* 89/07/03 Dennis Lo V1.1 Added more cmd line options. Code cleanups.
* Fixed "extra-initial-uplift" bug.
****************************************************************************/
#include
#include
/*
* External assembler routines. Actually only gr_frplot() needs to
* be done in assembler; the rest can be done in C without any
* animation performance loss.
*/
/* Datalight C does not prepend underscores to external names */
#ifdef DLC
# define GetKey _GetKey
# 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_fill _gr_fill
# define gr_addr _gr_addr
# define gr_value _gr_value
# define gr_frplot _gr_frplot
#endif
extern GetKey();
extern ChkKey();
extern gr_card();
extern gr_setcard();
extern gr_gmode();
extern gr_tmode();
extern gr_fill();
extern gr_addr();
extern gr_value();
extern gr_frplot();
#define DEADPOINT 32767 /* this must match definition in gr_frplot */
/*=====================================================================
* Configuration Parameters
*=====================================================================
*/
/* video parameters */
static int Interlace_factor;
static int Screen_Xsize;
static int Screen_Ysize;
/* explosion parameters */
#define NUM_POINTS 300
#define NUM_FRAMES 50
static int Num_points = 0;
static int Xsize;
static int Ysize;
static int Gravity;
static int Wind = 0;
static int Centre_x;
static int Centre_y;
static int Centre_y_mask;
/* Animation parameters */
static int Simul_exps = 0; /* # of simultaneous explosions */
static int Trail_length = 5; /* # of frames for erase to trail draw by */
static int Delay_factor = 0; /* amount to delay in each frame */
/*=====================================================================
* Structure of a single explosion point at creation
*=====================================================================
*/
typedef union
{
long l;
struct
{
unsigned short ls;
short ms;
} s;
} fixed;
typedef struct
{
fixed x, y; /* location of point */
fixed xv, yv; /* velocity of point */
fixed xa, ya; /* acceleration of point */
int alive; /* liveness: 0=dead */
} exp_pt_type;
/* Explosion creation points table - keeps track of points for creating
the explosion frames */
exp_pt_type Exp_table [NUM_POINTS+1];
/*=====================================================================
* Structure of one point in an explosion frame at playback
* Each frame consists of NUM_POINTS structures of
* offset (2 bytes)
* value (1 byte)
*=====================================================================
*/
/* Explosion playback frames table */
static unsigned char frame_table [NUM_FRAMES][NUM_POINTS][3];
/*=====================================================================
* Structure of an explosion event
*=====================================================================
*/
#define MAX_EXPS 50 /* max # of simultaneous explosion events */
typedef struct
{
int centre; /* addr of centre of explosion */
int frame_num; /* frame #. Dead if -1 */
} exp_event_type;
/* Explosion events table */
static exp_event_type exp_ev_tab [MAX_EXPS];
/*=====================================================================
* Main - loop to check input and call explosion steps
*=====================================================================
*/
main (argc, argv)
int argc;
char *argv[];
{
int frame_i;
int key;
int start_count = 0;
int start_interval;
int i, j;
start_interval = GetArgs (argc, argv);
puts ("\nSetting up, please wait...");
FrameTableInit (Num_points);
InitExpEvents();
gr_gmode();
while (ChkKey() != 27)
{
/* Start a new explosion event every start_interval loops */
if (++start_count == start_interval)
{
CreateExplosion (Screen_Xsize/7 + rnd (Screen_Xsize*5/7),
Screen_Ysize/7 + rnd (Screen_Ysize*5/7));
start_count = 0;
}
/* Animate one frame of each explosion */
Explosion ();
/*
* 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++)
Dummy (i*j);
}
gr_tmode ();
}
/*
* Dummy delay function
*/
Dummy (i)
int i;
{
return (i * i);
}
/*=====================================================================
* Process command line arguments. Returns start_interval.
* Also sets up explosion parameters according to video card type.
*=====================================================================
*/
int
GetArgs (argc, argv)
int argc;
char *argv[];
{
SetVideoParams (gr_card()); /* guess video card */
/* 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)*/
SetVideoParams ((*argv)[2]);
break;
case 's': /* -s: # of simultaneous explosions */
Simul_exps = atoi ((*argv) + 2);
break;
case 'g': /* -g: gravity (vert accel) */
Gravity = atoi ((*argv) + 2);
break;
case 'w': /* -w: wind (horiz accel) */
Wind = atoi ((*argv) + 2);
break;
case 'x': /* -x: explosion X size */
Xsize = atoi ((*argv) + 2);
break;
case 'y': /* -y: explosion Y size */
Ysize = atoi ((*argv) + 2);
break;
case 'p': /* -p: # of explosion points */
Num_points = atoi ((*argv) + 2);
break;
case 't': /* -t: trail length */
Trail_length = atoi ((*argv) + 2);
break;
case 'd': /* -d: delay factor */
Delay_factor = atoi ((*argv) + 2);
break;
default:
printf ("*** Invalid option: %s\n", *argv);
Instructions();
exit ();
}
}
}
return (NUM_FRAMES / Simul_exps);
}
/*=====================================================================
* Set video card-related parameters
*=====================================================================
*/
SetVideoParams (video_card)
char video_card;
{
gr_setcard (video_card);
if (video_card == 'c') /* if cga */
{
Interlace_factor = 2;
Screen_Xsize = 640;
Screen_Ysize = 200;
Xsize = 127;
Ysize = 50;
Gravity = 1500;
if (Simul_exps == 0) Simul_exps = 8;
if (Num_points == 0) Num_points = 120;
}
else /* if hgc */
{
Interlace_factor = 4;
Screen_Xsize = 720;
Screen_Ysize = 348;
Xsize = 150;
Ysize = 90;
Gravity = 2000;
if (Simul_exps == 0) Simul_exps = 10;
if (Num_points == 0) Num_points = 160;
}
Centre_x = (Screen_Xsize / 2);
Centre_y = (Screen_Ysize / 2);
Centre_y_mask = (0xffff - (Interlace_factor - 1));
}
/*=====================================================================
* Print instructions
*=====================================================================
*/
Instructions ()
{
puts ("\nEXPLOD 1.1 by Dennis Lo 89/07/03");
puts ("Usage: explod
puts ("Parameters can be one of");
puts (" -v
puts (" Default is auto-detect (but must specify for EGA/VGA)");
puts (" -s
puts (" -x
puts (" -y
puts (" -p
puts (" -t
puts (" -d
puts (" -g
puts (" -w
puts ("Examples:");
puts (" explod (for 8MHz 8088 XT with CGA or HGC card)");
puts (" explod -vc -s5 -t3 (for 4.77MHz XT with EGA card in CGA mode)");
puts (" explod -t10 -s15 (for 8MHz 80186 XT with HGC)");
puts (" explod -p300 -x200 -y120 -s6 -d10 (for 8 Mhz AT with HGC)");
puts ("\nPress ESCAPE to return to DOS");
}
/***************** Explosion event handling module *******************/
/*=====================================================================
* Perform 1 explosion step
*=====================================================================
*/
Explosion ()
{
int i, j;
/*
* Loop to animate one frame for each active explosion in the
* explosion table.
*/
for (i=0; i < MAX_EXPS; i++)
{
if (exp_ev_tab[i].frame_num != -1)
{
/* if finished last frame of this explosion event */
if (++exp_ev_tab[i].frame_num == NUM_FRAMES + Trail_length)
{
/* turn off final frame's points */
gr_frplot (Num_points,
frame_table[exp_ev_tab[i].frame_num - Trail_length-1],
exp_ev_tab[i].centre);
/* free current event's entry in explosion events table */
exp_ev_tab[i].frame_num = -1;
}
else
{
/* Turn off previous frame's points (unless no prev frame) */
if (exp_ev_tab[i].frame_num-Trail_length-1 >= 0)
gr_frplot (Num_points,
frame_table[exp_ev_tab[i].frame_num - Trail_length-1],
exp_ev_tab[i].centre);
/* Turn on current frame's points */
if (exp_ev_tab[i].frame_num < NUM_FRAMES)
gr_frplot (Num_points,
frame_table[exp_ev_tab[i].frame_num],
exp_ev_tab[i].centre);
}
}
}
}
/*=====================================================================
* Add an explosion to the events table
*=====================================================================
*/
CreateExplosion (x, y)
int x, y;
{
int i;
y &= Centre_y_mask;
/* Find the first free entry in the table */
for (i=0; i
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;
/* Turn on first frame's points */
gr_frplot (Num_points, frame_table[0], exp_ev_tab[i].centre);
}
/* Initialize events table */
InitExpEvents ()
{
int i;
for (i=0; i
}
/*********************** Explosion Frames *****************************/
/*====================================================================
* Create an explosion, storing it in the explosion frames table.
* Returns addr of explosion centre.
*====================================================================
*/
FrameTableInit (num_points)
int num_points;
{
exp_pt_type *curr_pt;
int i;
int point_count; /* total # of points processed */
int fade_window; /* fade window counter (can fade if 0) */
int delay;
int frame_i;
int centre_addr;
short *s;
/*
* Initialize points and plot them at their initial positions
*/
centre_addr = ExpInit (num_points, Exp_table);
/*
* Loop to move the explosion through NUM_FRAMES frames
*/
point_count = 0;
fade_window = 0;
for (frame_i = 0; frame_i < NUM_FRAMES; frame_i++)
{
/*
* Loop to reset, move, and set every point in the table
*/
for (i=0; i
curr_pt = Exp_table + i;
/* assume point is dead first */
*((int*)frame_table [frame_i][i]) = DEADPOINT;
/* Do the point only if it is alive */
if (curr_pt->alive)
{
/* can put code to reset point here */
/* calc next position */
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;
/* fade out period count */
fade_window = (fade_window + 1) & 7;
/* Check if point should die */
/* forget the screen bounds check... points will go out in re-animate anyways
if (curr_pt->x.s.ms >= 719 || curr_pt->x.s.ms < 0
|| curr_pt->y.s.ms > 347 || curr_pt->y.s.ms < 0
|| (++point_count > num_points * 30 && fade_window == 0))
*/
if (++point_count > num_points * 30 && fade_window == 0)
{
curr_pt->alive = 0;
}
else /* if not out */
{
/* if not out then set point and save it */
/* if plotting points in this function, uncomment this
gr_plot (curr_pt->x.s.ms, curr_pt->y.s.ms);
*/
/* save point's video value */
*(frame_table [frame_i][i] + 2) = (unsigned char)
gr_value (curr_pt->x.s.ms, curr_pt->y.s.ms);
/* save point's video address */
*((short *) frame_table[frame_i][i]) =
gr_addr (curr_pt->x.s.ms, curr_pt->y.s.ms)
- centre_addr;
}
}
/* if plotting in this function, substitute delay for dead point
else * substitute delay for dead point *
{
for (delay=0; delay<20; delay++);
}
*/
}
}
/* if plotting in this function, turn off remaining points here
for (i=0; i
gr_plot (Exp_table[i].x.s.ms, Exp_table[i].y.s.ms);
*/
}
/*====================================================================
* Set up explosion creation points table.
* Returns addr of explosion centre.
*====================================================================
*/
int
ExpInit (num_points, exp_table)
int num_points;
exp_pt_type exp_table[];
{
long dest_x, dest_y;
long src_x, src_y;
long accel, vel;
int cx;
int cy;
int i = 0;
/* Clear explosion table */
memset ((char*) exp_table, 0, num_points * sizeof(exp_pt_type));
/* Calc explosion centre coordinates */
cx = Centre_x;
cy = Centre_y & Centre_y_mask;
for (i=0; i
exp_table [i].alive = 1;
/*
* Put in explosion centre as starting coordinate
*/
src_x = ((long) cx) * 65536;
src_y = ((long) cy) * 65536;
exp_table [i].x.s.ms = (int) (src_x >> 16);
exp_table [i].x.s.ls = 0;
exp_table [i].y.s.ms = (int) (src_y >> 16);
exp_table [i].y.s.ls = 0;
/*
* Randomly select a destination that is inside the ellipse with
* X and Y radii of (Xsize, Ysize).
*/
do
{
dest_x = rnd (2*Xsize) - Xsize;
dest_y = rnd (2*Ysize) - Ysize;
} while ((long) Ysize * Ysize * dest_x * dest_x +
(long) Xsize * Xsize * dest_y * dest_y
> (long) Ysize * Ysize * Xsize * Xsize);
/* Convert to fixed pt. Can't use shifts because they are unsigned */
dest_x = (dest_x + cx) * 65536;
dest_y = (dest_y + cy) * 65536;
/*
* accel = 2 * distance / #steps^2 (#steps is equivalent to time)
* vel = accel * #steps
*/
accel = (2 * (dest_x - src_x)) / ((long) NUM_FRAMES*NUM_FRAMES);
vel = (2 * (dest_x - src_x)) / (long) NUM_FRAMES;
exp_table [i].xa.l = -accel + Wind;
exp_table [i].xv.l = vel;
accel = (2 * (dest_y - src_y)) / ((long) NUM_FRAMES*NUM_FRAMES);
vel = (2 * (dest_y - src_y)) / (long) NUM_FRAMES;
exp_table [i].ya.l = -accel + Gravity;
exp_table [i].yv.l = vel;
}
return (gr_addr (cx, cy));
}
/*====================================================================
* Return a random number between 1..maxval
*====================================================================
*/
int
rnd (maxval)
{
# define MAX_RAND 32767 /* max val returned by rand() */
long l;
l = (long) maxval * rand() / MAX_RAND;
return ((int) l);
}
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/