|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T m
Length: 7766 (0x1e56)
Types: TextFile
Names: »missile.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
└─⟦this⟧ »EUUGD18/Sun/Sdi/missile.c«
/********************************** 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);
}