From mipos3!intelca!amd!amdcad!ames!sri-spam!rutgers!mit-eddie!uw-beaver!tektronix!tekgen!tekred!games-request Thu Jun 18 10:11:07 PDT 1987 Article 3 of comp.sources.games: Path: td2cad!mipos3!intelca!amd!amdcad!ames!sri-spam!rutgers!mit-eddie!uw-beaver!tektronix!tekgen!tekred!games-request From: games-request@tekred.TEK.COM Newsgroups: comp.sources.games Subject: v01i056: sdi - missle command game for Suns, Part03/06 Message-ID: <1315@tekred.TEK.COM> Date: 17 Jun 87 18:32:31 GMT Sender: billr@tekred.TEK.COM Lines: 2095 Approved: billr@tekred.TEK.COM Submitted by: Mark Weiser Comp.sources.games: Volume 1, Issue 56 Archive-name: sdi/Part03 #! /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 argv.c <<'END_OF_argv.c' X/****************************************** argv.c *******************/ X#include X#include 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 * Handle command line arguments, and do some font fiddling. X */ X Xprocess_args(argc, argv) Xint argc; Xchar **argv; X{ X extern int time_to_play, X starting_icon, X starting_icon_time, X starting_level, X starting_skill, X restoring_game; X while (--argc > 0) { X argv++; X if ((*argv)[0] != '-') { X fprintf(stderr, "Unrecognizable argument '%s'.\n", *argv); X exit(1); X } else { X switch((*argv)[1]) { X case 'b': { X /* name of a file with a blast pixrect to use */ X struct pixrect *pr, *icon_load_mpr(); X char error_msg[256], *oldv = *argv; X argc--; argv++; X if (! out_of_args(argc, oldv)) { X if ((pr = icon_load_mpr(*argv, error_msg)) == NULL) { X printf("Could not get pr '%s'.\n", *argv); X printf("%s",error_msg); X } else { X switch(oldv[2]) { X /* cities */ case 'c': change_circ(citykillcircles, pr); break; X /* lasers */ case 'l': change_circ(lasercircles, pr); break; X /* laser ends */ case 'k': change_circ(laserkillcircles, pr); break; X /* missile death */ case 'm': change_circ(blastkillcircles, pr); break; X /* interceptors */ case 'b': change_circ(bigblastcircles, pr); break; X default: { X printf("unrecognized option: '%s'.\n",oldv); X exit(1); X } X } X } X } X break; X } X case 'c': { X /* name of a file with a city pixrect to use */ X argc--; argv++; X if (! out_of_args(argc, "-c")) { X init_city_bits(*argv); X } X break; X } X case 'd': { X /* delay to use between screen updates */ X argc--; argv++; X if (! out_of_args(argc, "-d")) { X blast_delay = atol(*argv); X } X break; X } X case 'f': { X /* new score file */ X argc--; argv++; X if (! out_of_args(argc, "-f")) { X scorefile = *argv; X } X break; X } X case 'g': { X extern int gamemaster; X /* set gamemaster mode */ X gamemaster = 1; X break; X } X case 'h': { X /* height of playing windows */ X argc--; argv++; X if (! out_of_args(argc, "-h")) { X max_y = max(MINWIN, atol(*argv)); X } X break; X } X case 'i': { X /* starting icon type */ X argc--; argv++; X if (! out_of_args(argc, "-i")) { X starting_icon = atol(*argv); X starting_icon = min(2, max(0, starting_icon)); X } X /* starting icon time */ X argc--; argv++; X if (! out_of_args(argc, "-i")) { X starting_icon_time = atol(*argv); X starting_icon_time = min(50, max(1, starting_icon_time)); X } X break; X } X case 'p': { X /* select the pointer style */ X extern int cursor_type; X argc--; argv++; X if (! out_of_args(argc, "-p")) { X cursor_type = atol(*argv); X cursor_type = min(2, max(0, cursor_type)); X } X break; X } X case 'r': { X /* restore a saved game */ X argc--; argv++; X if (! out_of_args(argc, "-r")) { X strcpy(save_file_name, *argv); X restoring_game = 1; X } X break; X } X case 's': { X /* starting skill*/ X argc--; argv++; X if (! out_of_args(argc, "-s")) { X starting_skill = atol(*argv); X starting_skill = min(2, max(0, starting_skill)); X } X break; X } X case 't': { X /* maximum playing time, in seconds */ X argc--; argv++; X if (! out_of_args(argc, "-t")) { X time_to_play = atol(*argv); X } X break; X } X case 'w': { X /* width of playing windows */ X argc--; argv++; X if (! out_of_args(argc, "-w")) { X max_x = max(MINWIN, atol(*argv)); X } X break; X } X default: { X fprintf(stderr, "Unrecognizable argument '%s'.\n", *argv); X break; X } X } X } X } X} X X X/* the following kludge is necessary because there seems to be no X * SunView subroutine which sets the default font for all the windows. X * WIN_FONT explicitly disclaims doing this. Only -Wt on the argument X * claims to.... X */ Xfixup_font(pargc, pargv, font_name) Xint *pargc; Xchar ***pargv; Xchar *font_name; X{ X int i; X int argc = *pargc; X char **argv = *pargv; X char **new_argv = (char **)calloc(sizeof(char *), argc+3); X for (i = 1; i < argc; i += 1) { X new_argv[i+2] = argv[i]; X } X new_argv[0] = argv[0]; X new_argv[1] = "-Wt"; X new_argv[2] = font_name; X *pargc += 2; X *pargv = new_argv; X} X Xopen_our_font(s) Xchar *s; X{ X if ((font = (struct pixfont *)pf_open(s)) == NULL) X font = (struct pixfont *)pf_default(); X} X Xout_of_args(n, s) Xchar *s; X{ X if (n > 0) { X return 0; X } else { X fprintf(stderr, "Argument '%s' not followed by a value.\n", s); X /* return 1; */ X exit(1); X } X} END_OF_argv.c if test 5019 -ne `wc -c blast.c <<'END_OF_blast.c' X/*************************************** blast.c ********************/ X#include X#include 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 * Blast-related routines are here and in intersect.c. Also here is X * the main dispatch point for display updating called, for historical X * reasons, 'blast_timer'. X */ X Xstatic Notify_value blast_timer(); Xextern int draw_blast(), doto_missiles(), update_missile(); X X/* X * Start the main dispatch timer. X */ Xinit_blast() X{ X static char *me = (char *)&me; X struct itimerval timer; X timer.it_interval.tv_usec = 0; X timer.it_interval.tv_sec = 0; X timer.it_value.tv_usec = 1; X timer.it_value.tv_sec = 0; X notify_set_itimer_func(me, blast_timer, ITIMER_REAL, &timer, NULL); X} X X/* X * Construct a new blast and put it on the display list. X */ Xstart_blast(x, y, xinc, yinc, pw, circle_type) Xint x, y; XPixwin *pw; Xstruct circ *circle_type; X{ X struct blast *bid = (struct blast *)malloc(sizeof(struct blast)); X bid->pw = pw; X bid->next = NULL; X bid->circ = 0; X bid->x = x; X bid->orig_y = bid->y = y; X bid->x_inc = xinc; X bid->y_inc = yinc; X bid->num_circles = circle_type->num_circles; X bid->circles = circle_type->circles; X bid->masks = circle_type->masks; X bid->width = bid->circles[0]->pr_size.x; X update_blast_rect(bid); X add_blast(bid); X draw_blast(bid); X} X X#define INSCRIBING_FUDGE_FACTOR 2 X X/* X * Construct a square which approximates the size of the current X * blast circle. X */ Xupdate_blast_rect(bid) Xstruct blast *bid; X{ X register int w = bid->width / 2 - INSCRIBING_FUDGE_FACTOR; X register int h = bid->width - 2*INSCRIBING_FUDGE_FACTOR; X bid->r.r_left = bid->x - w; X bid->r.r_top = bid->y - w; X bid->r.r_width = h; X bid->r.r_height = h; X} X X/* X * The main dispatch routine. X * 'blast_timer' is called at fixed intervals, queries routines X * for launch, missiles, lasers, and blasts for their next update. X */ Xstatic Notify_value Xblast_timer(me, which) Xint *me; Xint which; X{ X extern Panel_item foe_ground_item; X Pixwin *pw1 = citypw; X Pixwin *pw2 = launchpw; X struct itimerval timer; X struct rect r; X Event event; X X if (!running) return NOTIFY_DONE; X X if (suspended) { X suspendor(blast_timer, me, which, 1); X return NOTIFY_DONE; X } X X if (missile_count <= 0 && blast_count <= 0 && X panel_get_value(ballistic_item) <= 0 && X panel_get_value(foe_ground_item) <= 0) X finish_round(); X X checkinput(); X X timer.it_interval.tv_usec = 0; X timer.it_interval.tv_sec = 0; X timer.it_value.tv_usec = blast_delay; X timer.it_value.tv_sec = 0; X notify_set_itimer_func(pw1, blast_timer, ITIMER_REAL, &timer, NULL); X X X (void) pw_get_region_rect(pw1, &r); X pw_batch_on(pw1); X pw_lock(pw1, &r); X (void) pw_get_region_rect(pw2, &r); X pw_batch_on(pw2); X pw_lock(pw2, &r); X X if (need_a_bell != NULL) { X struct timeval tv; X tv.tv_sec = 0; X tv.tv_usec = 30000; /* this is the minimal reliable bell length */ X win_bell(window_get(cityframe, WIN_FD), tv, need_a_bell); X need_a_bell = NULL; X } X X doto_missiles(update_missile); X doto_lasers(); X doto_blasts(draw_blast); X doto_rocks(); X doto_launch(); X X pw_unlock(pw2); X pw_batch_off(pw2); X pw_unlock(pw1); X pw_batch_off(pw1); X X return NOTIFY_DONE; X} X X/* X * Helper routine passed into 'doto_blasts'. Updates the X * blast circle, and frees the blast structure if done. X */ Xdraw_blast(bid) Xstruct blast *bid; X{ X int old_circ = bid->circ; X X if (bid->circ < 0 || bid->x_inc || bid->y_inc) { X /* shrinking or moving, remove old blast */ X pw_rop(bid->pw, B_OFFSET_X(bid), B_OFFSET_Y(bid), X B_WIDTH(bid), B_HEIGHT(bid), X PIX_NOT(PIX_SRC) & PIX_DST, X bid->masks[ABS(bid->circ)], 0, 0); X } X X X /* Update the next blast circle. X Positive values are growing, negative are shrinking X */ X bid->circ += 1; X if (bid->circ >= bid->num_circles) { X bid->circ = -bid->num_circles +1; X } X if (bid->circ) { X /* Draw the new blast */ X bid->x += bid->x_inc; X bid->y += bid->y_inc; X bid->width = bid->circles[ABS((bid)->circ)]->pr_size.x; X pw_rop(bid->pw, B_OFFSET_X(bid), B_OFFSET_Y(bid), X B_WIDTH(bid), B_HEIGHT(bid), X PIX_SRC | PIX_DST, bid->circles[ABS(bid->circ)], 0, 0); X } X if (old_circ == -1) { X remove_blast(bid); X free(bid); X } X bid->width = bid->circles[ABS((bid)->circ)]->pr_size.x; X update_blast_rect(bid); X} END_OF_blast.c if test 4553 -ne `wc -c control_procs.c <<'END_OF_control_procs.c' X/***************************** control_procs.c ******************************/ X#include 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 * All the notification procs for the control panel are here. X * Other control panel-related code is in control.c, helpers.c, and main.c. X */ X Xextern Panel_item timeout_item, rock_item; Xvoid suspend_proc(), resume_proc(); X X/* X * Proc called when changing the slider for basic update time of the game display X */ Xvoid Xcycle_time_proc(item, value, event) XPanel_item item; XEvent *event; X{ X blast_delay = value*1000; X} X X/* X * Proc called when changing the slider for ballistic flight delay. X */ Xvoid Xballistic_time_proc(item, value, event) XPanel_item item; XEvent *event; X{ X extern int ballistic_delay; X ballistic_delay = value; X} X X/* X * Proc called for the 'quit' button. Tries to completely exit the game. X */ Xvoid Xquit_proc(item, event) XPanel_item item; XEvent *event; X{ X update_scores(); X suspend_proc(); X window_done(controlframe); X do_with_delay(resume_proc, 2, 0); /* in case the quit is refused. */ X} X X/* X * Proc called to skip to the next round in response to the 'next round' button. X */ Xvoid Xnext_round_proc() X{ X extern void init_blast(), start_running_proc(); X running = 0; X free_all_blasts(); X free_all_missiles(); X put_text(75, "Click to start next round."); X} X X/* X * Proc called to start a new game, usually in response to the 'new game' button. X */ Xvoid Xnew_game_proc() X{ X extern Panel_item foe_ground_item; X extern int restoring_game; X extern int time_to_play; X void restore_proc(); X running = 0; X if (restoring_game) { X restore_proc(); X } else { X update_scores(); X panel_set_value(level_item, "0"); X panel_set_value(score_item, "0"); X panel_set_value(interceptor_item, 0); X panel_set_value(laser_item, 0); X panel_set_value(foe_ground_item, 0); X panel_set_value(foe_item, 0); X panel_set_value(total_foe_item, "0"); X panel_set_value(rock_item, 0); X panel_set_value(ballistic_item, 0); X X } X X while (suspended) X resume_proc(); X free_all_blasts(); X free_all_missiles(); X init_intersect(); X X num_cities = 0; X total_cities_lost = 0; X draw_background(); X init_cities(); X panel_set(skill_item, PANEL_EVENT_PROC, panel_default_handle_event, 0); X panel_set(next_round_item, PANEL_SHOW_ITEM, TRUE, 0); X X put_text(75, "Click to start a new game."); X if (time_to_play) { X panel_set_value(timeout_item, time_to_play); X } X} X X/* X * Proc called to temporarily suspend a game, usually from the 'suspend' button. X */ Xvoid Xsuspend_proc() X{ X if (! suspended) { X panel_set(suspend_item, PANEL_SHOW_ITEM, FALSE, 0); X panel_set(resume_item, PANEL_SHOW_ITEM, TRUE, 0); X } X suspended += 1; X} X X/* X * Proc called to resume a suspended game, usually called via the 'resume' button, X * which is only displayed after a 'suspend'. X */ Xvoid Xresume_proc() X{ X if (suspended) { X suspended -= 1; X if (! suspended) { X panel_set(resume_item, PANEL_SHOW_ITEM, FALSE, 0); X panel_set(suspend_item, PANEL_SHOW_ITEM, TRUE, 0); X } X } X} X X/* X * Proc called to display the scores from the score file in a popup window. X */ Xvoid Xscores_proc(item, value, event) XPanel_item item; XEvent *event; X{ X Menu m; X int id = event_id(event); X char *a; X a = (char *)build_scores(); X easy_pop(a); X} X X/* X * Proc called to melt all the cities and then end the game, thus forcing all normal X * end-of-game actions. Usually called via the 'melt' button. X */ Xvoid Xend_proc(item, event) XPanel_item item; XEvent event; X{ X free_all_blasts(); X free_all_missiles(); X panel_set_value(ballistic_item, 0); X melt_all_cities(citypw, 1); X finish_round(); X} X X/* X * Toggle the write-ability of important panel items in response X * to the 'gamemaster' toggle (only visible in gamemaster mode.) X */ Xvoid Xmaster_proc(item, value, event) XPanel_item item; XEvent *event; X{ X extern Panel_item foe_ground_item; X if (value) { X panel_set(level_item, PANEL_EVENT_PROC, panel_default_handle_event, 0); X panel_set(score_item, PANEL_EVENT_PROC, panel_default_handle_event, 0); X panel_set(interceptor_item, PANEL_EVENT_PROC, panel_default_handle_event, 0); X panel_set(foe_ground_item, PANEL_EVENT_PROC, panel_default_handle_event, 0); X panel_set(foe_item, PANEL_EVENT_PROC, panel_default_handle_event, 0); X panel_set(laser_item, PANEL_EVENT_PROC, panel_default_handle_event, 0); X panel_set(rock_item, PANEL_EVENT_PROC, panel_default_handle_event, 0); X } else { X panel_set(level_item, PANEL_EVENT_PROC, (char *)no_events, 0); X panel_set(score_item, PANEL_EVENT_PROC, (char *)no_events, 0); X panel_set(interceptor_item, PANEL_EVENT_PROC, (char *)no_events, 0); X panel_set(foe_ground_item, PANEL_EVENT_PROC, (char *)no_events, 0); X panel_set(foe_item, PANEL_EVENT_PROC, (char *)no_events, 0); X panel_set(laser_item, PANEL_EVENT_PROC, (char *)no_events, 0); X panel_set(rock_item, PANEL_EVENT_PROC, (char *)no_events, 0); X } X} X Xvoid Xrestore_proc() X{ X void restore_timer_proc(); X if (running) { X easy_pop("Can only save or restore between rounds."); X return; X } X restoring_game = 1; X restore_game(); X X /* X * the kludge below puts us to sleep for a moment, and then turns X * off a control variable. This helps manage an infinite regress X * which can start if the 'restore_game' call above resizes windows. X * X * What I really need are genuine light-weight processes. X */ X do_with_delay(restore_timer_proc, 0, 500000); X} X Xvoid Xrestore_timer_proc() X{ X extern int restoring_game; X restoring_game = 0; X} X Xvoid Xsave_proc() X{ X if (running) { X easy_pop("Can only save or restore between rounds."); X } else { X save_game(); X } X} X Xvoid Xcursor_notify_proc(item, value, event) XPanel_item item; XEvent *event; X{ X extern int cursor_type; X cursor_type = value; X init_cursor(); X update_cursor(); X} X Xvoid Xnon_stop_notify_proc(item, value, event) XPanel_item item; XEvent *event; X{ X extern int continuous; X continuous = value; X} END_OF_control_procs.c if test 6150 -ne `wc -c incoming.c <<'END_OF_incoming.c' X/********************************* incoming.c ****************************/ X#include X#include 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 * This file contains routines for lauching 'foe' missiles. Since X * a round is over when all the foes are gone, end-of-round work X * is done here as well. And since the game is over when there are X * no cities left at the end of the round, end-of-game computations X * are mostly done here too. And, since the only difference between X * different skills is the difficulty of foe missiles, skill adjustment X * is also done in here. Why not just do everything here? Wouldn't fit. X */ X X/* The following two constants determine launch rates. */ X#define MAX_TIME_FOR_A_ROUND 45000000 X#define AVG_DELAY_BETWEEN_MISSILES 1000000 X Xstatic short *missiles_to_launch = NULL; Xstatic int next_missile_launch = 0; Xstatic int num_launch_intervals; X Xstatic bonus_threshold = 5000; X X/* X * Increase the game level by one, within reason. X */ X#define MAX_LEVEL 49 X Xint Xbump_level() X{ X int level; X char buf[32]; X level = atol((int)panel_get_value(level_item)) + 1; X if (level > MAX_LEVEL) { X level = MAX_LEVEL; X panel_set(next_round_item, PANEL_SHOW_ITEM, FALSE, 0); X } X sprintf(buf,"%d", level); X panel_set_value(level_item, buf); X return level; X} X X/* X * Compute the skill differentials, get the missiles ready to launch, X * and set the 'running' switch on. Normally 'init_incoming' is the last X * thing called when a round is started, and setting the 'running' switch X * immediately releases various notifications so the game really begins. X */ Xinit_incoming() X{ X extern Panel_item rock_item, foe_ground_item; X int foe_val, friend_val, laser_val, rocks_val, level, skill, count, range; X int base = 2; X char buf[128]; X if (running) X return; X X skill = (int)panel_get_value(skill_item); X switch (skill) { X case 0: /* novice */ X carryover_divisor = 1.0; X foe_divisor = 2.0; X min_missile_speed = 5; X max_missile_speed = 15; X foe_factor = 2; X break; X case 1: /* occasional */ X carryover_divisor = 1.3; X foe_divisor = 2.5; X min_missile_speed = 10; X max_missile_speed = 20; X foe_factor = 4; X break; X case 2: /* expert */ X carryover_divisor = 1.6; X foe_divisor = 3.0; X min_missile_speed = 15; X max_missile_speed = 25; X foe_factor = 6; X break; X } X X level = bump_level(); X X foe_val = foe_factor * level; X panel_set(foe_ground_item, PANEL_MAX_VALUE, foe_val, PANEL_VALUE, foe_val, 0); X panel_set(foe_item, PANEL_MAX_VALUE, foe_val*3, 0); X X laser_val = (int)panel_get_value(laser_item); X laser_val = ((int)((float)foe_val/foe_divisor)) + laser_val/carryover_divisor; X laser_val += base; X panel_set(laser_item, PANEL_MAX_VALUE, laser_val, PANEL_VALUE, laser_val, X 0); X panel_set(ballistic_item, PANEL_MAX_VALUE, foe_val, 0); X X friend_val = (int)panel_get_value(interceptor_item); X friend_val = ((int)((float)foe_val/foe_divisor)) + friend_val/carryover_divisor; X friend_val += base; X panel_set(interceptor_item, PANEL_MAX_VALUE, friend_val, PANEL_VALUE, friend_val, X 0); X X rocks_val = (int)panel_get_value(rock_item); X rocks_val = ((int)((float)foe_val/foe_divisor)) + rocks_val/carryover_divisor; X rocks_val += base; X panel_set(rock_item, PANEL_MAX_VALUE, rocks_val, PANEL_VALUE, rocks_val, X 0); X X if (missiles_to_launch != NULL) X free(missiles_to_launch); X num_launch_intervals = MAX_TIME_FOR_A_ROUND/blast_delay + 2; X missiles_to_launch = (short *)calloc(sizeof(short), num_launch_intervals); X next_missile_launch = 0; X count = (int)panel_get_value(foe_ground_item); X range = min( MAX_TIME_FOR_A_ROUND, AVG_DELAY_BETWEEN_MISSILES*count); X while (count--) { X missiles_to_launch[(random() % range) / blast_delay] += 1; X } X new_score(); X if (level <= 1) X bonus_threshold = 5000; X X} X X/* X * Called at each display update timestep, this routine launches X * any missiles which have come due. X */ Xdoto_launch() X{ X int level; X int num_missiles; X X if (!suspended) { X int x; X if (next_missile_launch >= num_launch_intervals) X return; X num_missiles = missiles_to_launch[next_missile_launch++]; X if (num_missiles) { X panel_set_value(foe_ground_item, X panel_get_value(foe_ground_item) - num_missiles); X level = atol((char *)panel_get_value(level_item)); X while (num_missiles--) { X x = random() % max_x; X start_missile(x, UP, X min(max(normal(min_missile_speed+level/2,level/2), X min_missile_speed), X max_missile_speed), launchpw); X } X } X } X} X X/* X * Compute which cites are still left, bonus scores, and end-of-game. X * Get ready for the next round. X */ Xfinish_round() X{ X char buf[128], score_buf[32]; X int cities_lost = compute_cities(citypw); X extern int continuous; X int level = atol((char *)panel_get_value(level_item)); X int score = atol((char *)panel_get_value(score_item)); X int bonus, extra_city = 0; X X running = 0; X put_text(25, "Round Over"); X total_cities_lost += cities_lost; X bonus = level*10*(num_cities-total_cities_lost); X update_cities(citypw, 1); X if ((score+bonus) >= bonus_threshold && total_cities_lost > 0) { X extra_city = 1; X total_cities_lost -= 1; X bonus_threshold += bonus_threshold; X } X bonus = level*10*(num_cities-total_cities_lost); X sprintf(buf, "You have %d cities left, for %d bonus points.",num_cities-total_cities_lost, bonus); X panel_set_value(score_item, sprintf(score_buf, "%d", score+bonus)); X if(total_cities_lost >= num_cities) { X panel_set(skill_item, PANEL_EVENT_PROC, panel_default_handle_event, 0); X if (!continuous) X do_game_over(); X update_scores(); X new_game_proc(); X } else { X put_text(50, buf); X if (extra_city) { X put_text(0, "BONUS CITY"); X new_city(citypw); X } X next_round_proc(); X if (continuous) { X sleep(1); X start_next_round(); X } X } X} X X/* X * this keeps any more missiles from being launched. Actually freeing X * of allocated structures happens on the next 'init_incoming' call. X */ Xfree_foe() X{ X num_launch_intervals = 0; X} END_OF_incoming.c if test 6261 -ne `wc -c interceptor_picture.h <<'END_OF_interceptor_picture.h' X/* Format_version=1, Width=16, Height=16, Depth=1, Valid_bits_per_item=16 X */ X 0x0000,0x07C0,0x0FE0,0x1FF0,0x3FF8,0x3FF8,0x3F88,0x3F38, X 0x3E7C,0x1EFE,0x0EFE,0x07FE,0x007C,0x0038,0x0000,0x0000 END_OF_interceptor_picture.h if test 193 -ne `wc -c intersect.c <<'END_OF_intersect.c' X/************************************ intersect.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 * The code to intersect blasts, missiles, and lasers is in here, X * as well as some blast-specific code. X */ X X#define LINE_GRAIN 20 X X/* each 'line' is the head of a linked list of current blasts */ Xstatic struct blast *lines_launch[MAX_LINES/LINE_GRAIN + 1], *lines_city[MAX_LINES/LINE_GRAIN + 1]; Xstatic struct blast **init_line_from_bid(), **init_line_from_mid(); X X/* X * Clear out data structures which keep track of blasts. X */ Xinit_intersect() X{ X int i; X for (i=0; i<(MAX_LINES/LINE_GRAIN +1); i++) { X lines_launch[i] = NULL; X lines_city[i] = NULL; X } X} X X/* X * Register a blast for later display. After this call the blast will X * automatically be incremented and decremented in size, and will be checked X * for intersection with missiles. X */ Xadd_blast(bid) Xregister struct blast *bid; X{ X /* for now don't sort, just stick at the head */ X register int pos = bid->orig_y / LINE_GRAIN; X struct blast **lines; X if (pos < 0 || pos >= MAX_LINES/LINE_GRAIN + 1) { X return; X } X lines = init_line_from_bid(bid); X bid->next = lines[pos]; X lines[pos] = bid; X blast_count++; X} X X/* X * Remove a blast from the display list. The blast will no longer X * intersect missiles, change in size, or be displayed. The blast must X * have already been cleared from the display elsewhere. The storage X * is not freed here, in case the blast is statically allocated. X */ Xremove_blast(bid) Xregister struct blast *bid; X{ X struct blast **lines = init_line_from_bid(bid); X register struct blast *ptr = lines[bid->orig_y / LINE_GRAIN]; X if (ptr == bid) { X /* head is special case */ X lines[bid->orig_y / LINE_GRAIN] = bid->next; X } else { X while ( ptr != NULL && ptr->next != bid ) X ptr = ptr->next; X if (ptr != NULL) X ptr->next = bid->next; X } X blast_count--; X} X X/* X * See if the missile 'mid' has run into any blasts. X */ Xintersect(mid) Xstruct missile *mid; X{ X int start = max((mid->y - (MAX_CIRCLE >> 1) - 1) / LINE_GRAIN, 0); X int end = min((mid->y + (MAX_CIRCLE >> 1) + 1) / LINE_GRAIN, max_y); X register int i; X register struct blast *ptr; X struct blast **lines = init_line_from_mid(mid); X for (i=start; i <= end; i++) { X ptr = lines[i]; X while (ptr != NULL) { X if (single_intersect(ptr, mid)) X return TRUE; X ptr = ptr->next; X } X } X return FALSE; X} X X/* X * See if the missile 'mid' is passing through blast 'bid'. This routine X * is also used for laser initialization, with a fake 'bid' to simulate X * the laser range. For purposes of computing intersection, the circular X * blast is considerd to be a rectangle with the same center and approximately X * the same area. An intersection has occured if the missile passed X * through the blast between its last update and now, even if both endpoints X * are outside the blast. X */ Xsingle_intersect(bid,mid) Xstruct missile *mid; Xstruct blast *bid; X{ X int x0 = mid->old_x, y0 = mid->old_y, x1 = mid->x, y1 = mid->y; X return rect_clipvector(&bid->r, &x0, &y0, &x1, &y1); X} X X/* X * Procedure 'func' is called for every blast on the display lists. X */ Xdoto_blasts(func) Xint (*func)(); X{ X int i; X struct blast *bid, *next; X struct blast **lines; X lines = lines_launch; X for (i=0; i< (MAX_LINES/LINE_GRAIN + 1); i++) { X bid = lines[i]; X while (bid != NULL) { X next = bid->next; /* in case func destroys it */ X (*func)(bid); X bid = next; X } X } X lines = lines_city; X for (i=0; i<(MAX_LINES/LINE_GRAIN + 1); i++) { X bid = lines[i]; X while (bid != NULL) { X next = bid->next; /* in case func destroys it */ X (*func)(bid); X bid = next; X } X } X} X X/* X * Given a blast, return the proper display on which it will be found. X */ Xstatic struct blast ** Xinit_line_from_bid(bid) Xstruct blast *bid; X{ X if (bid->pw == launchpw) { X return lines_launch; X } else { X return lines_city; X } X} X X/* X * Given a missile, return the proper display list on which intersecting X * blasts will be found. X */ Xstatic struct blast ** Xinit_line_from_mid(mid) Xstruct missile *mid; X{ X if (mid->pw == launchpw) { X return lines_launch; X } else { X return lines_city; X } X} X X/* X * Remove all blasts from the display lists and free their storage. X * Nothing is done here about getting them off the display. X */ Xstatic struct blast **line_list[] = {lines_launch, lines_city}; Xfree_all_blasts() X{ X int i, l; X struct blast *bid, *nextbid, **lines; X for (l=0; l < 2; l++) { X lines = line_list[l]; X for (i=0; i<(MAX_LINES/LINE_GRAIN + 1); i++) { X bid = lines[i]; X lines[i] = NULL; X while (bid != NULL) { X nextbid = bid->next; X free(bid); X bid = nextbid; X } X } X } X blast_count = 0; X} X X/* X This is the old style, now commented out. It would let a fast X moving missile pass right through, but did consider blasts to X be real circles. X Xsingle_intersect(bid, mid) Xstruct blast *bid; Xstruct missile *mid; X{ X register short offx = B_WIDTH(bid)/2; X register short x = bid->x - mid->x; X register short y = bid->y - mid->y; X return (x*x + y*y) < (offx*offx); X} X*/ X END_OF_intersect.c if test 5338 -ne `wc -c makefile <<'END_OF_makefile' XSCOREFILENAME = /tmp/sdi_scores XSCOREFILE = "${SCOREFILENAME}" X X# The breakdown into SRC 1, 2 and 3 is purely for shar purposes. XSRC1 = main.c helpers.c missile.c cursor.c scores.c save_game.c text.c piemenu_track.c X XSRC2 = control.c blast.c circles.c laser.c rocks.c input.c notify.c control_procs.c menu.c X XSRC3 = intersect.c random.c incoming.c cities.c pr_helpers.c game_over.c argv.c global.c icons.c X XSRC = ${SRC1} ${SRC2} ${SRC3} X XH1 = melt.h default_city.h cursor.h laser.h mushroom.h laserkill.h \ X missilekill.h city_icon1.h \ X city_icon2.h city_icon3.h city_icon4.h city_icon5.h city_icon6.h \ X city_icon7.h city_icon8.h rocks.h dynacursor.h foe_picture.h \ X laser_picture.h interceptor_picture.h rock_picture.h dyna_picture.h \ X silly_picture.h cross_picture.h foe_ground_picture.h \ X fancy_icon1.h fancy_icon2.h fancy_icon3.h X XH2 = fancy_icon4.h fancy_icon5.h \ X fancy_icon6.h fancy_icon7.h fancy_icon8.h fancy_icon9.h fancy_icon10.h \ X fancy_icon11.h fancy_icon12.h fancy_icon13.h fancy_icon14.h \ X fancy_icon15.h fancy_icon16.h fancy_icon17.h fancy_icon18.h \ X fancy_icon19.h fancy_icon20.h fancy_icon21.h fancy_icon22.h \ X fancy_icon23.h fancy_icon24.h walkmenu_impl.h image_impl.h center.h \ X incoming_picture.h pie_generic_cursor.h X XH = ${H1} ${H2} X XADMIN = README sdi.man HISTORY.nr NOTES TODO makefile genmessage.c \ X makehistory.awk editall source_converter.c longfile.nr sdi.h \ X lookup.h gameover.h icon.h talkingmark.h makeman.sed novice_advice.h \ X occasional_advice.h expert_advice.h about_msg.h instructions.h \ X piemenu.h makeversion version.c X XALLFILES = ${ADMIN} ${SRC} ${H} X XOBJ = main.o circles.o blast.o missile.o intersect.o random.o incoming.o \ X cities.o pr_helpers.o control.o game_over.o helpers.o argv.o global.o \ X laser.o icons.o scores.o save_game.o rocks.o notify.o input.o \ X control_procs.o cursor.o text.o menu.o piemenu_track.o \ X sourcecode.o history.o man.o version.o X X#If you are running SUNOS 3.0, use this: CLAGS = -DSUNOS3_0 X XCFLAGS = -DSUNOS3_0 X XLIBS = -lsuntool -lsunwindow -lpixrect -lm X Xall: sdi X Xsdi: ${OBJ} X cc ${CFLAGS} -o sdi ${OBJ} ${LIBS} X Xversion.o: ${SRC} ${H} ${ADMIN} X makeversion version.c X cc ${CFLAGS} -c version.c X Xfastsdi: X /bin/rm -f sdi X touch sourcecode.o X make sdi X sdi X Xsrc: X cat ${SRC} | expand -4 >src X Xsourcecode.o: ${SRC} source_converter X cat ${SRC} | expand -4 | source_converter source_code > /tmp/sourcecode.s X cc -c /tmp/sourcecode.s X /bin/rm -rf /tmp/sourcecode.s X Xhistory.o: HISTORY.nr source_converter X cat longfile.nr HISTORY.nr | tbl | nroff -me | col | awk -f makehistory.awk | source_converter history_text >/tmp/history.s X cc -c /tmp/history.s X /bin/rm -rf /tmp/history.s X Xman.o: sdi.man source_converter makeman.sed X nroff -man longfile.nr sdi.man | sed -f makeman.sed | col | source_converter man_text >/tmp/man.s X cc -c /tmp/man.s X /bin/rm -rf /tmp/man.s X Xgrind: X cat ${SRC} | expand -4 | vgrind -t -h SDI >source.grind X Xtextedit: X editall ${SRC} ${ADMIN} Xsize: X wc ${SRC} X wc ${ADMIN} X wc ${H} X Xclean: X /bin/rm -f sdi bigmessage.h genmessage *.o *shar X Xshar: X /bin/rm -f sdi.shar X makescript -o sdi.shar ${ALLFILES} X XZ: shar X /bin/rm -f sdi.shar.Z X compress sdi.shar X Xsplitshar: X makescript -o sdi1.shar ${ADMIN} X makescript -o sdi2.shar ${SRC1} X makescript -o sdi3.shar ${SRC2} X makescript -o sdi4.shar ${SRC3} X makescript -o sdi5.shar ${H1} X makescript -o sdi6.shar ${H2} X ls -l sdi1.shar sdi2.shar sdi3.shar sdi4.shar sdi5.shar sdi6.shar X X# X# ORIGSIZE for game and the constant for bigmessage.h X# are related by a factor of 64. X# Xgame_over.o: bigmessage.h game_over.c X cc ${CFLAGS} -c game_over.c -DORIGSIZE=256 X Xscores.o: scores.c X cc ${CFLAGS} -c scores.c '-DSCOREFILE=${SCOREFILE}' X Xbigmessage.h: genmessage talkingmark.h X genmessage talkingmark.h 4 >bigmessage.h X Xgenmessage: genmessage.c X cc ${CFLAGS} -o genmessage genmessage.c ${LIBS} X Xtestrandom: random.o testrandom.o X cc ${CFLAGS} -o testrandom testrandom.o random.o X Xvectortest: vectortest.o X cc ${CFLAGS} -o vectortest vectortest.o ${LIBS} X Xwormtest: wormtest.o X cc ${CFLAGS} -o wormtest wormtest.o ${LIBS} X Xicontest: icontest.o X cc ${CFLAGS} -o icontest icontest.o ${LIBS} X Xkeytest: keytest.o X cc ${CFLAGS} -o keytest keytest.o ${LIBS} X Xinvert: invert.o X cc ${CFLAGS} -o invert invert.o ${LIBS} X Xicons.o: city_icon1.h city_icon2.h city_icon3.h city_icon4.h city_icon5.h city_icon6.h city_icon7.h city_icon8.h END_OF_makefile if test 4377 -ne `wc -c save_game.c <<'END_OF_save_game.c' X/***************************** save_game.c ******************************/ X#include X#include 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 save and restore games. X */ X X/* If the save format is changed, change the version number. */ X#define SAVE_VERSION 6 X Xextern int time_to_play, gamemaster, cursor_type; Xextern char save_file_name[]; Xextern Panel_item cursor_item, cycle_time_item; Xextern char *strcpy(); X Xvoid Xsave_game() { X char tmpbuf[128]; X int control_x, control_y; X FILE *Savefile; X X if ((Savefile = fopen(SAVE_FILE_NAME, "r")) != NULL) { X sprintf(tmpbuf, "Save file '%s' already exists. Overwrite?", SAVE_FILE_NAME); X if (! easy_warn(tmpbuf)) X return; X fclose(Savefile); X } X X if ((Savefile = fopen(SAVE_FILE_NAME, "w")) == NULL) { X sprintf(tmpbuf, "Cannot open save file '%s'.", SAVE_FILE_NAME); X easy_pop(tmpbuf); X } X X X fprintf(Savefile, "version = %d\n", SAVE_VERSION); X X fprintf(Savefile, "level = %s\n",(char *)panel_get_value(level_item)); X X fprintf(Savefile, "skill = %d\n", panel_get_value(skill_item)); X X fprintf(Savefile, "interceptor_val = %d\n", panel_get_value(interceptor_item)); X X fprintf(Savefile, "laser_val = %d\n", panel_get_value(laser_item)); X X fprintf(Savefile, "rock_val = %d\n", panel_get_value(rock_item)); X X fprintf(Savefile, "game_master = %d\n", gamemaster); X X fprintf(Savefile, "score = %s\n", panel_get_value(score_item)); X X fprintf(Savefile, "name = '%s'\n", USER_NAME); X X fprintf(Savefile, "playing field size = %d, %d\n", X window_get(cityframe, WIN_WIDTH), X window_get(cityframe, WIN_HEIGHT)); X X fprintf(Savefile, "control panel position = %d, %d\n", X (control_x = (int)window_get(controlframe, WIN_X)), X (control_y = (int)window_get(controlframe, WIN_Y))); X X /* X * Kludge around a "feature" of Sunview in which negative X * positions are ignored. X */ X window_set(controlframe, WIN_X, 0, WIN_Y, 0, 0); X X fprintf(Savefile, "city field position = %d, %d\n", X window_get(cityframe, WIN_X), X window_get(cityframe, WIN_Y)); X X fprintf(Savefile, "launch field position = %d, %d\n", X window_get(launchframe, WIN_X), X window_get(launchframe, WIN_Y)); X X window_set(controlframe, WIN_X, control_x, WIN_Y, control_y, 0); X X fprintf(Savefile, "blast_delay = %d\n", blast_delay); X X fprintf(Savefile, "cursor_type = %d\n", cursor_type); X X fclose(Savefile); X} X Xvoid Xrestore_game() { X int version; X int tmpint, w, h, x, y; X int control_x, control_y; X char tmpbuf[256]; X FILE *Savefile; X if ((Savefile = fopen(SAVE_FILE_NAME, "r")) == NULL) { X sprintf(tmpbuf, "Can't open restore file '%s'.", SAVE_FILE_NAME); X easy_pop(tmpbuf); X return; X } X X fscanf(Savefile, "version = %d\n", &version); X if (version != SAVE_VERSION) { X easy_pop("The save file has the wrong version."); X return; X } X X fscanf(Savefile, "level = %s\n", tmpbuf); X panel_set_value(level_item, tmpbuf); X X fscanf(Savefile, "skill = %d\n", &tmpint); X panel_set_value(skill_item, tmpint); X X fscanf(Savefile, "interceptor_val = %d\n", &tmpint); X panel_set(interceptor_item, PANEL_VALUE, tmpint, X PANEL_MAX_VALUE, tmpint, X 0); X X fscanf(Savefile, "laser_val = %d\n", &tmpint); X panel_set(laser_item, PANEL_VALUE, tmpint, X PANEL_MAX_VALUE, tmpint, X 0); X X fscanf(Savefile, "rock_val = %d\n", &tmpint); X panel_set(rock_item, PANEL_VALUE, tmpint, X PANEL_MAX_VALUE, tmpint, X 0); X X fscanf(Savefile, "game_master = %d\n", &gamemaster); X X fscanf(Savefile, "score = %s\n", tmpbuf); X panel_set_value(score_item, tmpbuf); X X fscanf(Savefile, "name = '%[^']'\n", tmpbuf); X if (user_name[0] == '\0') X panel_set_value(user_name_item, tmpbuf); X strcpy(user_name, tmpbuf); X X fscanf(Savefile, "playing field size = %d, %d\n", &w, &h); X /* Only set one, they track each other. */ X window_set(cityframe, WIN_WIDTH, w, WIN_HEIGHT, h, 0); X X fscanf(Savefile, "control panel position = %d, %d\n",&control_x,&control_y); X /* X * Kludge around a "feature" of Sunview in which negative X * positions are ignored. X */ X window_set(controlframe, WIN_X, 0, WIN_Y, 0, 0); X X fscanf(Savefile, "city field position = %d, %d\n",&x,&y); X window_set(cityframe, WIN_X, x, WIN_Y, y, 0); X X fscanf(Savefile, "launch field position = %d, %d\n",&x,&y); X window_set(launchframe, WIN_X, x, WIN_Y, y, 0); X X window_set(controlframe, WIN_X, control_x, WIN_Y, control_y, 0); X X fscanf(Savefile, "blast_delay = %d\n", &blast_delay); X panel_set_value(cycle_time_item, blast_delay); X X fscanf(Savefile, "cursor_type = %d\n", &tmpint); X cursor_type = tmpint; X X fclose(Savefile); X} X XFILE * Xgetsavefile(s) Xchar *s; X{ X char *filename; X FILE *stream; X Event event; X filename = SAVE_FILE_NAME; X if (((stream = fopen(filename, s)) == NULL)) { X easy_pop("Can't open the save file."); X } X return stream; X} END_OF_save_game.c if test 5019 -ne `wc -c scores.c <<'END_OF_scores.c' X/********************************** scores.c **********************/ X#include X#include 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 * This code is responsible X * reading, updating, and displaying the score file. X */ X X#ifndef SCOREFILE X#define SCOREFILE "/usr/games/lib/sdi_scores" X#endif X Xstruct scores *get_scores(); X X/* Already updated is used to prevent rewriting the score file more than X * once per game. X */ Xstatic int already_updated = 0; X X/* X * This routine is called whenever there is absolutely positively a new X * game beginning, and so if it ever gets anywhere it is ok to update X * the score file. X */ Xnew_score() X{ X already_updated = 0; X} X X/* X * Read in the old scores and insert the current game score into the file X * if it is within the top ten. No scores are recorded in gamemaster mode. X */ Xupdate_scores() X{ X extern int gamemaster; X struct scores *scp, *new_pos = NULL; X int i; X int score = atol((char *)panel_get_value(score_item)); X int level = atol((char *)panel_get_value(level_item)); X int skill = (int)panel_get_value(skill_item); X if (already_updated || gamemaster) X return; X if ((scp = get_scores()) == NULL) X return; X while (scp->score > score) { X scp += 1; X } X if (scp->score >= 0) { X struct scores *new_sc = sc_end; X while (--new_sc > scp) { X strcpy(new_sc->name, (new_sc-1)->name); X new_sc->score = (new_sc-1)->score; X new_sc->level = (new_sc-1)->level; X new_sc->skill = (new_sc-1)->skill; X } X strcpy(scp->name, USER_NAME); X scp->score = score; X scp->level = level; X scp->skill = skill; X } X if (! put_scores(sc)) { X printf("Could not write to score file '%s'.\n",scorefile); X } X already_updated = 1; X} X X/* X * Get the name of the current user. X */ Xchar * Xget_name() X{ X char *s; X struct passwd *p; X if (s = (char *)getlogin()) X return s; X p = (struct passwd *)getpwuid(getuid()); X return p->pw_name; X} X X/* X * Read the score file. The format is obvious. Exactly 11 scores are always X * returned. The 11th is a sentinal with score '-1'. If the score file did X * not have 10, then the extras are for user '(nobody)', score 0. X * A user name may not contain a "'". The result of get_scores is an array X * of score structures, statically allocated. X */ Xstruct scores * Xget_scores() X{ X struct scores *scp; X char *tmpfile, *getenv(); X FILE *f; X if (scorefile) { X tmpfile = scorefile; X } else if ((tmpfile = getenv("SDI_SCORES")) == NULL) { X tmpfile = scorefile; X } else { X tmpfile = "/usr/games/lib/sdi_scores"; X } X /* Try hard to open some kind of score file */ X if (((f = fopen(tmpfile, "r+")) == NULL)) { X tmpfile = SCOREFILE; X if (((f = fopen(tmpfile, "r+")) == NULL)) { X tmpfile = "/usr/games/lib/sdi_scores"; X if ((f = fopen("/usr/games/lib/sdi_scores", "r+")) == NULL) X return NULL; X } X } X scorefile = tmpfile; X X /* read entries */ X scp = sc; X while (scp < sc_end && X (fscanf(f, " '%[^']' %d %d %d", scp->name, &scp->score, &scp->level, &scp->skill) == 4) && X scp->score > 0) { X scp += 1; X } X while (scp < sc_end) { X strcpy(scp->name, "(nobody)"); X scp->score = 0; X scp->level = 0; X scp->skill = 0; X scp += 1; X } X scp->score = -1; X fclose(f); X return sc; X} X X/* X * Write a list of scores to the score file. Never called directly, except X * by update_scores. X */ Xput_scores(scp) Xstruct scores *scp; X{ X FILE *f; X if ((f = fopen(scorefile, "w")) == NULL) X return 0; X /* write entries */ X while (scp->score > 0) { X fprintf(f, "'%s' %d %d %d\n", scp->name, scp->score, scp->level, scp->skill); X scp += 1; X } X fclose(f); X return 1; X} X X/* X * This routine formats the score file for display when the 'scores' X * button is pressed. X */ Xstatic char string_for_build_scores[1024]; X Xchar * Xbuild_scores() X{ X char *sp = string_for_build_scores; X struct scores *scp; X char *type_of_skill; X scp = (struct scores *)get_scores(); X if (scp == NULL) { X strcpy(sp, "Could not find a score file."); X } else { X strcpy(sp, "No scores yet: play some games."); X while (scp->score > 0) { X switch(scp->skill) { X case 0: X type_of_skill = " novice"; X break; X case 1: X type_of_skill = "n occasional user"; X break; X case 2: X type_of_skill = "n expert"; X break; X } X sprintf(sp, X "%s, playing as a%s, melted with score %d at level %d.\n", X scp->name, type_of_skill, scp->score, scp->level); X scp += 1; X sp += strlen(sp); X } X } X return string_for_build_scores; X} X X/* X * Free the result of a call to build_scores. X */ Xfree_scores(a) Xchar **a; X{ X/* Oh, how I long for garbage collection. */ X while (*++a) X free(*a); X} X END_OF_scores.c if test 4859 -ne `wc -c sdi.h <<'END_OF_sdi.h' X/* X * Copyright 1987 by Mark Weiser. X * Permission to reproduce and use in any manner whatsoever 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. X */ X/* includes needed by definitions in here, and so may as well put here */ X#include X#include X#include X X/* General Definitions */ X#undef min X#undef max X#define ABS(x) (((x) < 0) ? -(x) : (x)) X#define DOWN 1 X#define UP -1 X#define TRUE 1 X#define FALSE 0 X#define FIELD_MARGIN field_margin X X#define USER_NAME (user_name[0] == '\0' ? panel_get_value(user_name_item) : user_name) X#define SAVE_FILE_NAME (save_file_name[0] == '\0' ? panel_get_value(save_file_item) : save_file_name) X X/* space to leave on either side of row of cities. */ X#define MARGIN 30 X X/* minimum window size */ X#define MINWIN 128+(MARGIN*2)+(FIELD_MARGIN*2) X X/* Definitions affecting blasts */ Xextern struct circ { X int num_circles; X struct pixrect **circles; X struct pixrect **masks X} *lasercircles, X *laserkillcircles, X *bigblastcircles, X *littleblastcircles, X *blastkillcircles, X *citykillcircles, X *littlerockcircles, X *bigrockcircles, X *init_circ(); Xextern struct pixrect **blankcircles; Xextern int blast_count; Xstruct blast { X Pixwin *pw; X short x, y, circ, width; X short orig_y; /* used only for hashing */ X short x_inc, y_inc; X short num_circles; X struct pixrect **circles; X struct pixrect **masks; X struct blast *next; X Rect r; X }; X#define MAX_LINES 1024 X#define MAX_NUM_CIRCLES 8 X#define MAX_CIRCLE 64 X#define CIRCLE_SIZE_INC (MAX_CIRCLE/(MAX_NUM_CIRCLES+1)) X#define B_WIDTH(bid) ((bid)->width) X#define B_HEIGHT(bid) ((bid)->width) X#define B_OFFSET_X(bid) ((bid)->x-(B_WIDTH(bid)/2)) X#define B_OFFSET_Y(bid) ((bid)->y-(B_HEIGHT(bid)/2)) X X/* Definitions affecting missiles */ Xextern int missile_count, burst_distance; Xstruct missile { X Pixwin *pw; X short start_x, start_y, X old_x, old_y, X x, y, inc_x, inc_y, X slip_cnt, slip, speed, refs, destroyed; X struct missile *next; X }; X#define BALLISTIC_DELAY 5 X X X/* Definitions affecting everybody */ Xextern int suspended; Xextern long blast_delay; Xextern Pixwin *citypw, *launchpw; Xextern int max_x, max_y; Xextern int foe_value, running; Xextern Panel_item level_item, interceptor_item, foe_item, score_item, X ballistic_item, btime_item, next_round_item, new_game_item, skill_item, X resume_item, suspend_item, laser_item, non_stop_item, name_item, X rock_item, user_name_item, save_file_item; Xextern char user_name[], save_file_name[]; Xextern int city_fd; Xextern int launch_fd; Xextern Canvas citycanvas; Xextern Frame cityframe, controlframe, launchframe; Xextern char *panel_common[]; Xstruct pixrect *make_circle(); Xextern Canvas launchcanvas; Xextern int launch_delay; Xextern int num_cities; Xvoid no_events(); Xextern int total_cities_lost; X#define NUM_SCORES 10 Xextern struct scores { X char name[64]; X int score, level, skill; X } sc[], *sc_end; Xextern float carryover_divisor, foe_divisor; Xextern int foe_factor; Xextern int min_missile_speed, max_missile_speed; Xextern char *scorefile; Xextern struct pixfont *font; /* struct used for 3.0 compatibility */ Xextern Pixwin *need_a_bell; Xextern int field_margin; Xextern Panel_item total_foe_item; END_OF_sdi.h if test 3256 -ne `wc -c text.c <<'END_OF_text.c' X/***************************** text.c ******************************/ X#include "sdi.h" X#define PIES X#ifdef PIES X#include "piemenu.h" X#endif 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 * Find the size of the longest line in a string of lines separated by newlines X */ Xmax_line(s) Xchar *s; X{ X int max = 0, count = 0; X while (*s) { X if (*s++ == '\n') { X if (count > max) X max = count; X count = 0; X continue; X } X count += 1; X } X if (count > max) X max = count; X return max; X} X X/* X * Count the number of lines in a string of lines separated by newlines. X */ Xcount_lines(s) Xchar *s; X{ X int count = 0; X while (*s) { X if (*s++ == '\n') X count += 1; X } X return count+1; X} X Xstatic char *help_msg[] = { X#include "novice_advice.h" X , X#include "occasional_advice.h" X , X#include "expert_advice.h" X }; X X/* X * Display a brief message of advice appropriate to the current skill level. X */ Xvoid Xhelp_proc(item, event) XPanel_item item; XEvent *event; X{ X int skill = (int)panel_get_value(skill_item); X popup_msg(controlframe, event, help_msg[skill]); X} X Xstatic char *about_msg = X#include "about_msg.h" X ; X/* X * Display a brief informative message about the game. X */ Xvoid Xabout_proc(item, event) XPanel_item item; XEvent *event; X{ X popup_msg(controlframe, event, about_msg); X} X Xstatic char *art_msg = "This space reserved for Marcel Duchamp"; X/* X * Display a brief informative message about art. X */ Xvoid Xart_proc(item, event) XPanel_item item; XEvent *event; X{ X popup_msg(controlframe, event, art_msg); X} X X/* X * Display the complete source code of the game in a popup window. X * The external variable 'source code' must be properly filled elsewhere. X * (See the sdi makefile for one way.) X */ Xvoid Xsource_proc(item, event) XPanel_item item; XEvent *event; X{ X extern char *source_code; X popup_msg(controlframe, event, source_code); X} X X/* X * Display the history of the game's development in a popup window. X * The external variable 'history_text' must be properly filled elsewhere. X * (See the sdi makefile for one way.) X */ Xvoid Xhistory_proc(item, event) XPanel_item item; XEvent *event; X{ X extern char *history_text; X popup_msg(controlframe, event, history_text); X} X X/* X * Display the man entry in a popup (sort of) window. X * The external variable 'man_text' must be properly filled elsewhere. X * (See the sdi makefile for one way.) X */ Xvoid Xman_proc(item, event) XPanel_item item; XEvent *event; X{ X extern char *man_text; X popup_msg(controlframe, event, man_text); X} X Xvoid Xinstructions_proc() X{ X easy_pop( X#include "instructions.h" X ); X} X Xvoid Xversion_proc() X{ X extern char *version; X easy_pop(version); X X} X Xtext_options_proc(item, event) XPanel_item item; XEvent *event; X{ X extern scores_proc(); X extern struct pixfont *buttonfont; /* use 'struct pixfont' for 3.0 compatiblity */ X Menu_item mi; X Menu menu, menu_create(); X int (*selection)(); X suspend_proc(); X menu = menu_create(MENU_NOTIFY_PROC, menu_return_item, 0); X menu_set(menu, MENU_APPEND_ITEM, menu_create_item(MENU_STRING, "Source", MENU_CLIENT_DATA, source_proc, 0), 0); X menu_set(menu, MENU_APPEND_ITEM, menu_create_item(MENU_STRING, "History", MENU_CLIENT_DATA, history_proc, 0), 0); X menu_set(menu, MENU_APPEND_ITEM, menu_create_item(MENU_STRING, "Man", MENU_CLIENT_DATA, man_proc, 0), 0); X menu_set(menu, MENU_APPEND_ITEM, menu_create_item(MENU_STRING, "Scores", MENU_CLIENT_DATA, scores_proc, 0), 0); X menu_set(menu, MENU_APPEND_ITEM, menu_create_item(MENU_STRING, "About", MENU_CLIENT_DATA, about_proc, 0), 0); X menu_set(menu, MENU_APPEND_ITEM, menu_create_item(MENU_STRING, "Art", MENU_CLIENT_DATA, art_proc, 0), 0); X menu_set(menu, MENU_APPEND_ITEM, menu_create_item(MENU_STRING, "Advice", MENU_CLIENT_DATA, help_proc, 0), 0); X menu_set(menu, MENU_APPEND_ITEM, menu_create_item(MENU_STRING, "Version", MENU_CLIENT_DATA, version_proc, 0), 0); X special_menu_show(menu, event); X} X Xspecial_menu_show(menu, event) X{ X int notify_me(); X pie_menu_show(menu, controlframe, event, notify_me, "Things To Read ('pie' form)"); X} X Xnotify_me(mi, event) XMenu_item mi; X{ X int (*selection)(); X if (mi != NULL){ X (caddr_t)selection = (caddr_t)menu_item_get(mi, MENU_CLIENT_DATA); X (*selection)(0, event); X } X resume_proc(); X} END_OF_text.c if test 4472 -ne `wc -c