billr@saab.CNA.TEK.COM (Bill Randle) (12/07/89)
Submitted-by: Dennis Lo <dlo%idacom.cs.ubc.cdn@relay.cdnnet.ca>
Posting-number: Volume 8, Issue 72
Archive-name: ttyexp/Part01
[I tried this on my Sun 3/60 (OS3.5) and on a Vax (4.3bsd)
and it works (uncomment the #define for the Vax). -br]
[[From the author...
Here's a submission to fill in the void in comp.sources.games.
It is an explosion-screen-clearer that is actually a much more general
fireworks program with many optional parameters. Unfortunately, fireworks
more elaborate than a single explosion will require a fast, large screen
(eg. large text windows on a workstation) to be comprehensible.
For 80x24 terminals at 9600 baud, the program will serve nicely as an
interesting screen clearer, especially if it is set up to run on a press
of a function key.]]
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 1 (of 1)."
# Contents: README makefile ttyexp.c
# Wrapped by billr@saab on Wed Dec 6 09:00:10 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(570 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X
X Here's a submission to fill in the void in comp.sources.games.
XIt is an explosion-screen-clearer that is actually a much more general
Xfireworks program with many optional parameters. Unfortunately, fireworks
Xmore elaborate than a single explosion will require a fast, large screen
X(eg. large text windows on a workstation) to be comprehensible.
X
X For 80x24 terminals at 9600 baud, the program will serve nicely as an
Xinteresting screen clearer, especially if it is set up to run on a press
Xof a function key.
X
XDennis Lo
Xdlo%idacom.cs.ubc.cdn@relay.cdnnet.ca
END_OF_FILE
if test 570 -ne `wc -c <'README'`; then
echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'makefile' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'makefile'\"
else
echo shar: Extracting \"'makefile'\" \(85 characters\)
sed "s/^X//" >'makefile' <<'END_OF_FILE'
X#
X# Makefile for ttyexp
X#
Xttyexp: ttyexp.c
X cc ttyexp.c -lcurses -ltermcap -o ttyexp
END_OF_FILE
if test 85 -ne `wc -c <'makefile'`; then
echo shar: \"'makefile'\" unpacked with wrong size!
fi
# end of 'makefile'
fi
if test -f 'ttyexp.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'ttyexp.c'\"
else
echo shar: Extracting \"'ttyexp.c'\" \(19482 characters\)
sed "s/^X//" >'ttyexp.c' <<'END_OF_FILE'
X/* ttyexp.c - Explosion screen clearer for tty terminals
X *
X * Compiling:
X * Use the command "cc ttyexp.c -lcurses -ltermcap -o ttyexp"
X * I have only tested this on Sun 3's under SunOS 4.0, but I think it
X * should work under other flavours of Unix that support curses.
X *
X * Running:
X * Running "ttyexp" without any parameters will produce one explosion
X * optimized for a 9600 baud terminal. Command line switches can
X * be given to set the number of simultaneous explosions, the explosion
X * size, the number of points per explosion, etc. "ttyexp -h" will
X * print instructions.
X *
X * Bugs/Ugliness:
X * This was hacked out of the IBM-PC fireworks program EXPLOD 1.1,
X * so don't be surprised to see lots of useless pc-isms in the code.
X *
X * Versions for other machines:
X * The latest PC version is in /uploads/explod12.lzh at the ftp site
X * grape.ecs.clarkson.edu (128.153.13.196). An older version (V1.1) that
X * doesn't support EGA should be at comp.binaries.ibm.pc archive sites.
X * Email me if you're interested in a version for the Sun 3/50 console
X * it accesses the screen via PixRect so it's not that fast).
X *
X * Author
X * Dennis Lo 89/10/10
X * dlo@idacom.cs.ubc.ca or ...!alberta!ubc-cs!ubc-idacom!dlo
X * 4516 Albert St., Burnaby, B.C., Canada V5C 2G5
X *
X * This program is in the public domain.
X */
X#include <stdio.h>
X#include <ctype.h>
X#include <curses.h>
X#include <signal.h>
X
X/*#define LSWFIRST /* define this for machines that are LS word first (e.g. Vax) */
X#define DEADPOINT 32767
X
X/*=====================================================================
X * Configuration Parameters
X *=====================================================================
X */
X/* video parameters */
Xstatic int Interlace_factor;
Xstatic int Screen_Xsize;
Xstatic int Screen_Ysize;
X
X/* explosion parameters */
X#define NUM_POINTS 300
X#define NUM_FRAMES 10
Xstatic int Num_points;
Xstatic int Xsize;
Xstatic int Ysize;
Xstatic int Gravity;
Xstatic int Wind = 0;
Xstatic int Centre_x;
Xstatic int Centre_y;
Xstatic int Centre_y_mask;
Xstatic char Exp_char = '@';
X
X/* Animation parameters */
Xstatic int Simul_exps = 0; /* # of simultaneous explosions */
Xstatic int Trail_length = 4; /* # of frames for erase to trail draw by */
Xstatic int Delay_factor = 0; /* amount to delay in each frame */
Xstatic int Duration = NUM_FRAMES;
X
X/*=====================================================================
X * Structure of an explosion point at explosion creation time.
X *=====================================================================
X */
Xtypedef union /* 16.16 fixed point type */
X{
X long l;
X struct
X {
X#ifdef LSWFIRST
X unsigned short ls; /* the order is Endian-dependent! */
X short ms;
X#else
X short ms;
X unsigned short ls; /* the order is Endian-dependent! */
X#endif
X } s;
X} fixed;
X
Xtypedef struct /* structure of single explosion point */
X{
X fixed x, y; /* location of point */
X fixed xv, yv; /* velocity of point */
X fixed xa, ya; /* acceleration of point */
X int alive; /* liveness: 0=dead */
X} exp_pt_type;
X
X/* Explosion creation points table - keeps track of points for creating
X the explosion frames */
Xexp_pt_type Exp_table [NUM_POINTS+1];
X
X
X/*=====================================================================
X * Structure of a point in an explosion frame at playback time.
X *=====================================================================
X */
X/*
X * Each frame consists of NUM_POINTS structures of
X * offset (2 bytes)
X * value (1 byte)
X */
X/* Explosion playback frames table */
X/*
Xstatic unsigned char frame_table [NUM_FRAMES][NUM_POINTS][3];
X*/
X
Xtypedef struct
X{
X int x;
X int y;
X} coord_type;
X
Xtypedef coord_type frame_type [NUM_POINTS];
X
Xframe_type frame_table [NUM_FRAMES];
X
X
X/*=====================================================================
X * Structure of an explosion event
X *=====================================================================
X */
X#define MAX_EXPS 50 /* max # of simultaneous explosion events */
X
Xtypedef struct
X{
X coord_type centre; /* addr of centre of explosion */
X int frame_num; /* frame #. Dead if -1 */
X} exp_event_type;
X
X/* Explosion events table */
Xstatic exp_event_type exp_ev_tab [MAX_EXPS];
X
X
X
X
X/*=====================================================================
X * Main - loop to check input and call explosion steps
X *=====================================================================
X */
Xmain (argc, argv)
X int argc;
X char *argv[];
X{
X int step;
X int frame_i;
X int key;
X int start_count = 0;
X int start_interval;
X int i, j;
X
X start_interval = GetArgs (argc, argv);
X
X /*puts ("\nSetting up, please wait...");*/
X FrameTableInit (Num_points);
X InitExpEvents();
X gr_gmode();
X
X /* while (ChkKey() != 27) */
X Duration = start_interval + (Duration / NUM_FRAMES) * NUM_FRAMES
X + Trail_length;
X for (step=0; step<Duration; step++)
X {
X /* Start a new explosion event every start_interval loops */
X if (++start_count > start_interval && step < Duration-Trail_length)
X {
X CreateExplosion (Screen_Xsize/4 + rnd (Screen_Xsize*2/4),
X Screen_Ysize/4 + rnd (Screen_Ysize*2/4));
X start_count = 0;
X }
X
X /* Animate one frame of each explosion */
X Explosion ();
X
X /*
X * Optional delay for machines that are too fast.
X * The function call in the inner loop prevents optimizing
X * compilers from optimizing away the loop.
X */
X if (Delay_factor > 0)
X for (i=0; i < Delay_factor; i++)
X for (j=0; j<100; j++)
X DummyDelay (i*j);
X }
X gr_tmode ();
X}
X
X/*
X * Dummy function used for delays
X */
XDummyDelay (i)
Xint i;
X{
X return (i * i);
X}
X
X/*=====================================================================
X * Process command line arguments. Returns start_interval.
X * Also sets up explosion parameters according to video card type.
X *=====================================================================
X */
Xint
XGetArgs (argc, argv)
X int argc;
X char *argv[];
X{
X int video_type = gr_card(); /* guess video card */
X
X /* Set defaults based on assumed video card type */
X SetVideoParams (video_type);
X
X /* Print instructions if no command line parameters are given */
X/*
X if (argc == 1)
X Instructions();
X*/
X
X /*
X * Loop to parse each command line parameter
X */
X while (--argc > 0)
X {
X if (**++argv == '-')
X {
X switch ((*argv)[1])
X {
X case 'v': /* -v: video card type (c, h, e, s, t)*/
X SetVideoParams ((*argv)[2]);
X break;
X case 's': /* -s: # of simultaneous explosions */
X Simul_exps = atoi ((*argv) + 2);
X break;
X case 'g': /* -g: gravity (vert accel) */
X Gravity = atoi ((*argv) + 2);
X break;
X case 'w': /* -w: wind (horiz accel) */
X Wind = atoi ((*argv) + 2);
X break;
X case 'x': /* -x: explosion X size */
X Xsize = atoi ((*argv) + 2);
X break;
X case 'y': /* -y: explosion Y size */ Ysize = atoi ((*argv) + 2);
X break;
X case 'p': /* -p: # of explosion points */
X Num_points = atoi ((*argv) + 2);
X break;
X case 't': /* -t: trail length */
X Trail_length = atoi ((*argv) + 2);
X break;
X case 'd': /* -d: delay factor */
X Delay_factor = atoi ((*argv) + 2);
X break;
X case 'D': /* -D: Duration */
X Duration = atoi ((*argv) + 2);
X break;
X case 'c': /* -c: character */
X if (isdigit ((*argv)[3]))
X Exp_char = atoi ((*argv) + 2);
X else
X Exp_char = (*argv)[2];
X break;
X case 'h':
X Instructions();
X exit ();
X default:
X printf ("*** Invalid option: %s\n", *argv);
X Instructions();
X exit ();
X }
X }
X }
X return (NUM_FRAMES / Simul_exps);
X}
X
X/*=====================================================================
X * Set video card-related parameters
X *=====================================================================
X */
XSetVideoParams (video_card)
X char video_card;
X{
X int i;
X int *defarr;
X# define NUM_CARDS 6
X static char index_char[NUM_CARDS] =
X { 'c', 'h', 'e', 'v', 's', 't' };
X static int defaults [NUM_CARDS][9] = {
X 2, 640, 200, 127, 50, 1500, 8, 120, 3, /* cga */
X 4, 720, 348, 150, 90, 2000, 10, 160, 5, /* hgc */
X 1, 640, 350, 150, 90, 2000, 10, 160, 5, /* ega */
X 1, 640, 480, 150, 120, 2500, 12, 170, 5, /* vga */
X 1, 1600,1280,300, 250, 4000, 1, 300, 8, /* sun */
X 1, 80, 24, 40, 15, 1000, 1, 20, 1 /* tty */
X };
X
X /* return defaults index for the given video_card */
X for (i=0; i<NUM_CARDS; i++)
X if (video_card == index_char[i])
X break;
X
X defarr = defaults [i];
X Interlace_factor = defarr[0];
X Screen_Xsize = defarr[1];
X Screen_Ysize = defarr[2];
X if (Xsize == 0) Xsize = defarr[3];
X if (Ysize == 0) Ysize = defarr[4];
X if (Gravity == 0) Gravity = defarr[5];
X if (Simul_exps == 0) Simul_exps = defarr[6];
X if (Num_points == 0) Num_points = defarr[7];
X if (Trail_length == 0) Trail_length = defarr[8];
X
X Centre_x = (Screen_Xsize / 2);
X Centre_y = (Screen_Ysize / 2);
X Centre_y_mask = (0xffff - (Interlace_factor - 1));
X gr_setcard (video_card);
X}
X
X/*=====================================================================
X * Print instructions
X *=====================================================================
X */
XInstructions ()
X{
X puts ("Usage: ttyexp <parameters>");
X puts ("Parameters can be one of");
X puts (" -s<n> :<n> = # of simultaneous explosions. Default: 1");
X puts (" -x<n> :<n> = Explosion X size. Default: 40");
X puts (" -y<n> :<n> = Explosion Y size. Default: 15");
X puts (" -p<n> :<n> = #pts/explosion. Max 300. Default: 10");
X puts (" -t<n> :<n> = Trail length. Default: 4");
X puts (" -d<n> :<n> = Delay factor. Default: 0");
X puts (" -g<n> :<n> = Gravity (vert accel). Default: 1000");
X puts (" -w<n> :<n> = Wind (horiz accel). Default: 0");
X puts (" -c<n> :<n> = Explosion character. Default: '@'");
X puts (" -D<n> :<n> = Duration. Default: 10");
X}
X
X/***************** Explosion event handling module *******************/
X/*=====================================================================
X * Perform 1 explosion step
X *=====================================================================
X */
XExplosion ()
X{
X int i, j;
X
X /*
X * Loop to animate one frame for each active explosion in the
X * explosion table.
X */
X for (i=0; i < MAX_EXPS; i++)
X {
X if (exp_ev_tab[i].frame_num != -1)
X {
X /* if finished last frame of this explosion event */
X if (++exp_ev_tab[i].frame_num == NUM_FRAMES + Trail_length)
X {
X /* turn off final frame's points */
X gr_frplot (Num_points,
X frame_table[exp_ev_tab[i].frame_num - Trail_length-1],
X &exp_ev_tab[i].centre, ' ');
X
X /* free current event's entry in explosion events table */
X exp_ev_tab[i].frame_num = -1;
X }
X else
X {
X /* Turn off previous frame's points (unless no prev frame) */
X if (exp_ev_tab[i].frame_num-Trail_length-1 >= 0)
X gr_frplot (Num_points,
X frame_table[exp_ev_tab[i].frame_num - Trail_length-1],
X &exp_ev_tab[i].centre, ' ');
X
X /* Turn on current frame's points */
X if (exp_ev_tab[i].frame_num < NUM_FRAMES)
X gr_frplot (Num_points,
X frame_table[exp_ev_tab[i].frame_num],
X &exp_ev_tab[i].centre, Exp_char);
X }
X }
X }
X}
X
X
X/*=====================================================================
X * Add an explosion to the events table
X *=====================================================================
X */
XCreateExplosion (x, y)
X int x, y;
X{
X int i;
X
X y &= Centre_y_mask;
X
X /* Find the first free entry in the table */
X for (i=0; i<MAX_EXPS; i++)
X if (exp_ev_tab[i].frame_num == -1)
X break;
X
X /* don't do anything if table is full */
X if (i == MAX_EXPS)
X return;
X
X exp_ev_tab[i].centre.x = x;
X exp_ev_tab[i].centre.y = y;
X exp_ev_tab[i].frame_num = 0;
X
X /* Turn on first frame's points */
X gr_frplot (Num_points, frame_table[0], &exp_ev_tab[i].centre, Exp_char);
X}
X
X/*
X * Initialize events table
X */
XInitExpEvents ()
X{
X int i;
X for (i=0; i<MAX_EXPS; i++)
X exp_ev_tab[i].frame_num = -1;
X}
X
X
X
X/*********************** Explosion Frames *****************************/
X/*====================================================================
X * Create an explosion, storing it in the explosion frames table.
X * Returns addr of explosion centre.
X *====================================================================
X */
XFrameTableInit (num_points)
X int num_points;
X{
X exp_pt_type *curr_pt;
X int i;
X int point_count; /* total # of points processed */
X int fade_window; /* fade window counter (can fade if 0) */
X int delay;
X int frame_i;
X int centre_x;
X int centre_y;
X short *s;
X
X /*
X * Initialize points and plot them at their initial positions
X */
X ExpInit (num_points, Exp_table, ¢re_x, ¢re_y);
X
X /*
X * Loop to move the explosion through NUM_FRAMES frames
X */
X point_count = 0;
X fade_window = 0;
X for (frame_i = 0; frame_i < NUM_FRAMES; frame_i++)
X {
X /*
X * Loop to reset, move, and set every point in the table
X */
X for (i=0; i<num_points; i++)
X {
X curr_pt = Exp_table + i;
X
X /* assume point is dead first */
X frame_table [frame_i][i].x = DEADPOINT;
X
X /* Do the point only if it is alive */
X if (curr_pt->alive)
X {
X /* calc next position */
X curr_pt->x.l += curr_pt->xv.l;
X curr_pt->y.l += curr_pt->yv.l;
X curr_pt->xv.l += curr_pt->xa.l;
X curr_pt->yv.l += curr_pt->ya.l;
X
X /* fade out period count */
X fade_window = (fade_window + 1) & 7;
X
X /* Check if point should die */
X if (curr_pt->x.s.ms >= Screen_Xsize || curr_pt->x.s.ms < 0
X || curr_pt->y.s.ms > Screen_Ysize || curr_pt->y.s.ms < 0
X || (++point_count > num_points * 30 && fade_window == 0))
X curr_pt->alive = 0;
X
X else /* if not out */
X {
X /* if not out then save point's coords wrt centre */
X frame_table [frame_i][i].x = curr_pt->x.s.ms - centre_x;
X frame_table [frame_i][i].y = curr_pt->y.s.ms - centre_y;
X }
X }
X }
X }
X}
X
X/*====================================================================
X * Set up the initial points for an explosion.
X * Returns addr of explosion centre.
X *====================================================================
X */
XExpInit (num_points, exp_table, centre_x, centre_y)
X int num_points;
X exp_pt_type exp_table[];
X int *centre_x, *centre_y;
X{
X long dest_x, dest_y;
X long src_x, src_y;
X long accel, vel;
X int cx;
X int cy;
X int i = 0;
X
X /* Clear explosion table */
X memset ((char*) exp_table, 0, num_points * sizeof(exp_pt_type));
X
X /* Calc explosion centre coordinates */
X cx = Centre_x;
X cy = Centre_y & Centre_y_mask;
X
X for (i=0; i<num_points; i++)
X {
X exp_table [i].alive = 1;
X
X /*
X * Put in explosion centre as starting coordinate
X */
X src_x = ((long) cx) * 65536;
X src_y = ((long) cy) * 65536;
X exp_table [i].x.s.ms = (int) (src_x >> 16);
X exp_table [i].x.s.ls = 0;
X exp_table [i].y.s.ms = (int) (src_y >> 16);
X exp_table [i].y.s.ls = 0;
X
X /*
X * Randomly select a destination that is inside the ellipse with
X * X and Y radii of (Xsize, Ysize).
X */
X do
X {
X dest_x = rnd (2*Xsize) - Xsize;
X dest_y = rnd (2*Ysize) - Ysize;
X } while ((long) Ysize * Ysize * dest_x * dest_x +
X (long) Xsize * Xsize * dest_y * dest_y
X > (long) Ysize * Ysize * Xsize * Xsize);
X
X /* Convert to fixed pt. Can't use shifts because they are unsigned */
X dest_x = (dest_x + cx) * 65536;
X dest_y = (dest_y + cy) * 65536;
X
X /*
X * accel = 2 * distance / #steps^2 (#steps is equivalent to time)
X * vel = accel * #steps
X */
X accel = (2 * (dest_x - src_x)) / ((long) NUM_FRAMES*NUM_FRAMES);
X vel = (2 * (dest_x - src_x)) / (long) NUM_FRAMES;
X exp_table [i].xa.l = -accel + Wind;
X exp_table [i].xv.l = vel;
X
X accel = (2 * (dest_y - src_y)) / ((long) NUM_FRAMES*NUM_FRAMES);
X vel = (2 * (dest_y - src_y)) / (long) NUM_FRAMES;
X exp_table [i].ya.l = -accel + Gravity;
X exp_table [i].yv.l = vel;
X }
X *centre_x = cx;
X *centre_y = cy;
X}
X
X
X/*====================================================================
X * Return a random number between 1..maxval
X *====================================================================
X */
Xint
Xrnd (maxval)
X{
X# define MAX_RAND 32767 /* max val returned by rand() */
X long l;
X
X l = (long) maxval * (rand()&MAX_RAND) / MAX_RAND;
X return ((int) l);
X}
X
X
X
X
X/*=====================================================================
X * tty video routines - replaces the code in the PC version's expa.asm
X *=====================================================================
X */
Xint_handler()
X{
X signal(SIGINT, SIG_IGN);
X mvcur(0, COLS-1, LINES-1, 0);
X endwin();
X exit(0);
X}
Xgr_setcard()
X{
X}
Xgr_card()
X{
X srand (getpid());
X return ('t');
X}
Xgr_gmode()
X{
X char *getenv();
X char *sp;
X
X initscr();
X if (isatty(0))
X {
X gettmode();
X if (sp=(char*)getenv("TERM")) setterm(sp);
X }
X else
X setterm(Def_term);
X signal (SIGINT, int_handler);
X noecho();
X nonl();
X leaveok(stdscr, FALSE);
X scrollok(stdscr, FALSE);
X}
X
Xgr_tmode()
X{
X clear();
X move (0, 0);
X refresh();
X endwin();
X signal(SIGINT, SIG_IGN);
X}
X
Xgr_frplot(np, frame, centre, plotval)
Xint np;
Xcoord_type frame[];
Xcoord_type *centre;
Xchar plotval;
X{
X int i, x, y;
X for (i=0; i<Num_points; i++)
X {
X x = frame[i].x + centre->x;
X y = frame[i].y + centre->y;
X move (y,x);
X addch (plotval);
X }
X refresh();
X}
X
END_OF_FILE
if test 19482 -ne `wc -c <'ttyexp.c'`; then
echo shar: \"'ttyexp.c'\" unpacked with wrong size!
fi
# end of 'ttyexp.c'
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have the archive.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0