[comp.sources.games] v01i055: sdi - missle command game for Suns, Part02/06

games-request@tekred.UUCP (06/17/87)

Submitted by: Mark Weiser <weiser.pa@xerox.com>
Comp.sources.games: Volume 1, Issue 55
Archive-name: sdi/Part02



#! /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 2 (of 6)."
# Contents:  TODO circles.c cities.c input.c main.c missile.c
#   pr_helpers.c sdi.man
# Wrapped by billr@tekred on Wed Jun 17 11:20:43 1987
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f TODO -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"TODO\"
else
echo shar: Extracting \"TODO\" \(748 characters\)
sed "s/^X//" >TODO <<'END_OF_TODO'
X1. use rops into a single pixel for more efficient work in melting?
X2. turn off clipping for all rops to run faster?  (perhaps use a big canvas
X   under the window, so all blasts, etc. will fit in the canvas even
X   if not in the window).
X4. Originally the idea was for this to be a networked game, with
X   one person shooting missiles and the other blasting them down. Do this.
X7. warp all popups to fit on screen.
X8. make the different kinds of blast be pretty in color.
X11. have little launching sites that open up.
X12. have the save file save more things, like the city icon used.
X16. Have an ifdef to eliminate pies.
X17. Have a .sdirc, which points to a save_game file.
X18. Mirv at other times than the top of the city window.
X22. fix scores.
END_OF_TODO
if test 748 -ne `wc -c <TODO`; then
    echo shar: \"TODO\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f circles.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"circles.c\"
else
echo shar: Extracting \"circles.c\" \(6673 characters\)
sed "s/^X//" >circles.c <<'END_OF_circles.c'
X/*********************************  circles.c  ************************/
X#include <pixrect/pixrect_hs.h>
X#include <stdio.h>
X#include "sdi.h"
X
X/*
X * Copyright 1987 by Mark Weiser.
X * Permission to reproduce and use in any manner whatsoever on Suns is granted
X * so long as this copyright and other identifying marks of authorship
X * in the code and the game remain intact and visible.  Use of this code
X * in other products is reserved to me--I'm working on Mac and IBM versions.
X */
X
X/*
X * Here be everything associated with drawing circles, especially
X * all the different kinds of blasts (which are done by clipping
X * different pixrects to different shapes of circles.)  All the
X * blast pixrects are precomputed for every size to save time during
X * game display updating.
X */
X
Xstatic short default_laser_blast[] = {
X#include "laser.h"
X};
Xmpr_static(laser_blast_pr, 64, 64, 1, default_laser_blast);
X
Xstatic short default_laser_kill[] = {
X#include "laserkill.h"
X};
Xmpr_static(laser_kill_pr, 64, 64, 1, default_laser_kill);
X
X
Xstatic short default_city_blast[] = {
X#include "mushroom.h"
X};
Xmpr_static(city_blast_pr, 64, 64, 1, default_city_blast);
X
Xstatic short default_missile_kill[] = {
X#include "missilekill.h"
X};
Xmpr_static(missile_kill_pr, 64, 64, 1, default_missile_kill);
X
Xstatic short default_rocks[] = {
X#include "rocks.h"
X};
Xmpr_static(rocks_pr, 64, 64, 1, default_rocks);
X
Xstruct pixrect	*circles[MAX_NUM_CIRCLES];
Xstruct pixrect	*limited_circles[MAX_NUM_CIRCLES];
Xstruct pixrect	*rock_limited_circles[MAX_NUM_CIRCLES];
X
Xstatic struct {
X	int x, y;
X	} center = { 0, 0 };
X
Xstatic struct fill_line  {
X   int	left;
X   int	right;
X   int	y;
X}		 scan_lines[MAX_LINES], *free_line;
X
Xstatic void circle_fill_pair(), circle_fill();
X
X
X#define LIMIT(n) (((n) < 0) ? 0 : (((n) >= MAX_LINES) ? MAX_LINES-1 : (n)))
X
Xinit_circles()
X{
X	int i, size = 2*CIRCLE_SIZE_INC;
X	int limited_size = (MAX_NUM_CIRCLES-4)*CIRCLE_SIZE_INC + size;
X	int rock_limited_size = 2*CIRCLE_SIZE_INC + size;
X	for (i=0; i < MAX_NUM_CIRCLES; i++) {
X		if (size > MAX_CIRCLE)
X			size = MAX_CIRCLE;
X		circles[i] = make_circle(size);
X		limited_circles[i] = make_circle(size > limited_size ? limited_size : size);
X		rock_limited_circles[i] = make_circle(size > rock_limited_size ? rock_limited_size : size);
X		size += CIRCLE_SIZE_INC;
X	}
X	blankcircles =  circles;
X	lasercircles = init_circ(3, circles);
X	laserkillcircles = init_circ(3, circles);
X	bigblastcircles = init_circ(MAX_NUM_CIRCLES, circles);
X	littleblastcircles = init_circ(MAX_NUM_CIRCLES-2, limited_circles);
X	blastkillcircles = init_circ(MAX_NUM_CIRCLES-3, circles);
X	citykillcircles = init_circ(MAX_NUM_CIRCLES, circles);
X	littlerockcircles = init_circ(4, rock_limited_circles);
X	bigrockcircles = init_circ(7, rock_limited_circles);
X	change_circ(lasercircles, &laser_blast_pr);
X	change_circ(laserkillcircles, &laser_kill_pr);
X	change_circ(citykillcircles, &city_blast_pr);
X	change_circ(blastkillcircles, &missile_kill_pr);
X	change_circ(littlerockcircles, &rocks_pr);
X	change_circ(bigrockcircles, &rocks_pr);
X}
X
X/*
X * Create a new circ structure, and initialize it to contain the pixrect
X * list 'c'.
X */
Xstruct circ *
Xinit_circ(n, c)
Xstruct pixrect **c;
X{
X	struct circ *r;
X	r = (struct circ *)calloc(sizeof(struct circ), 1);
X	r->masks = r->circles = c;
X	r->num_circles = n;
X	return r;
X}
X
X/*
X * Routine to replace a list of pixrects in a circ structure with a new
X * list.  The new list is constructed by 'and'ing parameter p with
X * circles of the diameter contained in the old list.  This is the
X * basic routine used to construct all the different kinds of blasts.
X * 
X * Calling change_circ several times on the same circ structure
X * will waste memory because the calloc from previous calls is
X * never freed, nor are the pixrects.  It is not much memory, and nothing will die from it.
X */
Xchange_circ(c, p)
Xstruct circ *c;
Xstruct pixrect *p;
X{
X	int i;
X	struct pixrect **newcircles;
X	int size, psize;
X	newcircles = (struct pixrect **)calloc(sizeof(struct pixrect *),c->num_circles);
X	psize = p->pr_size.x;
X	for (i = 0; i < c->num_circles; i++) {
X		size = c->masks[i]->pr_size.x;
X		newcircles[i] = mem_create(size, size, 1);
X		pr_rop(newcircles[i], 0, 0, size, size, PIX_SRC, c->masks[i],
X			0, 0);
X		pr_rop(newcircles[i], 0, 0, size, size, PIX_SRC & PIX_DST,
X			p, psize/2 - size/2, psize/2 - size/2);
X	}
X	c->circles = newcircles;
X
X}
X
X/*
X * Build a black circle of the specified diameter, and return it in
X * a pixrect of just the right size to hold it.
X */
Xstruct pixrect *
Xmake_circle(diameter)
Xint diameter;
X{
X	struct pixrect *pr = mem_create(diameter, diameter, 1);
X	center.x = diameter/2;
X	center.y = diameter/2;
X	free_line = scan_lines;
X	circle_accept(pr, LIMIT((diameter/2)-2));
X	return pr;
X}
X
X/*
X * The routines below borrow ideas from the Sun Bresenham 
X * circle code in iconedit.
X */
X
X/*
X * Draw a circle inside pr, with length as given here, and with center as
X * set in global variable 'center'.
X */
Xcircle_accept(pr, length)
Xstruct pixrect *pr;
X{
X	int		d, x, y;
X
X	x = 0;
X	y = length;
X	d = 3 - 2*y;
X
X	while ( x < y ) {
X		circle_fill_pair(pr, x, y);
X		if (d < 0)
X			d += 4*x + 6;
X		else {
X			d += 4*(x-y) +10;
X			y -= 1;
X		}
X		x++;
X	}
X	if (x == y) {
X		circle_fill_pair(pr, x, y);
X	}
X	circle_fill(pr);
X}
X
Xstatic void
Xcircle_fill_pair(pr, x, y)
Xstruct pixrect *pr;
Xregister int	x, y;
X{
X	register struct fill_line *line_ptr = free_line;
X
X	free_line += 4;
X
X	line_ptr->left	= LIMIT(center.x - x);
X	line_ptr->right = LIMIT(center.x + x);
X	line_ptr->y	= LIMIT(center.y - y);
X
X	++line_ptr;
X	line_ptr->left  = LIMIT(center.x - y); 
X	line_ptr->right = LIMIT(center.x + y); 
X	line_ptr->y     = LIMIT(center.y - x);
X
X	++line_ptr;
X	line_ptr->left  = LIMIT(center.x - y);
X	line_ptr->right = LIMIT(center.x + y);
X	line_ptr->y     = LIMIT(center.y + x);
X
X	++line_ptr;
X	line_ptr->left  = LIMIT(center.x - x);
X	line_ptr->right = LIMIT(center.x + x);
X	line_ptr->y     = LIMIT(center.y + y);
X}
X
Xstatic int
Xcompare_lines(l1, l2)
X	register struct fill_line  *l1, *l2;
X{
X	if (l1->y < l2->y)
X		return -1;
X	else if (l1->y > l2->y)
X		return 1;
X	else if (l1->left < l2->left || l1->right > l2->right)
X		return -1;
X	else if (l1->left > l2->left || l1->right  <  l2->right)
X		return 1;
X	else return 0;
X}
X
Xstatic void
Xcircle_fill(pr)
Xstruct pixrect *pr;
X{
X	register struct fill_line *line_ptr = scan_lines;
X	register int		   len, y = -1;
X
X	qsort(scan_lines, free_line - scan_lines,
X		    sizeof(struct fill_line), compare_lines);
X	while (line_ptr < free_line)  {
X		register int	x0;
X
X		if (line_ptr->y != y) {
X			x0 = line_ptr->left;
X			y = line_ptr->y;
X			len = line_ptr->right - x0 + 1;
X			pr_vector(pr, x0, y, x0+len, y, PIX_SET, 1);
X		}
X		line_ptr++;
X	}
X}
END_OF_circles.c
if test 6673 -ne `wc -c <circles.c`; then
    echo shar: \"circles.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f cities.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"cities.c\"
else
echo shar: Extracting \"cities.c\" \(7166 characters\)
sed "s/^X//" >cities.c <<'END_OF_cities.c'
X/**********************************  cities.c  ************************/
X#include <pixrect/pixrect_hs.h>
X#include <sunwindow/notify.h>
X#include <stdio.h>
X#include "sdi.h"
X
X/*
X * Copyright 1987 by Mark Weiser.
X * Permission to reproduce and use in any manner whatsoever on Suns is granted
X * so long as this copyright and other identifying marks of authorship
X * in the code and the game remain intact and visible.  Use of this code
X * in other products is reserved to me--I'm working on Mac and IBM versions.
X */
X
X/*
X * Code to do things to cities.  Much of the code here consists of
X * passing a routine into doto_cities, which then calls that routine
X * on each city.  See the comment for doto_cities (near the end of the file)
X * for more information.
X */
X
Xstatic short default_city_data[] = {
X#include "default_city.h"
X};
Xmpr_static(default_city_pr, 64, 64, 1, default_city_data);
X
Xstatic struct pixrect *city_pr_ptr = &default_city_pr;
Xstatic colormap_t city_colormap, *city_colormap_ptr = NULL;
X
Xstatic short melted_city_data[] = {
X#include "melt.h"
X};
Xmpr_static(melted_city_pr, 64, 64, 1, melted_city_data);
X
X
X#define MIN_SPACE 4
X#define MAX_CITIES 40
X
Xstatic int city_space, excess, global_count;
Xstatic long bits_in_city;
X
Xstatic int do_update(), do_count(), do_placement(), do_kill(), 
X	   do_update_all(), do_grow(), do_update_cities(), do_melt_all(); 
X
Xstatic int cities_inited = 0;
Xstatic short cities[MAX_CITIES];
X
X
Xstatic int growcount;	/* ugh, another weird global.
X						 * set by do_update_cities, used only by 'do_grow'.
X						 */
X
X/*
X * Read a new city pixrect from a file.
X */
Xinit_city_bits(filename)
Xchar *filename;
X{
X	/* this routine is only called if there is non-default city. */
X	if (filename != NULL) {
X			char error_msg[256];
X			struct pixrect *tmp,*icon_load_mpr();
X			if ((tmp = icon_load_mpr(filename, error_msg)) == NULL) {
X				printf("Could not get pr '%s'.\n", filename);
X				printf("%s",error_msg);
X				printf("Using default cities.\n");
X			} else {
X				city_pr_ptr = tmp;
X			}
X	}
X}
X
X/*
X * Compute the positions of all the cities based on current screen size,
X * and declare all the cities to be unmelted.
X */
Xinit_cities()
X{
X	int i, old_num_cities = num_cities;
X	bits_in_city = count_bits(city_pr_ptr);
X	num_cities = ((max_x - MARGIN)/64) + 1;	/* bigger than possible */
X	city_space = 0;
X
X	while (city_space < MIN_SPACE) {
X		num_cities -= 1;
X		city_space = ((max_x - MARGIN) - (num_cities * 64))/(num_cities-1);
X	};
X	
X	excess = max_x - (MARGIN + 64*num_cities + city_space*(num_cities-1));
X	for (i=old_num_cities; i<num_cities; i++) {
X		cities[i] = 1;
X	}	
X	cities_inited = 1;
X}
X
X/*
X * display the cities, melted or otherwise.
X */
Xplace_cities(pw)
XPixwin *pw;
X{
X	pw_writebackground(pw, 0, max_y-8, max_x, max_y, PIX_NOT(PIX_SRC));
X	doto_cities(pw, do_placement, city_pr_ptr, 0);
X	doto_cities(pw, do_placement, &melted_city_pr, 1);
X}
X
X/* helper for 'place_cities', passed into 'doto_cities' */
Xstatic int
Xdo_placement(pr, city_pr)
Xstruct pixrect *pr, *city_pr;
X{
X	pr_rop(pr, 0, 0, 64, 64, PIX_SRC, city_pr, 0, 0);
X	return 1;	/* this forces the new city back into the pixwin */
X}
X
X/*
X * Pop a new city onto the display at a random empty position.
X */
Xnew_city(pw)
XPixwin *pw;
X{
X	int pick, num_gone = 0, i;
X	for (i=0; i < num_cities; i += 1) {
X		if (!cities[i])
X			num_gone += 1;
X	}
X	if (num_gone == 0)
X		return;
X	pick = (random() % num_gone) + 1;
X	for (i=0; i < num_cities; i += 1) {
X		if (!cities[i] && !--pick)
X			break;
X	}
X	/* restore a random melted city */
X	cities[i] = 1;
X	do_update_cities(pw, 1, do_grow);
X}
X
X/* helper for do_update_cites, grow a city. */
Xstatic int
Xdo_grow(pr, speed)
Xstruct pixrect *pr;
X{
X	grow(pr, city_pr_ptr, growcount+16);
X	return 1;
X}
X
X/* return how many died */
Xstatic int global_citycount;
Xcompute_cities(pw)
XPixwin *pw;
X{
X	global_citycount = 0;
X	doto_cities(pw, do_count, 0, 0);
X	return global_citycount;
X}
X
X/* helper for 'compute_cities', passed into 'doto_cities' */
Xstatic int
Xdo_count(pr, client)
Xstruct pixrect *pr;
Xint *client;
X{
X	if (city_dead(pr)) {
X		global_citycount += 1;
X	}
X	return 0;	/* avoids pw_write in doto_cities */
X}
X
X/*
X * Melt or grow each city, as appropriate.
X */
Xupdate_cities(pw, speed)
X{
X	do_update_cities(pw, speed, do_update);
X	doto_cities(pw, do_kill, 0, 0);
X}
X
X/* helper for 'update_cities', passed to 'do_update_cities', grows or melts. */
Xstatic int
Xdo_update(pr, speed)
Xstruct pixrect *pr;
Xint speed;
X{
X	if (city_dead(pr)) {
X		melt(pr, &melted_city_pr, speed);
X		return 1;	
X	} else {
X		grow(pr, city_pr_ptr, growcount+16);
X		return 1;   
X	}
X}
X
X/* Helper for 'update_cities', passed into doto_cities, computes dead cities. */
Xstatic int
Xdo_kill(pr, tmp)
Xstruct pixrect *pr;
X{
X	if (city_dead(pr))
X		cities[global_count] = 0;
X	return 0;
X}
X
X/* Do what it says. */
Xmelt_all_cities(pw, speed)
X{
X	do_update_cities(pw, speed, do_melt_all);
X}
X
X
X/* helper for 'melt_all_cities', passed into 'do_update_cities' */
Xstatic int
Xdo_melt_all(pr, speed)
Xstruct pixrect *pr;
Xint speed;
X{
X	melt(pr, &melted_city_pr, speed);
X	return 1;	/* forces writing out the melted city in doto_cities */
X}
X
X/*
X * Call function 'helper' numerous times on each city, thus causing
X * growing or melting (or both), depending upon 'helper'.
X */
Xstatic int
Xdo_update_cities(pw, speed, helper)
Xint (*helper)();
X{
X	int i;
X	int count = (64 / speed) + 1;
X	for (growcount = 1; growcount < count; growcount += 1) {
X		/* we might plausibly batch here, but the melt looks better without */
X		doto_cities(pw, helper, speed, 0);
X	}
X}
X
X/*
X   Cities are a kind of abstract datatype.  To do something to all
X   cities, pass a function and a piece of client data to 'doto_cities',
X   and the function will be called once for each city still in
X   existence (or if 'non-cities' is non-zero, once for each city NOT
X   still in existence.)  The calling sequence for the passed in
X   function will be:
X		func(pr, client_data);
X   where 'pr' is a 64x64 pixrect of a city.  If 'func' returns 0 then
X   'pr' is assumed to be unchanged, otherwise 'pr' is written back into
X   the pixwin so the change is visible. Global_count is set before the
X   call to the ordinal number of the city currently being operated on.
X
X   Init_cities must be called before any city operations.
X */
X
Xstatic char tmp_image_place[512];
Xmpr_static(tmpcity_pr, 64, 64, 1, tmp_image_place);
X
Xdoto_cities(pw, func, client_data, non_cities)
XPixwin *pw;
Xint (*func)();
Xint *client_data;
X{
X	int x = MARGIN/2 + excess/2, stop_x = max_x - MARGIN/2 - 64;
X	int y = max_y - 64;
X	if (! cities_inited) {
X		/* no return from here */
X		printf("'doto_cities called before 'init_cities'.\n");
X		abort();
X	}
X	global_count = 0;
X	while (x <= stop_x) {
X		if ((!non_cities && cities[global_count]) ||
X				(non_cities && !cities[global_count])) {
X			pw_read(&tmpcity_pr, 0, 0, 64, 64, PIX_SRC, pw, x, y);
X			if (func(&tmpcity_pr, client_data))
X				pw_write(pw, x, y, 64, 64, PIX_SRC, &tmpcity_pr, 0, 0);
X		}
X		global_count += 1;
X		x += 64 + city_space;
X	}
X}
X
X/*
X * See if a city is dead.  It is if 2/3's of its pixels are clobbered.
X */
Xcity_dead(pr)
Xstruct pixrect *pr;
X{
X	long bitcount = count_bits(pr);
X	if (bitcount < 2*bits_in_city/3)
X		return 1;
X	else return 0;
X}
X
END_OF_cities.c
if test 7166 -ne `wc -c <cities.c`; then
    echo shar: \"cities.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f input.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"input.c\"
else
echo shar: Extracting \"input.c\" \(7435 characters\)
sed "s/^X//" >input.c <<'END_OF_input.c'
X/************************************  input.c  *************************/
X#include <sunwindow/notify.h>
X#include <fcntl.h>
X#include <sys/ioctl.h>
X#include <stdio.h>
X#include <errno.h>
X#include "sdi.h"
X
X/*
X * Copyright 1987 by Mark Weiser.
X * Permission to reproduce and use in any manner whatsoever on Suns is granted
X * so long as this copyright and other identifying marks of authorship
X * in the code and the game remain intact and visible.  Use of this code
X * in other products is reserved to me--I'm working on Mac and IBM versions.
X */
X
X/*
X * interrupt handling is here, including mousing, resizing, etc.
X */
X
Xextern Panel launchpanel;
X
XNotify_value update_icon();
X
Xvoid
Xcanvas_resize_proc(canvas, width, height)
XCanvas canvas;
Xint width, height;
X{
X	void new_game_proc();
X	void draw_background();
X	struct pixwin *pw, *newpw;;
X
X	if (canvas == citycanvas || canvas == launchcanvas) {
X	    max_x = width-(2*FIELD_MARGIN)-4;
X	    max_y = height-(2*FIELD_MARGIN)-4;
X	    newpw = pw_region(canvas_pixwin(canvas), FIELD_MARGIN, FIELD_MARGIN,
X		    max_x, max_y);
X	}
X	/*
X	 * Can't do the pw_closes here, because lurking missiles may still
X	 * be depending on them.  So never do them--how many resizes are
X	 * there per game, anyway?
X	 */
X	if (canvas == citycanvas) {
X		/* pw_close(citypw); */
X		citypw = newpw;
X		num_cities = 0;
X		init_cities();
X	} else if (canvas == launchcanvas) {
X		/* pw_close(launchpw); */
X		launchpw = newpw;
X	}
X}
Xint running_icon_pictures = 0;
Xstatic int old_frame_width = -1, old_frame_height = -1;
X
X/*
X * This routine gets notifications even before SunView does.  Almost the first
X * thing it does is all 'notify_next_event_func', which lets SunView do
X * its work.  Resizes, opens, and closes are handled here.
X */
XNotify_value
Xsynch_event_proc(frame, event, arg, type)
XFrame frame;
XEvent *event;
XNotify_arg arg;
XNotify_event_type type;
X{
X	int new_game;
X	int closed;
X	static int oldclosed = 0;
X	Notify_value value;
X
X	/* send on the notification */
X	value = notify_next_event_func(frame, event, arg, type);
X
X	/* start post-processing */
X	closed = (int) window_get(frame, FRAME_CLOSED);
X	if (frame == controlframe) {
X		if ( closed && !oldclosed) {
X			/* not many events come in while closed,
X			 * so if we are closed, we are probably
X			 * just now closing.  Close everyone.
X			 */
X			window_set(cityframe, WIN_SHOW, FALSE,
X				0);
X			window_set(launchframe, WIN_SHOW, FALSE,
X				0);
X			if (running)
X				suspend_proc();
X			if (!running_icon_pictures) {
X				/* start the icon stuff */
X				running_icon_pictures = 1;
X				do_with_delay(update_icon, 0, 1);
X			}
X		} else if (!closed) {
X			/* opening control frame, and so show everybody */
X			if (! window_get(cityframe, WIN_SHOW))
X				window_set(cityframe, WIN_SHOW, TRUE, 0);
X			if (! window_get(launchframe, WIN_SHOW))
X				window_set(launchframe, WIN_SHOW, TRUE, 0);
X			if (running_icon_pictures) {
X				/* stop the icon stuff */
X				running_icon_pictures = 0;
X			}
X		}
X		oldclosed = closed;
X	} 
X	/* Check for a resize request.
X	   If either playing field is resized they both are.
X	 */
X	if (event_id(event) == WIN_RESIZE && 
X		(frame == cityframe || frame == launchframe)) {
X		int w = (int)window_get(frame, WIN_WIDTH);
X		int h = (int)window_get(frame, WIN_HEIGHT);
X		if ((old_frame_height == h && old_frame_width == w))
X			goto done;
X		if ((old_frame_height == -1 && old_frame_width == -1)
X			|| (!running)
X			|| popup_warning(frame, event, "Ok to restart game?")) {
X				new_game = 1;
X				old_frame_height = h;
X				old_frame_width = w;
X		} else {
X			new_game = 0;
X			h = old_frame_height;
X			w = old_frame_width;
X		}
X		/* can't get too small, or else things start to break. */
X		h = max(MINWIN, h);
X		w = max(MINWIN, w);
X		window_set(cityframe, WIN_WIDTH, w, WIN_HEIGHT, h, 0);
X		window_set(launchframe, WIN_WIDTH, w, WIN_HEIGHT, h, 0);
X		if (new_game)	{
X			/*
X			 * If resizing, it must be time to start a new game.
X			 */
X			do_with_delay(new_game_proc, 0, 100000);
X		}
X	}
Xdone:
X	return value;
X}
X
X/*
X * Handle mousing.
X */
X#define PINX(x) (max(0,min(max_x,x)))
X#define PINY(y) (max(0,min(max_y,y)))
X
Xstatic int rock_x = -1, rock_y;
XEvent rock_down_event;
X
Xvoid
Xmain_event_proc(window, event, arg)
XWindow window;
XEvent *event;
Xcaddr_t arg;
X{
X	extern Panel_item rock_item;
X	int times_around, offset, i;
X	int id = event_id(event);
X	int inc, left;
X	Pixwin *pw;
X
X	/*
X	 * The following totally silly call is a kludge to work-around
X	 * a Sun bug which, if we *don't* refuse the input focus, loses the 
X	 * middle-button down transition when we first are handed the input focus.
X	 */
X	if (event_id(event) == KBD_REQUEST) {
X		window_refuse_kbd_focus(window);
X		return;
X	}
X
X	if (! event_is_button(event)) return;
X	if (suspended) return;
X
X	if (window == citycanvas) {
X		pw = citypw;
X	} else {
X		pw = launchpw;
X	}
X
X	if (event_is_down(event)) {
X		if (!running) {
X			/* if not running, then try to start running. */
X			start_next_round();
X		} else {
X			switch(id) {
X			case MS_LEFT: {
X			    left = (int)panel_get_value(interceptor_item);
X			    if (left > 0) {
X					if (event_meta_is_down(event)) {
X						times_around = 2;
X						offset = event_shift_is_down(event) ? -31 : -20;
X					} else {
X						times_around = 1;
X						offset = 0;
X					}
X					for (i = 0; i < times_around; i += 1) {
X						if (event_shift_is_down(event)) {
X						    start_blast(PINX(event_x(event)+offset), event_y(event), 0, 0, pw, bigblastcircles);
X						} else {
X						    start_blast(PINX(event_x(event)+offset), event_y(event), 0, 0, pw, littleblastcircles);
X						}
X						offset = ABS(offset);
X					}
X				    panel_set_value(interceptor_item, left-times_around);
X					update_cursor();
X				} else {
X			    	need_a_bell = pw;
X			    }
X				break;
X			} 
X			case MS_RIGHT: {
X				left = (int)panel_get_value(laser_item);
X				if (left > 0) {
X					if (event_meta_is_down(event)) {
X						times_around = 2;
X						offset = event_shift_is_down(event) ? -100 : -64;
X					} else {
X						times_around = 1;
X						offset = 0;
X					}
X					for (i = 0; i < times_around; i += 1) {
X						if (event_shift_is_down(event)) {
X							start_laser(PINX(event_x(event)+offset), event_y(event), 
X								pw, 3, 256);
X						} else {
X							start_laser(PINX(event_x(event)+offset), event_y(event), 
X								pw, 6, 128);
X						}
X					offset = ABS(offset);
X					}
X					panel_set_value(laser_item, left-times_around);
X					update_cursor();
X				} else {
X					need_a_bell = pw;
X				}
X				break;
X			}
X			case MS_MIDDLE: {
X				left = (int)panel_get_value(rock_item);
X				if (left > 0) {
X					rock_x = event_x(event);
X					rock_y = event_y(event);
X					rock_down_event = *event;
X				} else {
X					rock_x = -1;
X					need_a_bell = pw;
X				}
X			}} /* end of switch */
X		}
X	} else if (/* implicit: event_is_up(event) && */
X			running && id == MS_MIDDLE && rock_x != -1) {
X		/* throw some rocks */
X		if (event_meta_is_down(&rock_down_event)) {
X			times_around = 2;
X			offset = -20;
X		} else {
X			times_around = 1;
X			offset = 0;
X		}
X		for (i = 0; i < times_around; i += 1) {
X			if (event_shift_is_down(&rock_down_event)) {
X				start_rocks(pw, rock_x, PINY(rock_y+offset),
X					event_x(event), PINY(event_y(event)+offset), 
X					3, bigrockcircles);
X			} else {
X				start_rocks(pw, rock_x, PINY(rock_y+offset),
X					event_x(event)+offset, PINY(event_y(event)+offset),
X					5, littlerockcircles);
X			}
X			offset = ABS(offset);
X		}
X		rock_x = -1;
X		panel_set_value(rock_item, panel_get_value(rock_item)-times_around);
X		update_cursor();
X	}
X}
END_OF_input.c
if test 7435 -ne `wc -c <input.c`; then
    echo shar: \"input.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"main.c\"
else
echo shar: Extracting \"main.c\" \(7400 characters\)
sed "s/^X//" >main.c <<'END_OF_main.c'
X/************************************  main.c  *************************/
X#include "sdi.h"
X
X/*
X * Copyright 1987 by Mark Weiser.
X * Permission to reproduce and use in any manner whatsoever on Suns is granted
X * so long as this copyright and other identifying marks of authorship
X * in the code and the game remain intact and visible.  Use of this code
X * in other products is reserved to me--I'm working on Mac and IBM versions.
X */
X
X/*
X * A big, long, initialization routine.
X */
X
Xstatic short cursor_data[] = {
X#include "cursor.h"
X};
Xmpr_static(cursor_pr, 16, 16, 1, cursor_data);
X
Xstatic short icon_image[] = {
X#include "city_icon1.h"
X};
XDEFINE_ICON_FROM_IMAGE(icon, icon_image);
X
Xstatic short i_pic_array[] = {
X#include "incoming_picture.h"
X};
Xmpr_static(incoming_pic, 16, 16, 1, i_pic_array);
X
Xstatic short g_pic_array[] = {
X#include "foe_ground_picture.h"
X};
Xmpr_static(foe_ground_pic, 16, 16, 1, g_pic_array);
X
Xstatic void done_proc();
Xextern void main_event_proc(), canvas_resize_proc();
Xextern Notify_value canvas_input_proc(), asynch_event_proc(), synch_event_proc();
XNotify_value scheduler(), input_notify();
X
X#define FONT_NAME "/usr/lib/fonts/fixedwidthfonts/serif.r.14"
X
Xstatic char tenblanks[] = "          ";
X
XPanel launchpanel;
X
X/*
X * In need of no comment:
X */
Xmain(argc, argv)
Xchar **argv;
X{
X	extern char *version;
X	Menu menu, null_menu_gen();
X	char tmp_string[128];
X	Panel controlpanel;
X	struct timeval tp;
X	char *s;
X
X	/* randomize us */
X	gettimeofday(&tp, 0);
X	srandom(tp.tv_sec);
X
X	/* init score file from environment, if possible */
X	if ((s = (char *)getenv("SDI_SCORES")) != NULL) 
X		scorefile = s;
X
X	init_circles();
X
X	init_city_bits(NULL);
X
X	fixup_font(&argc, &argv, FONT_NAME);
X
X	open_our_font(FONT_NAME);
X	sprintf(tmp_string, "   SDI Control Panel%s%s%s%s%sby mark weiser",
X		tenblanks,tenblanks,tenblanks,tenblanks,tenblanks);
X
X	s = (char *)get_name();
X	if (s && s[0] != '\0')
X		strcpy(user_name, s);
X
X	/* no background pre-write to our icon--otherwise we flicker. */
X	icon.ic_flags = 0;
X
X	/* make the control window, which serves as the base for all others. */
X	controlframe = window_create(NULL, FRAME,
X		FRAME_ARGC_PTR_ARGV, &argc, argv,
X		FRAME_LABEL, tmp_string,
X		FRAME_ICON, &icon,
X		WIN_ERROR_MSG, "Can't create window.",
X		WIN_FONT, font,
X		WIN_X, 0, WIN_Y, 0, /* start at zero, move later. */
X		0);
X
X	process_args(argc, argv);
X
X	init_icons();
X
X	build_playing_fields();
X
X	controlpanel = window_create(controlframe, PANEL, 
X		WIN_VERTICAL_SCROLLBAR, scrollbar_create(0), /* but provide a loophole */
X		PANEL_LABEL_FONT, font,
X		PANEL_VALUE_FONT, font,
X		WIN_FONT, font,
X		WIN_ERROR_MSG, "Can't create window.",
X		/* magic numbers which seem to look good: */
X		WIN_WIDTH, 730,
X		PANEL_ITEM_X_GAP, 30,
X		PANEL_ITEM_Y_GAP, 15,
X		0);
X	init_control(controlpanel);
X	window_fit(controlpanel);
X	window_fit(controlframe);
X
X	city_fd = (int)window_get(citycanvas, WIN_FD);
X	launch_fd = (int)window_get(launchcanvas, WIN_FD);
X
X	max_x = (int)window_get(citycanvas, CANVAS_WIDTH);
X	max_y = (int)window_get(citycanvas, CANVAS_HEIGHT);
X
X	{ /* little block for a bunch of little variables */
X	struct screen screen;
X	int playwidth = (int)window_get(cityframe, WIN_WIDTH);
X	int controlwidth = (int)window_get(controlframe, WIN_WIDTH);
X	int controlheight = (int)window_get(controlframe, WIN_HEIGHT);
X	int center;
X	win_screenget(city_fd, &screen);
X	center =  screen.scr_rect.r_width/2;
X
X	/* put the playing frames into position (control is at 0,0) */
X	window_set(cityframe, WIN_X, center - playwidth, 0);
X	window_set(launchframe, WIN_X, center, 0);
X
X	/* center the control frame */
X	window_set(controlframe, WIN_X, center - controlwidth/2, 
X		/* magic number which seems to look good: */
X		WIN_Y, 200, 0);
X
X	/* put the playing frames below it. */
X	window_set(cityframe, WIN_Y, controlheight, 0);
X	window_set(launchframe, WIN_Y, controlheight, 0);
X	} /* end of little block */
X
X	/*
X	 * menus in the playing fields are a distraction, but
X	 * they can't be just menu-destroyed, because that leaves a
X	 * dangling pointer inside sunview (and a core dump). 
X	 * So instead, we cleverly(?) modify the menu so that it will 
X	 * generate an empty contents.
X	 * (Ychhhh!)
X	 */
X	menu = window_get(launchframe, WIN_MENU);
X	menu_set(menu, MENU_GEN_PROC, null_menu_gen, 0);
X	menu = window_get(cityframe, WIN_MENU);
X	menu_set(menu, MENU_GEN_PROC, null_menu_gen, 0);
X
X	notify_interpose_event_func(launchframe, synch_event_proc, NOTIFY_SAFE);
X	notify_interpose_event_func(cityframe, synch_event_proc, NOTIFY_SAFE);
X	notify_interpose_event_func(controlframe, synch_event_proc, NOTIFY_SAFE);
X
X	notify_set_scheduler_func(scheduler);
X
X	notify_set_input_func(citycanvas, input_notify, city_fd);
X	notify_set_input_func(launchcanvas, input_notify, launch_fd);
X
X	init_cursor();
X	update_cursor();
X
X	window_main_loop(controlframe);
X	exit(0);
X}
X
Xstatic void
Xdone_proc(frame)
XFrame frame;
X{
X	/* do nothing */
X}
X
Xbuild_playing_fields()
X{
X	Panel citypanel;
X	extern Panel_item foe_ground_item;
X
X	cityframe = window_create(controlframe, FRAME,
X		FRAME_LABEL, "   SDI Friend Cities",
X		FRAME_SHOW_LABEL, TRUE,
X		FRAME_DONE_PROC, done_proc,
X		WIN_ERROR_MSG, "Can't create window.",
X		WIN_FONT, font,
X		FRAME_SUBWINDOWS_ADJUSTABLE, FALSE,
X		0);
X
X	citypanel = window_create(cityframe, PANEL, 0);
X	ballistic_item = panel_create_item(citypanel, PANEL_SLIDER,
X		ATTR_LIST, panel_common,
X		PANEL_LABEL_STRING, "Incoming missiles: ",
X		0);
X	window_fit_height(citypanel);
X
X	citycanvas = window_create(cityframe, CANVAS,
X		WIN_CONSUME_PICK_EVENTS, WIN_UP_EVENTS,  0,
X		WIN_EVENT_PROC, main_event_proc,
X		WIN_CURSOR, cursor_create(CURSOR_IMAGE, &cursor_pr,
X			CURSOR_XHOT, 8, CURSOR_YHOT, 8,
X			CURSOR_OP, PIX_SRC ^ PIX_DST,
X			0),
X		WIN_WIDTH, max_x+(2*FIELD_MARGIN), WIN_HEIGHT, max_y+(2*FIELD_MARGIN),
X		CANVAS_RESIZE_PROC, canvas_resize_proc,
X		CANVAS_RETAINED, TRUE,	/* need retained for city computations */
X		WIN_ERROR_MSG, "Can't create window.",
X		CANVAS_MARGIN, 0,
X		0);
X	window_fit(cityframe);
X	citypw = pw_region(canvas_pixwin(citycanvas), FIELD_MARGIN, FIELD_MARGIN, 
X		max_x, max_y);
X
X	launchframe = window_create(controlframe, FRAME,
X		FRAME_LABEL, "   SDI Foe Launch",
X		FRAME_SHOW_LABEL, TRUE,
X		FRAME_DONE_PROC, done_proc,
X		WIN_ERROR_MSG, "Can't create window.",
X		WIN_FONT, font,
X		FRAME_SUBWINDOWS_ADJUSTABLE, FALSE,
X		0);
X
X	launchpanel = window_create(launchframe, PANEL, 0);
X	foe_ground_item = panel_create_item(launchpanel, PANEL_SLIDER,
X		ATTR_LIST, panel_common,
X		PANEL_LABEL_STRING, "Missiles on the ground:", 
X		0);
X	window_fit_height(launchpanel);
X	launchcanvas = window_create(launchframe, CANVAS,
X		WIN_CONSUME_PICK_EVENTS, WIN_UP_EVENTS,  0,
X		WIN_EVENT_PROC, main_event_proc,
X		WIN_CURSOR, cursor_create(CURSOR_IMAGE, &cursor_pr,
X			CURSOR_XHOT, 8, CURSOR_YHOT, 8,
X			CURSOR_OP, PIX_SRC ^ PIX_DST,
X			0),
X		WIN_WIDTH, max_x+(2*FIELD_MARGIN), WIN_HEIGHT, max_y+(2*FIELD_MARGIN),
X		CANVAS_RESIZE_PROC, canvas_resize_proc,
X		CANVAS_RETAINED, TRUE,
X		WIN_ERROR_MSG, "Can't create window.",
X		CANVAS_MARGIN, 0,
X		0);
X
X	window_fit(launchframe);
X
X	launchpw = pw_region(canvas_pixwin(launchcanvas), FIELD_MARGIN, FIELD_MARGIN,
X		max_x, max_y);
X
X/*
X *	A noble sentiment, but too much trouble to handle resizing correctly.
X	window_set(launchcanvas, 
X		WIN_HEIGHT, window_get(launchcanvas, WIN_HEIGHT),
X		WIN_Y, 0,
X 		0);
X	window_set(launchpanel, WIN_BELOW, launchcanvas, 
X		0);
X
X*/
X
X	draw_background();
X
X}
END_OF_main.c
if test 7400 -ne `wc -c <main.c`; then
    echo shar: \"main.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f missile.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"missile.c\"
else
echo shar: Extracting \"missile.c\" \(7766 characters\)
sed "s/^X//" >missile.c <<'END_OF_missile.c'
X/**********************************  missile.c  ***********************/
X#include <pixrect/pixrect_hs.h>
X#include <sunwindow/notify.h>
X#include "sdi.h"
X
X/*
X * Copyright 1987 by Mark Weiser.
X * Permission to reproduce and use in any manner whatsoever on Suns is granted
X * so long as this copyright and other identifying marks of authorship
X * in the code and the game remain intact and visible.  Use of this code
X * in other products is reserved to me--I'm working on Mac and IBM versions.
X */
X
X/*
X * Code to start and update missiles lives here, including missiles
X * traveling between the two windows.  Launching of missiles
X * is done in incoming.c.
X */
X
Xstatic struct missile *m_head = NULL;
Xstatic Notify_value ballistic_timer();
X
X/*
X * Throw a missile onto a window. Only x is suppied, because direction
X * determines whether the missile starts at the top or bottom of the window.
X * Speed is in units of approximate pixels-per-timestep.  Direction
X * should be UP or DOWN, which are defined in sdi.h
X */
Xstart_missile(x, direction, speed, pw)
Xint x, direction, speed;
XPixwin *pw;
X{
X	struct missile *mid = (struct missile *)malloc(sizeof(struct missile));
X	int ratio, number_of_steps;
X	int final_x = (random() % (max_x - MARGIN)) + (MARGIN/2);
X
X	panel_set_value(foe_item, panel_get_value(foe_item) + 1);
X
X	mid->start_x = mid->x = x;
X	mid->speed = speed;
X	mid->refs = 1;
X	mid->destroyed = FALSE;
X
X	number_of_steps = max(1,(ABS(final_x - mid->start_x) + max_y)/speed);
X	mid->inc_x = (final_x - mid->start_x)/number_of_steps;
X	mid->inc_y = max_y/number_of_steps;
X	if (mid->inc_y < 1) {
X		mid->inc_y += 1;
X		mid->inc_x -= 1;
X	}
X
X	
X	/* I'm making this up as I go... */
X	{
X	    double desired = (double)(ABS(final_x - mid->start_x)/(double)max_y);
X	    double actual = (double)ABS(mid->inc_x)/(double)ABS(mid->inc_y);
X	    mid->slip = (double)1.0 / (desired - actual);
X	    mid->slip_cnt = 0;		
X	} 
X
X	if (direction == DOWN) {
X		mid->start_y = mid->y = 0;
X	} else {
X		mid->start_y = mid->y = max_y;
X		mid->inc_y = -mid->inc_y;
X	}
X	mid->pw = pw;
X			
X	inc_missile(mid);
X
X	missile_count++;
X	mid->next = m_head;
X	m_head = mid;
X}
X
X/*
X * Move a missile ahead and see if hits anything.
X * Helper routine passed into doto_missiles.
X */
Xupdate_missile(mid)
Xstruct missile *mid;
X{
X	inc_missile(mid);
X	if (intersect(mid)) {
X		start_blast(mid->x, mid->y, 0, 0, mid->pw, blastkillcircles);
X		destroy_missile(mid);
X		if (mid->pw == citypw)
X			bump_score(foe_value/5);
X		else bump_score(foe_value);
X	} else if (mid->inc_y > 0 && mid->y >= max_y-burst_distance) {
X		start_blast(mid->x, mid->y - 10, 0, 0, mid->pw, citykillcircles);
X		destroy_missile(mid);
X	} else if (mid->inc_y < 0 && mid->y <= 0) {
X		start_ballistic(mid->x, mid->speed);
X		destroy_missile(mid);
X	} else if (mid->x < 0 || mid->x > max_x) {
X		start_blast(mid->x, mid->y, 0, 0, mid->pw, blastkillcircles);
X		destroy_missile(mid);
X	}
X	return 0;
X}
X
X/*
X * Update the missile track.
X */
Xinc_missile(mid)
Xstruct missile *mid;
X{
X	/* Compute basic update */
X	mid->old_x = mid->x;
X	mid->old_y = mid->y;
X	mid->x += mid->inc_x;
X	mid->y += mid->inc_y;
X
X	/* Adjust skew for straighter lines */
X	if (mid->slip && ++mid->slip_cnt >= ABS(mid->slip)) {
X		mid->slip_cnt = 0;
X		if (mid->slip > 0) {
X			mid->x += 1;
X		} else {
X			mid->y += 1;
X		}
X	}
X
X	/* Draw missile trail */
X	pw_vector(mid->pw, mid->old_x-1, mid->old_y, mid->x-1, mid->y, PIX_SRC, 1);
X	pw_vector(mid->pw, mid->old_x, mid->old_y, mid->x, mid->y, PIX_SRC, 1);
X	pw_vector(mid->pw, mid->old_x+1, mid->old_y, mid->x+1, mid->y, PIX_SRC, 1);
X}
X
X/*
X * Get rid of a missile by erasing its track, removing it from
X * the missile display list, and freeing its structure.  Explosion
X * of the missile is the responsibility of the caller.
X */
Xdestroy_missile(mid)
Xstruct missile *mid;
X{
X	char buff[128];
X	struct rect r;
X
X	if (!mid->destroyed) {
X		panel_set_value(foe_item, panel_get_value(foe_item) - 1);
X		sprintf(buff, "%d", atol(panel_get_value(total_foe_item))+1);
X		panel_set_value(total_foe_item, buff);
X		mid->destroyed = TRUE;
X		pw_vector(mid->pw, mid->start_x - 2, mid->start_y,
X			mid->x - 2, mid->y,
X			PIX_NOT(PIX_SRC), 1);
X		pw_vector(mid->pw, mid->start_x - 1, mid->start_y,
X			mid->x - 1, mid->y,
X			PIX_NOT(PIX_SRC), 1);
X		pw_vector(mid->pw, mid->start_x, mid->start_y,
X			mid->x, mid->y,
X			PIX_NOT(PIX_SRC), 1);
X		pw_vector(mid->pw, mid->start_x + 1, mid->start_y,
X			mid->x + 1, mid->y,
X			PIX_NOT(PIX_SRC), 1);
X		pw_vector(mid->pw, mid->start_x + 2, mid->start_y,
X			mid->x + 2, mid->y,
X			PIX_NOT(PIX_SRC), 1);
X	
X		if (m_head == mid) {
X			m_head = mid->next;
X		} else {
X			struct missile *tmpmid = m_head;
X			while (tmpmid != NULL && tmpmid->next != mid) 
X				tmpmid = tmpmid->next;
X			if (tmpmid != NULL)
X				tmpmid->next = mid->next;
X		}
X		missile_count--;
X	}
X	if (--mid->refs == 0) {
X		free(mid);
X	}
X}
X
X/*
X * Update the score by 'inc', augmented by skill level.
X */
Xbump_score(inc)
X{
X	int score, skill;
X	float skill_multiplier;
X	char buf[128];
X	skill = (int)panel_get_value(skill_item);
X	switch (skill) {
X		case 0: skill_multiplier = 1.0; break;
X		case 1: skill_multiplier = 1.5; break;
X		case 2: skill_multiplier = 3; break;
X	}
X	score = atol(panel_get_value(score_item)) + (int)(((float)inc)*skill_multiplier);
X	sprintf(buf,"%d", score);
X	panel_set_value(score_item, buf);
X}
X
X/*
X * Call 'func' for missiles in the display list.  If func
X * returns non-zero, stop.  Search the missiles round-robin,
X * so we don't always find the same ones.
X */
Xdoto_missiles(func)
Xint (*func)();
X{
X	struct missile *ptr = m_head, *next;
X	while (ptr != NULL) {
X		next = ptr->next; /* in case 'func' destroys the missile */
X		(*func)(ptr);
X		ptr = next;
X	}
X}
X
X/*
X * Track a missile when traveling between windows.
X */
Xstruct ballistic_type {int x, speed};
Xstart_ballistic(x, speed)
X{
X	extern int ballistic_delay;
X	struct itimerval timer;
X	struct ballistic_type *xptr = (struct ballistic_type *)calloc(1,sizeof(struct ballistic_type));
X	int old_value = (int)panel_get_value(ballistic_item);
X	xptr->x = x;
X	xptr->speed = speed;
X	panel_set_value(ballistic_item, old_value + 1);
X	
X	if (old_value == 0) {
X		ballistic_warning();
X	}
X	timer.it_interval.tv_usec = 0;
X	timer.it_interval.tv_sec = 0;
X	timer.it_value.tv_usec = 0;
X	timer.it_value.tv_sec = ballistic_delay;
X	if (timer.it_value.tv_sec > 0) {
X		notify_set_itimer_func(xptr, ballistic_timer, ITIMER_REAL, &timer, NULL);
X	} else {
X		ballistic_timer(xptr, NULL);
X	}
X}
X
X/*
X * Called when the between-window flight time of a missile is up.
X */
Xstatic Notify_value
Xballistic_timer(xptr, which)
Xstruct ballistic_type *xptr;
Xint which;
X{
X	extern int ballistic_delay;
X	int val;
X	if (running) {
X		if (suspended) {
X			/* by rechecking at each in-flight interval for each missile, we
X			   approximate remembering when the real relaunch rate.
X			*/
X			suspendor(ballistic_timer, xptr, which, ballistic_delay);
X			return NOTIFY_DONE;
X		} else {
X			val = (int)panel_get_value(ballistic_item);
X			if (val > 0) {
X				/* Three new missiles appear. */
X				start_missile(xptr->x, DOWN, xptr->speed, citypw);
X				start_missile(xptr->x, DOWN, xptr->speed, citypw);
X				start_missile(xptr->x, DOWN, xptr->speed, citypw);
X				panel_set_value(ballistic_item, panel_get_value(ballistic_item)-1);
X			}
X		}
X	}
X	free(xptr);
X	return NOTIFY_DONE;
X}
X
X/*
X * Just what it says.
X */
Xfree_all_missiles()
X{
X	free_foe();
X	panel_set_value(ballistic_item, 0);
X	while(m_head != NULL)
X		destroy_missile(m_head);
X}
X
Xdo_warn_bell()
X{
X	struct timeval tv;
X	tv.tv_sec = 0;
X	tv.tv_usec = 20000;	/* very short bell */
X	win_bell(window_get(cityframe, WIN_FD), tv, 0);
X}
X
X#define WARN_INTERVAL 100000
X
Xballistic_warning()
X{
X	do_with_delay(do_warn_bell, 0, WARN_INTERVAL);
X	do_with_delay(do_warn_bell, 0, 2*WARN_INTERVAL);
X	do_with_delay(do_warn_bell, 0, 3*WARN_INTERVAL);
X}
END_OF_missile.c
if test 7766 -ne `wc -c <missile.c`; then
    echo shar: \"missile.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f pr_helpers.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"pr_helpers.c\"
else
echo shar: Extracting \"pr_helpers.c\" \(6495 characters\)
sed "s/^X//" >pr_helpers.c <<'END_OF_pr_helpers.c'
X/****************************  pr_helpers.c  *************************/
X#include <pixrect/pixrect_hs.h>
X
X/*
X * Copyright 1987 by Mark Weiser.
X * Permission to reproduce and use in any manner whatsoever on Suns is granted
X * so long as this copyright and other identifying marks of authorship
X * in the code and the game remain intact and visible.  Use of this code
X * in other products is reserved to me--I'm working on Mac and IBM versions.
X */
X
X/* These routines are pure pixrect operators, used mostly for city operations */
X
Xstatic short pattern[] = {
X	0x8000, 0x4000, 0x2000, 0x1000, 0x800, 0x400, 0x200, 0x100,
X	0x80,   0x40,   0x20,   0x10,   0x8,   0x4,   0x2,   0x1
X	};
Xstatic short *end_of_pattern_ptr = &pattern[16];
X
X
X#define lefthalf(x) (((x) & 0xff00) >> 8)
X#define righthalf(x) ((x) & 0xff)
X
X/*
X * Does an incremental melt of old into target, replacing
X * old, by dropping pixels down until they hit target
X * pixels.  Melts 'speed' pixels per call.  Old and target should be
X * memory pixrects.  Probably won't work as written for color.
X *
X * Pretty dumb and slow, undoubtedly could be done better.
X */
X
X/* alg: drop topmost pixels by speed pixels.  Any pixels which were on
X   in the old which matched on's in the target, still stay on.
X   Warning: the speed parameter does not work for any value but 1.
X */
X
X
Xmelt(old, target, speed)
Xstruct pixrect *old, *target;
Xint speed;
X{
X	short x_count, y_count, max_x, count, base = 0, bit_count;
X	int w = old->pr_size.x, h = old->pr_size.y;
X	struct pixrect *final;
X	struct mpr_data *mpr_final, *mpr_old;
X	short num_shorts, speed_inc;
X	short *old_image, *final_image;
X	unsigned short *remember_all_bits;
X	unsigned short *remember_bits, *bit_ptr;
X	register short *pattern_ptr, *old_image_ptr, *final_image_ptr;
X
X	if (w != target->pr_size.x || h != target->pr_size.y) {
X		/* never leave here */
X		printf("melt requires equal size pixrects.\n");
X		abort();
X	}
X
X	mpr_old = mpr_d(old);
X
X	if (mpr_old->md_offset.x != 0 || mpr_old->md_offset.y != 0) {
X		/* Never leave here */
X		printf("Can't handle region pixrects in 'melt'.\n");
X		abort();
X	};
X
X	final = mem_create(w, h, 1);
X
X	/* see if there is any work to do */
X	pr_rop(final, 0, 0, w, h, PIX_SRC, old, 0, 0);
X	pr_rop(final, 0, 0, w, h, PIX_NOT(PIX_SRC) & PIX_DST, target, 0, 0);
X	if (all_zero_bits(final)) {
X		pr_destroy(final);
X		return;
X	}
X	
X	/* remember what was ok from before */
X	pr_rop(final, 0, 0, w, h, PIX_SRC, old, 0, 0);
X	pr_rop(final, 0, 0, w, h, PIX_SRC & PIX_DST, target, 0, 0);
X	
X	/* melt some bits */
X
X	mpr_final = mpr_d(final);
X	num_shorts = mpr_final->md_linebytes / 2;
X	speed_inc = num_shorts*speed;
X	final_image = mpr_final->md_image;
X	old_image = mpr_old->md_image;
X	remember_all_bits = (unsigned short *)calloc(num_shorts+1, 2);
X	remember_bits = (unsigned short *)calloc(w+1, 2);
X
X	/* Melt the top */
X	for(y_count = 0; y_count < h - speed; y_count += 1) {
X		if (all_ones(remember_all_bits, num_shorts))
X			goto next;
X		bit_ptr = remember_bits;
X		old_image_ptr = &old_image[base];
X		final_image_ptr = &final_image[base];
X		for (x_count = 0; x_count < num_shorts; x_count += 1) {
X			remember_all_bits[x_count] |= *old_image_ptr;
X			for(pattern_ptr = pattern; pattern_ptr < end_of_pattern_ptr; pattern_ptr++) {
X				/* for each bit... */
X				if (*old_image_ptr & *pattern_ptr) {
X					/* if you saw one in this 'x' position before... */
X					if (*bit_ptr) {
X						/* just copy this one in place. */
X						*final_image_ptr |= *pattern_ptr;
X					} else {
X						/* if this one is the first one here, melt it. */
X						*bit_ptr = 1;
X						*(final_image_ptr+speed_inc) |= *pattern_ptr;
X					}
X				}
X				bit_ptr++;
X			} 
X			old_image_ptr++;
X			final_image_ptr++;
X		}
X	base += num_shorts;
X	}
X
X	/* Move the rest of the image as is */
Xnext:
X	for(; y_count < h - speed; y_count += 1) {
X		old_image_ptr = &old_image[base];
X		final_image_ptr = &final_image[base];
X		for (x_count = 0; x_count < num_shorts; x_count += 1) {
X			*final_image_ptr |= *old_image_ptr;
X			old_image_ptr++;
X			final_image_ptr++;
X		}
X	base += num_shorts;
X	}
X
X
X	/* return value in old */
X	pr_rop(old, 0, 0, w, h, PIX_SRC, final, 0, 0);
X	pr_destroy(final);
X	free(remember_bits);
X	free(remember_all_bits);
X}
X
X
Xstatic lookup[] = {
X#include "lookup.h"
X};	
X
X/*
X * Count the number of bits in a pixrect.
X   Not tested on, and may not work for, color.
X */
Xcount_bits(pr)
Xstruct pixrect *pr;		/* should be a memory pixrect for dvc ind. */
X{
X	register short x_count, y_count, max_x, count, base = 0, num_shorts;
X	struct mpr_data *mpr = mpr_d(pr);
X	if (mpr->md_offset.x != 0 || mpr->md_offset.y != 0) {
X		/* Never leave here */
X		printf("Can't handle region pixrects in 'count_bits'.\n");
X		abort();
X	};
X	count = 0;
X	num_shorts = mpr->md_linebytes / 2;
X	for(y_count = 0; y_count < pr->pr_size.y; y_count++) {
X		for (x_count = 0; x_count < num_shorts; x_count += 1) {
X			count += lookup[lefthalf(mpr->md_image[base+x_count])]
X				+lookup[righthalf(mpr->md_image[base+x_count])];
X		}
X		base += num_shorts;
X	}
X	return count;
X}
X
X/*
X * See if a memory pixrect is all zero.
X */
Xall_zero_bits(pr)
Xstruct pixrect *pr;		/* should be a memory pixrect */
X{
X	register short x_count, y_count, max_x, count, base = 0, num_shorts;
X	struct mpr_data *mpr = mpr_d(pr);
X	if (mpr->md_offset.x != 0 || mpr->md_offset.y != 0) {
X		/* Never leave here */
X		printf("Can't handle region pixrects in 'count_bits'.\n");
X		abort();
X	};
X	count = 0;
X	num_shorts = mpr->md_linebytes / 2;
X	for(y_count = 0; y_count < pr->pr_size.y; y_count++) {
X		for (x_count = 0; x_count < num_shorts; x_count += 1) {
X			if (mpr->md_image[base+x_count])
X				return 0;
X		}
X		base += num_shorts;
X	}
X	return 1;
X}
X
X/*
X * See if an array of shorts contains all ones.
X */
Xall_ones(x, len)
Xregister len;
Xregister unsigned short *x;
X{
X	for(; len; len--) {
X		if (*x++ != 0xffff) {
X			return 0;
X		}
X	}
X	return 1;
X}
X
X
X/*
X * Grow could, and possibly should, be made to work like melt, and
X * grow only at the edge of black areas, but growing linearly up
X * from the bottom looks ok too. (Which is not true in revese for melting!).
X * Unfortunately they are now asymmetrical, because grow needs a 'position'
X * parameter which says how far from the bottom we are.
X *
X * Grow only works for 64x64 bit pixrects (because of hardwired constants),
X * unlike melt which can melt anything.
X */
X
Xgrow(old, target, position)
Xstruct pixrect *old, *target;
X{
X	if (position < 1 || position > 64)
X		return;
X	pr_rop(old, 0, 64 - position, 64, position, PIX_SRC,
X		target, 0, 64 - position); 
X}
X
END_OF_pr_helpers.c
if test 6495 -ne `wc -c <pr_helpers.c`; then
    echo shar: \"pr_helpers.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f sdi.man -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"sdi.man\"
else
echo shar: Extracting \"sdi.man\" \(6607 characters\)
sed "s/^X//" >sdi.man <<'END_OF_sdi.man'
X.TH SDI 1 "Feb. 5, 1987"
X.AT 3
X.SH NAME
Xsdi \- a game of shooting missiles coming and going
X.SH SYNOPSIS
X.B sdi
X[[options] ]...
X.SH DESCRIPTION
X.I sdi
Xis based on the classic 
X.IR "missile command" ,
Xof arcade, Macintosh, and Alto fame.  Your mouse buttons control defenses
Xagainst the missiles flying by in two windows, and a third window is your
Xcontrol panel.
XMissiles are launched up in one window,
Xand, if you don't kill them there, they (after a few seconds of off-screen
Xballistic mode), start down on your cities in a second window.
X.PP
XYour left button aims a high-speed interceptor missile, which
Xexplodes leaving a large growing cloud of debris which destroys anything
Xattempting to pass through.  
XShifted interceptors have a larger cloud (but watch out near your
Xown cities.)
X.PP
XYour right button activates a pop-up x-ray laser, which detonates a small
Xatom bomb for energy, and then directs a beam at the six most-recently-launched missiles within range.
XShifted lasers have twice the range, but for no more 
Xthan three missiles.
XLasered missiles die with a fizzle.  If a missile disappears off the top
Xof the screen before being sufficiently lasered, it lives on.
X.PP
XYour middle button activates a rock-dropping satellite.  Rocks are
Xdropped on a line between button-down and button-up, and start to drop
Xto the ground before they burn up in the atmosphere.
XShifted rocks are fewer, but last longer before burn up.
X.PP
XMissiles killed by blasts and rocks are worth 5 points, but
Xthose killed by lasers are worth 50 points.  All missiles killed
Xon the city playing field (as opposed to the launch playing field)
Xare worth only one fifth as much.  A bonus city is awarded after
X5000 points, then 10000, then 20000, and so on by powers of two.
XIf there is no place to build a bonus city, then the bonus is saved
Xuntil needed.  Each city left at the end of a turn is worth ten times
Xthe current game level in points.
X.PP
XThe windows will flash and beep when you try to shoot with an empty button.
XA triple-beep sounds as an air raid warning whenever a
Xmissile enters ballistic mode between the screens, and there were
Xpreviously no missiles there.
X.PP
XThe control window should
Xbe used for all window opening and closing--the others will follow.
XPlaying fields can be resized for some interesting variations, and the
Xnumber of cities will be adjusted.  However, this will always start
Xa new game.  There are three skill levels, everything is worth more
Xpoints at higher skills.  Skill level can only be changed between games.
X.PP
XGames can be saved and restored using the appropriate control panel
Xbuttons, but only between rounds.  Window position and size are
Xamong the parameters remembered in a saved game.
X.PP
XShifted mouse buttons increase the 'size'
Xof the defense, but trade-off something else.  Meta moused buttons cause
Xyour action to be done twice, spread to either side of the mouse position.
XYour defenses are used up twice as fast as well.
X.PP
XIn the control window,
Xthe three top 'sliders' show the 'ammo' associated with your three
Xmouse buttons, the two bottom 'sliders' show the missiles-in-flight and
Xmissiles-on-the-ground, respectively.
XThe 'Things To Read' button pops up an assortment of reading options,
Xincluding the manual entry.  The different 'options' buttons also pop
Xup subwindows.
X.PP
XThe game is automatically suspended when in a subwindow.  If you want
Xto retain the subwindow while playing, move the subwindow
Xout of the way and explicitly 'resume' the game.
XOnly one subwindow at a time, though.
X.PP
XFor the real junky, the 'non-stop' button restarts each
Xround without waiting for confirmation.  The big 'game over' message
Xat the end of the game is also bypassed.
X.PP
XFor variety there are various options,
Xeach followed by one or more parameters.  Spaces separate options and parameters.
X.TP
X.B -c
Xsets the cities to an arbitrary icon.  (A "ziggy" icon is popular here.)
X.TP
X.B -d
Xsets the delay between screen updates (in microseconds, default 150000),
X.TP
X.B -f
Xlooks for a score file here.  If this option is not present, then
Xthe environment is checked for an SDI_SCORES variable, and if it
Xis not present then a check is made for a /usr/game/lib/sdi_scores file,
Xand if that is not present then an attempt is made to open a file
Xcalled /tmp/sdi_scores (or other location specified by -DSCOREFILE when
X.I sdi
Xwas compiled.)  
X.I Sdi
Xwill never create a score file.   An easy way to start score-keeping is to
Xissue the shell command 'touch /tmp/sdi_scores', then play.
X.TP
X.B -g
XAdds the 'gamemaster' item to the control panel, which when selected makes
Xall control panel items editable, and brings up a couple of more panels
Xto control (scroll down to see them).  Using this mode disables score file recording.
X.TP
X.B -h
Xset the height of the playing fields.
X.TP
X.B -i
Xmust be followed by two numbers, the icon type and the icon-update-time in tenths of seconds.  Icon update time defaults to 5 (half a second).  Icon types are 0 for normal sit-there-and-do-nothing icon, 1 (the default) for an
Xicon with subtle amusing flavor, and 2 for wild bubbling icon.
X.TP
X.B -l
Xset the starting level, from 0 to 49.
X.TP
X.B -p
XSelect a type of pointer (i.e. cursor).
XThe following parameter is 0 for normal cursor, 1 for dynamic cursor, and 2 for cross hairs.
X.TP
X.B -r
Xthe following parameter is the name of a file from which to restore a saved game.
X.TP
X.B -s
Xset the starting skill: 0 for novice, 1 for intermediate, 2 for expert.
X.TP
X.B -t
Xset the maximum time for a game, in seconds.  Using this option causes
Xa new slider to appear which ticks down the remaining seconds.  It also
Xautomatically uses 'Non-stop' mode between rounds but not at the end of game.
XWhen time runs out, the 'melt' button is implicitly pushed.
X.TP
X.B -w
Xset the height of the playing fields.
X.PP
XThe following options, all starting with -b, specify different pixrects to be used in different
Xkind of blasts:
X.TP
X.B -bb
Xblast of an interceptor.
X.TP
X.B -bm
Xblast of a missile blowing up via interceptor.
X.TP
X.B -bk
Xblast of a missile blowing up via a laser.
X.TP
X.B -bl
Xblast of a laser's bomb source.
X.TP
X.B -bc
Xblast of a missile hitting a city.
X.SH Bugs
XWhen compiled against Sun 3.0 operating system libraries, the wrong window
Xsizes are used if the game starts iconic ('-Wi' option).  Works ok with
Xthe 3.2 libraries, or if started non-iconic and then later closed.
X.PP
XThe low-res 'game-over' picture keeps the shar-file size down for shipping,
Xbut doesn't look great.
X.PP
XToo many silly control panel buttons, like 'melt'.
X.PP
XFar, far too many options.
X.SH Author
XMark Weiser
END_OF_sdi.man
if test 6607 -ne `wc -c <sdi.man`; then
    echo shar: \"sdi.man\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 2 \(of 6\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 archives.
    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