DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T s

⟦c54dca274⟧ TextFile

    Length: 10615 (0x2977)
    Types: TextFile
    Names: »sparks.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/X/Qix/sparks.c« 

TextFile

#include "qix.h"

/*
 * This file deals with the sparks excplicitely.  A fuse is a spark, but
 * travels along the the line the user is drawing.
 */

#ifdef X11
#include	"spark1.pr.xbm"
#include	"spark2.pr.xbm"
#include	"spark3.pr.xbm"
#include	"spark4.pr.xbm"

struct image_stuff {
    Pixmap *image;
    int w, h;
    char *bits;
};
static Pixmap spark_icons[4];

static struct image_stuff sparx[] = {
    { &spark_icons[0], spark1_pr_width, spark1_pr_height, spark1_pr_bits },
    { &spark_icons[1], spark2_pr_width, spark2_pr_height, spark2_pr_bits },
    { &spark_icons[2], spark3_pr_width, spark3_pr_height, spark3_pr_bits },
    { &spark_icons[3], spark4_pr_width, spark4_pr_height, spark4_pr_bits },
};

init_sparx()
{
    int i, w, h;
    Pixmap pix;
    int scr = DefaultScreen(dpy);

    for (i = 0; i < sizeof(sparx) / sizeof (struct image_stuff); i++)
	if (!(*sparx[i].image = XCreatePixmapFromBitmapData(dpy, draw_win,
	    sparx[i].bits, sparx[i].w, sparx[i].h,
	    BlackPixel(dpy, scr), WhitePixel(dpy, scr),
	    DefaultDepth(dpy, scr))))
	    perror("init_sparx"), exit(1);
}

#else

short spark1_dat[] = {
#include "spark1.pr"
};
mpr_static(spark1,     16, 16, 1, spark1_dat);

short spark2_dat[] = {
#include "spark2.pr"
};
mpr_static(spark2,     16, 16, 1, spark2_dat);

short spark3_dat[] = {
#include "spark3.pr"
};
mpr_static(spark3,     16, 16, 1, spark3_dat);

short spark4_dat[] = {
#include "spark4.pr"
};
mpr_static(spark4,     16, 16, 1, spark4_dat);

static Pixrect *spark_icons[4] = { &spark1, &spark2, &spark3, &spark4 };
#endif /* X11 */

static int spark_time, aggressive;

/*
 * Macor to draw a spark at x,y -- intended to call this macro twice with
 * the same x,y coords to remove the first spark icon. There are four spark
 * icons to give a "sparkling" effect when it moves. Since sparks can only
 * move left-right or up-down the formula given finds which icon to use to
 * to guarantee that it's not the last one used.
 */
#ifdef X11
#define draw_spark(x, y, color) 	\
    XCopyArea(dpy, spark_icons[(x+y)&3], draw_win, xor_gc, 0, 0, \
	      16, 16, pen_coord_x(x), pen_coord_y(y))
#else
#define draw_spark(x, y, color) 	\
    pw_rop(draw_win, pen_coord_x(x), pen_coord_y(y), 16,16, \
	XOR| PIX_COLOR(color), spark_icons[(x + y) & 3], 0,0)
#endif /* X11 */

struct spark {
    int x, y, oldx, oldy;
} sparks[] = {
    { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 },
    { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 },
    { -1, -1, -1, -1 }, { -1, -1, -1, -1 }
};
int MAX_SPARKS = sizeof (sparks) / sizeof (struct spark);

#define CLOCKWISE(spark_number) (spark_number & 1)

/* start a new spark at this x,y coord.  Since sparks are released in
 * pairs, odd spark goes left, even spark goes right, and those directions
 * are [supposed] to remain with the spark thruout its life.
 */
start_spark(x, y)
{
    register int sp;

#ifdef DEBUG
    if (debug > 1)
	return;
#endif DEBUG

    for (sp = 0; sp < MAX_SPARKS; sp++)
	if (sparks[sp].x < 0) {
	    if (CLOCKWISE(sp)) /* odd number spark */
		sparks[sp].oldx = x-1, sparks[sp].oldy = y;
	    else
		sparks[sp].oldx = x+1, sparks[sp].oldy = y;
	    sparks[sp].x = x, sparks[sp].y = y;
	    return;
	}
}

/*
 * Spark movement checks... can't move back onto himself... must only move
 * onto a square which has a connecting line.  If it's on a square which
 * is completely painted, it may move anywhere.  Otherwise, the square has
 * to have at least one quad which is not painted.  Sparks may only move
 * on "old" (not currently being drawn) lines unless they are aggressive.
 */
#define check_up(curx, cury, newx, newy, oldy) \
    (newy != oldy && (board[curx][cury] & CL_LN_UP) && \
    (aggressive || (board[newx][newy] & OLD_LINE) && \
    (!check_painted(newx, newy, PAINTED) || check_painted(curx, cury,PAINTED))))

#define check_down(curx, cury, newx, newy, oldy) \
    (newy != oldy && (board[curx][cury] & CL_LN_DN) && \
    (aggressive || (board[newx][newy] & OLD_LINE) && \
    (!check_painted(newx, newy, PAINTED) || check_painted(curx, cury,PAINTED))))

#define check_left(curx, cury, newx, newy, oldx) \
    (newx != oldx && (board[curx][cury] & CL_LN_LF) && \
    (aggressive || (board[newx][newy] & OLD_LINE) && \
    (!check_painted(newx, newy, PAINTED) || check_painted(curx, cury,PAINTED))))

#define check_right(curx, cury, newx, newy, oldx) \
    (newx != oldx && (board[curx][cury] & CL_LN_RT) && \
    (aggressive || (board[newx][newy] & OLD_LINE) && \
    (!check_painted(newx, newy, PAINTED) || check_painted(curx, cury,PAINTED))))

/* return -1 if player dies.  0 otherwise. */
move_sparks()
{
    register int x, y, sp, move_clockwise, came_from, dir;
    /* new spark x and y coord */

    pw_putattributes(draw_win, &qix_mask);
    for (sp = 0; sp < MAX_SPARKS; sp++) {
	if (sparks[sp].x < 0)
	    break;
	/* if the spark was just introduced, this will not erase the spark,
	 * but actually create two images.  however, since sparks are intro-
	 * duced in pairs, the second spark will have the same coords and
	 * erase this mark. (clever, huh?)
	 */
	draw_spark(sparks[sp].x, sparks[sp].y,
		   aggressive? AGGR_SPARK_COLOR : SPARKS_COLOR);
	x = sparks[sp].x, y = sparks[sp].y;
	/* user bit the big one */
	if (x == pen_x && y == pen_y) {
	    draw_spark(sparks[sp].x, sparks[sp].y,
		   aggressive? AGGR_SPARK_COLOR : SPARKS_COLOR);
	    change_life(DIE);
	    return -1;
	}

	came_from = (x > sparks[sp].oldx)? LEFT :
		    (x < sparks[sp].oldx)? RIGHT :
		    (y > sparks[sp].oldy)? UP : DOWN;
	if (check_painted(x, y, PAINTED))
	    move_clockwise = (random() & 1);
	else {
	    move_clockwise = (CLOCKWISE(sp));
	    if (check_painted(sparks[sp].oldx, sparks[sp].oldy, PAINTED))
	    /* we just exited a painted region onto open territory.
	     * pretend we came from along a border, as usual.
	     */
		while (came_from == UP && check_painted(x,y, CL_PNT_TOP) ||
		       came_from == DOWN && check_painted(x,y, CL_PNT_BOT) ||
		       came_from == LEFT && check_painted(x,y, CL_PNT_LEFT) ||
		       came_from == RIGHT && check_painted(x,y, CL_PNT_RIGHT))
		    if (CLOCKWISE(sp))
			came_from = LEFT_OF(came_from);
		    else
			came_from = RIGHT_OF(came_from);
	}
	dir = came_from;

	/* if we are not on a border (surrounded by painted quads) */
	do  {
	    if (move_clockwise)
		dir = LEFT_OF(dir); /* this is right, don't argue */
	    else
		dir = RIGHT_OF(dir);
#ifdef DEBUG
	    if (dir == came_from) {
		box(convert_x(x)-10, convert_y(y)-10,
		    convert_x(x)+10, convert_y(y)+10, XOR);
		msg("HALT! infinite-loop police! [y] (%d, %d)", x, y);
		Sleep(2);
		remove_msgs(0);
		box(convert_x(x)-10, convert_y(y)-10,
		    convert_x(x)+10, convert_y(y)+10, XOR);
		break;
	    }
#endif DEBUG
	    switch (dir) {
		when LEFT:
		    if (check_left(x, y, x - 1, y, sparks[sp].oldx))
			x--;
		when RIGHT:
		    if (check_right(x,y,x+1,y,sparks[sp].oldx))
			x++;
		when UP:
		    if (check_up(x,y,x,y-1,sparks[sp].oldy))
			y--;
		when DOWN:
		    if (check_down(x, y, x, y+1, sparks[sp].oldy))
			y++;
	    }
	} while (x == sparks[sp].x && y == sparks[sp].y);

	sparks[sp].oldx = sparks[sp].x, sparks[sp].oldy = sparks[sp].y;
	/* draw the new spark */
	draw_spark(x, y, aggressive? AGGR_SPARK_COLOR : SPARKS_COLOR);
	sparks[sp].x = x, sparks[sp].y = y;

	if (x == pen_x && y == pen_y) {
	    change_life(DIE);
	    return -1;
	}
    }
    /* if the timeout has occured, release two sparks */
    if (spark_time-- <= 0) {
	spark_time = SPARK_TIME;
	if (sp >= MAX_SPARKS/2) {
	    if (!aggressive) {
		/* give the only warning we can without a sound chip :-) */
		fputc(7, stderr), fflush(stderr);
		msg("Sparx are now aggressive.");
		Sleep(2);
		remove_msgs(0);
		/* erase red sparks now or blue sparks will leave green */
		toggle_sparks();
		aggressive = 1;
		/* now draw blue sparks */
		toggle_sparks();
	    }
	    if (sp == MAX_SPARKS) {
		return 0; /* no sparks left to start, so don't do a countdown */
	    }
	}
	start_spark(BOARD_WIDTH/2, 0);
	start_spark(BOARD_WIDTH/2, 0);
	draw(BORDER, 20, BOARD_WIDTH_IN_PIXELS-BORDER, 20, 
		PIX_SRC|PIX_COLOR(SPARKS_COLOR));
	draw(BORDER, 21, BOARD_WIDTH_IN_PIXELS-BORDER, 21, 
		PIX_SRC|PIX_COLOR(SPARKS_COLOR));
    }
    if (sp < MAX_SPARKS) {
	/* calculate the percentage of the width of the board in pixels */
	register int len = (((spark_time*100)/SPARK_TIME)) *
	       (BOARD_WIDTH_IN_PIXELS-2*BORDER)/200;

	draw(BORDER, 20, BOARD_WIDTH_IN_PIXELS/2 - len, 20, PIX_CLR);
	draw(BORDER, 21, BOARD_WIDTH_IN_PIXELS/2 - len, 21, PIX_CLR);
	draw(BOARD_WIDTH_IN_PIXELS/2 + len, 20,
	     BOARD_WIDTH_IN_PIXELS-BORDER, 20, PIX_CLR);
	draw(BOARD_WIDTH_IN_PIXELS/2 + len, 21,
	     BOARD_WIDTH_IN_PIXELS-BORDER, 21, PIX_CLR);
    }
    return 0;
}

/*
 * move fuse -- first, remove the last location (if applicable). If
 * the fuse has burned out, then programmer just wants to erase last one.
 * next, since the fuse only travels along new lines, move down the list.
 */
move_fuse(pos)
register struct region **pos;
{
    static x = -1, y;
    int n;

    /* fuse is always red */
    pw_putattributes(draw_win, &qix_mask);
    if (x > -1)
	draw_spark(x, y, SPARKS_COLOR);
    if (!pos || !*pos) {
	x = -1;
	return 0;
    }
    draw_spark((*pos)->x, (*pos)->y, SPARKS_COLOR);
    x = (*pos)->x, y = (*pos)->y;

    if ((*pos)->x == pen_x && (*pos)->y == pen_y) {
	change_life(DIE);
	pen_x = region->x, pen_y = region->y;
	return -1;
    }
    if (!(*pos = (*pos)->next))
	*pos = NULL, x = -1;
    return 0;
}

/*
 * removes all sparks from the screen and their x/y coords.
 * reset the sparktime value and draw the timeout line.
 */
clear_sparks()
{
    int n;

    pw_putattributes(draw_win, &qix_mask);
    /* for each spark, if active, make it go away and reset to -1 */
    for (n = 0; n < MAX_SPARKS; n++)
	if (sparks[n].x > -1) {
	    draw_spark(sparks[n].x, sparks[n].y,
			aggressive? AGGR_SPARK_COLOR : SPARKS_COLOR);
	    sparks[n].oldx = sparks[n].x = -1;
	}
    draw(BORDER, 20, BOARD_WIDTH_IN_PIXELS-BORDER, 20, PIX_CLR);
    draw(BORDER, 21, BOARD_WIDTH_IN_PIXELS-BORDER, 21, PIX_CLR);
    aggressive = spark_time = 0;
}

/* routine to turn on/off all sparks.  When user closes a region, call
 * this routine to turn off sparks so when the region is filled, the
 * spark doesn't leave it's mark once it starts moving again.
 */
toggle_sparks()
{
    register int sp;

    pw_putattributes(draw_win, &qix_mask);
    for (sp = 0; sp < MAX_SPARKS; sp++) {
	if (sparks[sp].x < 0)
	    break;
	draw_spark(sparks[sp].x, sparks[sp].y,
	    aggressive? AGGR_SPARK_COLOR : SPARKS_COLOR);
    }
}