dslinux/user/pixil/apps/games/nxbill Bucket.cc Bucket.h Cable.cc Cable.h ChangeLog Computer.cc Computer.h Game.cc Game.h Horde.cc Horde.h INSTALL Imakefile Library.cc Library.h MCursor.cc MCursor.h Makefile Makefile.org Monster.cc Monster.h NX.cc NX.h NXMCursor.cc NXMCursor.h NXPicture.cc NXPicture.h NXUI.h NXwidgets.cc NXwidgets.h Network.cc Network.h Picture.cc Picture.h README README.Ports Scorelist.cc Scorelist.h Spark.cc Spark.h Strings.h UI.cc UI.h menu.h nanox-UI.cc nanox-utils.cc objects.h scores x11-athena.cc x11-motif.cc x11.cc x11.h xbill.man

amadeus dslinux_amadeus at user.in-berlin.de
Tue Oct 3 13:24:39 CEST 2006


Update of /cvsroot/dslinux/dslinux/user/pixil/apps/games/nxbill
In directory antilope:/tmp/cvs-serv11916/apps/games/nxbill

Added Files:
	Bucket.cc Bucket.h Cable.cc Cable.h ChangeLog Computer.cc 
	Computer.h Game.cc Game.h Horde.cc Horde.h INSTALL Imakefile 
	Library.cc Library.h MCursor.cc MCursor.h Makefile 
	Makefile.org Monster.cc Monster.h NX.cc NX.h NXMCursor.cc 
	NXMCursor.h NXPicture.cc NXPicture.h NXUI.h NXwidgets.cc 
	NXwidgets.h Network.cc Network.h Picture.cc Picture.h README 
	README.Ports Scorelist.cc Scorelist.h Spark.cc Spark.h 
	Strings.h UI.cc UI.h menu.h nanox-UI.cc nanox-utils.cc 
	objects.h scores x11-athena.cc x11-motif.cc x11.cc x11.h 
	xbill.man 
Log Message:
adding pristine copy of pixil to HEAD so I can branch from it

--- NEW FILE: Strings.h ---


#ifndef STRINGS_H
#define STRINGS_H

#define storystr \
"             The Story:\n\
\n\
Yet again, the fate of the world rests\n\
in your hands!  An evil computer hacker,\n\
known only by his handle 'Bill', has\n\
created the ultimate computer virus.  A\n\
virus so powerful that it has the power\n\
to transmute an ordinary computer into\n\
a toaster oven.  (oooh!) 'Bill' has\n\
cloned himself into a billion-jillion\n\
micro-Bills.  Their sole purpose is to\n\
deliver the nefarious virus, which has\n\
been cleverly diguised as a popular\n\
operating system.\n\
\n\
As System Administrator/Exterminator,\n\
your job is to keep Bill from succeeding\n\
at his task."

#define rulesstr \
"             The Rules:\n\
\n\
xBill has been painstakingly designed and\n\
researched in order to make it as easy to use\n\
for the whole family as it is for little Sally.\n\
Years - nay - days of beta testing and \n\
consulting with the cheapest of human interface\n\
designers have resulted in a game that is easy\n\
to use, yet nothing at all like a Macintosh.\n\
\n\
I.   Whack the Bills (click)\n\
II.  Restart the computer (click)\n\
III. Pick up stolen OSes & return(drag)\n\
     them to their respective computers\n\
IV.  Drag the bucket to extinguish sparks\n\
V.   Scoring is based on total uptime,\n\
     with bonuses for killing Bills.\n\
\n\
As for the rest, you can probably figure\n\
it out.  We did, so it can't be too hard."

#define endgamestr \
"Module xBill has caused a \nsegmentation fault\n\
at memory address 097E:F1A0.\nCore dumped.\n\
\nPlease try again."

#define warpstr "Warp to level?"
#define quitstr "Quit Game?"
#define newgamestr "New Game?"
#define pausestr "Game paused.  Press Continue to continue."
#define enternamestr "You earned a high score.\nEnter your name:"

#endif

--- NEW FILE: nanox-utils.cc ---
 /*
 * Copyright (C) 200-2002 Century Embedded Techonlogies
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/* These are NanoX utilties designed to act */
/* like the Xt counterparts (but better) */

#include "objects.h"
#include "NXUI.h"

GR_GC_ID menubargc;

typedef struct wcallback
{
    GR_WINDOW_ID wid;
    int event;
    GR_FNCALLBACKEVENT callback;
    struct wcallback *next;
}
widget_callback;

widget_callback *callback_list;




GR_WINDOW_ID
NXAppInit(char *title, int xsize, int ysize)
{
    GR_WINDOW_ID newwin;

    newwin =
	GrNewWindow(GR_ROOT_WINDOW_ID, 0, 0, xsize, ysize, 0, BLACK, WHITE);

    GrSelectEvents(newwin, GR_EVENT_MASK_CLOSE_REQ);

    /* Create a top level window with the appropriate title */
    return (newwin);
}

void
NXRealizeWidget(GR_WINDOW_ID widget)
{
    GR_WINDOW_INFO ptr;
    GR_WINDOW_ID child;

    /* First show the parent */
    GrMapWindow(widget);

    GrGetWindowInfo(widget, &ptr);

    if (!ptr.child)
	return;


    child = ptr.child;

    GrMapWindow(child);

    GrGetWindowInfo(child, &ptr);

    while (ptr.sibling) {
	GrMapWindow(ptr.sibling);

	GrGetWindowInfo(ptr.sibling, &ptr);
    }
}


void
check_menubar(GR_EVENT * event)
{
    int x, y;
    GR_RECT rect;

    /* Check to see if we have to do any events */

    rect.x = 2;
    rect.y = 2;
    rect.width = 40;
    rect.height = 23;


    x = event->button.x;
    y = event->button.y;

    if (PtInRect(&rect, event->button.x, event->button.y))
	game.warp_to_level(1);
}


void
redraw_menubar(GR_EVENT * event)
{

}

GR_WINDOW_ID
CreateMenuBar(char *name, GR_WINDOW_ID parent)
{
    /* Create a menu bar with three beautiful buttons */

    menubargc = GrNewGC();

    return (GrNewWindow(parent, 0, 0, 240, 35, 0, BLACK, GRAY));
}

GR_WINDOW_ID
CreatePixmapBox(const char *name, GR_WINDOW_ID parent,
		GR_WINDOW_ID pixmap, const char *text)
{
    printf("I would create a pixmap box here!\n");
}



GR_WINDOW_ID
CreateDrawingArea(char *name, GR_WINDOW_ID parent, int width, int height)
{
    return GrNewWindow(parent, 0, 30, width, height, 0, BLACK, WHITE);
}

GR_WINDOW_ID
CreateRowCol(char *name, GR_WINDOW_ID parent)
{
    printf("I would be creating something here\n");
    return (0);
}

int
NXGetWidgetCallback(GR_WINDOW_ID wid, GR_EVENT * event)
{
    widget_callback *n = callback_list;

    if (!n)
	return (0);

    while (n) {
	if (n->wid == wid && n->event == event->type) {
	    n->callback(event);
	    return (1);
	}

	n = n->next;
    }

    return (0);
}

void
NXRegisterWidgetCallback(GR_WINDOW_ID wid, int event,
			 GR_FNCALLBACKEVENT callback)
{
    widget_callback *n;

    if (!callback_list) {
	callback_list = (widget_callback *) malloc(sizeof(widget_callback));
	n = callback_list;
    } else {
	n = callback_list;
	while (n->next)
	    n = n->next;

	n->next = (widget_callback *) malloc(sizeof(widget_callback));
	n = n->next;
    }

    n->wid = wid;
    n->event = event;
    n->callback = callback;
    n->next = 0;

}

void
NXPopup(GR_WINDOW_ID wid)
{
    printf("Poping up a dialog box!\n");
    /* Pop me up, give me the focus and don't do a damn thing until */
    /* I respond */

    GrMapWindow(wid);
    GrRaiseWindow(wid);
    GrSetFocus(wid);
}


GR_WINDOW_ID
NXCreateDialog(GR_WINDOW_ID parent, char *name, char *str)
{
    /* By default, we are popped up right smack in the middle of the screen */


    return (GrNewWindow(parent, 0, 0, 10, 10, 0, BLACK, WHITE));
}

--- NEW FILE: Scorelist.cc ---
 /*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "objects.h"

extern char xbill_path[256];

FILE *
Scorelist::open_file(char *mode)
{
    char file[255];
    sprintf(file, "%sscores", xbill_path);
    return fopen(file, mode);
}

void
Scorelist::read()
{
    FILE *scorefile = open_file("r");
    int i;
    if (scorefile) {
	for (i = 0; i < 10; i++) {
	    fgets(name[i], 21, scorefile);
	    fscanf(scorefile, "%d%d\n", &(level[i]), &(score[i]));
	}
	fclose(scorefile);
    } else
	for (i = 0; i < 10; i++) {
	    strcpy(name[i], "me");
	    level[i] = score[i] = 0;
	}
}

void
Scorelist::write()
{
    int i, j;
    FILE *scorefile = open_file("w");
    if (!scorefile)
	return;
    for (i = 0; i < 10; i++) {
	fputs(name[i], scorefile);
	for (j = strlen(name[i]); j < 25; j++)
	    fputc(' ', scorefile);
	fprintf(scorefile, " %d %d\n", level[i], score[i]);
    }
    fclose(scorefile);
}

/*  Add new high score to list   */
void
Scorelist::recalc(char *str)
{
    int i;
    if (score[9] >= game.score)
	return;
    for (i = 9; i > 0; i--) {
	if (score[i - 1] < game.score) {
	    strcpy(name[i], name[i - 1]);
	    level[i] = level[i - 1];
	    score[i] = score[i - 1];
	} else
	    break;
    }
    strcpy(name[i], str);
    level[i] = game.level;
    score[i] = game.score;
}

void
Scorelist::update()
{
    char str[500], temp[40];
    int i, j;
    strcpy(str, "High Scores:\n\n");
    strcat(str, "Name                 Level    Score\n");
    for (i = 0; i < 10; i++) {
	strcat(str, name[i]);
	for (j = strlen(name[i]); j < 21; j++)
	    strcat(str, " ");
	sprintf(temp, "%5d  %7d\n", level[i], score[i]);
	strcat(str, temp);
    }
    ui.update_hsbox(str);
}

--- NEW FILE: UI.h ---

#ifndef X11_UI_H
#define X11_UI_H

#include "Picture.h"
#include "MCursor.h"

class UI
{
    XtIntervalId timer;
    int playing;
    Picture icon;
    void get_coords(Position * x, Position * y);
    MCursor defaultcursor, downcursor;
    GC stdgc, whitegc;
  public:
      UI()
    {
	playing = 0;
	timer = (XtIntervalId) 0;
    }
    Display *display;
    XtAppContext app;
    Drawable window, rootwindow;
    Colormap colormap;
    int depth;
    XColor white, black;
    Pixmap offscreen;

    void restart_timer();
    void kill_timer();

    void pause_game();
    void resume_game();

    void initialize(int *argc, char **argv);
    void make_mainwin();
    void make_windows();
    void popup_dialog(int dialog);

    void set_cursor(int cursor);
    void load_cursors();
    void graph_init();
    void clear();
    void refresh();
    void draw(Picture picture, int x, int y);
    void draw_centered(Picture picture);
    void draw_line(int x1, int y1, int x2, int y2);
    void draw_str(char *str, int x, int y);

    void set_pausebutton(int action);
    void MainLoop();

    void update_scorebox(int level, int score);
    void update_hsbox(char *str);
};

#endif

--- NEW FILE: NXwidgets.cc ---
 /* Copyright (C) 200-2002 Century Embedded Techonlogies
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/* This is an attempt to put some method to the maddness */
/* of the various widgets created and handled by NXBill  */

/* It is my sincere hope that will will be merged with   */
/* any standard Microwindows widgets at some point in    */
/* the future                                            */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "NXwidgets.h"

typedef struct nx_callback_t
{
    GR_WINDOW_ID wid;
    int event;
    GR_FNCALLBACKEVENT callback;
    struct nx_callback_t *next;
}
NX_CALLBACK;

typedef struct nx_dialog_t
{
    char str[255];
}
NX_DIALOG;

typedef struct nx_widget_t
{
    int x;			/* Position of the widget */
    int y;

    GR_WINDOW_ID wid;
    GR_WINDOW_ID pid;		/* Parent of the widget */

    NX_DIALOG dialog;

    NX_CALLBACK *callback_list;
    struct nx_widget_t *next;
}
NX_WIDGET;

typedef struct nx_app_t
{
    int wid;
    NX_WIDGET *widgets;
}
NX_APP;

static NX_APP global_app;
extern GR_FONT_ID global_font;

static int handle_dialog_up(GR_WINDOW_ID wid);
static void handle_dialog_expose(GR_WINDOW_ID wid, char *str);

static NX_WIDGET *
find_widget(GR_WINDOW_ID wid)
{
    NX_WIDGET *ptr = global_app.widgets;

    while (ptr) {
	if (ptr->wid == wid)
	    return (ptr);

	ptr = ptr->next;
    }

    return (0);
}

GR_WINDOW_ID
createNXApp(char *title, int xsize, int ysize)
{
    global_app.wid =
	GrNewWindowEx(GR_WM_PROPS_APPWINDOW, (GR_CHAR *) "nxBill",
		      GR_ROOT_WINDOW_ID, 0, 0, xsize, ysize, WHITE);

    GrSelectEvents(global_app.wid, GR_EVENT_MASK_CLOSE_REQ);

    GrMapWindow(global_app.wid);
    global_app.widgets = 0;

    return (global_app.wid);
}

void
killNXApp(GR_WINDOW_ID app)
{
    NX_WIDGET *ptr = global_app.widgets;
    NX_WIDGET *nxt;

    while (ptr) {
	NX_CALLBACK *n, *t;

	nxt = ptr->next;

	if ((n = ptr->callback_list))
	    while (n) {
		t = n->next;
		free(n);
		n = t;
	    }

	free(ptr);
	ptr = nxt;
    }
}

GR_WINDOW_ID
createNXWidget(GR_WINDOW_ID parent, int x, int y, int width, int height)
{
    NX_WIDGET *ptr;

    /* Create a entry for the widget in the list */
    if (global_app.widgets == 0) {
	global_app.widgets = (NX_WIDGET *) malloc(sizeof(NX_WIDGET));
	ptr = global_app.widgets;
    } else {
	ptr = global_app.widgets;
	while (ptr->next)
	    ptr = ptr->next;
	ptr->next = (NX_WIDGET *) malloc(sizeof(NX_WIDGET));
	ptr = ptr->next;
    }

    ptr->x = x;
    ptr->y = y;

    ptr->pid = parent;

    ptr->next = 0;
    ptr->callback_list = 0;

    ptr->wid = GrNewWindow(parent, x, y, width, height, 0, WHITE, WHITE);

    return (ptr->wid);
}

void
registerNXWidgetCallback(GR_WINDOW_ID wid, int event,
			 GR_FNCALLBACKEVENT callback)
{
    GR_WINDOW_INFO iinfo;
    NX_WIDGET *ptr = find_widget(wid);
    NX_CALLBACK *n;

    if (!ptr)
	return;

    if (!ptr->callback_list) {
	ptr->callback_list = (NX_CALLBACK *) malloc(sizeof(NX_CALLBACK));
	n = ptr->callback_list;
    } else {
	n = ptr->callback_list;

	while (n->next)
	    n = n->next;

	n->next = (NX_CALLBACK *) malloc(sizeof(NX_CALLBACK));
	n = n->next;
    }

    n->event = event;
    n->callback = callback;
    n->next = 0;

    /* Get the current event mask */
    GrGetWindowInfo(wid, &iinfo);

    /* Set this window to respond to the event in question */
    GrSelectEvents(wid, GR_EVENTMASK(event) | iinfo.eventmask);
}

int
fireNXWidgetCallback(GR_WINDOW_ID wid, GR_EVENT * event)
{
    NX_WIDGET *ptr = find_widget(wid);
    NX_CALLBACK *n;

    if (!ptr)
	return (0);

    n = ptr->callback_list;

    if (!n)
	return (0);

    while (n) {
	if (n->event == event->type) {
	    n->callback(event);
	    return (1);
	}

	n = n->next;
    }

    return (0);
}

void
realizeNXWidget(GR_WINDOW_ID widget)
{
    GR_WINDOW_INFO ptr;
    GR_WINDOW_ID child;

    /* First show the parent */
    GrMapWindow(widget);

    GrGetWindowInfo(widget, &ptr);

    if (!ptr.child)
	return;

    child = ptr.child;

    GrMapWindow(child);
    GrGetWindowInfo(child, &ptr);

    while (ptr.sibling) {
	GrMapWindow(ptr.sibling);
	GrGetWindowInfo(ptr.sibling, &ptr);
    }
}

GR_WINDOW_ID
createNXDialog(GR_WINDOW_ID parent, char *str)
{
    NX_WIDGET *ptr;

    GR_WINDOW_ID wid = createNXWidget(parent, 5, 100, 220, 125);

    ptr = find_widget(wid);

    if (!ptr)
	return (0);

    if (str) {
	int count, i;

	/* Count the carriage returns so we know how big to resize the window */

	for (i = 0, count = 0; i < (int) strlen(str); i++)
	    if (str[i] == '\n')
		count++;

	GrResizeWindow(wid, 220, ((count + 1) * 15) + 20);

	strncpy(ptr->dialog.str, str, 254);
    } else
	ptr->dialog.str[0] = 0;

    return (wid);
}

void
popupNXDialog(GR_WINDOW_ID dialog, char *str)
{
    GR_EVENT event;

    GrSelectEvents(dialog,
		   GR_EVENT_MASK_BUTTON_DOWN |
		   GR_EVENT_MASK_BUTTON_UP | GR_EVENT_MASK_EXPOSURE);

    GrMapWindow(dialog);
    GrRaiseWindow(dialog);

    /* Here we wait for a button down */

    while (1) {
	GrGetNextEvent(&event);

	switch (event.type) {
	case GR_EVENT_TYPE_BUTTON_UP:
	    if (event.button.wid != dialog)
		break;

	    if (handle_dialog_up(event.button.wid)) {
		GrUnmapWindow(dialog);
		return;
	    }

	    break;

	case GR_EVENT_TYPE_CLOSE_REQ:
	    GrClose();
	    exit(0);

	case GR_EVENT_TYPE_EXPOSURE:
	    handle_dialog_expose(dialog, str);
	    fireNXWidgetCallback(event.exposure.wid, &event);
	    break;
	}
    }
}

void
handle_dialog_expose(GR_WINDOW_ID wid, char *str)
{
    char *c;
    GR_GC_ID newgc;
    GR_WINDOW_INFO iinfo;
    int ypos;

    /* Show the dialog box */

    NX_WIDGET *ptr = find_widget(wid);

    if (!ptr)
	return;

    /* If we are using a dynamic string, then resize the window */

    if (ptr->dialog.str[0] == 0) {
	int count = 0, i;

	/* Count the carriage returns so we know how big to resize the window */
	for (i = 0; i < (int) strlen(str); i++)
	    if (str[i] == '\n')
		count++;

	GrResizeWindow(wid, 220, ((count + 1) * 15) + 20);
    }

    GrGetWindowInfo(wid, &iinfo);

    newgc = GrNewGC();

    GrSetGCMode(newgc, GR_MODE_SET);
    GrSetGCFont(newgc, GrCreateFont((GR_CHAR *) GR_FONT_GUI_VAR, 0, 0));

    /* Do some pretty drawing */

    GrSetGCForeground(newgc, LTGRAY);
    GrFillRect(wid, newgc, 0, 0, iinfo.width, iinfo.height);

    nxDraw3dBox(ptr->wid, 0, 0, iinfo.width, iinfo.height, GRAY, BLACK);

    GrSetGCBackground(newgc, LTGRAY);
    GrSetGCForeground(newgc, BLACK);

    if (ptr->dialog.str[0] != 0)
	c = ptr->dialog.str;
    else
	c = str;

    ypos = 20;

    while (*c != 0) {
	char *s = c;

	for (; *c != 0 && *c != '\n'; c++);

	GrText(wid, newgc, 10, ypos, s, (int) (c - s), 0);

	if (*c)
	    c++;

	/* Figure this out responsibly! */
	ypos += 15;
    }

    GrDestroyGC(newgc);
}

int
handle_dialog_up(GR_WINDOW_ID wid)
{
    return (1);
}

--- NEW FILE: nanox-UI.cc ---
 /*
 * Copyright (C) 200-2002 Century Embedded Techonlogies
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/* Nano-X UI for XBill rewritten by Jordan Crouse */
/* Embed this, baby! */


#include "objects.h"
#include "Strings.h"
#include "NXwidgets.h"
#include "NXUI.h"
#include "NX.h"

/**************************/
/* Timer control routines */
/**************************/

void
UI::restart_timer()
{
    playing = 0;
    timeout = 250;
}

void
UI::kill_timer()
{
    timeout = 0;
}

void
UI::pause_game()
{
    if (timeout)
	playing = 1;
    kill_timer();
}

void
UI::resume_game()
{
    if (playing && !timeout)
	restart_timer();
    playing = 0;
}

/*******************/
/* Window routines */
/*******************/

void
UI::initialize(int *argc, char **argv)
{
    /* Open the graphics */

    if (GrOpen() < 0)
	exit(-1);

    /* Allocate a font for use by everybody */
    global_font = GrCreateFont((GR_CHAR *) GR_FONT_GUI_VAR, 0, 0);

    toplevel = createNXApp("nxBill", game.scrwidth, game.scrheight);
}

void
UI::make_mainwin()
{
    /* Give the menubar its own GC */

    menubargc = GrNewGC();
    GrSetGCFont(menubargc, global_font);

    menubar = createNXWidget(toplevel, 0, 0, game.scrwidth, 30);

    registerNXWidgetCallback(menubar, GR_EVENT_TYPE_EXPOSURE,
			     redraw_menubar_eh);
    registerNXWidgetCallback(menubar, GR_EVENT_TYPE_BUTTON_UP,
			     menubar_buttonup_eh);
    registerNXWidgetCallback(menubar, GR_EVENT_TYPE_BUTTON_DOWN,
			     menubar_buttondown_eh);

    /* Set some text for it */

    field = createNXWidget(toplevel, 0, 30, game.playwidth, game.playheight);

    /* And register the callbacks for later use */
    registerNXWidgetCallback(field, GR_EVENT_TYPE_BUTTON_DOWN,
			     button_press_eh);
    registerNXWidgetCallback(field, GR_EVENT_TYPE_BUTTON_UP,
			     button_release_eh);

#ifndef PDA			/* These are only valid for the non pda version */
    registerNXWidgetCallback(field, GR_EVENT_TYPE_MOUSE_ENTER,
			     enter_window_eh);
    registerNXWidgetCallback(field, GR_EVENT_TYPE_MOUSE_EXIT,
			     leave_window_eh);
#endif

    registerNXWidgetCallback(field, GR_EVENT_TYPE_EXPOSURE, redraw_window_eh);

    /* Map the various widgets */

    realizeNXWidget(menubar);
    realizeNXWidget(field);

#ifdef NOTUSED
    screen = XtScreen(toplevel);
    depth = DefaultDepthOfScreen(screen);
    rootwindow = RootWindowOfScreen(screen);
    window = XtWindow(field);

    colormap = DefaultColormapOfScreen(screen);
    white.pixel = WhitePixelOfScreen(screen);
    XQueryColor(display, colormap, &white);
    black.pixel = BlackPixelOfScreen(screen);
    XQueryColor(display, colormap, &black);

    XtVaGetValues(toplevel, XtNwidth, &winwidth, XtNheight, &winheight, NULL);
    h.width = h.base_width = h.min_width = h.max_width = winwidth;
    h.height = h.base_height = h.min_height = h.max_height = winheight;
    h.flags = USSize | PSize | PMaxSize | PMinSize;
    XSetNormalHints(display, window, &h);
#endif

}

void
UI::make_windows()
{

    /* Dialog boxes? */
    endgamebox = createNXDialog(toplevel, endgamestr);
    scorebox = createNXDialog(toplevel, NULL);

#ifdef NOTYET
    newgamebox = CreateDialog("New Game", base, OK | CANCEL, (Pixmap) NULL,
			      newgamestr, (char *) NULL, new_game_cb);
    pausebox = CreateDialog("Pause Game", base, OK, icon.pix,
			    pausestr, "Continue", NULL);
    quitbox = CreateDialog("Quit", base, OK | CANCEL, (Pixmap) NULL,
			   quitstr, (char *) NULL, quit_game_cb);
    warpbox = CreateEnterText("Warp To Level", base, warpstr,
			      (XtCallbackProc) warp_apply);
    about.load("about");

    aboutbox = CreatePixmapBox("About", base, about.pix, "");
    rulesbox = CreatePixmapBox("Rules", base, (Pixmap) NULL, rulesstr);
    storybox = CreatePixmapBox("Story", base, (Pixmap) NULL, storystr);

    scorebox = CreateDialog("Score", base, OK, (Pixmap) NULL,
			    "", (char *) NULL, NULL);

    highscorebox = CreateDialog("HighScore", base, OK, (Pixmap) NULL,
				"", (char *) NULL, NULL);
#endif

}

void
UI::popup_dialog(int dialog)
{
    GR_WINDOW_ID w = 0;

    switch (dialog) {
    case game.ENDGAME:
	w = endgamebox;
	break;
    }

    if (w)
	popupNXDialog(w, NULL);
}

/*********************/
/* Graphics routines */
/*********************/

/* If we are on a PDA, don't bother with */
/* mouse cursors */

#ifndef PDA

void
UI::set_cursor(int cursor)
{
    switch (cursor) {
    case game.BUCKETC:
	bucket.cursor.setCursor(toplevel);
	break;
    case game.DOWNC:
	bucket.cursor.setCursor(toplevel);
	break;
    case game.DEFAULTC:
	bucket.cursor.setCursor(toplevel);
	break;
    default:
	bucket.cursor.setCursor(toplevel);
	break;
    }
}

void
UI::load_cursors()
{

    defaultcursor.load("hand_up", defaultcursor.SEP_MASK);

    defaultcursor.setCursor(toplevel);

    downcursor.load("hand_down", downcursor.SEP_MASK);
}
#endif

void
UI::graph_init()
{
    /* Create a gc */

    stdgc = GrNewGC();

    /* Set the font that we want to use */
    GrSetGCFont(stdgc, global_font);

    /* Not used, yet */
    /* XSetLineAttributes (display, stdgc, 3, LineSolid, CapRound, JoinMiter); */

    GrSetGCBackground(stdgc, WHITE);
    GrSetGCForeground(stdgc, BLACK);

    whitegc = GrNewGC();
    GrSetGCBackground(stdgc, WHITE);
    GrSetGCForeground(stdgc, WHITE);

    /* Create an offscreen pixmap for good times */


    //offscreen = GrNewWindow(GR_ROOT_WINDOW_ID, 0, 0, game.playwidth, game.playheight, 0, BLACK, WHITE);
    //GrMapWindow(offscreen);

    offscreen = GrNewPixmap(game.playwidth, game.playheight, NULL);
}

void
UI::clear()
{
    GrFillRect(offscreen, whitegc, 0, 0, game.playwidth, game.playheight);
}

void
UI::refresh()
{
    GrCopyArea(field, stdgc, 0, 0, game.playwidth, game.playheight,
	       offscreen, 0, 0, MWROP_SRCCOPY);
}

void
UI::draw(NXPicture * pict, int x, int y)
{
    GR_GC_ID tgc;

#ifdef NOTUSED
    GR_REGION_ID clipregion;
    GR_RECT rect;
    clipregion = GrNewRegion();

    rect.x = x;
    rect.y = y;
    rect.width = pict->width;
    rect.height = pict->height;

    GrUnionRectWithRegion(clipregion, &rect);
#endif

    tgc = GrNewGC();

#ifdef NOTUSED
    GrSetGCRegion(tgc, clipregion);
#endif

#ifdef NOTUSED
    GrCopyArea(offscreen, tgc, x, y, pict->width, pict->height,
	       pict->pixmap, 0, 0, MWROP_SRCCOPY);
#endif

    GrDrawImageToFit(offscreen, tgc, x, y,
		     pict->width, pict->height, pict->image);

    GrDestroyGC(tgc);

#ifdef NOTUSED
    GrDestroyRegion(clipregion);
#endif
}

void
UI::draw_centered(NXPicture * pict)
{
    draw(pict, (game.playwidth - pict->width) / 2,
	 (game.playheight - pict->height) / 2);
}

void
UI::draw_line(int x1, int y1, int x2, int y2)
{
    GrSetGCForeground(stdgc, BLACK);
    GrLine(offscreen, stdgc, x1, y1, x2, y2);
}

void
UI::draw_str(char *str, int x, int y)
{
    GrSetGCForeground(stdgc, WHITE);
    GrFillRect(offscreen, stdgc, 0, y, game.playwidth, game.playheight);
    GrPoint(offscreen, stdgc, x, y);

    GrSetGCForeground(stdgc, BLACK);
    GrText(offscreen, stdgc, x, y, str, strlen(str), 0);
}


/******************/
/* Other routines */
/******************/

void
UI::set_pausebutton(int action)
{
}


void
UI::MainLoop()
{
    GR_EVENT event;

    /* Ok, so we want to handle the main loop here */

    while (1) {
	if (timeout)
	    GrGetNextEventTimeout(&event, timeout);
	else
	    GrGetNextEvent(&event);

	switch (event.type) {
	case GR_EVENT_TYPE_BUTTON_DOWN:
	    fireNXWidgetCallback(event.button.wid, &event);
	    break;

	case GR_EVENT_TYPE_BUTTON_UP:
	    fireNXWidgetCallback(event.button.wid, &event);
	    break;

	case GR_EVENT_TYPE_MOUSE_ENTER:
	    break;

	case GR_EVENT_TYPE_MOUSE_EXIT:
	    break;

	case GR_EVENT_TYPE_EXPOSURE:
	    fireNXWidgetCallback(event.exposure.wid, &event);
	    break;

	case GR_EVENT_TYPE_TIMEOUT:
	    timer_eh();
	    break;

	case GR_EVENT_TYPE_CLOSE_REQ:
	    close_program();
	}
    }
}

/******* MENUBAR CALLBACKS ******** */


#define BUTTON_SIZE 70
#define BUTTON_SPACING 3

static char *button_labels[] = { "New Game", "Pause Game", "Exit Game" };

static GR_BOOL
PtInRect(GR_RECT * prc, GR_SIZE x, GR_SIZE y)
{
    return (x >= prc->x && x < (prc->x + prc->width) &&
	    y >= prc->y && y < (prc->y + prc->height));
}

void
UI::menubar_buttonup(int x, int y)
{
    GR_WINDOW_INFO winfo;

    int bsize, startx, bspacing;
    GR_RECT rect_start, rect_pause, rect_end;

    GrGetWindowInfo(menubar, &winfo);

    bsize = (winfo.width / 2) - (BUTTON_SIZE / 2);
    startx = (bsize - BUTTON_SIZE) / 2;
    bspacing = (bsize - startx) - BUTTON_SIZE;

    /* Check for a button down */

    rect_start.x = startx;
    rect_start.y = 5;
    rect_start.width = BUTTON_SIZE;
    rect_start.height = 20;

    rect_pause.x = rect_start.x + (BUTTON_SIZE + bspacing);
    rect_pause.y = rect_start.y;
    rect_pause.width = BUTTON_SIZE;
    rect_pause.height = rect_start.height;

    rect_end.x = rect_pause.x + (BUTTON_SIZE + bspacing);
    rect_end.y = rect_pause.y;
    rect_end.width = BUTTON_SIZE;
    rect_end.height = rect_pause.height;

    if (PtInRect(&rect_start, x, y))
	game.warp_to_level(1);
    else if (PtInRect(&rect_pause, x, y)) {
	if (playing)
	    resume_game();
	else
	    pause_game();

	redraw_menubar();
    } else if (PtInRect(&rect_end, x, y))
	close_program();

}

void
UI::redraw_menubar()
{
    GR_WINDOW_INFO winfo;

    int i, state;
    int bsize, startx, bspacing;

    if (!menubargc)
	return;

    /* Get the window information so we know how big to make the screen */
    GrGetWindowInfo(menubar, &winfo);

    GrSetGCForeground(menubargc, GRAY);
    GrFillRect(menubar, menubargc, 0, 0, winfo.width, winfo.height);

    /* If we are playing PDA, then ensure that we go with the 2D look */

#ifdef PDA
    GrSetGCForeground(menubargc, BLACK);
    GrRect(menubar, menubargc, 0, 0, winfo.width, winfo.height);
#else
    nxDraw3dBox(menubar, 0, 0, winfo.width, winfo.height, (GR_COLOR) WHITE,
		(GR_COLOR) BLACK);
#endif

    /* We want the middle button to be centered, so figure how much room that leaves us */
    /* for the other two */

    bsize = (winfo.width / 2) - (BUTTON_SIZE / 2);
    startx = (bsize - BUTTON_SIZE) / 2;
    bspacing = (bsize - startx) - BUTTON_SIZE;

    for (i = 0; i < 3; i++) {
	if (i == 1) {
	    state = playing;
	} else
	    state = 0;

#ifdef PDA
	if (!state)
	    GrSetGCForeground(menubargc, LTGRAY);
	else
	    GrSetGCForeground(menubargc, BLACK);
#else
	GrSetGCForeground(menubargc, LTGRAY);
#endif

	GrFillRect(menubar, menubargc,
		   startx + (i * (BUTTON_SIZE + bspacing)),
		   5, BUTTON_SIZE, 20);

#ifdef PDA
	GrSetGCForeground(menubargc, BLACK);
	GrRect(menubar, menubargc, startx + (i * (BUTTON_SIZE + bspacing)), 5,
	       BUTTON_SIZE, 20);
#else
	nxDraw3dUpDownState(menubar, startx + (i * (BUTTON_SIZE + bspacing)),
			    5, BUTTON_SIZE, 20, state);
#endif


#ifdef PDA
	if (!state) {
	    GrSetGCBackground(menubargc, LTGRAY);
	    GrSetGCForeground(menubargc, BLACK);
	} else {
	    GrSetGCBackground(menubargc, BLACK);
	    GrSetGCForeground(menubargc, LTGRAY);
	}
#else
	GrSetGCBackground(menubargc, LTGRAY);
	GrSetGCForeground(menubargc, BLACK);
#endif

	GrText(menubar, menubargc,
	       (startx + 3) + (i * (BUTTON_SIZE + bspacing)), 20,
	       button_labels[i], strlen(button_labels[i]), 0);
    }
}

void
UI::update_scorebox(int level, int score)
{
    char scorestr[100];

    sprintf(scorestr,
	    "After %d grueling levels\nyour mind bending score is %d!\nKeep going!",
	    level, score);

    popupNXDialog(scorebox, scorestr);
}

/* We really don't have a high score box right now..  sorry */

void
UI::update_hsbox(char *str)
{
    return;
}

void
UI::close_program()
{
    /* Images will kill themselves as the program dies */

    killNXApp(toplevel);
    GrClose();
    exit(0);
}

/* Moved here from the headre file */

UI::UI()
{
    playing = 0;
    timeout = 0;
}

--- NEW FILE: MCursor.h ---

#ifndef X11_MCURSOR_H
#define X11_MCURSOR_H

#include <X11/Xlib.h>
#include <X11/xpm.h>

class MCursor
{
  public:
    static const int SEP_MASK = 0;
    static const int OWN_MASK = 1;
    Pixmap cursor;
    void load(const char *name, int masked);
};

#endif

--- NEW FILE: Computer.cc ---
 /* This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "objects.h"

int
Computer::check_intersect(int i, int x, int y)
{
    for (int j = 0; j < i; j++) {
	if (game.INTERSECT(x, y,
			   net.width - bill.list[0].XOFFSET + bill.width,
			   net.height, net.computers[j].x,
			   net.computers[j].y,
			   net.width - bill.list[0].XOFFSET + bill.width,
			   net.height))
	    return (j);
    }

    return (-1);
}

int
Computer::setup(int i)
{
    int count;
    int p;

    for (count = 0; count < 4000; count++) {
	/* Get an inital X and Y for the computer */
	x = game.RAND(BORDER, game.playwidth - BORDER - net.width);
	y = game.RAND(BORDER, game.playheight - BORDER - net.height);

	/* Check to see if we intersect */
	if ((p = check_intersect(i, x, y)) == -1)
	    break;

	/* Try to shift X one way or the other */

	if (x > (BORDER + net.width))
	    x = x - net.width;
	else
	    x = x + net.width;

	if ((p = check_intersect(i, x, y)) == -1)
	    break;

	/* One more check, try our y */

	if (y > (BORDER + net.height))
	    y = y - net.height;
	else
	    y = y + net.height;

	if ((p = check_intersect(i, x, y)) == -1)
	    break;

	/* Doh!  Go back around and try to pick an entirely new x and y */
    }

    if (count == 4000) {
	return (0);
    }

    type = game.RAND(1, net.NUM_SYS);
    os = determineOS();
    busy = 0;
    return (1);
}

#ifdef NOTUSED
int
Computer::setup(int i)
{
    int j, counter = 0, flag;
    do {
	if (++counter > 4000)
	    return 0;
	x = game.RAND(BORDER, game.playwidth - BORDER - net.width);
	y = game.RAND(BORDER, game.playheight - BORDER - net.height);
	flag = 1;
	/*checks for conflicting computer placement */
	for (j = 0; j < i && flag; j++)
	    if (game.INTERSECT(x, y,
			       net.width - bill.list[0].XOFFSET + bill.width,
			       net.height, net.computers[j].x,
			       net.computers[j].y,
			       net.width - bill.list[0].XOFFSET + bill.width,
			       net.height))
		flag = 0;
    } while (!flag);
    type = game.RAND(1, net.NUM_SYS);
    os = determineOS();
    busy = 0;
    return 1;
}
#endif

int
Computer::find_stray()
{
    int i;
    for (i = 0; i < bill.MAX_BILLS; i++) {
	if (bill.list[i].state != bill.list[i].STRAY)
	    continue;
	if (game.INTERSECT(x, y, net.width, net.height, bill.list[i].x,
			   bill.list[i].y, OS.width, OS.height))
	    return i;
    }
    return -1;
}

int
Computer::oncomputer(int locx, int locy)
{
    return (abs(locx - x) < net.width && abs(locy - y) < net.height);
}

int
Computer::compatible(int system)
{
    return (type == system || (type >= PC && system >= OS.PC));
}

int
Computer::determineOS()
{
    if (type < PC)
	return type;
    else
	return game.RAND(OS.PC, OS.NUM_OS);
}

void
Computer::draw()
{
    ui.draw(&(net.pictures[type]), x, y);
    if (os != OS.OFF)
	ui.draw(&(OS.os[os]), x + OFFSET, y + OFFSET);
}

--- NEW FILE: menu.h ---

#ifndef MENU_H
#define MENU_H

#include <X11/Intrinsic.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>

#define MAXMENUS 2
#define MAXMENUSIZE 5

typedef struct _menubuttontype
{
    char *name;
    Widget *dialog;
}
menubuttontype;

typedef struct _submenutype
{
    char *name;
    int size;
    menubuttontype button[MAXMENUSIZE];
    Widget pulldown, pshell;
}
submenutype;

typedef struct _menutype
{
    int size;
    submenutype submenu[MAXMENUS];
}
menutype;

extern Widget toplevel, base, menubar, field;
extern Widget aboutbox, rulesbox, storybox;
extern Widget warpbox, quitbox, newgamebox, pausebox;
extern Widget scorebox, highscorebox;
extern Widget endgamebox, enternamebox;

menutype menu = { 2,
    {
     {"Game", 5,
      {
       {"New game", &newgamebox},
       {"Pause game", &pausebox},
       {"Warp to level...", &warpbox},
       {"View high scores", &highscorebox},
       {"Quit game", &quitbox},
       }
      },
     {"Info", 3,
      {
       {"Story of xBill", &storybox},
       {"Rules", &rulesbox},
       {"About xBill", &aboutbox},
       }
      }
     }
};

#endif

--- NEW FILE: INSTALL ---
To install:
	edit Imakefile
	xmkmf -a
	make
	If you have root access:
		1) make install
		1) make installman
	If not:
		1) make -k install (and ignore the error)
		2) copy 'xbill' to somewhere in your path.
		2) copy xbill.man to somewhere in your manpath.

Notes:
 - libXpm is required.  If you don't have it, get it from any X ftp site.

 - If you're using GCC, you need 2.6.x or newer.  If not, I have no idea
   how current of a C++ compiler you need.

 - The game looks a bit better when compiled with Motif widgets, but may be
   easier to compile with Athena widgets.  In Imakefile, select one of these.

 - In Imakefile, select whether to install the images in a standard place or
   your home directory.

 - The game doesn't run too well over a slow network.  Sorry.

--- NEW FILE: objects.h ---

#ifndef OBJECTS_H
#define OBJECTS_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>

#include "Horde.h"
#include "Network.h"
#include "Library.h"
#include "Bucket.h"
#include "Spark.h"
#include "Game.h"
#include "NXUI.h"
#include "Scorelist.h"

extern Horde bill;
extern Network net;
extern Library OS;
extern Bucket bucket;
extern Spark spark;
extern Scorelist scores;
extern Game game;
extern UI ui;

#endif

--- NEW FILE: Monster.cc ---
 /*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "objects.h"

void
Monster::get_border()
{
    int i = game.RAND(0, 3);
    if (i % 2 == 0)
	target_x = game.RAND(0, game.playwidth - bill.width);
    else
	target_y = game.RAND(0, game.playheight - bill.height);
    switch (i) {
    case 0:
	target_y = -bill.height - 16;
	break;
    case 1:
	target_x = game.playwidth + 1;
	break;
    case 2:
	target_y = game.playheight + 1;
	break;
    case 3:
	target_x = -bill.width - 2;
	break;
    }
}

/*  Adds a bill to the in state*/
void
Monster::enter()
{
    state = IN;
    get_border();
    x = target_x;
    y = target_y;
    index = 0;
    cels = bill.lcels;
    cargo = OS.WINGDOWS;
    x_offset = -2;
    y_offset = -15;
    target_c = game.RAND(0, net.units - 1);
    target_x = net.computers[target_c].x + net.width - XOFFSET;
    target_y = net.computers[target_c].y + YOFFSET;
    bill.on_screen++;
    bill.off_screen--;
}

/*  Moves bill toward his target - returns whether or not he moved */
int
Monster::move(int mode)
{
    int xdist = target_x - x;
    int ydist = target_y - y;
    int step = step_size(game.level);
    int dx, dy;
    int signx = xdist >= 0 ? 1 : -1;
    int signy = ydist >= 0 ? 1 : -1;
    xdist = abs(xdist);
    ydist = abs(ydist);
    if (!xdist && !ydist)
	return 0;
    else if (xdist < step && ydist < step) {
	x = target_x;
	y = target_y;
    } else {
	dx = (xdist * step * signx) / (xdist + ydist);
	dy = (ydist * step * signy) / (xdist + ydist);
	switch (mode) {
	case SLOW:
	    break;
	case FAST:
	    dx = 5 * dx / 4;
	    dy = 5 * dy / 4;
	    break;
	}
	x += dx;
	y += dy;
	if (dx < 0)
	    cels = bill.lcels;
	else if (dx > 0)
	    cels = bill.rcels;
    }
    return 1;
}

void
Monster::draw()
{
    switch (state) {
    case IN:
    case OUT:
    case DYING:
	draw_std();
	break;
    case AT:
	draw_at();
	break;
    case STRAY:
	draw_stray();
	break;
    default:
	break;
    }
}

/*  Update Bill's position */
void
Monster::update_in()
{
    int moved = move(SLOW);
    if (!moved && (net.computers[target_c].os != OS.WINGDOWS)
	&& !(net.computers[target_c].busy)) {
	net.computers[target_c].busy = 1;
	cels = bill.acels;
	index = 0;
	state = AT;
	return;
    } else if (!moved) {
	int i;
	do {
	    i = game.RAND(0, net.units - 1);
	} while (i == target_c);
	target_c = i;
	target_x = net.computers[target_c].x + net.width - XOFFSET;
	target_y = net.computers[target_c].y + YOFFSET;
    }
    index++;
    index %= bill.WCELS;
    y_offset += (8 * (index % 2) - 4);
}

/*  Update Bill standing at a computer  */
void
Monster::update_at()
{
    int sys;
    if (index == 0 && net.computers[target_c].os == OS.OFF) {
	index = 6;
	sys = net.computers[target_c].find_stray();
	if (sys < 0)
	    cargo = -1;
	else {
	    cargo = bill.list[sys].cargo;
	    bill.list[sys].state = OFF;
	}
    } else
	index++;
    if (index == 13) {
	y_offset = -15;
	x_offset = -2;
	get_border();
	index = 0;
	cels = bill.lcels;
	state = OUT;
	net.computers[target_c].busy = 0;
	return;
    }
    y_offset = bill.height - OS.height;
    switch (index) {
    case 1:
    case 2:
	x -= 8;
	x_offset += 8;
	break;
    case 3:
	x -= 10;
	x_offset += 10;
	break;
    case 4:
	x += 3;
	x_offset -= 3;
	break;
    case 5:
	x += 2;
	x_offset -= 2;
	break;
    case 6:
	if (net.computers[target_c].os != OS.OFF) {
	    net.base--;
	    net.off++;
	    cargo = net.computers[target_c].os;
	} else {
	    x -= 21;
	    x_offset += 21;
	}
	net.computers[target_c].os = OS.OFF;
	y_offset = -15;
	x += 20;
	x_offset -= 20;
	break;
    case 7:
	sy = y_offset;
	sx = -2;
	break;
    case 8:
	sy = -15;
	sx = -2;
	break;
    case 9:
	sy = -7;
	sx = -7;
	x -= 8;
	x_offset += 8;
	break;
    case 10:
	sy = 0;
	sx = -7;
	x -= 15;
	x_offset += 15;
	break;
    case 11:
	sy = 0;
	sx = -7;
	net.computers[target_c].os = OS.WINGDOWS;
	net.off--;
	net.win++;
	break;
    case 12:
	x += 11;
	x_offset -= 11;
    }
}

/* Updates Bill fleeing with his ill gotten gain */
void
Monster::update_out()
{
    if (game.INTERSECT(x, y, bill.width, bill.height, 0, 0, game.playwidth,
		       game.playheight)) {
	move(FAST);
	index++;
	index %= bill.WCELS;
	y_offset += (8 * (index % 2) - 4);
    } else {
	state = OFF;
	bill.on_screen--;
	bill.off_screen++;
    }
}


/* Updates Bill who is dying */
void
Monster::update_dying()
{
    if (index < bill.DCELS - 1) {
	y_offset += (index * GRAVITY);
	index++;
    } else {
	y += y_offset;
	if (cargo < 0 || cargo == OS.WINGDOWS)
	    state = OFF;
	else
	    state = STRAY;
	bill.on_screen--;
    }
}

void
Monster::update()
{
    switch (state) {
    case IN:
	update_in();
	break;
    case AT:
	update_at();
	break;
    case OUT:
	update_out();
	break;
    case DYING:
	update_dying();
	break;
    default:
	break;
    }
}

int
Monster::clicked(int locx, int locy)
{
    return (locx > x && locx < x + bill.width && locy > y
	    && locy < y + bill.height);
}

int
Monster::clickedstray(int locx, int locy)
{
    return (locx > x && locx < x + OS.width && locy > y
	    && locy < y + OS.height);
}

int
Monster::step_size(unsigned int lev)
{
    return game.MIN(14 + lev, 18);
}

void
Monster::draw_std()
{
    if (cargo >= 0)
	ui.draw(&(OS.os[cargo]), x + x_offset, y + y_offset);
    ui.draw(&(cels[index]), x, y);
}

void
Monster::draw_at()
{
    if (index > 6 && index < 12)
	ui.draw(&(OS.os[0]), x + sx, y + sy);
    if (cargo >= 0)
	ui.draw(&(OS.os[cargo]), x + x_offset, y + y_offset);
    ui.draw(&(cels[index]), net.computers[target_c].x,
	    net.computers[target_c].y);
}

void
Monster::draw_stray()
{
    if (game.grabbed == -1 || x != bill.list[game.grabbed].x)
	ui.draw(&(OS.os[cargo]), x, y);
}

--- NEW FILE: Network.h ---

#ifndef NETWORK_H
#define NETWORK_H

#include "Computer.h"
#include "Cable.h"

class Network
{				/*structure for global network of computers */
  public:
    static const int MAX_COMPUTERS = 20;	/* max computers on screen */
    static const int NUM_SYS = 6;	/* number of computer types */
    NXPicture pictures[NUM_SYS + 1];	/* array of cpu pictures */
    int width, height;		/* size of cpu picture */
    int units;			/* number of cpus in network */
    int win, base, off;		/* number in each state */
    Computer computers[MAX_COMPUTERS];	/* array of cpu info */
    Cable cables[MAX_COMPUTERS];
    int ncables;
    void setup();
    void load_pix();
    void draw();
    void update();
    void toasters();
    int on(int lev);

};

#endif

--- NEW FILE: Horde.h ---

#ifndef HORDE_H
#define HORDE_H

#include "Monster.h"
#include "NXPicture.h"

class Horde
{				/*global structure of all bills */
  public:
    static const int MAX_BILLS = 100;	/*max Bills per level */
    static const int WCELS = 4;	/* # of bill walking animation frames */
    static const int DCELS = 5;	/* # of bill dying animation frames */
    static const int ACELS = 13;	/* # of bill switching OS frames */
    Monster list[MAX_BILLS];	/* list of monsters in all states */
    int width, height;
    int on_screen, off_screen;
    NXPicture lcels[WCELS], rcels[WCELS], acels[ACELS], dcels[DCELS];
    void load_pix();
    void setup();
    void launch(int max);
    int on(unsigned int lev);
    int max_at_once(unsigned int lev);
    int between(unsigned int lev);
    void update();
    void draw();
};

#endif

--- NEW FILE: NXUI.h ---
/* Copyright 2003, Century Software */

#ifndef NX_UI_H
#define NX_UI_H

#include "NXPicture.h"

#ifndef PDA
#include "NXMCursor.h"
#endif

extern "C"
{
#include "nano-X.h"
#include "nxdraw.h"
}

class UI
{
  private:

    /* Widgets */
    GR_WINDOW_ID toplevel, menubar, field;
    GR_WINDOW_ID scorebox, endgamebox;

    /* Graphics contexts */
    GR_GC_ID stdgc, whitegc, menubargc;

    /* Font ID */
    GR_FONT_ID global_font;

    GR_TIMEOUT timeout;
    int playing;
    NXPicture icon;

#ifndef PDA
    NXMCursor defaultcursor, downcursor;
#endif

  public:
      UI();

    GR_WINDOW_ID offscreen;

    void restart_timer();
    void kill_timer();

    void pause_game();
    void resume_game();

    void initialize(int *argc, char **argv);
    void make_mainwin();
    void make_windows();
    void popup_dialog(int dialog);

#ifndef PDA
    void set_cursor(int cursor);
    void load_cursors();
#endif

    void graph_init();
    void clear();
    void refresh();
    void draw(NXPicture * picture, int x, int y);
    void draw_centered(NXPicture * picture);
    void draw_line(int x1, int y1, int x2, int y2);
    void draw_str(char *str, int x, int y);

    void set_pausebutton(int action);
    void MainLoop();

    void update_scorebox(int level, int score);
    void update_hsbox(char *str);

    void redraw_menubar();
    void menubar_buttonup(int x, int y);
    void close_program();

    int paused()
    {
	return (playing);
    }
};

#endif

--- NEW FILE: NXPicture.h ---
/* Copyright 2003, Century Software */
#ifndef NX_PICTURE_H
#define NX_PICTURE_H

#define MWINCLUDECOLORS
extern "C"
{
#include "nano-X.h"
}
class NXPicture
{
  public:
    GR_IMAGE_ID image;
    GR_WINDOW_ID pixmap;
    GR_GC_ID gc;

    int width, height;

    void draw(int x, int y);
    void draw_centered();
    void load(char *name, int index = -1);
      NXPicture::~NXPicture();
};

#endif

--- NEW FILE: Game.cc ---
 /*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "objects.h"

#define True 1
#define False 0

Horde bill;
Network net;
Library OS;
Bucket bucket;
Spark spark;
Scorelist scores;
Game game;
UI ui;

#ifndef XBILL_HOME
#define XBILL_HOME "/usr/local/share/xbill/images";
#endif

char xbill_path[256] = XBILL_HOME;

int
Game::RAND(int lb, int ub)
{
    return (rand() % (ub - lb + 1) + lb);
}

int
Game::MAX(int x, int y)
{
    return (x > y ? x : y);
}

int
Game::MIN(int x, int y)
{
    return (x < y ? x : y);
}

int
Game::INTERSECT(int x1, int y1, int w1, int h1, int x2, int y2, int w2,
		int h2)
{
    return (((x2 - x1 <= w1 && x2 - x1 >= 0)
	     || (x1 - x2 <= w2 && x1 - x2 >= 0))
	    && ((y2 - y1 <= h1 && y2 - y1 >= 0)
		|| (y1 - y2 <= h2 && y1 - y2 >= 0)));
}

void
Game::setup_level(unsigned int lev)
{
    level = lev;
    bill.setup();
    grabbed = EMPTY;

#ifndef PDA
    ui.set_cursor(DEFAULTC);
#endif

    net.setup();
    iteration = efficiency = 0;
}

void
Game::start(unsigned int lev)
{
    state = PLAYING;
    score = 0;
    ui.restart_timer();
    ui.set_pausebutton(True);
    setup_level(lev);
}

void
Game::quit()
{
    scores.write();
    exit(0);
}

void
Game::update_info()
{
    static char str[80];
    sprintf(str, "Bill:%d/%d  System:%d/%d/%d  Level:%d  Score:%d",
	    bill.on_screen, bill.off_screen, net.base, net.off,
	    net.win, level, score);
    ui.draw_str(str, 5, playheight - 5);
    efficiency += ((100 * net.base - 10 * net.win) / net.units);
}

void
Game::update_score(int action)
{
    switch (action) {
    case ENDLEVEL:
	score += (level * efficiency / iteration);
	break;
    default:
	score += (action * action * BILLPOINTS);
    }
}

void
Game::warp_to_level(unsigned int lev)
{
    if (state == (int) PLAYING) {
	if (lev <= level)
	    return;
	setup_level(lev);
    } else {
	if (lev <= 0)
	    return;
	start(lev);
    }
}

void
Game::button_press(int x, int y)
{
    int i, counter = 0, flag = 0;
    if (state != (int) PLAYING)
	return;

    /* Ignore button presses if we are paused! */

    if (ui.paused())
	return;

#ifndef PDA
    ui.set_cursor(DOWNC);
#endif

    if (bucket.clicked(x, y)) {
#ifndef PDA
	ui.set_cursor(BUCKETC);
#endif
	grabbed = BUCKET;
    }
    for (i = 0; i < bill.MAX_BILLS && !flag; i++) {
	if (bill.list[i].state == bill.list[i].OFF
	    || bill.list[i].state == bill.list[i].DYING)
	    continue;
	if (bill.list[i].state == bill.list[i].STRAY &&
	    bill.list[i].clickedstray(x, y)) {
#ifndef PDA
	    ui.set_cursor(bill.list[i].cargo);
#endif
	    grabbed = i;
	    flag = 1;
	} else if (bill.list[i].state != bill.list[i].STRAY &&
		   bill.list[i].clicked(x, y)) {
	    if (bill.list[i].state == bill.list[i].AT)
		net.computers[bill.list[i].target_c].busy = 0;
	    bill.list[i].index = -1;
	    bill.list[i].cels = bill.dcels;
	    bill.list[i].x_offset = -2;
	    bill.list[i].y_offset = -15;
	    bill.list[i].state = bill.list[i].DYING;
	    counter++;
	}
    }
    if (counter)
	update_score(counter);
}

void
Game::button_release(int x, int y)
{
    int i;

#ifndef PDA
    ui.set_cursor(DEFAULTC);
#endif
    if (state != (int) PLAYING || grabbed == EMPTY)
	return;
    if (grabbed == BUCKET) {
	grabbed = EMPTY;
	for (i = 0; i < net.ncables; i++)
	    if (net.cables[i].onspark(x, y)) {
		net.cables[i].active = 0;
		net.cables[i].delay = spark.delay(level);
	    }
	return;
    }
    for (i = 0; i < net.units; i++)
	if (net.computers[i].oncomputer(x, y)
	    && net.computers[i].compatible(bill.list[grabbed].cargo)
	    &&
	    (net.computers[i].os == OS.WINGDOWS ||
	     net.computers[i].os == OS.OFF)) {
	    net.base++;
	    if (net.computers[i].os == OS.WINGDOWS)
		net.win--;
	    else
		net.off--;
	    net.computers[i].os = bill.list[grabbed].cargo;
	    bill.list[grabbed].state = bill.list[grabbed].OFF;
	    grabbed = EMPTY;
	    return;
	}
    grabbed = EMPTY;
}

void
Game::update()
{
    switch (state) {
    case PLAYING:
	ui.clear();
	bucket.draw();
	net.update();
	net.draw();
	bill.update();
	bill.draw();
	update_info();
	if (!(bill.on_screen + bill.off_screen)) {
	    update_score(ENDLEVEL);
	    state = BETWEEN;
	}
	if ((net.base + net.off) <= 1)
	    state = END;
	break;
    case END:
	ui.clear();
	net.toasters();
	net.draw();
	ui.refresh();
	ui.popup_dialog(ENDGAME);
	if (score > scores.score[9])
	    ui.popup_dialog(ENTERNAME);
	scores.update();
	ui.popup_dialog(HIGHSCORE);
	ui.clear();
	ui.draw_centered(&logo);
	ui.kill_timer();
	ui.set_pausebutton(False);
	state = WAITING;
	break;
    case BETWEEN:
	ui.update_scorebox(level, score);
	ui.popup_dialog(SCORE);
	state = PLAYING;
	setup_level(++level);
	break;
    }
    ui.refresh();
    iteration++;
}

void
Game::main(int argc, char **argv)
{
    int c;
    extern char *optarg;

    level = 0;
    //xbill_path[0] = 0;

    while (argv && argv[0] && (c = getopt(argc, argv, "I:l:L:")) != -1)
	switch (c) {
	case 'l':
	case 'L':
	    level = MAX(1, atoi(optarg));
	    break;
	case 'I':
	    if (strlen(optarg)) {
		strcpy(xbill_path, optarg);

		if (xbill_path[strlen(xbill_path) - 1] != '/')
		    strcat(xbill_path, "/");
	    }

	    break;
	}

    ui.initialize(&argc, argv);

    srand(time(NULL));
    ui.make_mainwin();
    ui.graph_init();
    ui.clear();
    logo.load("logo");
    ui.draw_centered(&logo);
    ui.refresh();
    ui.make_windows();
    scores.read();
    scores.update();

    bill.load_pix();
    OS.load_pix();
    net.load_pix();
    bucket.load_pix();
    spark.load_pix();

#ifndef PDA
    ui.load_cursors();
#endif
    state = WAITING;
    if (level)
	start(level);
    else
	ui.set_pausebutton(False);
    ui.MainLoop();
    exit(0);
}

int
main(int argc, char **argv)
{
    if (argc > 1 && !strcmp(argv[1], "-v")) {
	printf("XBill version 2.0\n\n");
	exit(0);
    }
    if (argc > 1 && !strcmp(argv[1], "-h")) {
	printf("microBill version 1.0\n");
	printf("Options:\n");
	printf("-l n, -L n\tStart at level n.\n");
	printf("-i [path]\tIndicate where the images live\n");
	printf("if not ./pixmaps\n");
	exit(0);
    }
    game.main(argc, argv);
}

--- NEW FILE: x11.h ---

#ifndef X11_WIDGETS_H
#define X11_WIDGETS_H

#include <X11/Xlib.h>
#include <X11/Intrinsic.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xresource.h>
#include <X11/xpm.h>

#ifdef VMS
#include <signal.h>
#include <X11VMS/vmsutil.h>
#endif

#include "UI.h"

#define OK	1
#define CANCEL	2

void popup(Widget w, Widget * box, XtPointer client_data);
void popdown(Widget w, XtPointer call_data, XtPointer client_data);

void new_game_cb(Widget w, XtPointer client_data, XtPointer call_data);
void quit_game_cb(Widget w, XtPointer call_data, XtPointer client_data);

void leave_window_eh(Widget w, XtPointer client_data, XEvent * event);
void enter_window_eh(Widget w, XtPointer client_data, XEvent * event);
void redraw_window_eh(Widget w, XtPointer client_data, XEvent * event);
void button_press_eh(Widget w, XtPointer data, XButtonEvent * event);
void button_release_eh(Widget w, XtPointer data, XButtonEvent * event);
void timer_eh(XtPointer client_data, XtIntervalId * timer_id);

Widget CreateMenuBar(const char *name, Widget parent);
Widget CreatePixmapBox(const char *name, Widget parent, Pixmap pixmap,
		       const char *text);
Widget CreateEnterText(const char *name, Widget parent, const char *text,
		       XtCallbackProc callback);
Widget CreateDialog(const char *name, Widget parent, int buttonmask,
		    Pixmap icon, const char *text, const char *buttonlabel,
		    XtCallbackProc callback);
Widget CreateDrawingArea(const char *name, Widget parent, int width,
			 int height);

void print_to_widget(Widget w, const char *str);
Widget CreateRowCol(const char *name, Widget parent);

void setup_main_widgets();
void setup_other_widgets(Pixmap about, Pixmap rules, Pixmap story);

void warp_apply(Widget w, Widget text, XtPointer client_data);
void enter_name(Widget w, Widget text, XtPointer client_data);

#endif

--- NEW FILE: Horde.cc ---
 /*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "objects.h"

void
Horde::setup()
{
    for (int i = 0; i < MAX_BILLS; i++)
	list[i].state = list[i].OFF;
    off_screen = on(game.level);
    on_screen = 0;
}

/*  Launches Bills whenever called  */
void
Horde::launch(int max)
{
    int i, n;
    if (!max || !off_screen)
	return;
    n = game.RAND(1, game.MIN(max, off_screen));
    for (i = 0; n; n--) {
	for (i++; i < MAX_BILLS; i++)
	    if (list[i].state == list[i].OFF)
		break;
	if (i == MAX_BILLS)
	    return;
	list[i++].enter();
    }
}

int
Horde::on(unsigned int lev)
{
    return game.MIN(8 + 3 * lev, MAX_BILLS);
}

int
Horde::max_at_once(unsigned int lev)
{
    return game.MIN(2 + lev / 4, 12);
}

int
Horde::between(unsigned int lev)
{
    return game.MAX(14 - lev / 3, 10);
}

void
Horde::load_pix()
{
    int i;
    for (i = 0; i < WCELS - 1; i++) {
	lcels[i].load("billL", i);
	rcels[i].load("billR", i);
    }
    lcels[WCELS - 1] = lcels[1];
    rcels[WCELS - 1] = rcels[1];

    for (i = 0; i < DCELS; i++)
	dcels[i].load("billD", i);
    width = dcels[0].width;
    height = dcels[0].height;

    for (i = 0; i < ACELS; i++)
	acels[i].load("billA", i);
}

void
Horde::update()
{
    int i;
    if (!(game.iteration % between(game.level)))
	launch(max_at_once(game.level));
    for (i = 0; i < MAX_BILLS; i++)
	list[i].update();
}

void
Horde::draw()
{
    int i;
    for (i = 0; i < MAX_BILLS; i++)
	list[i].draw();
}

--- NEW FILE: Bucket.h ---

#ifndef BUCKET_H
#define BUCKET_H

#include "NXPicture.h"

#ifndef PDA
#include "NXMCursor.h"
#endif

class Bucket
{
  public:
    NXPicture picture;
#ifndef PDA
    NXMCursor cursor;
#endif
    int width, height;
    void draw();
    int clicked(int x, int y);
    void load_pix();
};

#endif

--- NEW FILE: NXwidgets.h ---

/* Copyright 2003, Century Software */

#ifndef NXWIDGETS_H
#define NXWIDGETS_H

#define MWINCLUDECOLORS

extern "C"
{
#include <nano-X.h>
#include <nxdraw.h>
}

GR_WINDOW_ID createNXApp(char *title, int xsize, int ysize);
void killNXApp(GR_WINDOW_ID app);
GR_WINDOW_ID createNXWidget(GR_WINDOW_ID parent, int x, int y, int width,
			    int height);
void registerNXWidgetCallback(GR_WINDOW_ID wid, int event,
			      GR_FNCALLBACKEVENT callback);
int fireNXWidgetCallback(GR_WINDOW_ID wid, GR_EVENT * event);
void realizeNXWidget(GR_WINDOW_ID widget);
GR_WINDOW_ID createNXDialog(GR_WINDOW_ID parent, char *str);
void popupNXDialog(GR_WINDOW_ID dialog, char *str);

#endif

--- NEW FILE: UI.cc ---
 /*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "objects.h"
#include "x11.h"
#include "Strings.h"

Widget toplevel, base, menubar, field;
Widget scorebox, highscorebox;
Widget endgamebox, enternamebox;
Widget warpbox, quitbox, newgamebox, pausebox;
Widget aboutbox, rulesbox, storybox;

/**************************/
/* Timer control routines */
/**************************/

void
UI::restart_timer()
{
    timer = XtAppAddTimeOut(app, 250, timer_eh, NULL);	/* 250 ms */
}

void
UI::kill_timer()
{
    if (timer) {
	XtRemoveTimeOut(timer);
	timer = (XtIntervalId) 0;
    }
}

void
UI::pause_game()
{
    if (timer)
	playing = 1;
    kill_timer();
}

void
UI::resume_game()
{
    if (playing && !timer)
	restart_timer();
    playing = 0;
}

/*******************/
/* Window routines */
/*******************/

void
UI::initialize(int *argc, char **argv)
{
    toplevel = XtAppInitialize(&app, "XBill", NULL, 0, argc, argv,
			       NULL, NULL, 0);
}

void
UI::make_mainwin()
{
    Screen *screen;
    XrmDatabase database;
    XSizeHints h;
    Dimension winwidth, winheight;

/*
	XtAddEventHandler(toplevel, (EventMask)0, TRUE,
		_XEditResCheckMessages, NULL);
*/
    display = XtDisplay(toplevel);

    database = XrmGetDatabase(display);
    XrmPutStringResource(&database, "*background", "#c4c4c4");
    XrmSetDatabase(display, database);

    base = CreateRowCol("base", toplevel);
    menubar = CreateMenuBar("menubar", base);
    field = CreateDrawingArea("field", base, game.scrwidth, game.scrheight);
    XtAddEventHandler(field, ButtonPressMask, FALSE,
		      (XtEventHandler) button_press_eh, NULL);
    XtAddEventHandler(field, ButtonReleaseMask, FALSE,
		      (XtEventHandler) button_release_eh, NULL);
    XtAddEventHandler(field, LeaveWindowMask, FALSE,
		      (XtEventHandler) leave_window_eh, NULL);
    XtAddEventHandler(field, EnterWindowMask, FALSE,
		      (XtEventHandler) enter_window_eh, NULL);
    XtAddEventHandler(field, ExposureMask, FALSE,
		      (XtEventHandler) redraw_window_eh, NULL);

    XtRealizeWidget(toplevel);
    screen = XtScreen(toplevel);
    depth = DefaultDepthOfScreen(screen);
    rootwindow = RootWindowOfScreen(screen);
    window = XtWindow(field);

    colormap = DefaultColormapOfScreen(screen);
    white.pixel = WhitePixelOfScreen(screen);
    XQueryColor(display, colormap, &white);
    black.pixel = BlackPixelOfScreen(screen);
    XQueryColor(display, colormap, &black);

    XtVaGetValues(toplevel, XtNwidth, &winwidth, XtNheight, &winheight, NULL);
    h.width = h.base_width = h.min_width = h.max_width = winwidth;
    h.height = h.base_height = h.min_height = h.max_height = winheight;
    h.flags = USSize | PSize | PMaxSize | PMinSize;
    XSetNormalHints(display, window, &h);
}

void
UI::make_windows()
{
    Picture about;

    icon.load("icon");
    XtVaSetValues(toplevel, XtNiconPixmap, icon.pix, NULL);

    newgamebox = CreateDialog("New Game", base, OK | CANCEL, (Pixmap) NULL,
			      newgamestr, (char *) NULL, new_game_cb);
    pausebox = CreateDialog("Pause Game", base, OK, icon.pix,
			    pausestr, "Continue", NULL);
    quitbox = CreateDialog("Quit", base, OK | CANCEL, (Pixmap) NULL,
			   quitstr, (char *) NULL, quit_game_cb);
    warpbox = CreateEnterText("Warp To Level", base, warpstr,
			      (XtCallbackProc) warp_apply);
    about.load("about");

    aboutbox = CreatePixmapBox("About", base, about.pix, "");
    rulesbox = CreatePixmapBox("Rules", base, (Pixmap) NULL, rulesstr);
    storybox = CreatePixmapBox("Story", base, (Pixmap) NULL, storystr);

    scorebox = CreateDialog("Score", base, OK, (Pixmap) NULL,
			    "", (char *) NULL, NULL);
    endgamebox = CreateDialog("Endgame", base, OK, (Pixmap) NULL,
			      endgamestr, "Nuts!", NULL);
    highscorebox = CreateDialog("HighScore", base, OK, (Pixmap) NULL,
				"", (char *) NULL, NULL);
    enternamebox = CreateEnterText("Enter Name", base,
				   enternamestr, (XtCallbackProc) enter_name);
}

void
UI::popup_dialog(int dialog)
{
    Widget w;
    switch (dialog) {
    case game.ENTERNAME:
	w = enternamebox;
	break;
    case game.HIGHSCORE:
	w = highscorebox;
	break;
    case game.SCORE:
	w = scorebox;
	break;
    case game.ENDGAME:
	w = endgamebox;
	break;
    }
    popup(NULL, &w, NULL);
}

/*********************/
/* Graphics routines */
/*********************/

void
UI::set_cursor(int cursor)
{
    switch (cursor) {
    case game.BUCKETC:
	XDefineCursor(display, window, bucket.cursor.cursor);
	break;
    case game.DOWNC:
	XDefineCursor(display, window, downcursor.cursor);
	break;
    case game.DEFAULTC:
	XDefineCursor(display, window, defaultcursor.cursor);
	break;
    default:
	XDefineCursor(display, window, OS.cursor[cursor].cursor);
    }
}

void
UI::load_cursors()
{
    defaultcursor.load("hand_up", defaultcursor.SEP_MASK);
    XDefineCursor(display, window, defaultcursor.cursor);
    downcursor.load("hand_down", downcursor.SEP_MASK);
}

void
UI::graph_init()
{
    XGCValues gcval;
    unsigned long gcmask;
    gcmask = GCGraphicsExposures;
    gcval.graphics_exposures = False;
    stdgc = XCreateGC(display, window, gcmask, &gcval);
    XSetLineAttributes(display, stdgc, 3, LineSolid, CapRound, JoinMiter);
    XSetBackground(display, stdgc, white.pixel);
    XSetForeground(display, stdgc, black.pixel);
    whitegc = XCreateGC(display, window, gcmask, &gcval);
    XSetBackground(display, whitegc, white.pixel);
    XSetForeground(display, whitegc, white.pixel);

    offscreen = XCreatePixmap(display, rootwindow, game.scrwidth,
			      game.scrheight, depth);
}

void
UI::clear()
{
    XFillRectangle(display, offscreen, whitegc, 0, 0,
		   game.scrwidth, game.scrheight);
}

void
UI::refresh()
{
    XCopyArea(display, offscreen, window, stdgc, 0, 0,
	      game.scrwidth, game.scrheight, 0, 0);
}

void
UI::draw(Picture pict, int x, int y)
{
    XSetClipOrigin(display, pict.gc, x, y);
    XCopyArea(display, pict.pix, offscreen, pict.gc, 0, 0,
	      pict.width, pict.height, x, y);
}

void
UI::draw_centered(Picture pict)
{
    draw(pict, (game.scrwidth - pict.width) / 2,
	 (game.scrheight - pict.height) / 2);
}

void
UI::draw_line(int x1, int y1, int x2, int y2)
{
    XDrawLine(display, offscreen, stdgc, x1, y1, x2, y2);
}

void
UI::draw_str(char *str, int x, int y)
{
    XDrawString(display, offscreen, stdgc, x, y, str, strlen(str));
}


/******************/
/* Other routines */
/******************/

void
UI::set_pausebutton(int action)
{
    Widget w = XtNameToWidget(menubar,
#ifdef athena
			      "Game.menu.Pause game");
#else
			      "popup_menu.menu.Pause game");
#endif
    if (w)
	XtSetSensitive(w, action);
}


void
UI::MainLoop()
{
    XtAppMainLoop(app);
}

--- NEW FILE: README.Ports ---
Here's the status of the various ports:

Mac:
Josh Adams <jadams at hyperimage.com> mostly finished this, based on a beta
of 2.0, but never released it for some reason.

Java:
Greg Seidman <anthro at cs.umd.edu> and I were working on this, but it's been
stalled for a while.  We'll finish it at some point.

XFree86 for OS/2:
Darwin O'Connor <doconno at cc.UManitoba.CA> ported it, and you can get it from
http://home.cc.umanitoba.ca/~doconno/xprogs.html

Linux SVGA:
I got this mostly working on a beta of 2.0, but it had a couple problems
(mouse support wasn't very good, no menus or windows), and is now hopelessly
outdated.  It does have an XPM and XBM reader.  So, if anyone wants to
finish this (write the missing parts and the new parts), let me know.

Brian (bwelling at tis.com)

--- NEW FILE: Monster.h ---

#ifndef BILL_H
#define BILL_H

#include "NXPicture.h"

class Monster
{				/*structure for Bills */
  public:
    int state;			/*what is it doing? */
    int index;			/*index to animation frame */
    NXPicture *cels;		/*pointer to array of animation frames */
    int x, y;			/*location */
    int target_x;		/*target x position */
    int target_y;		/*target y position */
    int target_c;		/*target computer */
    int cargo;			/*which OS carried */
    int x_offset;		/*accounts for width differences */
    int y_offset;		/*'bounce' factor for OS carried */
    int sx, sy;			/*used for drawing extra OS during switch */

    static const int SLOW = 0;	/* speeds of moving bills */
    static const int FAST = 1;

    static const int OFF = 0;	/* Bill's states */
    static const int IN = 1;
    static const int AT = 2;
    static const int OUT = 3;
    static const int DYING = 4;
    static const int STRAY = 5;

    static const int GRAVITY = 3;	/*speed at which os drops */

    static const int XOFFSET = 20;	/*offset from right of computer */
    static const int YOFFSET = 3;	/*offset from top of computer */

    void get_border();
    void enter();
    int move(int mode);
    void draw();
    void draw_std();
    void draw_at();
    void draw_stray();
    void update();
    void update_in();
    void update_at();
    void update_out();
    void update_dying();
    int clicked(int locx, int locy);
    int clickedstray(int locx, int locy);
    int step_size(unsigned int lev);

};

#endif

--- NEW FILE: NXMCursor.h ---
/* Copyright 2003, Century Software */
#ifndef NX_MCURSOR_H
#define NX_MCURSOR_H

#define MWINCLUDECOLORS
extern "C"
{
#include "nano-X.h"
}

class NXMCursor
{
  public:
    static const int SEP_MASK = 0;
    static const int OWN_MASK = 1;

    GR_BITMAP *cursor;
    GR_BITMAP *mask;

    int width, height, hx, hy;

    void setCursor(GR_WINDOW_ID window);
    void load(char *file, int mask);

};

#endif

--- NEW FILE: NXPicture.cc ---
 /* Copyright (C) 200-2002 Century Embedded Techonlogies
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "NXPicture.h"
#include "objects.h"

extern char xbill_path[256];

NXPicture::~NXPicture()
{
    if (gc)
	GrDestroyGC(gc);

    if (image)
	GrFreeImage(image);

    if (pixmap)
	GrDestroyWindow(pixmap);
}

void
NXPicture::load(char *name, int index)
{
    GR_IMAGE_INFO iinfo;
    char file[255];

    if (index >= 0)
	sprintf(file, "%s%s_%d.xpm", xbill_path, name, index);
    else
	sprintf(file, "%s%s.xpm", xbill_path, name);

    /* Ok, load the pix */
    image = GrLoadImageFromFile(file, 0);

    if (image) {
	GrGetImageInfo(image, &iinfo);

	width = iinfo.width;
	height = iinfo.height;

	/* Create a new pixmap for off screen drawing */


	pixmap = GrNewPixmap(width + 3, height + 3, NULL);
	gc = GrNewGC();

	GrSetGCBackground(gc, WHITE);
	GrFillRect(pixmap, gc, 0, 0, width, height);

	/* And draw our boy there */
	GrDrawImageToFit(pixmap, gc, 0, 0, width, height, image);
    }
}

--- NEW FILE: x11-athena.cc ---
 /*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "objects.h"
#include "x11.h"
#include "menu.h"

#include <X11/Xaw/XawInit.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/MenuButton.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/SmeBSB.h>
#include <X11/Xaw/SmeLine.h>
#include <X11/Xaw/AsciiText.h>

extern Widget scorebox, highscorebox;

Widget
CreateMenuBar(const char *name, Widget parent)
{
    int i, j;
    Widget menubar, temp;
    menubar = XtVaCreateManagedWidget(name, boxWidgetClass, parent,
				      XtNborderWidth, 0, XtNorientation,
				      XtEhorizontal, NULL);
    for (j = 0; j < menu.size; j++) {
	temp = XtCreateManagedWidget(menu.submenu[j].name,
				     menuButtonWidgetClass, menubar, NULL, 0);
	menu.submenu[j].pshell = XtCreatePopupShell("menu",
						    simpleMenuWidgetClass,
						    temp, NULL, 0);
	for (i = 0; i < menu.submenu[j].size; i++) {
	    if (strlen(menu.submenu[j].button[i].name)) {
		temp = XtCreateManagedWidget(menu.submenu[j].button[i].name,
					     smeBSBObjectClass,
					     menu.submenu[j].pshell, NULL, 0);
		XtAddCallback(temp, XtNcallback,
			      (XtCallbackProc) popup,
			      menu.submenu[j].button[i].dialog);
	    } else
		XtCreateManagedWidget("", smeLineObjectClass,
				      menu.submenu[j].pshell, NULL, 0);
	}
    }
    return menubar;
}

void
close_window(Widget w, XtPointer client_data, XtPointer call_data)
{
    XtPopdown(XtParent(XtParent(w)));
}

Widget
CreatePixmapBox(const char *name, Widget parent, Pixmap pixmap,
		const char *text)
{
    Widget base, pshell, button;

    pshell = XtCreatePopupShell(name, transientShellWidgetClass,
				parent, NULL, 0);

    base = CreateRowCol("", pshell);

    XtVaCreateManagedWidget("", labelWidgetClass, base,
			    XtNbitmap, game.logo.pix, XtNborderWidth, 0,
			    NULL);

    if (pixmap)
	XtVaCreateManagedWidget("", labelWidgetClass, base,
				XtNbitmap, pixmap, XtNborderWidth, 0, NULL);
    if (text)
	XtVaCreateManagedWidget("", labelWidgetClass, base,
				XtNlabel, text, XtNborderWidth, 0, NULL);

    button = XtVaCreateManagedWidget("OK", commandWidgetClass, base, NULL);
    XtAddCallback(button, XtNcallback, (XtCallbackProc) close_window, NULL);
    return base;
}

void
warp_apply(Widget w, Widget text, XtPointer client_data)
{
    char *str;
    XtVaGetValues(text, XtNstring, &str, NULL);
    game.warp_to_level(atoi(str));
}

void
enter_name(Widget w, Widget text, XtPointer client_data)
{
    char *str, *nl;
    XtVaGetValues(text, XtNstring, &str, NULL);
    if (!str[0])
	strcpy(str, "Anonymous");
    else if ((nl = strchr(str, '\n')))
	*nl = 0;
    if (strlen(str) > 20)
	str[20] = 0;		/* truncate string if too long */
    scores.recalc(str);
}

Widget
CreateEnterText(const char *name, Widget parent, const char *text,
		XtCallbackProc callback)
{
    Widget base, pshell, button, textfield;
    pshell = XtCreatePopupShell(name, transientShellWidgetClass,
				parent, NULL, 0);
    base = CreateRowCol("", pshell);
    XtVaCreateManagedWidget("", labelWidgetClass, base,
			    XtNlabel, text, XtNborderWidth, 0, NULL);

    textfield = XtVaCreateManagedWidget("", asciiTextWidgetClass, base,
					XtNeditType, XawtextEdit, XtNstring,
					"", XtNwidth, 200, NULL);

    button = XtVaCreateManagedWidget("OK", commandWidgetClass, base, NULL);
    XtAddCallback(button, XtNcallback, (XtCallbackProc) callback, textfield);
    XtAddCallback(button, XtNcallback, (XtCallbackProc) close_window, NULL);
    button = XtVaCreateManagedWidget("Cancel", commandWidgetClass, base,
				     NULL);
    XtAddCallback(button, XtNcallback, (XtCallbackProc) close_window, NULL);
    return base;
}

Widget
CreateDialog(const char *name, Widget parent, int buttonmask,
	     Pixmap icon, const char *text, const char *buttonlabel,
	     XtCallbackProc callback)
{
    Widget base, pshell, button;
    char *ttext = (char *) malloc(strlen(text) + 5);
    pshell = XtCreatePopupShell(name, transientShellWidgetClass,
				parent, NULL, 0);
    base = CreateRowCol("base", pshell);
    strcpy(ttext, text);
    if (strlen(ttext) < 12)
	strcat(ttext, "     ");
    XtVaCreateManagedWidget("label", labelWidgetClass, base,
			    XtNlabel, ttext, XtNborderWidth, 0, NULL);
    if (icon)
	XtVaCreateManagedWidget("", labelWidgetClass, base,
				XtNbitmap, icon, XtNborderWidth, 0, NULL);
    if (buttonmask & OK) {
	if (!buttonlabel)
	    buttonlabel = "OK";
	button = XtVaCreateManagedWidget(buttonlabel,
					 commandWidgetClass, base, NULL);
	if (callback)
	    XtAddCallback(button, XtNcallback,
			  (XtCallbackProc) callback, NULL);
	XtAddCallback(button, XtNcallback,
		      (XtCallbackProc) close_window, NULL);
    }
    if (buttonmask & CANCEL) {
	button = XtVaCreateManagedWidget("Cancel", commandWidgetClass,
					 base, NULL);
	XtAddCallback(button, XtNcallback,
		      (XtCallbackProc) close_window, NULL);
    }
    return base;
}

Widget
CreateDrawingArea(const char *name, Widget parent, int width, int height)
{
    return XtVaCreateManagedWidget(name, coreWidgetClass, parent, XtNwidth,
				   width, XtNheight, height, NULL);
}

void
UI::update_hsbox(char *str)
{
    WidgetList t;
    XtVaGetValues(highscorebox, XtNchildren, &t, NULL);
    XtVaSetValues(t[0], XtNlabel, str, NULL);
}

void
UI::update_scorebox(int level, int score)
{
    WidgetList t;
    char str[40];
    sprintf(str, "After Level %d:     \nYour score: %d\n", level, score);
    XtVaGetValues(scorebox, XtNchildren, &t, NULL);
    XtVaSetValues(t[0], XtNlabel, str, NULL);
}

Widget
CreateRowCol(const char *name, Widget parent)
{
    return XtCreateManagedWidget(name, boxWidgetClass, parent, NULL, 0);
}

--- NEW FILE: NX.h ---
/* Copyright 2003, Century Software */

#ifndef NX_H
#define NX_H

#define OK	1
#define CANCEL	2


void popup(GR_WINDOW_ID w);
void popdown(GR_WINDOW_ID w);

void new_game_cb(GR_WINDOW_ID w);
void quit_game_cb(GR_WINDOW_ID w);

void leave_window_eh(GR_EVENT * event);
void enter_window_eh(GR_EVENT * event);
void redraw_window_eh(GR_EVENT * event);
void button_press_eh(GR_EVENT * event);
void button_release_eh(GR_EVENT * event);
void timer_eh();

void redraw_menubar_eh(GR_EVENT * event);
void menubar_buttonup_eh(GR_EVENT * event);
void menubar_buttondown_eh(GR_EVENT * event);

#ifdef NOTUSED
GR_WINDOW_ID CreateMenuBar(const char *name, GR_WINDOW_ID parent);
GR_WINDOW_ID CreatePixmapBox(const char *name, GR_WINDOW_ID parent,
			     Pixmap pixmap, const char *text);
GR_WINDOW_ID CreateEnterText(const char *name, GR_WINDOW_ID parent,
			     const char *text, XtCallbackProc callback);
GR_WINDOW_ID CreateDialog(const char *name, GR_WINDOW_ID parent,
			  int buttonmask, Pixmap icon, const char *text,
			  const char *buttonlabel, XtCallbackProc callback);
GR_WINDOW_ID CreateDrawingArea(const char *name, GR_WINDOW_ID parent,
			       int width, int height);

void print_to_widget(GR_WINDOW_ID w, const char *str);
GR_WINDOW_ID CreateRowCol(char *name, GR_WINDOW_ID parent);

void setup_main_widgets();
void setup_other_widgets(Pixmap about, Pixmap rules, Pixmap story);

void warp_apply(GR_WINDOW_ID w, GR_WINDOW_ID text, XtPointer client_data);
void enter_name(GR_WINDOW_ID w, GR_WINDOW_ID text, XtPointer client_data);
#endif

#endif

--- NEW FILE: NX.cc ---
 /*
 * Copyright (C) 200-2002 Century Embedded Techonlogies
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "objects.h"
#include "NX.h"

//static int in_popup = 0;

/**********************/
/* Callback functions */
/**********************/

void
new_game_cb(GR_WINDOW_ID w)
{
    game.start(1);
}

void
quit_game_cb(GR_WINDOW_ID w)
{
    game.quit();
}

void
get_coords(GR_EVENT * event, int *x, int *y)
{


    *x = event->mouse.x;
    *y = event->mouse.y;
}

#ifdef NOTUSED
void
popup(Widget w, Widget * box, XtPointer call_data)
{
    Position x, y;
    in_popup = 1;
#ifdef athena
    get_coords(&x, &y);
    XtMoveWidget(XtParent(*box), x, y);
#endif
    XtManageChild(*box);
    XtAddCallback(XtParent(*box), XtNpopdownCallback,
		  (XtCallbackProc) popdown, NULL);
    XtPopup(XtParent(*box), XtGrabExclusive);
    while (in_popup || XtAppPending(ui.app))
	XtAppProcessEvent(ui.app, XtIMXEvent);
}

void
popdown(Widget w, XtPointer client_data, XtPointer call_data)
{
    in_popup = 0;
}
#endif

/******************/
/* Event handlers */
/******************/

void
redraw_menubar_eh(GR_EVENT * event)
{
    ui.redraw_menubar();
}

void
menubar_buttonup_eh(GR_EVENT * event)
{
    ui.menubar_buttonup(event->button.x, event->button.y);
}

void
menubar_buttondown_eh(GR_EVENT * event)
{
    /* NOP */
}

void
leave_window_eh(GR_EVENT * event)
{
    ui.pause_game();
}

void
enter_window_eh(GR_EVENT * event)
{
    ui.resume_game();
}

void
redraw_window_eh(GR_EVENT * event)
{
    ui.refresh();
}

void
button_press_eh(GR_EVENT * event)
{
    game.button_press(event->button.x, event->button.y);
}

void
button_release_eh(GR_EVENT * event)
{
    game.button_release(event->button.x, event->button.y);
}

void
timer_eh()
{
    ui.restart_timer();
    game.update();
}

--- NEW FILE: Picture.cc ---
 /*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "Picture.h"
#include "objects.h"

void
Picture::load(const char *name, int index)
{
    static char *dir =
	strdup(access(XBILL_HOME "images/logo.xpm", R_OK) ? "" : XBILL_HOME);
    int i;
    char file[255];
    Pixmap mask;
    XpmAttributes attr;
    unsigned long gcmask;
    XGCValues gcval;
    gcmask = GCForeground | GCBackground | GCGraphicsExposures;
    gcval.graphics_exposures = False;
    attr.valuemask = XpmCloseness | XpmReturnPixels | XpmColormap | XpmDepth;
    attr.closeness = 65535;
    attr.colormap = ui.colormap;
    attr.depth = ui.depth;
    if (index >= 0)
	sprintf(file, "%simages/%s_%d.xpm", dir, name, index);
    else
	sprintf(file, "%simages/%s.xpm", dir, name);
    i = XpmReadFileToPixmap(ui.display, ui.rootwindow, file, &pix,
			    &mask, &attr);
    if (i < 0) {
	printf("cannot open %s\n", file);
	exit(1);
    }
    gc = XCreateGC(ui.display, ui.offscreen, gcmask, &gcval);
    XSetClipMask(ui.display, gc, mask);
    width = attr.width;
    height = attr.height;
}

--- NEW FILE: Game.h ---

#ifndef GAME_H
#define GAME_H

#include "objects.h"

class Game
{
    unsigned state;
    int efficiency;
  public:
    unsigned score, level, iteration;
    NXPicture logo;
    int grabbed;

    /* This is the actual size of the whole shooting match */

    static const unsigned short scrwidth = 240;
    static const unsigned short scrheight = 286;

    /* This is the size of the playground */
    static const unsigned short playwidth = 240;
    static const unsigned short playheight = 256;

    static const int PLAYING = 1;
    static const int BETWEEN = 2;
    static const int END = 3;
    static const int WAITING = 4;

    static const int DEFAULTC = 0;	/* cursors */
    static const int DOWNC = -1;
    static const int BUCKETC = -2;

    static const int ENDGAME = 200;	/* dialog window IDs */
    static const int ENTERNAME = 201;
    static const int HIGHSCORE = 202;
    static const int SCORE = 203;

    static const int ENDLEVEL = -1;	/* Codes for updating score */
    static const int BILLPOINTS = 5;

    static const int EMPTY = -2;	/* Grabbed object */
    static const int BUCKET = -1;

    int RAND(int lb, int ub);
    int MAX(int x, int y);
    int MIN(int x, int y);
    int INTERSECT(int x1, int y1, int w1, int h1, int x2, int y2, int w2,
		  int h2);

    void setup_level(unsigned int lev);
    void start(unsigned int lev);
    void quit();
    void update_info();
    void update_score(int action);
    void warp_to_level(unsigned int lev);
    void button_press(int x, int y);
    void button_release(int x, int y);
    void update();
    void main(int argc, char **argv);
};

#endif

--- NEW FILE: x11.cc ---
 /*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "objects.h"
#include "x11.h"

static int in_popup = 0;

/**********************/
/* Callback functions */
/**********************/

void
new_game_cb(Widget w, XtPointer client_data, XtPointer call_data)
{
    game.start(1);
}

void
quit_game_cb(Widget w, XtPointer client_data, XtPointer call_data)
{
    game.quit();
}

void
get_coords(Position * x, Position * y)
{
    XWindowAttributes wattr;
    Window junk;
    int rx, ry;
    XGetWindowAttributes(ui.display, ui.window, &wattr);
    XTranslateCoordinates(ui.display, ui.window, wattr.root,
			  -wattr.border_width, -wattr.border_width, &rx, &ry,
			  &junk);
    *x = rx + 20;
    *y = ry + 40;
}

void
popup(Widget w, Widget * box, XtPointer call_data)
{
    Position x, y;
    in_popup = 1;
#ifdef athena
    get_coords(&x, &y);
    XtMoveWidget(XtParent(*box), x, y);
#endif
    XtManageChild(*box);
    XtAddCallback(XtParent(*box), XtNpopdownCallback,
		  (XtCallbackProc) popdown, NULL);
    XtPopup(XtParent(*box), XtGrabExclusive);
    while (in_popup || XtAppPending(ui.app))
	XtAppProcessEvent(ui.app, XtIMXEvent);
}

void
popdown(Widget w, XtPointer client_data, XtPointer call_data)
{
    in_popup = 0;
}

/******************/
/* Event handlers */
/******************/

void
leave_window_eh(Widget w, XtPointer client_data, XEvent * event)
{
    ui.pause_game();
}

void
enter_window_eh(Widget w, XtPointer client_data, XEvent * event)
{
    ui.resume_game();
}

void
redraw_window_eh(Widget w, XtPointer client_data, XEvent * event)
{
    ui.refresh();
}

void
button_press_eh(Widget w, XtPointer data, XButtonEvent * event)
{
    game.button_press(event->x, event->y);
}

void
button_release_eh(Widget w, XtPointer data, XButtonEvent * event)
{
    game.button_release(event->x, event->y);
}

void
timer_eh(XtPointer client_data, XtIntervalId * timer_id)
{
    ui.restart_timer();
    game.update();
}

--- NEW FILE: Makefile.org ---
CXX=arm-linux-g++
LD=arm-linux-ld

DOPDA = Y


NXLIBDIR = -L/home/jasonk/projects/microwin/src/lib
NXLIBS   =  -lnano-X

XBILLHOME = -DXBILL_HOME=\"/home/jasonk/projects/xbill-2.0/\"

CXXFLAGS = -O2 -I/home/jasonk/projects/microwin/src/include $(XBILLHOME)

ifeq ($(DOPDA), Y)
CXXFLAGS += -DPDA
endif

SRCS =	Bucket.cc \
	Cable.cc \
	Computer.cc \
	Game.cc \
	Horde.cc \
	Library.cc \
	Monster.cc \
	Network.cc \
	Scorelist.cc \
	Spark.cc \
	NXPicture.cc \
	nanox-UI.cc  \
	NXwidgets.cc \
	NX.cc 


OBJS =	Bucket.o \
	Cable.o \
	Computer.o \
	Game.o \
	Horde.o \
	Library.o \
	Monster.o \
	Network.o \
	Scorelist.o \
	Spark.o \
	NXPicture.o \
	NXwidgets.o \
        NX.o \
        nanox-UI.o

ifeq ($(DOPDA), N)
SRCS += NXMCursor.cc
OBJS += NXMCursor.o
endif

nbill: $(OBJS)
	$(CXX)  $(OBJS) $(NXLIBDIR) $(NXLIBS) -o nbill

clean:
	rm *.o

SUFFIXES:      .cc .o

.cc.o :
	$(CXX) $(CXXFLAGS) -c -o $@ $<


--- NEW FILE: README ---
       Welcome to xbill...

       Ever  get the feeling that nothing is going right?  You're
       a sysadmin, and someone's trying to destroy  your  comput-
       ers.  The little people running around the screen are try-
       ing to infect your computers with Wingdows [TM],  a  virus
       cleverly  designed to resemble a popular operating system.
       Your objective is to click the mouse on them, ending their
       potential  threat.  If one of the people reaches a comput-
       er, it will attempt to replace your operating system  with
       the  virus it carries. It will then attempt to run off the
       screen with your vital software.  The game ends when  only
       0 or 1 of your computers is being productive.  Additional-
       ly, some computers  are  connected  with  network  cables.
       When  one  computer on a network becomes infected, a spark
       will be sent down the cable, and will infect the  computer
       on the other end when it reaches there.

       Clicking the button on one of the little people will cause
       it to cry out in pain and melt (id software eat your heart
       out!), dropping the stolen os if it is carrying one.  If a
       computer is running Wingdows or is temporarily off, the os
       can  be  dragged back to the computer (or another computer
       compatible with that os).  To extinguish a spark drag  the
       bucket of water from the upper left corner onto it.

       The status bar at the bottom tells the following:
               Number of Bills on/off the screen
               Number of Computers running their OS/off/Wingdows
               Level
               Score

OPTIONS
       -l n, -L n
              Start at level n.

       -v     Print version number and exit.

       -h     Print help and exit.

       All standard X Intrinsics options are also supported.


AUTHORS
       Main Programmer:
            Brian Wellington <bwelling at tis.com>
       Programming & graphics:
            Matias Duarte <matias at hyperimage.com>


COPYING
       Copyright (c) 1994-6 Psychosoft

       It's  FREE!  If you want to express your undying gratitude
       to us for bringing a small bit of meaning into your other-
       wise pointless existence, you could always send us e-mail.
       XBill is distributed under the GNU Public License.

       Go play the game now!


--- NEW FILE: Spark.h ---

#ifndef SPARK_H
#define SPARK_H

#include "NXPicture.h"

class Spark
{
  public:
    NXPicture pictures[2];
    int width, height;
    void draw();
    void load_pix();
    static const int speed = 5;
    int delay(unsigned int lev);
};

#endif

--- NEW FILE: scores ---
brian                10 2000
matias               9 1800
me                   8 1600
me                   7 1400
me                   6 1200
me                   5 1000
me                   4 800
me                   3 600
me                   2 400
me                   1 200

--- NEW FILE: Cable.h ---

#ifndef CABLE_H
#define CABLE_H

class Cable
{
  public:
    int c1, c2;			/*computers connected */
    int x1, y1, x2, y2;		/*endpoints of line representing cable */
    int x, y;			/*current location of spark */
    float fx, fy;		/*needed for line drawing */
    int delay;			/*how much time until spark leaves */
    int active;			/*is spark moving and from which end */
    int index;
    void setup();
    void draw();
    void update();
    int onspark(int locx, int locy);

};

#endif

--- NEW FILE: NXMCursor.cc ---
/*
 * Copyright (C) 200-2002 Century Embedded Techonlogies
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <stdio.h>
#include "objects.h"
#include "NXMCursor.h"

void
NXMCursor::setCursor(GR_WINDOW_ID window)
{
    GrSetCursor(window, width, height, hx, hy, BLACK, WHITE, cursor, cursor);
}

static int
load_file(char *filename, GR_BITMAP ** bitmap, int *x, int *y)
{
    char *c;

    int width, height, bm;
    FILE *infile;
    static char *dir =
	strdup(access(xbill_path "pixmaps/logo.xpm", R_OK) ? "" : xbill_path);
    char buf[BUFSIZ];
    char tempa[40];
    char tempb[40];
    char file[255];
    GR_BITMAP *cursorptr, *cursor;

    width = 0;
    height = 0;

    sprintf(file, "%sbitmaps/%s.xbm", dir, filename);

    /* Ok, lets do this.  We have two defines that indicate the width and the height.  Grab em! */
    infile = fopen(file, "r");

    fgets(buf, BUFSIZ, infile);

    buf[strlen(buf)] = 0;

    if (buf[0] == '#') {
	char *c;
	/* Read to the second space */
	c = buf;
	for (c = buf; *c != ' '; c++);
	for (++c; *c != ' '; c++);

	c++;

	width = atoi(c);
    }

    fgets(buf, BUFSIZ, infile);

    if (buf[0] == '#') {
	char *c;
	/* Read to the second space */
	c = buf;
	for (c = buf; *c != ' '; c++);
	for (++c; *c != ' '; c++);

	height = atoi(c);
    }

    fgets(buf, BUFSIZ, infile);

    /* Now that we know the width and height, we can construct */
    /* our bitmask.  First, allocate the space required for the file */

    cursor = (GR_BITMAP *) malloc(sizeof(GR_BITMAP) * height);

    /* Now fill it up */

    fgets(buf, BUFSIZ, infile);
    c = buf;

    for (bm = 0; bm < height; bm++) {
	char *d;
	unsigned long tval, val;
	int i;
	/* Read the right number of bits.  If we are at the end, then get a new line */

	val = 0;

	for (i = ((width / 8) - 1); i >= 0; i--) {
	    if (*c == '\n') {
		fgets(buf, BUFSIZ, infile);
		c = buf;
	    }

	    if (*c == ',')
		c++;

	    tval = strtol(c, &d, 16);

	    val |= tval << (i * 8);

	    c = d;
	}

	cursor[bm] = val;
    }

    fclose(infile);

    *x = width;
    *y = height;
    *bitmap = cursor;
}

void
NXMCursor::load(char *file, int mask)
{
    load_file(file, &cursor, &width, &height);
    hx = 0;
    hy = 0;
}

--- NEW FILE: Library.h ---

#ifndef LIBRARY_H
#define LIBRARY_H

#include "NXPicture.h"
#include "NXMCursor.h"

class Library
{				/* global structure of all OSes */
  public:
    static const int WINGDOWS = 0;	/* OS 0 is wingdows */
    static const int OFF = -1;	/* OS -1 means the computer is off */
    static const int PC = 5;	/* OS >= PC means the OS is a PC OS */
    static const int NUM_OS = 9;	/* The number of OSes (not Wingdows) */
    int width, height;		/* size of OS picture */
    NXPicture os[NUM_OS + 1];	/* array of OS pictures */
    NXMCursor cursor[NUM_OS + 1];	/* array of OS cursors (drag/drop) */
    void load_pix();
};

#endif

--- NEW FILE: MCursor.cc ---
 /*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "MCursor.h"
#include "objects.h"

void
MCursor::load(char *data, int width, height)
{
    static char *dir =
	strdup(access(XBILL_HOME "images/logo.xpm", R_OK) ? "" : XBILL_HOME);

    Pixmap bitmap, mask;
    int i, xh, yh;
    unsigned width, height;
    char file[255];
    char mfile[255];
    sprintf(file, "%simages/%s.xbm", dir, name);

    i = NXReadBitmapFile(ui.rootwindow, file, &width, &height, &bitmap, &xh,
			 &yh);

    i = XReadBitmapFile(ui.display, ui.rootwindow, file,
			&width, &height, &bitmap, &xh, &yh);

    if (i == BitmapOpenFailed) {
	printf("cannot open %s\n", file);
	exit(1);
    }
    if (masked == SEP_MASK) {
	sprintf(mfile, "%simages/%s_mask.xbm", dir, name);
	i = XReadBitmapFile(ui.display, ui.rootwindow,
			    mfile, &width, &height, &mask, &xh, &yh);
    } else
	mask = bitmap;
    if (i == BitmapOpenFailed) {
	printf("cannot open %s\n", file);
	exit(1);
    }
    cursor = XCreatePixmapCursor(ui.display, bitmap, mask,
				 &ui.black, &ui.white, width / 2, height / 2);
}

--- NEW FILE: Scorelist.h ---

#ifndef SCORELIST_H
#define SCORELIST_H

class Scorelist
{
  public:
    char name[10][21];
    unsigned level[10];
    unsigned score[10];
    FILE *open_file(char *mode);
    void read();
    void write();
    void recalc(char *str);
    void update();
};

#endif

--- NEW FILE: Spark.cc ---
 /*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "objects.h"

int
Spark::delay(unsigned int lev)
{
    return game.MAX(20 - lev, 0);
}

void
Spark::load_pix()
{
    int i;
    for (i = 0; i < 2; i++)
	pictures[i].load("spark", i);
    width = pictures[0].width;
    height = pictures[0].height;
}

--- NEW FILE: ChangeLog ---
XBill history:

0.01 (7/21/94):  
	- Bill moves, and he's in color too.  You can even click on
		him and he excaims "OUCH!" or "SPLAT!"
	- window resizing is very wrong
	
0.02 (7/22/94):	
	- program no longer guaranteed to run predictably for 
		longer than nine years (sorry)
	- ridiculously improved code style (no really a lot!)
	- added linked list unit and support for multiple monsters
	- added support for computers
	- bill says "POW!!!!!!" on button 2
	- improved Makefile
	- remembered to include app-defaults file in tar

0.03 (7/24/94):
	- forgot to initialize a variable.  either the stupid aix compiler 
		initialized it anyway or we were really lucky testing it.
	- removed annoying flicker
	- has multiple computers on the screen with random OSes
	- has multiple bills moving on the screen in random directions
	- used sxpm to create smaller .xpm files, minor savings in memoy
		and executable size, easier to edit pixmaps
	- left button (button 1) removes bills from screen
	- right button (button 3) now resets computers to wingdows.

0.04 (7/25/94):
	- got masking to work (well, maybe not...)
	- bill now carries the wingdows box around
	- event handling/speed improved

0.1 (7/26/94):
	- masking really works now
	- fixed computer pixmap so it looks nice(r)
	- randomized computer layout now leaves room for bill to stand on right
	- support for bills walking in, standing at computers and walking out
	- bills walk towards a specific computer to plunder (primitive ai)
	- bill turns off computer, 'steals' native os and installs wingdows
	- count of bills remaining is kept: decreased when bill enters screen
					  - increased if bill leaves
	- bill is killable in all states
	- computer reset to native os on right button
	- cleaned up code and internal structures
	- event handling/speed really improved (optimized for the new code)
	- server lag problems identified
	- linked list unit fixed so that function to move between lists works
	- window resizing is still very wrong
	
0.2 (8/14/94)
	- programmers woke up after being asleep since 7/26.	
	- code structures were fixed very much (again)
	- bill faces in the direction he's walking
	- bill explodes in a gory shower of blood when clicked on (yeah!)
	- bill drops os when killed
	- the os stays on the ground when bill is killed if it had been stolen
	- the os bounces up and down while bill carries it
	- changed default cursor (matias will have to draw a better one later)
	- cursor changes during drag and drop operation
	- drag and drop works!  there's a little hack involved, but not 
		too bad...
	- bill now smart enough to notice that a computer is already
		corrupted and find a new one
	- game ends if all computers are lost

0.21 (8/15/94)
	- attempt to port code to athena widgets.  it compiles and
		runs w/o motif now (i hate C macros) a bit
	- improved the makefile.  an imakefile one day maybe...

0.22 (8/16/94)
	- when bill leaves the field, he drops the os he's carrying
	- status bar widget now does something

0.3 (8/23/94)
	- improved responsiveness a lot :)
	- menubar does something (new game, pause and quit buttons) if 
		motif is used.
	- levels now exist (barely)
	- yet more code cleanup

0.31 (8/24/94)
	- a few things depend on the level (freq. and number of appearing
		bills, number of computers, step size)
	- bug where a computer is ignored if off is removed
	- menu code written.
	- athena code started.  this works more or less, but not too well.
		i'd recommend using motif and/or a statically linked binary.

0.32 (9/18/94)
	- about box works.  help almost works also.
	- a bunch of bugs fixed
	- have an Imakefile now (thanks to Greg Seidman - anthro at cs.umd.edu)

0.9 (11/28/94 - a bit busier during school)
	- warp to arbitrary level works
	- game pauses when cursor leaves window
	- cursor warps to near upper left corner of opened dialog boxes
	- redefined both reset and drag to right button (button 3),
		added -1 option for people with a one button mouse.
		-1 may slow the game down a bit. 
	- added -l, -L to specify starting level
	- added -v for version info
	- improved pictures a lot
	- added confirmations for actions
	- game now pauses well
	- fixed level difficulty stuff
	- bill walks at two speeds
	- minimizes to an icon (a cool one too...)
	- scoring improved
	- window cannot be resized now, no matter how hard you try :)
	- much cooler animations for bill replacing os
	- added high score list
	- fixed lots of silly bugs
	- made program not die from colormap error (i hope)

1.0 (4/5/95-4/9/95)
	- remembered that the game's not done yet :)
	- replaced usleep() calls with XtAppAddTimeout().  should make
		the game more responsive
	- changed all popup windows to modal dialogs.  cleans up code
		a lot
	- removed Athena support, since it would take too long to finish.
	- made a couple pixmaps a bit smaller
	- changed colors to gray.  why not?
	- finally got everything to work with full colormaps
	- got rid of app-defaults file.  Not really used anyway
	- Only uses one button now (any button).  Easier to play.
	- Some Imakefile fixes

1.1 (4/16/95)
	- modularized widget code, and added Athena widget support (rewritten
		from scratch).  The game looks better with Motif, but that's
		not too important.
	- made pause button only active during game play
	- warping to a level starts a game if one isn't being played
	- fixed a potentially nasty bug that could cause bills to get lost
	- works in TrueColor now (I think - it works in 16 bit mode at least)

1.1a (9/22/95)
	- fixed bug where getopt() returned a char instead of an int.
	- fixed bug where hitting Enter when entering a high score
		corrupted the high score file.
	- don't fclose() nonexistant files any more.
	- added BSD as another operating system (patches by Joerg Wunsch,
		joerg_wunsch at uriah.heep.sax.de)
	- it was really easy to play forever by guarding one computer.  Now
		you lose when there's only one computer left running its
		normal OS.
	- added man page, written by Pekka Marjola (marjola at trshp.ntc.nokia.com)

2.0 ()
	- changed around some timer code.
	- removed Athena DrawingArea widget since CoreWidget works too.
	- massive code reorganization to improve portability to other
		GUIs, languages, etc.
	- Some computers are connected by network cables
	- When a computer with a network cable becomes infected, it will
		release a spark down the cable which will infect the
		computer on the other end.  Pouring the bucket of water
		on the spark will extinguish it.
	- Made cursors and various other images look better.
	- Removed references to defenestration.dorm.umd.edu, which no
		longer exists.
	- Added Red Hat logo (fixed broken Red Hat patch).
	- Added GNU Hurd logo
	- Added Linux penguin logo
	- The BSD, Red Hat, Linux, OS/2, and Hurd operating systems are
		interchangable on the 2 PC computers.
	- The score is now displayed in the playing field.
	- Made Athena version far better looking.
	- Motif version almost completely works with Lesstif.

--- NEW FILE: x11-motif.cc ---
 /*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "objects.h"
#include "x11.h"
#include "menu.h"

#include <Xm/Xm.h>
#include <Xm/Label.h>
#include <Xm/RowColumn.h>
#include <Xm/DrawingA.h>
#include <Xm/PushB.h>
#include <Xm/CascadeB.h>
#include <Xm/MessageB.h>
#include <Xm/SelectioB.h>
#include <Xm/Text.h>

extern Widget scorebox, highscorebox;

Widget
CreateMenuBar(const char *name, Widget parent)
{
    int i, j;
    Widget menubar, temp;
    menubar = XmCreateMenuBar(parent, name, NULL, 0);
    XtManageChild(menubar);
    for (j = 0; j < menu.size; j++) {
	menu.submenu[j].pulldown = XmCreatePulldownMenu(menubar,
							"menu", NULL, 0);
	temp = XtVaCreateManagedWidget(menu.submenu[j].name,
				       xmCascadeButtonWidgetClass, menubar,
				       XmNsubMenuId, menu.submenu[j].pulldown,
				       NULL);
	for (i = 0; i < menu.submenu[j].size; i++) {
	    temp = XtCreateManagedWidget(menu.submenu[j].button[i].name,
					 xmPushButtonWidgetClass,
					 menu.submenu[j].pulldown, NULL, 0);
	    XtAddCallback(temp, XmNactivateCallback,
			  (XtCallbackProc) popup,
			  menu.submenu[j].button[i].dialog);
	}
    }
    return menubar;
}

Widget
CreatePixmapBox(const char *name, Widget parent, Pixmap pixmap,
		const char *text)
{
    Arg wargs[2];
    XmString mstr;
    Widget dialog, base;
    mstr = XmStringCreateLtoR("", XmSTRING_DEFAULT_CHARSET);
    XtSetArg(wargs[0], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL);
    XtSetArg(wargs[1], XmNmessageString, mstr);
    dialog = XmCreateMessageDialog(parent, name, wargs, 2);

    base = CreateRowCol("", dialog);

    XtVaCreateManagedWidget("", xmLabelWidgetClass, base, XmNlabelType,
			    XmPIXMAP, XmNlabelPixmap, game.logo.pix, NULL);

    if (pixmap)
	XtVaCreateManagedWidget("", xmLabelWidgetClass, base,
				XmNlabelType, XmPIXMAP, XmNlabelPixmap,
				pixmap, NULL);

    if (text) {
	mstr = XmStringCreateLtoR(text, XmSTRING_DEFAULT_CHARSET);
	XtVaCreateManagedWidget(text, xmLabelWidgetClass, base,
				XmNlabelString, mstr, NULL);
	XmStringFree(mstr);
    }

    XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
    XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
    XtAddCallback(XtParent(dialog), XtNpopdownCallback,
		  (XtCallbackProc) popdown, NULL);
    return dialog;
}

void
warp_apply(Widget w, Widget text, XtPointer client_data)
{
    char *str;
    int i;
    str = XmTextGetString(text);
    i = atoi(str);
    XtFree(str);
    game.warp_to_level(i);
}

void
enter_name(Widget w, Widget text, XtPointer client_data)
{
    char *str, *nl;
    str = XmTextGetString(text);
    if (!str[0])
	strcpy(str, "Anonymous");
    else if ((nl = strchr(str, '\n')))
	*nl = 0;
    if (strlen(str) > 20)
	str[20] = 0;		/* truncate string if too long */
    scores.recalc(str);
    XtFree(str);
}

Widget
CreateEnterText(const char *name, Widget parent, const char *text,
		XtCallbackProc callback)
{
    Widget dialog;
    Arg wargs[2];
    XmString mstr = XmStringCreateLtoR(text, XmSTRING_DEFAULT_CHARSET);
    XtSetArg(wargs[0], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL);
    XtSetArg(wargs[1], XmNselectionLabelString, mstr);
    dialog = XmCreatePromptDialog(parent, name, wargs, 2);
    XtUnmanageChild(XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
    XtUnmanageChild(XmSelectionBoxGetChild(dialog, XmDIALOG_APPLY_BUTTON));
    XtAddCallback(dialog, XmNokCallback, callback,
		  XmSelectionBoxGetChild(dialog, XmDIALOG_TEXT));
    XtAddCallback(XtParent(dialog), XtNpopdownCallback, popdown, NULL);
    return dialog;
}

Widget
CreateDialog(const char *name, Widget parent, int buttonmask,
	     Pixmap icon, const char *text, const char *buttonlabel,
	     XtCallbackProc callback)
{
    Widget dialog;
    Arg wargs[2];
    XmString mstr = XmStringCreateLtoR(text, XmSTRING_DEFAULT_CHARSET);
    XtSetArg(wargs[0], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL);
    XtSetArg(wargs[1], XmNmessageString, mstr);
    dialog = XmCreateMessageDialog(parent, name, wargs, 2);
    if (icon)
	XtVaSetValues(dialog, XmNsymbolPixmap, icon, NULL);
    XmStringFree(mstr);
    if (!(buttonmask & CANCEL))
	XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
    XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
    if (buttonlabel) {
	mstr = XmStringCreateLtoR(buttonlabel, XmSTRING_DEFAULT_CHARSET);
	XtVaSetValues(XmMessageBoxGetChild(dialog, XmDIALOG_OK_BUTTON),
		      XmNlabelString, mstr, NULL);
	XmStringFree(mstr);
    }
    if (callback)
	XtAddCallback(dialog, XmNokCallback, callback, NULL);
    XtAddCallback(XtParent(dialog), XtNpopdownCallback, popdown, NULL);
    return dialog;
}

Widget
CreateDrawingArea(const char *name, Widget parent, int width, int height)
{
    return XtVaCreateManagedWidget(name, xmDrawingAreaWidgetClass, parent,
				   XtNwidth, width, XtNheight, height,
				   XmNresizePolicy, FALSE, NULL);
}

void
UI::update_hsbox(char *str)
{
    XmString mstr = XmStringCreateLtoR(str, XmSTRING_DEFAULT_CHARSET);
    XtVaSetValues(XmMessageBoxGetChild(highscorebox, XmDIALOG_MESSAGE_LABEL),
		  XmNlabelString, mstr, NULL);
    XmStringFree(mstr);
}

void
UI::update_scorebox(int level, int score)
{
    char str[40];
    XmString mstr;
    sprintf(str, "After Level %d:\nYour score: %d", level, score);
    mstr = XmStringCreateLtoR(str, XmSTRING_DEFAULT_CHARSET);
    XtVaSetValues(XmMessageBoxGetChild(scorebox, XmDIALOG_MESSAGE_LABEL),
		  XmNlabelString, mstr, NULL);
    XmStringFree(mstr);
}

Widget
CreateRowCol(const char *name, Widget parent)
{
    return XtCreateManagedWidget(name, xmRowColumnWidgetClass, parent,
				 NULL, 0);
}

--- NEW FILE: Cable.cc ---
 /*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "objects.h"

void
Cable::setup()
{
    c1 = game.RAND(0, net.units - 1);
    do {
	c2 = game.RAND(0, net.units - 1);
    } while (c2 == c1);
    active = index = 0;
    delay = spark.delay(game.level);
    x1 = net.computers[c1].x + net.width / 3;
    x2 = net.computers[c2].x + net.width / 3;
    y1 = net.computers[c1].y + net.height / 2;
    y2 = net.computers[c2].y + net.height / 2;
}

void
Cable::update()
{
    if (active) {
	if ((net.computers[c1].os == OS.WINGDOWS) ==
	    (net.computers[c2].os == OS.WINGDOWS))
	    active = 0;
	else if (net.computers[c1].os == OS.WINGDOWS ||
		 net.computers[c2].os == OS.WINGDOWS) {
	    int dir, xdist, ydist, c;
	    float sx, sy;
	    dir = (net.computers[c2].os == OS.WINGDOWS);
	    if (dir) {
		xdist = x1 - x;
		ydist = y1 - y;
	    } else {
		xdist = x2 - x;
		ydist = y2 - y;
	    }
	    sx = xdist >= 0 ? 1.0 : -1.0;
	    sy = ydist >= 0 ? 1.0 : -1.0;
	    xdist = abs(xdist);
	    ydist = abs(ydist);
	    if (xdist == 0 && ydist == 0) {
		if (dir == 0)
		    c = c2;
		else
		    c = c1;
		if (!net.computers[c].busy) {
		    if (net.computers[c].os == OS.OFF)
			net.off--;
		    else
			net.base--;
		    net.win++;
		    net.computers[c].os = OS.WINGDOWS;
		}
		active = 0;
	    } else if (game.MAX(xdist, ydist) < spark.speed) {
		if (dir) {
		    x = x1;
		    y = y1;
		} else {
		    x = x2;
		    y = y2;
		}
	    } else {
		fx += (xdist * spark.speed * sx) / (xdist + ydist);
		fy += (ydist * spark.speed * sy) / (xdist + ydist);
		x = (int) fx;
		y = (int) fy;
	    }
	    index = 1 - index;
	}
    } else {
	if ((net.computers[c1].os == OS.WINGDOWS) ==
	    (net.computers[c2].os == OS.WINGDOWS))
	    delay = spark.delay(game.level);
	else if (net.computers[c1].os == OS.WINGDOWS ||
		 net.computers[c2].os == OS.WINGDOWS) {
	    if (delay > 0)
		delay--;
	    else {
		active = 1;
		if (net.computers[c1].os == OS.WINGDOWS) {
		    fx = x = x1;
		    fy = y = y1;
		} else {
		    fx = x = x2;
		    fy = y = y2;
		}
	    }
	}
    }
}

int
Cable::onspark(int locx, int locy)
{
    if (!active)
	return 0;
    return (abs(locx - x) < spark.width && abs(locy - y) < spark.height);
}

void
Cable::draw()
{
    int rx = x - spark.width / 2;
    int ry = y - spark.height / 2;
    ui.draw_line(x1, y1, x2, y2);
    if (active)
	ui.draw(&(spark.pictures[index]), rx, ry);
}

--- NEW FILE: Imakefile ---
XBILL_DIR = /var/lib/games/xbill/
XCOMM XBILL_DIR = $(HOME)/.xbill/

XCOMM Which widget set?  Motif looks slightly better; Athena is free.

#define Use_Athena
XCOMM #define Use_Motif

XCOMM If you do not have libXpm installed in the standard place, uncomment
XCOMM the statement below and insert the correct path.
XCOMM Make sure xpm.h can be referenced as <X11/xpm.h>

XPMINC = -I$(HOME)/include
XPMLIB = -lXpm

XCOMM You shouldn't have to change anything below this line.

XBILL_DEF = -DXBILL_HOME=\"$(XBILL_DIR)\"

INCLUDES = -I. $(XPMINC)
CXXDEFINES = $(XBILL_DEF) $(DEFS) $(INCS)
CCFLAGS = $(ALLDEFINES) -Wall -g

CXX = g++ $(CCFLAGS)
CCC = $(CXX)
CC = $(CXX)

#ifdef Use_Motif
  WIDGET = motif
  XMLIB = -lXm
  WIDGETLIB = $(XMLIB)
#else
  WIDGET = athena
  WIDGETLIB = $(XAWLIB) $(XMULIB)
#endif

LOCAL_LIBRARIES = $(WIDGETLIB) $(XTOOLLIB) $(XPMLIB) $(XLIB)
DEFINES = -D$(WIDGET)

TARGET = xbill

SRCS =	Bucket.cc \
	Cable.cc \
	Computer.cc \
	Game.cc \
	Horde.cc \
	Library.cc \
	Monster.cc \
	Network.cc \
	Scorelist.cc \
	Spark.cc \
	MCursor.cc \
	Picture.cc \
	UI.cc \
	x11-$(WIDGET).cc \
	x11.cc

OBJS =	Bucket.o \
	Cable.o \
	Computer.o \
	Game.o \
	Horde.o \
	Library.o \
	Monster.o \
	Network.o \
	Scorelist.o \
	Spark.o \
	MCursor.o \
	Picture.o \
	UI.o \
	x11-$(WIDGET).o \
	x11.o

XPMS =	pixmaps/about.xpm \
	pixmaps/apple.xpm \
	pixmaps/billA_0.xpm \
	pixmaps/billA_1.xpm \
	pixmaps/billA_10.xpm \
	pixmaps/billA_11.xpm \
	pixmaps/billA_12.xpm \
	pixmaps/billA_2.xpm \
	pixmaps/billA_3.xpm \
	pixmaps/billA_4.xpm \
	pixmaps/billA_5.xpm \
	pixmaps/billA_6.xpm \
	pixmaps/billA_7.xpm \
	pixmaps/billA_8.xpm \
	pixmaps/billA_9.xpm \
	pixmaps/billD_0.xpm \
	pixmaps/billD_1.xpm \
	pixmaps/billD_2.xpm \
	pixmaps/billD_3.xpm \
	pixmaps/billD_4.xpm \
	pixmaps/billL_0.xpm \
	pixmaps/billL_1.xpm \
	pixmaps/billL_2.xpm \
	pixmaps/billR_0.xpm \
	pixmaps/billR_1.xpm \
	pixmaps/billR_2.xpm \
	pixmaps/bsd.xpm \
	pixmaps/bsdcpu.xpm \
	pixmaps/bucket.xpm \
	pixmaps/hurd.xpm \
	pixmaps/icon.xpm \
	pixmaps/linux.xpm \
	pixmaps/logo.xpm \
	pixmaps/maccpu.xpm \
	pixmaps/next.xpm \
	pixmaps/nextcpu.xpm \
	pixmaps/os2.xpm \
	pixmaps/os2cpu.xpm \
	pixmaps/redhat.xpm \
	pixmaps/sgi.xpm \
	pixmaps/sgicpu.xpm \
	pixmaps/spark_0.xpm \
	pixmaps/spark_1.xpm \
	pixmaps/sun.xpm \
	pixmaps/suncpu.xpm \
	pixmaps/toaster.xpm \
	pixmaps/wingdows.xpm

XBMS =	bitmaps/apple.xbm \
	bitmaps/bsd.xbm \
	bitmaps/bucket.xbm \
	bitmaps/hand_down.xbm \
	bitmaps/hand_down_mask.xbm \
	bitmaps/hand_up.xbm \
	bitmaps/hand_up_mask.xbm \
	bitmaps/hurd.xbm \
	bitmaps/linux.xbm \
	bitmaps/next.xbm \
	bitmaps/os2.xbm \
	bitmaps/redhat.xbm \
	bitmaps/sgi.xbm \
	bitmaps/sun.xbm

ComplexProgramTarget($(TARGET))

InstallProgramWithFlags(scores, $(XBILL_DIR), -m 777)
InstallMultiple ($(XPMS), $(XBILL_DIR)pixmaps)
InstallMultiple ($(XBMS), $(XBILL_DIR)bitmaps)

--- NEW FILE: xbill.man ---
.\" This man page originally written by pema at niksula.hut.fi
.TH xbill 1 "January 1997" "Version 2.0"
.de BP
.sp
.ti -.2i
\(**
..

.SH NAME
xbill -- save your computers from Wingdows [TM] virus
.SH SYNOPSIS
.hy 0
.na
.B xbill [-l|-L\fI starting level\fP] [-v]
.ad b
.hy 1
.SH DESCRIPTION
Ever get the feeling that nothing is going right?  You're a sysadmin, and
someone's trying to destroy your computers.  The little people running
around the screen are trying to infect your computers with Wingdows [TM],
a virus cleverly designed to resemble a popular operating system.  Your
objective is to click the mouse on them, ending their potential threat.
If one of the people reaches a computer, it will attempt to replace your
operating system with the virus it carries. It will then attempt to run off
the screen with your vital software.  The game ends when only 0 or 1 of
your computers is being productive.  Additionally, some computers are
connected with network cables.  When one computer on a network becomes 
infected, a spark will be sent down the cable, and will infect the computer
on the other end when it reaches there.
.PP
Clicking the button on one of the little people will cause it to cry out in
pain and melt (id software eat your heart out!), dropping the stolen os if it
is carrying one.  If a computer is running Wingdows or is temporarily off, the
os can be dragged back to the computer (or another computer compatible with
that os).  
To extinguish a spark drag the bucket of water from the upper left corner onto
it.
.PP
The status bar at the bottom tells the following:
.br
        Number of Bills on/off the screen
.br
        Number of Computers running their OS/off/Wingdows
.br
        Level
.br
        Score
.SH OPTIONS
.TP
.B \-l\fI n\fP, \-L\fI n
Start at level \fIn\fP.
.TP
.B \-v
Print version number and exit.
.TP
.B \-h
Print help and exit.
.TP
All standard X Intrinsics options are also supported.

.SH AUTHORS
Main Programmer:
.br
	Brian Wellington <bwelling at tis.com>
.br
Programming & graphics:
.br
	Matias Duarte <matias at hyperimage.com>
.br

.SH COPYING
Copyright (c) 1994-6 Psychosoft
.PP
It's FREE! If you want to express your undying gratitude to us for
bringing a small bit of meaning into your otherwise pointless
existence, you could always send us e-mail.
XBill is distributed under the GNU Public License.
.PP
Go play the game now!

--- NEW FILE: Makefile ---
#games/nxbill/Makefile

TARGET_CXX=nxbill

OBJS=	Bucket.o Cable.o Computer.o Game.o Horde.o Library.o Monster.o Network.o \
	Scorelist.o Spark.o NXPicture.o NXwidgets.o NX.o nanox-UI.o

LIBS+=-lnano-X
CFLAGS ?= 
CFLAGS += -DPDA -DXBILL_HOME="\"$(INSTALL_DIR)/share/nxbill/\""

INSTALL_EXTRAS=inst-nxbill

include $(BASE_DIR)/Rules.make

inst-nxbill:
	mkdir -p $(INSTALL_DIR)/share/nxbill
	cp pixmaps/*.xpm $(INSTALL_DIR)/share/nxbill


--- NEW FILE: Bucket.cc ---
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "objects.h"
//#include "bitmaps/bucket.xbm"

int
Bucket::clicked(int x, int y)
{
    return (x > 0 && y > 0 && x < width && y < height);
}

void
Bucket::draw()
{
    if (game.grabbed != game.BUCKET)
	ui.draw(&picture, 0, 0);
}

void
Bucket::load_pix()
{
    picture.load("bucket");

    /* If this on a PDA, we have no mouse cursor stuff */
    /* Plus, it doesn't work so welll :( */

#ifndef PDA
    cursor.load("bucket", cursor.OWN_MASK);
#endif

    width = picture.width;
    height = picture.height;
}

--- NEW FILE: Picture.h ---


#ifndef X11_PICTURE_H
#define X11_PICTURE_H

#include <X11/Xlib.h>
#include <X11/Intrinsic.h>
#include <X11/xpm.h>

class Picture
{
  public:
    Dimension width, height;
    Pixmap pix;
    GC gc;
    void draw(int x, int y);
    void draw_centered();
    void load(const char *name, int index = -1);
};

#endif

--- NEW FILE: Network.cc ---
 /*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "objects.h"

/*sets up network for each level*/
void
Network::setup()
{
    int i;
    units = on(game.level);

    i = 0;

    while (1) {
	if (i == units)
	    break;

	if (!net.computers[i].setup(i))
	    units--;
	else
	    i++;
    }

    base = units;

    off = win = 0;
    ncables = game.MIN(game.level, units / 2);
    for (i = 0; i < ncables; i++)
	cables[i].setup();
}

/*redraws the computers at their location with the proper image*/
void
Network::draw()
{
    int i;
    for (i = 0; i < ncables; i++)
	cables[i].draw();
    for (i = 0; i < units; i++)
	computers[i].draw();
}

void
Network::update()
{
    for (int i = 0; i < ncables; i++)
	cables[i].update();
}

void
Network::toasters()
{
    for (int i = 0; i < units; i++) {
	computers[i].type = computers[i].TOASTER;
	computers[i].os = OS.OFF;
    }
    ncables = 0;
}

int
Network::on(int lev)
{
    return game.MIN(8 + lev, MAX_COMPUTERS);
}

void
Network::load_pix()
{
    int i;
    char *name[] = { "toaster", "maccpu", "nextcpu", "sgicpu", "suncpu",
	"os2cpu", "bsdcpu"
    };
    for (i = 0; i <= NUM_SYS; i++)
	pictures[i].load(name[i]);
    width = pictures[0].width;
    height = pictures[0].height;
}

--- NEW FILE: Library.cc ---
 /*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "objects.h"

void
Library::load_pix()
{
    int i;
    char *name[] = { "wingdows", "apple", "next", "sgi", "sun", "os2",
	"bsd", "linux", "redhat", "hurd"
    };
    for (i = 0; i <= NUM_OS; i++) {
	os[i].load(name[i]);
#ifndef PDA
	if (i)
	    cursor[i].load(name[i], cursor[i].OWN_MASK);
#endif
    }
    width = os[0].width;
    height = os[0].height;
}

--- NEW FILE: Computer.h ---

#ifndef COMPUTER_H
#define COMPUTER_H


class Computer
{				/*structure for Computers */
  private:
    int check_intersect(int, int, int);
  public:
    int type;			/*CPU type */
    int os;			/*current OS */
    int x, y;			/*location */
    int busy;			/*is the computer being used? */
    int setup(int i);
    void draw();
    int find_stray();
    int oncomputer(int locx, int locy);
    int compatible(int system);
    int determineOS();
    static const int TOASTER = 0;	/* computer 0 is a toaster */
    static const int PC = 5;	/* type>=PC means the computer is a PC */
    static const int OFFSET = 4;	/* offset of screen from 0,0 */
    static const int BORDER = 50;	/* BORDER pixels free on all sides */
};

#endif




More information about the dslinux-commit mailing list