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