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 m

⟦5270608fe⟧ TextFile

    Length: 7766 (0x1e56)
    Types: TextFile
    Names: »missile.c«

Derivation

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

TextFile

/**********************************  missile.c  ***********************/
#include <pixrect/pixrect_hs.h>
#include "sdi.h"
#include <sunwindow/notify.h>

/*
 * Copyright 1987 by Mark Weiser.
 * Permission to reproduce and use in any manner whatsoever on Suns is granted
 * so long as this copyright and other identifying marks of authorship
 * in the code and the game remain intact and visible.  Use of this code
 * in other products is reserved to me--I'm working on Mac and IBM versions.
 */

/*
 * Code to start and update missiles lives here, including missiles
 * traveling between the two windows.  Launching of missiles
 * is done in incoming.c.
 */

static struct missile *m_head = NULL;
static Notify_value ballistic_timer();

/*
 * Throw a missile onto a window. Only x is suppied, because direction
 * determines whether the missile starts at the top or bottom of the window.
 * Speed is in units of approximate pixels-per-timestep.  Direction
 * should be UP or DOWN, which are defined in sdi.h
 */
start_missile(x, direction, speed, pw)
int x, direction, speed;
Pixwin *pw;
{
	struct missile *mid = (struct missile *)malloc(sizeof(struct missile));
	int ratio, number_of_steps;
	int final_x = (random() % (max_x - MARGIN)) + (MARGIN/2);

	panel_set_value(foe_item, panel_get_value(foe_item) + 1);

	mid->start_x = mid->x = x;
	mid->speed = speed;
	mid->refs = 1;
	mid->destroyed = FALSE;

	number_of_steps = max(1,(ABS(final_x - mid->start_x) + max_y)/speed);
	mid->inc_x = (final_x - mid->start_x)/number_of_steps;
	mid->inc_y = max_y/number_of_steps;
	if (mid->inc_y < 1) {
		mid->inc_y += 1;
		mid->inc_x -= 1;
	}

	
	/* I'm making this up as I go... */
	{
	    double desired = (double)(ABS(final_x - mid->start_x)/(double)max_y);
	    double actual = (double)ABS(mid->inc_x)/(double)ABS(mid->inc_y);
	    mid->slip = (double)1.0 / (desired - actual);
	    mid->slip_cnt = 0;		
	} 

	if (direction == DOWN) {
		mid->start_y = mid->y = 0;
	} else {
		mid->start_y = mid->y = max_y;
		mid->inc_y = -mid->inc_y;
	}
	mid->pw = pw;
			
	inc_missile(mid);

	missile_count++;
	mid->next = m_head;
	m_head = mid;
}

/*
 * Move a missile ahead and see if hits anything.
 * Helper routine passed into doto_missiles.
 */
update_missile(mid)
struct missile *mid;
{
	inc_missile(mid);
	if (intersect(mid)) {
		start_blast(mid->x, mid->y, 0, 0, mid->pw, blastkillcircles);
		destroy_missile(mid);
		if (mid->pw == citypw)
			bump_score(foe_value/5);
		else bump_score(foe_value);
	} else if (mid->inc_y > 0 && mid->y >= max_y-burst_distance) {
		start_blast(mid->x, mid->y - 10, 0, 0, mid->pw, citykillcircles);
		destroy_missile(mid);
	} else if (mid->inc_y < 0 && mid->y <= 0) {
		start_ballistic(mid->x, mid->speed);
		destroy_missile(mid);
	} else if (mid->x < 0 || mid->x > max_x) {
		start_blast(mid->x, mid->y, 0, 0, mid->pw, blastkillcircles);
		destroy_missile(mid);
	}
	return 0;
}

/*
 * Update the missile track.
 */
inc_missile(mid)
struct missile *mid;
{
	/* Compute basic update */
	mid->old_x = mid->x;
	mid->old_y = mid->y;
	mid->x += mid->inc_x;
	mid->y += mid->inc_y;

	/* Adjust skew for straighter lines */
	if (mid->slip && ++mid->slip_cnt >= ABS(mid->slip)) {
		mid->slip_cnt = 0;
		if (mid->slip > 0) {
			mid->x += 1;
		} else {
			mid->y += 1;
		}
	}

	/* Draw missile trail */
	pw_vector(mid->pw, mid->old_x-1, mid->old_y, mid->x-1, mid->y, PIX_SRC, 1);
	pw_vector(mid->pw, mid->old_x, mid->old_y, mid->x, mid->y, PIX_SRC, 1);
	pw_vector(mid->pw, mid->old_x+1, mid->old_y, mid->x+1, mid->y, PIX_SRC, 1);
}

/*
 * Get rid of a missile by erasing its track, removing it from
 * the missile display list, and freeing its structure.  Explosion
 * of the missile is the responsibility of the caller.
 */
destroy_missile(mid)
struct missile *mid;
{
	char buff[128];
	struct rect r;

	if (!mid->destroyed) {
		panel_set_value(foe_item, panel_get_value(foe_item) - 1);
		sprintf(buff, "%d", atol(panel_get_value(total_foe_item))+1);
		panel_set_value(total_foe_item, buff);
		mid->destroyed = TRUE;
		pw_vector(mid->pw, mid->start_x - 2, mid->start_y,
			mid->x - 2, mid->y,
			PIX_NOT(PIX_SRC), 1);
		pw_vector(mid->pw, mid->start_x - 1, mid->start_y,
			mid->x - 1, mid->y,
			PIX_NOT(PIX_SRC), 1);
		pw_vector(mid->pw, mid->start_x, mid->start_y,
			mid->x, mid->y,
			PIX_NOT(PIX_SRC), 1);
		pw_vector(mid->pw, mid->start_x + 1, mid->start_y,
			mid->x + 1, mid->y,
			PIX_NOT(PIX_SRC), 1);
		pw_vector(mid->pw, mid->start_x + 2, mid->start_y,
			mid->x + 2, mid->y,
			PIX_NOT(PIX_SRC), 1);
	
		if (m_head == mid) {
			m_head = mid->next;
		} else {
			struct missile *tmpmid = m_head;
			while (tmpmid != NULL && tmpmid->next != mid) 
				tmpmid = tmpmid->next;
			if (tmpmid != NULL)
				tmpmid->next = mid->next;
		}
		missile_count--;
	}
	if (--mid->refs == 0) {
		free(mid);
	}
}

/*
 * Update the score by 'inc', augmented by skill level.
 */
bump_score(inc)
{
	int score, skill;
	float skill_multiplier;
	char buf[128];
	skill = (int)panel_get_value(skill_item);
	switch (skill) {
		case 0: skill_multiplier = 1.0; break;
		case 1: skill_multiplier = 1.5; break;
		case 2: skill_multiplier = 3; break;
	}
	score = atol(panel_get_value(score_item)) + (int)(((float)inc)*skill_multiplier);
	sprintf(buf,"%d", score);
	panel_set_value(score_item, buf);
}

/*
 * Call 'func' for missiles in the display list.  If func
 * returns non-zero, stop.  Search the missiles round-robin,
 * so we don't always find the same ones.
 */
doto_missiles(func)
int (*func)();
{
	struct missile *ptr = m_head, *next;
	while (ptr != NULL) {
		next = ptr->next; /* in case 'func' destroys the missile */
		(*func)(ptr);
		ptr = next;
	}
}

/*
 * Track a missile when traveling between windows.
 */
struct ballistic_type {int x, speed};
start_ballistic(x, speed)
{
	extern int ballistic_delay;
	struct itimerval timer;
	struct ballistic_type *xptr = (struct ballistic_type *)calloc(1,sizeof(struct ballistic_type));
	int old_value = (int)panel_get_value(ballistic_item);
	xptr->x = x;
	xptr->speed = speed;
	panel_set_value(ballistic_item, old_value + 1);
	
	if (old_value == 0) {
		ballistic_warning();
	}
	timer.it_interval.tv_usec = 0;
	timer.it_interval.tv_sec = 0;
	timer.it_value.tv_usec = 0;
	timer.it_value.tv_sec = ballistic_delay;
	if (timer.it_value.tv_sec > 0) {
		notify_set_itimer_func(xptr, ballistic_timer, ITIMER_REAL, &timer, NULL);
	} else {
		ballistic_timer(xptr, NULL);
	}
}

/*
 * Called when the between-window flight time of a missile is up.
 */
static Notify_value
ballistic_timer(xptr, which)
struct ballistic_type *xptr;
int which;
{
	extern int ballistic_delay;
	int val;
	if (running) {
		if (suspended) {
			/* by rechecking at each in-flight interval for each missile, we
			   approximate remembering when the real relaunch rate.
			*/
			suspendor(ballistic_timer, xptr, which, ballistic_delay);
			return NOTIFY_DONE;
		} else {
			val = (int)panel_get_value(ballistic_item);
			if (val > 0) {
				/* Three new missiles appear. */
				start_missile(xptr->x, DOWN, xptr->speed, citypw);
				start_missile(xptr->x, DOWN, xptr->speed, citypw);
				start_missile(xptr->x, DOWN, xptr->speed, citypw);
				panel_set_value(ballistic_item, panel_get_value(ballistic_item)-1);
			}
		}
	}
	free(xptr);
	return NOTIFY_DONE;
}

/*
 * Just what it says.
 */
free_all_missiles()
{
	free_foe();
	panel_set_value(ballistic_item, 0);
	while(m_head != NULL)
		destroy_missile(m_head);
}

do_warn_bell()
{
	struct timeval tv;
	tv.tv_sec = 0;
	tv.tv_usec = 20000;	/* very short bell */
	win_bell(window_get(cityframe, WIN_FD), tv, 0);
}

#define WARN_INTERVAL 100000

ballistic_warning()
{
	do_with_delay(do_warn_bell, 0, WARN_INTERVAL);
	do_with_delay(do_warn_bell, 0, 2*WARN_INTERVAL);
	do_with_delay(do_warn_bell, 0, 3*WARN_INTERVAL);
}