Browse Source

Full game source.

tags/1.0
Gethyn ThomasQuail 6 years ago
parent
commit
344096b34b
100 changed files with 10913 additions and 0 deletions
  1. +393
    -0
      Bill.c
  2. +41
    -0
      Bill.h
  3. +49
    -0
      Bucket.c
  4. +19
    -0
      Bucket.h
  5. +151
    -0
      Cable.c
  6. +12
    -0
      Cable.h
  7. +4
    -0
      ChangeLog
  8. +103
    -0
      Computer.c
  9. +23
    -0
      Computer.h
  10. +340
    -0
      Game.c
  11. +17
    -0
      Game.h
  12. +175
    -0
      Horde.c
  13. +23
    -0
      Horde.h
  14. +14
    -0
      INSTALL
  15. +105
    -0
      Makefile.in
  16. +120
    -0
      Network.c
  17. +22
    -0
      Network.h
  18. +56
    -0
      OS.c
  19. +30
    -0
      OS.h
  20. +65
    -0
      README
  21. +24
    -0
      README.Ports
  22. +100
    -0
      Scorelist.c
  23. +10
    -0
      Scorelist.h
  24. +29
    -0
      Spark.c
  25. +20
    -0
      Spark.h
  26. +246
    -0
      UI.c
  27. +86
    -0
      UI.h
  28. +8
    -0
      acconfig.h
  29. +11
    -0
      bitmaps/arch.xbm
  30. +10
    -0
      bitmaps/bsd.xbm
  31. +8
    -0
      bitmaps/bucket.xbm
  32. +11
    -0
      bitmaps/centos.xbm
  33. +11
    -0
      bitmaps/debian.xbm
  34. +11
    -0
      bitmaps/gentoo.xbm
  35. +6
    -0
      bitmaps/hand_down.xbm
  36. +6
    -0
      bitmaps/hand_down_mask.xbm
  37. +6
    -0
      bitmaps/hand_up.xbm
  38. +6
    -0
      bitmaps/hand_up_mask.xbm
  39. +11
    -0
      bitmaps/initfail.xbm
  40. +11
    -0
      bitmaps/mandriva.xbm
  41. +10
    -0
      bitmaps/redhat.xbm
  42. +11
    -0
      bitmaps/slackware.xbm
  43. +11
    -0
      bitmaps/suse.xbm
  44. +11
    -0
      bitmaps/ubuntu.xbm
  45. +22
    -0
      config.h.in
  46. +0
    -0
      config.in
  47. +2922
    -0
      configure
  48. +102
    -0
      configure.in
  49. +672
    -0
      gtk.c
  50. +9
    -0
      gtk.h
  51. +251
    -0
      install-sh
  52. +40
    -0
      mkinstalldirs
  53. BIN
      pixmaps/about.xcf
  54. +387
    -0
      pixmaps/about.xpm
  55. +173
    -0
      pixmaps/arch.xpm
  56. +52
    -0
      pixmaps/billA_0.xpm
  57. +52
    -0
      pixmaps/billA_1.xpm
  58. +52
    -0
      pixmaps/billA_10.xpm
  59. +52
    -0
      pixmaps/billA_11.xpm
  60. +52
    -0
      pixmaps/billA_12.xpm
  61. +52
    -0
      pixmaps/billA_2.xpm
  62. +52
    -0
      pixmaps/billA_3.xpm
  63. +52
    -0
      pixmaps/billA_4.xpm
  64. +51
    -0
      pixmaps/billA_5.xpm
  65. +52
    -0
      pixmaps/billA_6.xpm
  66. +52
    -0
      pixmaps/billA_7.xpm
  67. +52
    -0
      pixmaps/billA_8.xpm
  68. +52
    -0
      pixmaps/billA_9.xpm
  69. +49
    -0
      pixmaps/billD_0.xpm
  70. +50
    -0
      pixmaps/billD_1.xpm
  71. +48
    -0
      pixmaps/billD_2.xpm
  72. +46
    -0
      pixmaps/billD_3.xpm
  73. +44
    -0
      pixmaps/billD_4.xpm
  74. +49
    -0
      pixmaps/billL_0.xpm
  75. +49
    -0
      pixmaps/billL_1.xpm
  76. +49
    -0
      pixmaps/billL_2.xpm
  77. +49
    -0
      pixmaps/billR_0.xpm
  78. +49
    -0
      pixmaps/billR_1.xpm
  79. +49
    -0
      pixmaps/billR_2.xpm
  80. +38
    -0
      pixmaps/bsd.xpm
  81. +60
    -0
      pixmaps/bsdcpu.xpm
  82. +40
    -0
      pixmaps/bucket.xpm
  83. +391
    -0
      pixmaps/centos.xpm
  84. +184
    -0
      pixmaps/debian.xpm
  85. +322
    -0
      pixmaps/gentoo.xpm
  86. +85
    -0
      pixmaps/icon.xpm
  87. +87
    -0
      pixmaps/initfail.xpm
  88. BIN
      pixmaps/logo.xcf
  89. +332
    -0
      pixmaps/logo.xpm
  90. +58
    -0
      pixmaps/maccpu.xpm
  91. +268
    -0
      pixmaps/mandriva.xpm
  92. +54
    -0
      pixmaps/nextcpu.xpm
  93. +57
    -0
      pixmaps/os2cpu.xpm
  94. +58
    -0
      pixmaps/sgicpu.xpm
  95. +314
    -0
      pixmaps/slackware.xpm
  96. +30
    -0
      pixmaps/spark_0.xpm
  97. +30
    -0
      pixmaps/spark_1.xpm
  98. +55
    -0
      pixmaps/suncpu.xpm
  99. +166
    -0
      pixmaps/suse.xpm
  100. +64
    -0
      pixmaps/toaster.xpm

+ 393
- 0
Bill.c View File

@@ -0,0 +1,393 @@
#include <stdlib.h>

#include "types.h"
#include "util.h"

#include "Bill.h"
#include "Computer.h"
#include "Game.h"
#include "Horde.h"
#include "Network.h"
#include "OS.h"
#include "UI.h"

/* speed at which OS drops */
#define GRAVITY 3

/* speed of moving Bill */
#define SLOW 0
#define FAST 1

#define WCELS 4 /* # of bill walking animation frames */
#define DCELS 5 /* # of bill dying animation frames */
#define ACELS 13 /* # of bill switching OS frames */

static Picture *lcels[WCELS], *rcels[WCELS], *acels[ACELS], *dcels[DCELS];
static int width, height;

static void
get_border(int *x, int *y) {
int i = RAND(0, 3);
int screensize = Game_screensize();

if (i % 2 == 0)
*x = RAND(0, screensize - width);
else
*y = RAND(0, screensize - height);

switch (i) {
case 0:
*y = -height - 16;
break;
case 1:
*x = screensize + 1;
break;
case 2:
*y = screensize + 1;
break;
case 3:
*x = - width - 2;
break;
}
}

/* Adds a bill to the in state */
void
Bill_enter(Bill **billp) {
Bill *bill;
Computer *computer;

bill = xalloc(sizeof *bill);

bill->state = BILL_STATE_IN;
get_border(&bill->x, &bill->y);
bill->index = 0;
bill->cels = lcels;
bill->cargo = OS_WINGDOWS;
bill->x_offset = -2;
bill->y_offset = -15;
bill->target_c = RAND(0, Network_num_computers() - 1);
computer = Network_get_computer(bill->target_c);
bill->target_x = computer->x + Computer_width() - BILL_OFFSET_X;
bill->target_y = computer->y + BILL_OFFSET_Y;
Horde_inc_counter(HORDE_COUNTER_ON, 1);
Horde_inc_counter(HORDE_COUNTER_OFF, -1);
bill->prev = NULL;
bill->next = NULL;
*billp = bill;
}

static int
step_size(unsigned int level) {
return MIN(11 + level, 15);
}

/* Moves bill toward his target - returns whether or not he moved */
static int
move(Bill *bill, int mode) {
int xdist = bill->target_x - bill->x;
int ydist = bill->target_y - bill->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) {
bill->x = bill->target_x;
bill->y = bill->target_y;
}
else {
dx = (xdist*step*signx)/(xdist+ydist);
dy = (ydist*step*signy)/(xdist+ydist);
if (mode == FAST) {
dx *= 1.25;
dy *= 1.25;
}
bill->x += dx;
bill->y += dy;
if (dx < 0)
bill->cels = lcels;
else if (dx > 0)
bill->cels = rcels;
}
return 1;
}

static void
draw_std(Bill *bill) {
if (bill->cargo >= 0)
OS_draw(bill->cargo, bill->x + bill->x_offset,
bill->y + bill->y_offset);
UI_draw(bill->cels[bill->index], bill->x, bill->y);
}

static void
draw_at(Bill *bill) {
Computer *computer = Network_get_computer(bill->target_c);
if (bill->index > 6 && bill->index < 12)
OS_draw(0, bill->x + bill->sx, bill->y + bill->sy);
if (bill->cargo >= 0)
OS_draw(bill->cargo, bill->x + bill->x_offset,
bill->y + bill->y_offset);
UI_draw(bill->cels[bill->index], computer->x, computer->y);
}

static void
draw_stray(Bill *bill) {
OS_draw(bill->cargo, bill->x, bill->y);
}

void
Bill_draw(Bill *bill) {
switch (bill->state) {
case BILL_STATE_IN:
case BILL_STATE_OUT:
case BILL_STATE_DYING:
draw_std(bill);
break;
case BILL_STATE_AT:
draw_at(bill);
break;
case BILL_STATE_STRAY:
draw_stray(bill);
break;
default:
break;
}
}

/* Update Bill's position */
static void
update_in(Bill *bill) {
int moved = move(bill, SLOW);
Computer *computer = Network_get_computer(bill->target_c);
if (!moved && computer->os != OS_WINGDOWS && !computer->busy) {
computer->busy = 1;
bill->cels = acels;
bill->index = 0;
bill->state = BILL_STATE_AT;
return;
}
else if (!moved) {
int i;
do {
i = RAND(0, Network_num_computers() - 1);
} while (i == bill->target_c);
computer = Network_get_computer(i);
bill->target_c = i;
bill->target_x = computer->x + Computer_width() - BILL_OFFSET_X;
bill->target_y = computer->y + BILL_OFFSET_Y;
}
bill->index++;
bill->index %= WCELS;
bill->y_offset += (8 * (bill->index % 2) - 4);
}

/* Update Bill standing at a computer */
static void
update_at(Bill *bill) {
Computer *computer = Network_get_computer(bill->target_c);
if (bill->index == 0 && computer->os == OS_OFF) {
bill->index = 6;
if (computer->stray == NULL)
bill->cargo = -1;
else {
bill->cargo = computer->stray->cargo;
Horde_remove_bill(computer->stray);
computer->stray = NULL;
}
} else
bill->index++;
if (bill->index == 13) {
bill->y_offset = -15;
bill->x_offset = -2;
get_border(&bill->target_x, &bill->target_y);
bill->index = 0;
bill->cels = lcels;
bill->state = BILL_STATE_OUT;
computer->busy = 0;
return;
}
bill->y_offset = height - OS_height();
switch (bill->index) {
case 1:
case 2:
bill->x -= 8;
bill->x_offset +=8;
break;
case 3:
bill->x -= 10;
bill->x_offset +=10;
break;
case 4:
bill->x += 3;
bill->x_offset -=3;
break;
case 5:
bill->x += 2;
bill->x_offset -=2;
break;
case 6:
if (computer->os != OS_OFF) {
Network_inc_counter(NETWORK_COUNTER_BASE, -1);
Network_inc_counter(NETWORK_COUNTER_OFF, 1);
bill->cargo = computer->os;
}
else {
bill->x -= 21;
bill->x_offset += 21;
}
computer->os = OS_OFF;
bill->y_offset = -15;
bill->x += 20;
bill->x_offset -=20;
break;
case 7:
bill->sy = bill->y_offset;
bill->sx = -2;
break;
case 8:
bill->sy = -15;
bill->sx = -2;
break;
case 9:
bill->sy = -7;
bill->sx = -7;
bill->x -= 8;
bill->x_offset +=8;
break;
case 10:
bill->sy = 0;
bill->sx = -7;
bill->x -= 15;
bill->x_offset +=15;
break;
case 11:
bill->sy = 0;
bill->sx = -7;
computer->os = OS_WINGDOWS;
Network_inc_counter(NETWORK_COUNTER_OFF, -1);
Network_inc_counter(NETWORK_COUNTER_WIN, 1);
break;
case 12:
bill->x += 11;
bill->x_offset -=11;
}
}

/* Updates Bill fleeing with his ill gotten gain */
static void
update_out(Bill *bill) {
int screensize = Game_screensize();
if (UI_intersect(bill->x, bill->y, width, height, 0, 0,
screensize, screensize))
{
move(bill, FAST);
bill->index++;
bill->index %= WCELS;
bill->y_offset += (8*(bill->index%2)-4);
}
else {
Horde_remove_bill(bill);
Horde_inc_counter(HORDE_COUNTER_ON, -1);
Horde_inc_counter(HORDE_COUNTER_OFF, 1);
}
}


/* Updates a Bill who is dying */
static void
update_dying(Bill *bill) {
if (bill->index < DCELS - 1){
bill->y_offset += (bill->index * GRAVITY);
bill->index++;
}
else {
bill->y += bill->y_offset;
if (bill->cargo < 0 || bill->cargo == OS_WINGDOWS)
Horde_remove_bill(bill);
else {
Horde_move_bill(bill);
bill->state = BILL_STATE_STRAY;
}
Horde_inc_counter(HORDE_COUNTER_ON, -1);
}
}

void
Bill_update(Bill *bill) {
switch (bill->state) {
case BILL_STATE_IN:
update_in(bill);
break;
case BILL_STATE_AT:
update_at(bill);
break;
case BILL_STATE_OUT:
update_out(bill);
break;
case BILL_STATE_DYING:
update_dying(bill);
break;
default:
break;
}
}

void
Bill_set_dying(Bill *bill) {
bill->index = -1;
bill->cels = dcels;
bill->x_offset = -2;
bill->y_offset = -15;
bill->state = BILL_STATE_DYING;
}

int
Bill_clicked(Bill *bill, int locx, int locy) {
return (locx > bill->x && locx < bill->x + width &&
locy > bill->y && locy < bill->y + height);
}

int
Bill_clickedstray(Bill *bill, int locx, int locy) {
return (locx > bill->x && locx < bill->x + OS_width() &&
locy > bill->y && locy < bill->y + OS_height());
}

void
Bill_load_pix () {
int i;
for (i = 0; i < WCELS - 1; i++) {
UI_load_picture_indexed("billL", i, 1, &lcels[i]);
UI_load_picture_indexed("billR", i, 1, &rcels[i]);
}
lcels[WCELS - 1] = lcels[1];
rcels[WCELS - 1] = rcels[1];

for (i = 0; i < DCELS; i++)
UI_load_picture_indexed("billD", i, 1, &dcels[i]);
width = UI_picture_width(dcels[0]);
height = UI_picture_height(dcels[0]);

for (i = 0; i < ACELS; i++)
UI_load_picture_indexed("billA", i, 1, &acels[i]);
}

int
Bill_width() {
return width;
}

int
Bill_height() {
return height;
}

int
Bill_get_state(Bill *bill) {
return bill->state;
}

+ 41
- 0
Bill.h View File

@@ -0,0 +1,41 @@
#ifndef BILL_H
#define BILL_H

/* Bill's states */
#define BILL_STATE_IN 1
#define BILL_STATE_AT 2
#define BILL_STATE_OUT 3
#define BILL_STATE_DYING 4
#define BILL_STATE_STRAY 5

/* Offsets from upper right of computer */
#define BILL_OFFSET_X 20
#define BILL_OFFSET_Y 3

struct Bill {
int state; /* what is it doing? */
int index; /* index of animation frame */
Picture **cels; /* 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 */
Bill *prev, *next;
};

void Bill_enter(Bill **billp);
void Bill_draw(Bill *bill);
void Bill_update(Bill *bill);
void Bill_set_dying(Bill *bill);
int Bill_clicked(Bill *bill, int locx, int locy);
int Bill_clickedstray(Bill *bill, int locx, int locy);
void Bill_load_pix(void);
int Bill_width(void);
int Bill_height(void);
int Bill_get_state(Bill *bill);

#endif

+ 49
- 0
Bucket.c View File

@@ -0,0 +1,49 @@
#include <util.h>

#include "Bucket.h"
#include "Cable.h"
#include "Game.h"
#include "Network.h"
#include "UI.h"

static Picture *picture;
static MCursor *cursor;
static int grabbed;

void
Bucket_load_pix() {
UI_load_picture("bucket", 1, &picture);
UI_load_cursor("bucket", CURSOR_OWN_MASK, &cursor);
}

int
Bucket_clicked(int x, int y) {
return (x > 0 && x < UI_picture_width(picture) &&
y > 0 && y < UI_picture_height(picture));
}

void
Bucket_draw() {
if (!grabbed)
UI_draw(picture, 0, 0);
}

void
Bucket_grab(int x, int y) {
UNUSED(x);
UNUSED(y);

UI_set_cursor(cursor);
grabbed = 1;
}

void
Bucket_release(int x, int y) {
int i;
for (i = 0; i < Network_num_cables(); i++) {
Cable *cable = Network_get_cable(i);
if (Cable_onspark(cable, x, y))
Cable_reset(cable);
}
grabbed = 0;
}

+ 19
- 0
Bucket.h View File

@@ -0,0 +1,19 @@
#ifndef BUCKET_H
#define BUCKET_H

void
Bucket_load_pix(void);

void
Bucket_draw(void);

int
Bucket_clicked(int x, int y);

void
Bucket_grab(int x, int y);

void
Bucket_release(int x, int y);

#endif

+ 151
- 0
Cable.c View File

@@ -0,0 +1,151 @@
#include "stdio.h"
#include "stdlib.h"

#include "types.h"
#include "util.h"

#include "Cable.h"
#include "Computer.h"
#include "Game.h"
#include "Network.h"
#include "OS.h"
#include "Spark.h"
#include "UI.h"

struct Cable {
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;
};

#define SWAP(x, y) do {int _t; _t = x; x = y; y = _t;} while(0)

static void
reverse(Cable *cable) {
SWAP(cable->c1, cable->c2);
SWAP(cable->x1, cable->x2);
SWAP(cable->y1, cable->y2);
}

void
Cable_setup(Cable **cablep) {
Cable *cable;
Computer *comp1, *comp2;
int cwidth, cheight;

cable = xalloc(sizeof *cable);

cable->c1 = RAND(0, Network_num_computers() - 1);
do {
cable->c2 = RAND(0, Network_num_computers() - 1);
} while (cable->c2 == cable->c1);
cable->active = 0;
cable->index = 0;
cable->delay = SPARK_DELAY(Game_level());

comp1 = Network_get_computer(cable->c1);
comp2 = Network_get_computer(cable->c2);
cwidth = Computer_width();
cheight = Computer_height();
cable->x1 = comp1->x + cwidth/3;
cable->x2 = comp2->x + cwidth/3;
cable->y1 = comp1->y + cheight/2;
cable->y2 = comp2->y + cheight/2;

*cablep = cable;
}


void
Cable_draw(Cable *cable) {
UI_draw_line(cable->x1, cable->y1, cable->x2, cable->y2);
if (cable->active) {
int rx = cable->x - Spark_width()/2;
int ry = cable->y - Spark_height()/2;
Spark_draw(rx, ry, cable->index);
}
}

void
Cable_update(Cable *cable) {
Computer *comp1, *comp2;
comp1 = Network_get_computer(cable->c1);
comp2 = Network_get_computer(cable->c2);

if (cable->active) {
if ((comp1->os == OS_WINGDOWS) == (comp2->os == OS_WINGDOWS))
cable->active = 0;
else if (comp1->os == OS_WINGDOWS || comp2->os == OS_WINGDOWS) {
int xdist, ydist;
float sx, sy;

if (comp2->os == OS_WINGDOWS)
reverse(cable);

xdist = cable->x2 - cable->x;
ydist = cable->y2 - cable->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 (!comp2->busy) {
int counter;
if (comp2->os == OS_OFF)
counter = NETWORK_COUNTER_OFF;
else
counter = NETWORK_COUNTER_BASE;
Network_inc_counter(counter, -1);
Network_inc_counter(NETWORK_COUNTER_WIN,
1);
comp2->os = OS_WINGDOWS;
}
cable->active = 0;
}
else if (MAX(xdist, ydist) < SPARK_SPEED) {
cable->x = cable->x2;
cable->y = cable->y2;
}
else {
cable->fx+=(xdist*SPARK_SPEED*sx)/(xdist+ydist);
cable->fy+=(ydist*SPARK_SPEED*sy)/(xdist+ydist);
cable->x = (int)cable->fx;
cable->y = (int)cable->fy;
}
cable->index = 1 - cable->index;
}
}
else {
if ((comp1->os == OS_WINGDOWS) == (comp2->os == OS_WINGDOWS))
;
else if (comp1->os == OS_WINGDOWS || comp2->os == OS_WINGDOWS) {
cable->active = 1;
cable->delay = SPARK_DELAY(Game_level());
if (comp2->os == OS_WINGDOWS)
reverse(cable);
cable->x = cable->x1;
cable->fx = cable->x1;
cable->y = cable->y1;
cable->fy = cable->y1;
}
}
}

int
Cable_onspark(Cable *cable, int locx, int locy) {
if (!cable->active)
return 0;
return (abs(locx - cable->x) < Spark_width() &&
abs(locy - cable->y) < Spark_height());
}

void
Cable_reset(Cable *cable) {
cable->active = 0;
cable->delay = SPARK_DELAY(Game_level());
}

+ 12
- 0
Cable.h View File

@@ -0,0 +1,12 @@
#ifndef CABLE_H
#define CABLE_H

#include "types.h"

void Cable_setup(Cable **cablep);
void Cable_draw(Cable *cable);
void Cable_update(Cable *cable);
int Cable_onspark(Cable *cable, int locx, int locy);
void Cable_reset(Cable *cable);

#endif

+ 4
- 0
ChangeLog View File

@@ -0,0 +1,4 @@
XLennart history:

1.0 (29/10/2014):
- First release! A controversy is sure to broil!

+ 103
- 0
Computer.c View File

@@ -0,0 +1,103 @@
#include <stdlib.h>

#include "types.h"
#include "util.h"

#include "Bill.h"
#include "Computer.h"
#include "Horde.h"
#include "Network.h"
#include "Game.h"
#include "OS.h"
#include "UI.h"

#define OS_OFFSET 4 /* offset of screen from 0,0 */
#define BORDER(size) (size / 10) /* at least this far from a side */

#define MIN_PC 6 /* type >= MIN_PC means the computer is a PC */

static const char *cpuname[] = {"toaster", "maccpu", "nextcpu", "sgicpu",
"suncpu", "os2cpu", "bsdcpu"};

#define NUM_SYS (sizeof(cpuname) / sizeof(cpuname[0]))

static Picture *pictures[NUM_SYS]; /* array of cpu pictures */
static int width, height;


static int
determineOS(Computer *computer) {
if (computer->type < MIN_PC)
return computer->type;
else
return OS_randpc();
}

int
Computer_setup(Computer *computer, int index) {
int j, counter = 0, flag;
int x, y;
int screensize = Game_screensize();
int border = BORDER(screensize);
do {
if (++counter > 4000)
return 0;
x = RAND(border, screensize - border - width);
y = RAND(border, screensize - border - height);
flag = 1;
/* check for conflicting computer placement */
for (j = 0; j < index && flag; j++) {
Computer *c = Network_get_computer(j);
int twidth = width - BILL_OFFSET_X + Bill_width();
if (UI_intersect(x, y, twidth, height,
c->x, c->y, twidth, height))
flag = 0;
}
} while (!flag);
computer->x = x;
computer->y = y;
computer->type = RAND(1, NUM_SYS - 1);
computer->os = determineOS(computer);
computer->busy = 0;
computer->stray = NULL;
return 1;
}

int
Computer_on(Computer *computer, int locx, int locy) {
return (abs(locx - computer->x) < width &&
abs(locy - computer->y) < height);
}

int
Computer_compatible(Computer *computer, int system) {
return (computer->type == system ||
(computer->type >= MIN_PC && OS_ispc(system)));
}

void
Computer_draw(Computer *computer) {
UI_draw(pictures[computer->type], computer->x, computer->y);
if (computer->os != OS_OFF)
OS_draw(computer->os,
computer->x + OS_OFFSET, computer->y + OS_OFFSET);
}

void
Computer_load_pix() {
unsigned int i;
for (i = 0; i < NUM_SYS; i++)
UI_load_picture(cpuname[i], 1, &pictures[i]);
width = UI_picture_width(pictures[0]);
height = UI_picture_height(pictures[0]);
}

int
Computer_width() {
return width;
}

int
Computer_height() {
return height;
}

+ 23
- 0
Computer.h View File

@@ -0,0 +1,23 @@
#ifndef COMPUTER_H
#define COMPUTER_H

struct Computer {
int type; /* CPU type */
int os; /* current OS */
int x, y; /* location */
int busy; /* is the computer being used? */
Bill *stray;
};


int Computer_setup(Computer *computer, int i);
void Computer_draw(Computer *computer);
int Computer_on (Computer *computer, int locx, int locy);
int Computer_compatible(Computer *computer, int system);
void Computer_load_pix(void);
int Computer_width(void);
int Computer_height(void);

#define COMPUTER_TOASTER 0 /* computer 0 is a toaster */

#endif

+ 340
- 0
Game.c View File

@@ -0,0 +1,340 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>

#include "types.h"
#include "util.h"

#include "Bill.h"
#include "Bucket.h"
#include "Computer.h"
#include "Cable.h"
#include "Game.h"
#include "Horde.h"
#include "Network.h"
#include "OS.h"
#include "Scorelist.h"
#include "Spark.h"
#include "UI.h"

#define SCREENSIZE 400

/* Game states */
#define STATE_PLAYING 1
#define STATE_BETWEEN 2
#define STATE_END 3
#define STATE_WAITING 4

/* Score related constants */
#define SCORE_ENDLEVEL -1
#define SCORE_BILLPOINTS 5

static unsigned int state;
static int efficiency;
static int score, level, iteration;
static Picture *logo, *icon, *about;
static MCursor *defaultcursor, *downcursor;
static Bill *grabbed;
static const char *gui;
static int screensize = SCREENSIZE;

static void
setup_level(int newlevel) {
level = newlevel;
Horde_setup();
grabbed = NULL;
UI_set_cursor(defaultcursor);
Network_setup();
iteration = 0;
efficiency = 0;
}

void
Game_start(int newlevel) {
state = STATE_PLAYING;
score = 0;
UI_restart_timer();
UI_set_pausebutton(1);
setup_level(newlevel);
}

void
Game_quit() {
Scorelist_write();
exit(0);
}

static void
update_info(void) {
char str[80];
int on_screen = Horde_get_counter(HORDE_COUNTER_ON);
int off_screen = Horde_get_counter(HORDE_COUNTER_OFF);
int base = Network_get_counter(NETWORK_COUNTER_BASE);
int off = Network_get_counter(NETWORK_COUNTER_OFF);
int win = Network_get_counter(NETWORK_COUNTER_WIN);
int units = Network_num_computers();
sprintf(str, "Lenn:%d/%d System:%d/%d/%d Level:%d Score:%d",
on_screen, off_screen, base, off, win, level, score);
UI_draw_str(str, 5, screensize - 5);
efficiency += ((100 * base - 10 * win) / units);
}

void
Game_warp_to_level(int lev) {
if (state == STATE_PLAYING) {
if (lev <= level)
return;
setup_level(lev);
}
else {
if (lev <= 0)
return;
Game_start(lev);
}
}

void
Game_add_high_score(const char *str) {
Scorelist_recalc(str, level, score);
}

void
Game_button_press(int x, int y) {
int counter;

if (state != STATE_PLAYING)
return;
UI_set_cursor(downcursor);

if (Bucket_clicked(x, y)) {
Bucket_grab(x, y);
return;
}

grabbed = Horde_clicked_stray(x, y);
if (grabbed != NULL) {
OS_set_cursor(grabbed->cargo);
return;
}

counter = Horde_process_click(x, y);
score += (counter * counter * SCORE_BILLPOINTS);
}

void
Game_button_release(int x, int y) {
int i;
UI_set_cursor(defaultcursor);

if (state != STATE_PLAYING)
return;

if (grabbed == NULL) {
Bucket_release(x, y);
return;
}

for (i = 0; i < Network_num_computers(); i++) {
Computer *computer = Network_get_computer(i);

if (Computer_on(computer, x, y) &&
Computer_compatible(computer, grabbed->cargo) &&
(computer->os == OS_WINGDOWS || computer->os == OS_OFF)) {
int counter;

Network_inc_counter(NETWORK_COUNTER_BASE, 1);
if (computer->os == OS_WINGDOWS)
counter = NETWORK_COUNTER_WIN;
else
counter = NETWORK_COUNTER_OFF;
Network_inc_counter(counter, -1);
computer->os = grabbed->cargo;
Horde_remove_bill(grabbed);
grabbed = NULL;
return;
}
}
Horde_add_bill(grabbed);
grabbed = NULL;
}

static void
draw_logo(void) {
UI_clear();
UI_draw(logo,
(screensize - UI_picture_width(logo)) / 2,
(screensize - UI_picture_height(logo)) / 2);
}

void
Game_update() {
char str[40];

switch (state) {
case STATE_PLAYING:
UI_clear();
Bucket_draw();
Network_update();
Network_draw();
Horde_update(iteration);
Horde_draw();
update_info();
if (Horde_get_counter(HORDE_COUNTER_ON) +
Horde_get_counter(HORDE_COUNTER_OFF) == 0) {
score += (level * efficiency / iteration);
state = STATE_BETWEEN;
}
if ((Network_get_counter(NETWORK_COUNTER_BASE) +
Network_get_counter(NETWORK_COUNTER_OFF)) <= 1)
state = STATE_END;
break;
case STATE_END:
UI_set_cursor(defaultcursor);
UI_clear();
Network_toasters();
Network_draw();
UI_refresh();
UI_popup_dialog(DIALOG_ENDGAME);
if (Scorelist_ishighscore(score)) {
UI_popup_dialog(DIALOG_ENTERNAME);
Scorelist_update();
}
UI_popup_dialog(DIALOG_HIGHSCORE);
draw_logo();
UI_kill_timer();
UI_set_pausebutton(0);
state = STATE_WAITING;
break;
case STATE_BETWEEN:
UI_set_cursor(defaultcursor);
sprintf(str, "After Level %d:\nScore: %d", level, score);
UI_update_dialog(DIALOG_SCORE, str);
UI_popup_dialog(DIALOG_SCORE);
state = STATE_PLAYING;
setup_level(++level);
break;
}
UI_refresh();
iteration++;
}

int
Game_score() {
return score;
}

int
Game_level() {
return level;
}

int
Game_screensize() {
return screensize;
}

double
Game_scale(int dimensions) {
double scale = (double)screensize / SCREENSIZE;
double d = 1;
for ( ; dimensions > 0; dimensions--)
d *= scale;
return (d);
}

/*
* Note - don't use getopt, since it might reorder the args or do something
* that the UI-specific argument parser doesn't like.
*/
static void
parse_args(int argc, char **argv) {
char *s;
char *endp;
int i;

for (i = 1; i < argc; i++) {
if (strncasecmp(argv[i], "-l", 2) == 0) {
if (strlen(argv[i]) == 2 && i == argc - 1)
fatal("-l takes an argument");
if (strlen(argv[i]) > 2)
s = argv[i] + 2;
else
s = argv[++i];
level = strtol(s, &endp, 10);
if (*endp != '\0' || level <= 0)
fatal("invalid level '%s'", s);
} else if (strcmp(argv[i], "--gui") == 0) {
if (i == argc - 1)
fatal("--gui takes an argument");
gui = argv[++i];
} else if (strcmp(argv[i], "--size") == 0) {
if (i == argc - 1)
fatal("--size takes an argument");
s = argv[++i];
screensize = strtol(s, &endp, 10);
if (*endp != '\0' || screensize <= 0)
fatal("invalid screensize '%s'", s);
if (screensize < SCREENSIZE)
fatal("screensize must be larger than '%d'",
SCREENSIZE);
} else if (strcmp(argv[1], "-v") == 0 ||
strcmp(argv[1], "--version") == 0)
{
printf ("XLennart version 1.0\n\n");
exit(0);
} else if (strcmp(argv[1], "-h") == 0 ||
strcmp(argv[1], "--help") == 0)
{
printf("XLennart version 1.0\n");
printf("Options:\n");
printf("-l <n>\tStart at level n.\n");
printf("--gui <gui> \tUse a specific gui "
"(athena, motif, gtk)\n");
printf("--size <size>\t\tUse a larger playing area.\n");
printf("-v\t\tPrint version number and exit.\n");
printf("-h\t\tPrint help and exit.\n");
printf("All standard toolkit options are also ");
printf("supported.\n\n");
exit(0);
}
}
}

int
main(int argc, char **argv) {
srand(time(NULL));
parse_args(argc, argv);
UI_initialize(gui, &argc, argv);
UI_make_main_window(screensize);
UI_graphics_init();
UI_load_picture("logo", 0, &logo);
UI_load_picture("icon", 0, &icon);
UI_load_picture("about", 0, &about);
draw_logo();
UI_refresh();
UI_make_dialogs(logo, icon, about);
UI_set_icon(icon);

Scorelist_read();
Scorelist_update();

UI_load_cursor("hand_up", CURSOR_SEP_MASK, &defaultcursor);
UI_load_cursor("hand_down", CURSOR_SEP_MASK, &downcursor);
UI_set_cursor(defaultcursor);

Bill_load_pix();
OS_load_pix();
Computer_load_pix();
Bucket_load_pix();
Spark_load_pix();

state = STATE_WAITING;
if (level)
Game_start(level);
else
UI_set_pausebutton(0);
UI_main_loop();
exit(0);
}

+ 17
- 0
Game.h View File

@@ -0,0 +1,17 @@
#ifndef GAME_H
#define GAME_H

void Game_start(int newlevel);
void Game_quit(void);
void Game_warp_to_level(int lev);
void Game_add_high_score(const char *str);
void Game_button_press(int x, int y);
void Game_button_release(int x, int y);
void Game_update(void);

int Game_score(void);
int Game_level(void);
int Game_screensize(void);
double Game_scale(int dimensions);

#endif

+ 175
- 0
Horde.c View File

@@ -0,0 +1,175 @@
#include <stdlib.h>

#include "types.h"
#include "util.h"

#include "Bill.h"
#include "Computer.h"
#include "Game.h"
#include "Horde.h"
#include "Network.h"
#include "UI.h"

static Bill *alive, *strays;
static int counters[HORDE_COUNTER_MAX + 1];

#define MAX_BILLS 100 /* max Bills per level */

#define UNLINK(bill, list) \
do { \
if ((bill)->next != NULL) \
(bill)->next->prev = (bill)->prev; \
if ((bill)->prev != NULL) \
(bill)->prev->next = (bill)->next; \
else if ((bill) == list) \
(list) = (bill)->next; \
(bill)->prev = NULL; \
(bill)->next = NULL; \
} while (0)

#define PREPEND(bill, list) \
do { \
(bill)->next = (list); \
if ((list) != NULL) \
(list)->prev = (bill); \
(list) = (bill); \
} while (0)

static int
on(unsigned int lev) {
int perlevel = (int)((8 + 3 * lev) * Game_scale(2));
return MIN(perlevel, MAX_BILLS);
}

static int
max_at_once(unsigned int lev) {
return MIN(2 + lev / 4, 12);
}

static int
between(unsigned int lev) {
return MAX(14 - lev / 3, 10);
}

/* Launches Bills whenever called */
static void
launch(int max) {
Bill *bill;
int n;
int off_screen = counters[HORDE_COUNTER_OFF];

if (max == 0 || off_screen == 0)
return;
n = RAND(1, MIN(max, off_screen));
for (; n > 0; n--) {
Bill_enter(&bill);
PREPEND(bill, alive);
}
}

void
Horde_setup() {
Bill *bill;
while (alive != NULL) {
bill = alive;
UNLINK(bill, alive);
free(bill);
}
while (strays != NULL) {
bill = strays;
UNLINK(bill, strays);
free(bill);
}
counters[HORDE_COUNTER_OFF] = on(Game_level());
counters[HORDE_COUNTER_ON] = 0;
}

void
Horde_update(int iteration) {
Bill *bill, *next;
int level = Game_level();
if (iteration % between(level) == 0)
launch(max_at_once(level));
for (bill = alive; bill != NULL; bill = next) {
next = bill->next;
Bill_update(bill);
}
}

void
Horde_draw() {
Bill *bill;

for (bill = strays; bill != NULL; bill = bill->next)
Bill_draw(bill);
for (bill = alive; bill != NULL; bill = bill->next)
Bill_draw(bill);
}

void
Horde_move_bill(Bill *bill) {
UNLINK(bill, alive);
PREPEND(bill, strays);
}

void
Horde_remove_bill(Bill *bill) {
if (bill->state == BILL_STATE_STRAY)
UNLINK(bill, strays);
else
UNLINK(bill, alive);
Network_clear_stray(bill);
free(bill);
}

void
Horde_add_bill(Bill *bill) {
if (bill->state == BILL_STATE_STRAY)
PREPEND(bill, strays);
else
PREPEND(bill, alive);
}

Bill *
Horde_clicked_stray(int x, int y) {
Bill *bill;

for (bill = strays; bill != NULL; bill = bill->next) {
if (!Bill_clickedstray(bill, x, y))
continue;
UNLINK(bill, strays);
return bill;
}
return NULL;
}

int
Horde_process_click(int x, int y) {
Bill *bill;
int counter = 0;

for (bill = alive; bill != NULL; bill = bill->next) {
if (bill->state == BILL_STATE_DYING ||
!Bill_clicked(bill, x, y))
continue;
if (bill->state == BILL_STATE_AT) {
Computer *comp;
comp = Network_get_computer(bill->target_c);
comp->busy = 0;
comp->stray = bill;
}
Bill_set_dying(bill);
counter++;
}
return counter;
}

void
Horde_inc_counter(int counter, int val) {
counters[counter] += val;
}

int
Horde_get_counter(int counter) {
return counters[counter];
}

+ 23
- 0
Horde.h View File

@@ -0,0 +1,23 @@
#ifndef HORDE_H
#define HORDE_H

#include "types.h"

/* Counters */
#define HORDE_COUNTER_OFF 0
#define HORDE_COUNTER_ON 1
#define HORDE_COUNTER_MAX 1

void Horde_setup(void);
void Horde_update(int iteration);
void Horde_draw(void);
Bill * Horde_get_bill(int index);
void Horde_move_bill(Bill *bill);
void Horde_remove_bill(Bill *bill);
void Horde_add_bill(Bill *bill);
Bill *Horde_clicked_stray(int x, int y);
int Horde_process_click(int x, int y);
void Horde_inc_counter(int counter, int val);
int Horde_get_counter(int counter);

#endif

+ 14
- 0
INSTALL View File

@@ -0,0 +1,14 @@
To install:
./configure
make
make install

Notes:
- libXpm is required when using Motif or Athena widgets. If you don't
have it, get it from any X ftp site.

- By default, xbill will be detect the presence of GTK, Motif, and Athena
widgets, and build with all that are present. It will also use Xaw3d
as a replacement for the standard Athena sidgets if present.

- The default UI is GTK, if compiled in, followed by Motif and Athena.

+ 105
- 0
Makefile.in View File

@@ -0,0 +1,105 @@
CC = @CC@
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@ @X_LIBS@ @WIDGET_LIBS@ @X_PRE_LIBS@
INSTALL=@INSTALL@
INSTALL_DATA=@INSTALL_DATA@
MKINSTALLDIRS = $(SHELL) $(top_srcdir)/mkinstalldirs

X_CFLAGS=@X_CFLAGS@
GTK_CFLAGS=@GTK_CFLAGS@

prefix=@prefix@
exec_prefix=@exec_prefix@
bindir=@bindir@
mandir=@mandir@
datadir=@datadir@
localstatedir=@localstatedir@
top_srcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@

ALL_CFLAGS = $(CFLAGS) $(CPPFLAGS) -I$(srcdir)
ALL_LDFLAGS = $(CFLAGS) $(LDFLAGS)
IMAGE_DEFINES=-DIMAGES=\"${datadir}/xlennart\"
SCORE_DEFINES=-DSCOREFILE=\"${localstatedir}/xlennart/scores\"

PROG = xlennart

OBJS = Bill.o Bucket.o Cable.o Computer.o Game.o Horde.o Network.o \
OS.o Scorelist.o Spark.o UI.o util.o @WIDGET_OBJS@

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/arch.xpm \
pixmaps/icon.xpm pixmaps/centos.xpm pixmaps/logo.xpm \
pixmaps/maccpu.xpm pixmaps/debian.xpm pixmaps/nextcpu.xpm \
pixmaps/gentoo.xpm pixmaps/os2cpu.xpm \
pixmaps/palm.xpm pixmaps/palmcpu.xpm pixmaps/mandriva.xpm \
pixmaps/spark_0.xpm pixmaps/slackware.xpm pixmaps/suse.xpm \
pixmaps/spark_1.xpm pixmaps/ubuntu.xpm pixmaps/suncpu.xpm \
pixmaps/toaster.xpm pixmaps/initfail.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/palm.xbm bitmaps/redhat.xbm \
bitmaps/sgi.xbm bitmaps/sun.xbm

MANDIR = man6
MAN = xlennart.6

all: ${PROG}

xlennart: ${OBJS}
$(CC) $(ALL_LDFLAGS) -o $@ ${OBJS} ${LIBS}

.c.o:
$(CC) $(ALL_CFLAGS) -c $< -o $@

Scorelist.o: Scorelist.c
$(CC) $(ALL_CFLAGS) $(SCORE_DEFINES) -c $< -o $@

x11-motif.o: x11-motif.c
$(CC) $(ALL_CFLAGS) $(X_CFLAGS) -c $< -o $@

x11-athena.o: x11-athena.c
$(CC) $(ALL_CFLAGS) $(X_CFLAGS) -c $< -o $@

x11.o: x11.c
$(CC) $(ALL_CFLAGS) $(X_CFLAGS) $(IMAGE_DEFINES) -c $< -o $@

gtk.o: gtk.c
$(CC) $(ALL_CFLAGS) $(GTK_CFLAGS) $(IMAGE_DEFINES) -c $< -o $@

install:
$(MKINSTALLDIRS) ${DESTDIR}${bindir}
$(INSTALL) ${PROG} ${DESTDIR}${bindir}/${PROG}
$(MKINSTALLDIRS) ${DESTDIR}${mandir}/${MANDIR}
$(INSTALL_DATA) ${srcdir}/${MAN} ${DESTDIR}${mandir}/${MANDIR}
$(MKINSTALLDIRS) ${DESTDIR}${localstatedir}/xlennart
$(INSTALL_DATA) -m 0666 ${srcdir}/scores ${DESTDIR}${localstatedir}/xlennart
$(MKINSTALLDIRS) ${DESTDIR}${datadir}/xlennart
$(MKINSTALLDIRS) ${DESTDIR}${datadir}/xlennart/pixmaps
$(MKINSTALLDIRS) ${DESTDIR}${datadir}/xlennart/bitmaps
for i in ${XPMS}; do \
${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${datadir}/xlennart/pixmaps ; \
done
for i in ${XBMS}; do \
${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${datadir}/xlennart/bitmaps ; \
done

distclean::
rm -f config.cache config.h config.log config.status Makefile

distclean clean::
rm -f ${PROG} *.o
rm -f *core core*

+ 120
- 0
Network.c View File

@@ -0,0 +1,120 @@
#include <stdlib.h>
#include <stdio.h>

#include "types.h"
#include "util.h"

#include "Cable.h"
#include "Computer.h"
#include "Game.h"
#include "Network.h"
#include "OS.h"
#include "UI.h"

#define STD_MAX_COMPUTERS 20

static Computer *computers;
static int ncomputers;
static Cable **cables;
static int ncables;
static int counters[NETWORK_COUNTER_MAX + 1]; /* number in each state */

static int
on(int level) {
int normal = MIN(8 + level, STD_MAX_COMPUTERS);
return (int)(normal * Game_scale(2));
}

/* sets up network for each level */
void
Network_setup() {
int i;
ncomputers = on(Game_level());
if (computers != NULL)
free(computers);
if (cables != NULL) {
for (i = 0; i < ncables; i++)
if (cables[i] != NULL)
free(cables[i]);
free(cables);
}
computers = xalloc(ncomputers * sizeof(Computer));
for (i = 0; i < ncomputers; i++)
if (!Computer_setup(&computers[i], i)) {
ncomputers = i - 1;
break;
}
counters[NETWORK_COUNTER_OFF] = 0;
counters[NETWORK_COUNTER_BASE] = ncomputers;
counters[NETWORK_COUNTER_WIN] = 0;
ncables = MIN(Game_level(), ncomputers/2);
cables = xalloc(ncables * sizeof(Cable *));
for (i = 0; i < ncables; i++)
Cable_setup(&cables[i]);
}

/* redraws the computers at their location with the proper image */
void
Network_draw () {
int i;
for (i = 0; i < ncables; i++)
Cable_draw(cables[i]);
for (i = 0; i < ncomputers; i++)
Computer_draw(&computers[i]);
}

void
Network_update () {
int i;
for (i = 0; i < ncables; i++)
Cable_update(cables[i]);
}

void
Network_toasters () {
int i;
for (i = 0; i < ncomputers; i++) {
computers[i].type = COMPUTER_TOASTER;
computers[i].os = OS_OFF;
}
ncables = 0;
}

Computer *
Network_get_computer(int index) {
return &computers[index];
}

int
Network_num_computers() {
return ncomputers;
}

Cable *
Network_get_cable(int index) {
return cables[index];
}

int
Network_num_cables() {
return ncables;
}

void
Network_clear_stray(Bill *bill) {
int i;
for (i = 0; i < ncomputers; i++) {
if (computers[i].stray == bill)
computers[i].stray = NULL;
}
}

void
Network_inc_counter(int counter, int val) {
counters[counter] += val;
}

int
Network_get_counter(int counter) {
return counters[counter];
}

+ 22
- 0
Network.h View File

@@ -0,0 +1,22 @@
#ifndef NETWORK_H
#define NETWORK_H

/* Counters */
#define NETWORK_COUNTER_OFF 0
#define NETWORK_COUNTER_BASE 1
#define NETWORK_COUNTER_WIN 2
#define NETWORK_COUNTER_MAX 2

void Network_setup(void);
void Network_draw(void);
void Network_update(void);
void Network_toasters(void);
Computer * Network_get_computer(int index);
int Network_num_computers(void);
Cable * Network_get_cable(int index);
int Network_num_cables(void);
void Network_clear_stray(Bill *bill);
void Network_inc_counter(int counter, int val);
int Network_get_counter(int counter);

#endif

+ 56
- 0
OS.c View File

@@ -0,0 +1,56 @@
#include "types.h"
#include "util.h"

#include "OS.h"
#include "UI.h"

#define MIN_PC 6 /* OS >= MIN_PC means the OS is a PC OS */

static const char *osname[] = { "initfail", "arch", "bsd", "centos", "debian",
"gentoo", "mandriva", "slackware", "suse",
"ubuntu"};
#define NUM_OS (sizeof(osname) / sizeof(osname[0]))

static Picture *os[NUM_OS]; /* array of OS pictures*/
static MCursor *cursor[NUM_OS]; /* array of OS cursors (drag/drop) */


void
OS_load_pix() {
unsigned int i;
for (i = 0; i < NUM_OS; i++) {
UI_load_picture(osname[i], 1, &os[i]);
if (i != 0)
UI_load_cursor(osname[i], CURSOR_OWN_MASK, &cursor[i]);
}
}

void
OS_draw(int index, int x, int y) {
UI_draw(os[index], x, y);
}

int
OS_width() {
return UI_picture_width(os[0]);
}

int
OS_height() {
return UI_picture_height(os[0]);
}

void
OS_set_cursor(int index) {
UI_set_cursor(cursor[index]);
}

int
OS_randpc() {
return (RAND(MIN_PC, NUM_OS - 1));
}

int
OS_ispc(int index) {
return (index >= MIN_PC);
}

+ 30
- 0
OS.h View File

@@ -0,0 +1,30 @@
#ifndef OS_H
#define OS_H

#define OS_WINGDOWS 0 /* OS 0 is the init */
#define OS_OFF -1 /* OS -1 means the computer is off */
#define OS_PC 6 /* OS >= PC means the OS is a PC OS */

void
OS_load_pix(void);

void
OS_draw(int index, int x, int y);

int
OS_width(void);

int
OS_height(void);

void
OS_set_cursor(int index);

int
OS_randpc(void);

int
OS_ispc(int index);


#endif

+ 65
- 0
README View File

@@ -0,0 +1,65 @@
XLennart 1.0

Welcome to XLennart...

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
SystenD [TM], a virus cleverly designed to resemble a popular
init system. Your objective is to click the mouse on them, ending
the 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 1 (or 0) of your computers are 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.

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 SystenD 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 Lenns on/off the screen
Number of Computers running their init/off/SystenD
Level
Score

Options:
-l <n> Start at level n.

--gui <gui>
Use a specific front end. The possible values are
gtk, motif, and athena. Note that some of these
may not be compiled into the binary.

-size <size>
Play on a field of size x size, instead of the normal
400x400. <size> must be larger than 400.

-v Print version number and exit.

-h Print help and exit.

When using the GTK gui, all standard GTK options are supported.
When using the Athena or Motif GUI, all standard X Intrinsics
options are supported.


Authors:

Main Programmer:

Brian Wellington <bwelling@xbill.org> for XBill 2.1

Gethyn ThomasQuail <xylem2020@gmail.com> for XLennart

Programming & graphics:

Matias Duarte <matias@hyperimage.com> for XBill 2.0

Gethyn ThomasQuail <xylem2020@gmail.com> for XLennart

+ 24
- 0
README.Ports View File

@@ -0,0 +1,24 @@
Here's the status of the various ports:

Mac:
Josh Adams <jadams@hyperimage.com> mostly finished this, based on a beta
of 2.0, but never released it for some reason. If I can borrow a Mac OS X
machine for a day or two, porting it should be easy now.

Java:
There are a bunch of Java ports around. I've never found one that works
well. I started porting 2.0 a few years ago, and never finished. It's
possible I'll start again.

XFree86 for OS/2:
Darwin O'Connor <doconno@cc.UManitoba.CA> ported 2.0, and you can get it from
http://www.reamined.on.ca/doconnor/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. If anyone wants to finish
this (write the missing parts and the new parts), let me know, and I can find
the old code.

- Brian (bwelling@xbill.org)

+ 100
- 0
Scorelist.c View File

@@ -0,0 +1,100 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "Scorelist.h"
#include "UI.h"

#define NAMELEN 20
#define SCORES 10

typedef struct Score {
char name[NAMELEN + 1];
int level;
int score;
} Score;

static Score scores[SCORES];

void
Scorelist_read() {
FILE *scorefile = fopen(SCOREFILE, "r");
int i;

if (scorefile != NULL) {
for (i = 0; i < SCORES; i++)
fscanf(scorefile, "%20s%d%d\n", scores[i].name,
&scores[i].level, &scores[i].score);
fclose(scorefile);
}
else {
for (i = 0; i < SCORES; i++) {
strcpy(scores[i].name, "Anonymous");
scores[i].level = 0;
scores[i].score = 0;
}
}
}

void
Scorelist_write() {
FILE *scorefile = fopen(SCOREFILE, "w");
int i;
if (scorefile == NULL)
return;
for (i = 0; i < SCORES; i++)
fprintf(scorefile, "%-*s %d %d\n", NAMELEN,
scores[i].name, scores[i].level, scores[i].score);
fclose(scorefile);
}

/* Add new high score to list */
void
Scorelist_recalc(const char *str, int level, int score) {
int i;
char tname[NAMELEN + 1];
char *nl;

if (scores[SCORES - 1].score >= score)
return;
for (i = SCORES - 1; i > 0; i--) {
if (scores[i - 1].score < score) {
strcpy (scores[i].name, scores[i - 1].name);
scores[i].level = scores[i - 1].level;
scores[i].score = scores[i - 1].score;
}
else
break;
}

memset(tname, 0, sizeof(tname));
if (str == NULL || str[0] == 0)
strcpy(tname, "Anonymous");
strncpy(tname, str, sizeof(tname) - 1);
nl = strchr(tname,'\n');
if (nl != NULL)
*nl = 0;
strcpy(scores[i].name, tname);
scores[i].level = level;
scores[i].score = score;
}

void
Scorelist_update() {
char str[500];
int i;
sprintf(str, "%s\n\n", "High Scores:");
sprintf(str, "%s%-*s %6s %7s\n", str, NAMELEN,
"Name", "Level", "Score");
for (i = 0; i < SCORES; i++) {
sprintf(str, "%s%-*s %6d %7d\n", str, NAMELEN,
scores[i].name, scores[i].level, scores[i].score);
}
UI_update_dialog(DIALOG_HIGHSCORE, str);
}

int
Scorelist_ishighscore(int val) {
return (val > scores[SCORES - 1].score);
}

+ 10
- 0
Scorelist.h View File

@@ -0,0 +1,10 @@
#ifndef SCORELIST_H
#define SCORELIST_H

void Scorelist_read(void);
void Scorelist_write(void);
void Scorelist_recalc(const char *str, int level, int score);
void Scorelist_update(void);
int Scorelist_ishighscore(int val);

#endif

+ 29
- 0
Spark.c View File

@@ -0,0 +1,29 @@
#include "types.h"
#include "util.h"

#include "Spark.h"
#include "UI.h"

static Picture *pictures[2];

void
Spark_load_pix() {
int i;
for (i = 0; i < 2; i++)
UI_load_picture_indexed("spark", i, 1, &pictures[i]);
}

int
Spark_width() {
return UI_picture_width(pictures[0]);
}

int
Spark_height() {
return UI_picture_height(pictures[0]);
}

void
Spark_draw(int x, int y, int index) {
UI_draw(pictures[index], x, y);
}

+ 20
- 0
Spark.h View File

@@ -0,0 +1,20 @@
#ifndef SPARK_H
#define SPARK_H

#define SPARK_SPEED 4
#define SPARK_DELAY(level) (MAX(20 - (level), 0))

void
Spark_load_pix(void);

int
Spark_width(void);

int
Spark_height(void);

void
Spark_draw(int x, int y, int index);


#endif

+ 246
- 0
UI.c View File

@@ -0,0 +1,246 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "strings.h"
#include "types.h"
#include "util.h"

#include "config.h"

#include "Game.h"
#include "UI.h"

#if USE_ATHENA
#include "x11-athena.h"
#endif

#if USE_MOTIF
#include "x11-motif.h"
#endif

#if USE_GTK
#include "gtk.h"
#endif

static int playing;
static UI_methods *methods;
static const char *dialog_strings[DIALOG_MAX + 1];
static const char *menu_strings[DIALOG_MAX + 1];

/*
* Timer control routines
*/

void
UI_restart_timer() {
methods->start_timer(200);
}

void
UI_kill_timer() {
methods->stop_timer();
}

void
UI_pause_game() {
if (methods->timer_active())
playing = 1;
UI_kill_timer();
}

void
UI_resume_game() {
if (playing && !methods->timer_active())
UI_restart_timer();
playing = 0;
}

/*
* Window routines
*/

typedef struct guimap {
const char *name;
void (*setmethods)(UI_methods **methodsp);
} guimap;

static guimap guis[] = {
#ifdef USE_GTK
{"gtk", gtk_ui_setmethods},
#endif
#ifdef USE_MOTIF
{"motif", x11_motif_setmethods},
#endif
#ifdef USE_ATHENA
{"athena", x11_athena_setmethods},
#endif
{NULL, NULL},
};

void
UI_initialize(const char *gui, int *argc, char **argv) {
guimap *map;
if (gui == NULL) {
map = guis;
if (map->name == NULL)
fatal("no configured GUIs");
map->setmethods(&methods);
} else {
for (map = guis; map->name != NULL; map++)
if (strcasecmp(gui, map->name) == 0)
break;
if (map->name == NULL)
fatal("GUI '%s' not found", gui);
map->setmethods(&methods);
}
methods->initialize(argc, argv);
}

void
UI_make_main_window(int size) {
menu_strings[DIALOG_NEWGAME] = newgame_menu_str;
menu_strings[DIALOG_PAUSEGAME] = pause_menu_str;
menu_strings[DIALOG_WARPLEVEL] = warp_menu_str;
menu_strings[DIALOG_HIGHSCORE] = highscore_menu_str;
menu_strings[DIALOG_QUITGAME] = quit_menu_str;
menu_strings[DIALOG_STORY] = story_menu_str;
menu_strings[DIALOG_RULES] = rules_menu_str;
menu_strings[DIALOG_ABOUT] = about_menu_str;
menu_strings[DIALOG_SCORE] = score_menu_str;
menu_strings[DIALOG_ENDGAME] = endgame_menu_str;
menu_strings[DIALOG_ENTERNAME] = entername_menu_str;
methods->make_main_window(size);
}

void
UI_graphics_init() {
methods->graphics_init();
}