|
|
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 c
Length: 7166 (0x1bfe)
Types: TextFile
Names: »cities.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
└─⟦this⟧ »EUUGD18/Sun/Sdi/cities.c«
/********************************** cities.c ************************/
#include <pixrect/pixrect_hs.h>
#include <stdio.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 do things to cities. Much of the code here consists of
* passing a routine into doto_cities, which then calls that routine
* on each city. See the comment for doto_cities (near the end of the file)
* for more information.
*/
static short default_city_data[] = {
#include "default_city.h"
};
mpr_static(default_city_pr, 64, 64, 1, default_city_data);
static struct pixrect *city_pr_ptr = &default_city_pr;
static colormap_t city_colormap, *city_colormap_ptr = NULL;
static short melted_city_data[] = {
#include "melt.h"
};
mpr_static(melted_city_pr, 64, 64, 1, melted_city_data);
#define MIN_SPACE 4
#define MAX_CITIES 40
static int city_space, excess, global_count;
static long bits_in_city;
static int do_update(), do_count(), do_placement(), do_kill(),
do_update_all(), do_grow(), do_update_cities(), do_melt_all();
static int cities_inited = 0;
static short cities[MAX_CITIES];
static int growcount; /* ugh, another weird global.
* set by do_update_cities, used only by 'do_grow'.
*/
/*
* Read a new city pixrect from a file.
*/
init_city_bits(filename)
char *filename;
{
/* this routine is only called if there is non-default city. */
if (filename != NULL) {
char error_msg[256];
struct pixrect *tmp,*icon_load_mpr();
if ((tmp = icon_load_mpr(filename, error_msg)) == NULL) {
printf("Could not get pr '%s'.\n", filename);
printf("%s",error_msg);
printf("Using default cities.\n");
} else {
city_pr_ptr = tmp;
}
}
}
/*
* Compute the positions of all the cities based on current screen size,
* and declare all the cities to be unmelted.
*/
init_cities()
{
int i, old_num_cities = num_cities;
bits_in_city = count_bits(city_pr_ptr);
num_cities = ((max_x - MARGIN)/64) + 1; /* bigger than possible */
city_space = 0;
while (city_space < MIN_SPACE) {
num_cities -= 1;
city_space = ((max_x - MARGIN) - (num_cities * 64))/(num_cities-1);
};
excess = max_x - (MARGIN + 64*num_cities + city_space*(num_cities-1));
for (i=old_num_cities; i<num_cities; i++) {
cities[i] = 1;
}
cities_inited = 1;
}
/*
* display the cities, melted or otherwise.
*/
place_cities(pw)
Pixwin *pw;
{
pw_writebackground(pw, 0, max_y-8, max_x, max_y, PIX_NOT(PIX_SRC));
doto_cities(pw, do_placement, city_pr_ptr, 0);
doto_cities(pw, do_placement, &melted_city_pr, 1);
}
/* helper for 'place_cities', passed into 'doto_cities' */
static int
do_placement(pr, city_pr)
struct pixrect *pr, *city_pr;
{
pr_rop(pr, 0, 0, 64, 64, PIX_SRC, city_pr, 0, 0);
return 1; /* this forces the new city back into the pixwin */
}
/*
* Pop a new city onto the display at a random empty position.
*/
new_city(pw)
Pixwin *pw;
{
int pick, num_gone = 0, i;
for (i=0; i < num_cities; i += 1) {
if (!cities[i])
num_gone += 1;
}
if (num_gone == 0)
return;
pick = (random() % num_gone) + 1;
for (i=0; i < num_cities; i += 1) {
if (!cities[i] && !--pick)
break;
}
/* restore a random melted city */
cities[i] = 1;
do_update_cities(pw, 1, do_grow);
}
/* helper for do_update_cites, grow a city. */
static int
do_grow(pr, speed)
struct pixrect *pr;
{
grow(pr, city_pr_ptr, growcount+16);
return 1;
}
/* return how many died */
static int global_citycount;
compute_cities(pw)
Pixwin *pw;
{
global_citycount = 0;
doto_cities(pw, do_count, 0, 0);
return global_citycount;
}
/* helper for 'compute_cities', passed into 'doto_cities' */
static int
do_count(pr, client)
struct pixrect *pr;
int *client;
{
if (city_dead(pr)) {
global_citycount += 1;
}
return 0; /* avoids pw_write in doto_cities */
}
/*
* Melt or grow each city, as appropriate.
*/
update_cities(pw, speed)
{
do_update_cities(pw, speed, do_update);
doto_cities(pw, do_kill, 0, 0);
}
/* helper for 'update_cities', passed to 'do_update_cities', grows or melts. */
static int
do_update(pr, speed)
struct pixrect *pr;
int speed;
{
if (city_dead(pr)) {
melt(pr, &melted_city_pr, speed);
return 1;
} else {
grow(pr, city_pr_ptr, growcount+16);
return 1;
}
}
/* Helper for 'update_cities', passed into doto_cities, computes dead cities. */
static int
do_kill(pr, tmp)
struct pixrect *pr;
{
if (city_dead(pr))
cities[global_count] = 0;
return 0;
}
/* Do what it says. */
melt_all_cities(pw, speed)
{
do_update_cities(pw, speed, do_melt_all);
}
/* helper for 'melt_all_cities', passed into 'do_update_cities' */
static int
do_melt_all(pr, speed)
struct pixrect *pr;
int speed;
{
melt(pr, &melted_city_pr, speed);
return 1; /* forces writing out the melted city in doto_cities */
}
/*
* Call function 'helper' numerous times on each city, thus causing
* growing or melting (or both), depending upon 'helper'.
*/
static int
do_update_cities(pw, speed, helper)
int (*helper)();
{
int i;
int count = (64 / speed) + 1;
for (growcount = 1; growcount < count; growcount += 1) {
/* we might plausibly batch here, but the melt looks better without */
doto_cities(pw, helper, speed, 0);
}
}
/*
Cities are a kind of abstract datatype. To do something to all
cities, pass a function and a piece of client data to 'doto_cities',
and the function will be called once for each city still in
existence (or if 'non-cities' is non-zero, once for each city NOT
still in existence.) The calling sequence for the passed in
function will be:
func(pr, client_data);
where 'pr' is a 64x64 pixrect of a city. If 'func' returns 0 then
'pr' is assumed to be unchanged, otherwise 'pr' is written back into
the pixwin so the change is visible. Global_count is set before the
call to the ordinal number of the city currently being operated on.
Init_cities must be called before any city operations.
*/
static char tmp_image_place[512];
mpr_static(tmpcity_pr, 64, 64, 1, tmp_image_place);
doto_cities(pw, func, client_data, non_cities)
Pixwin *pw;
int (*func)();
int *client_data;
{
int x = MARGIN/2 + excess/2, stop_x = max_x - MARGIN/2 - 64;
int y = max_y - 64;
if (! cities_inited) {
/* no return from here */
printf("'doto_cities called before 'init_cities'.\n");
abort();
}
global_count = 0;
while (x <= stop_x) {
if ((!non_cities && cities[global_count]) ||
(non_cities && !cities[global_count])) {
pw_read(&tmpcity_pr, 0, 0, 64, 64, PIX_SRC, pw, x, y);
if (func(&tmpcity_pr, client_data))
pw_write(pw, x, y, 64, 64, PIX_SRC, &tmpcity_pr, 0, 0);
}
global_count += 1;
x += 64 + city_space;
}
}
/*
* See if a city is dead. It is if 2/3's of its pixels are clobbered.
*/
city_dead(pr)
struct pixrect *pr;
{
long bitcount = count_bits(pr);
if (bitcount < 2*bits_in_city/3)
return 1;
else return 0;
}