1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <time.h>
6
7 #include "types.h"
8 #include "util.h"
9
10 #include "Bill.h"
11 #include "Bucket.h"
12 #include "Computer.h"
13 #include "Cable.h"
14 #include "Game.h"
15 #include "Horde.h"
16 #include "Network.h"
17 #include "OS.h"
18 #include "Scorelist.h"
19 #include "Spark.h"
20 #include "UI.h"
21
22 #define SCREENSIZE 400
23
24 /* Game states */
25 #define STATE_PLAYING 1
26 #define STATE_BETWEEN 2
27 #define STATE_END 3
28 #define STATE_WAITING 4
29
30 /* Score related constants */
31 #define SCORE_ENDLEVEL -1
32 #define SCORE_BILLPOINTS 5
33
34 static unsigned int state;
35 static int efficiency;
36 static int score, level, iteration;
37 static Picture *logo, *icon, *about;
38 static MCursor *defaultcursor, *downcursor;
39 static Bill *grabbed;
40 static const char *gui;
41 static int screensize = SCREENSIZE;
42
43 static void
setup_level(int newlevel)44 setup_level(int newlevel) {
45 level = newlevel;
46 Horde_setup();
47 grabbed = NULL;
48 UI_set_cursor(defaultcursor);
49 Network_setup();
50 iteration = 0;
51 efficiency = 0;
52 }
53
54 void
Game_start(int newlevel)55 Game_start(int newlevel) {
56 state = STATE_PLAYING;
57 score = 0;
58 UI_restart_timer();
59 UI_set_pausebutton(1);
60 setup_level(newlevel);
61 }
62
63 void
Game_quit()64 Game_quit() {
65 Scorelist_write();
66 exit(0);
67 }
68
69 static void
update_info(void)70 update_info(void) {
71 char str[80];
72 int on_screen = Horde_get_counter(HORDE_COUNTER_ON);
73 int off_screen = Horde_get_counter(HORDE_COUNTER_OFF);
74 int base = Network_get_counter(NETWORK_COUNTER_BASE);
75 int off = Network_get_counter(NETWORK_COUNTER_OFF);
76 int win = Network_get_counter(NETWORK_COUNTER_WIN);
77 int units = Network_num_computers();
78 sprintf(str, "Lenn:%d/%d System:%d/%d/%d Level:%d Score:%d",
79 on_screen, off_screen, base, off, win, level, score);
80 UI_draw_str(str, 5, screensize - 5);
81 efficiency += ((100 * base - 10 * win) / units);
82 }
83
84 void
Game_warp_to_level(int lev)85 Game_warp_to_level(int lev) {
86 if (state == STATE_PLAYING) {
87 if (lev <= level)
88 return;
89 setup_level(lev);
90 }
91 else {
92 if (lev <= 0)
93 return;
94 Game_start(lev);
95 }
96 }
97
98 void
Game_add_high_score(const char * str)99 Game_add_high_score(const char *str) {
100 Scorelist_recalc(str, level, score);
101 }
102
103 void
Game_button_press(int x,int y)104 Game_button_press(int x, int y) {
105 int counter;
106
107 if (state != STATE_PLAYING)
108 return;
109 UI_set_cursor(downcursor);
110
111 if (Bucket_clicked(x, y)) {
112 Bucket_grab(x, y);
113 return;
114 }
115
116 grabbed = Horde_clicked_stray(x, y);
117 if (grabbed != NULL) {
118 OS_set_cursor(grabbed->cargo);
119 return;
120 }
121
122 counter = Horde_process_click(x, y);
123 score += (counter * counter * SCORE_BILLPOINTS);
124 }
125
126 void
Game_button_release(int x,int y)127 Game_button_release(int x, int y) {
128 int i;
129 UI_set_cursor(defaultcursor);
130
131 if (state != STATE_PLAYING)
132 return;
133
134 if (grabbed == NULL) {
135 Bucket_release(x, y);
136 return;
137 }
138
139 for (i = 0; i < Network_num_computers(); i++) {
140 Computer *computer = Network_get_computer(i);
141
142 if (Computer_on(computer, x, y) &&
143 Computer_compatible(computer, grabbed->cargo) &&
144 (computer->os == OS_WINGDOWS || computer->os == OS_OFF)) {
145 int counter;
146
147 Network_inc_counter(NETWORK_COUNTER_BASE, 1);
148 if (computer->os == OS_WINGDOWS)
149 counter = NETWORK_COUNTER_WIN;
150 else
151 counter = NETWORK_COUNTER_OFF;
152 Network_inc_counter(counter, -1);
153 computer->os = grabbed->cargo;
154 Horde_remove_bill(grabbed);
155 grabbed = NULL;
156 return;
157 }
158 }
159 Horde_add_bill(grabbed);
160 grabbed = NULL;
161 }
162
163 static void
draw_logo(void)164 draw_logo(void) {
165 UI_clear();
166 UI_draw(logo,
167 (screensize - UI_picture_width(logo)) / 2,
168 (screensize - UI_picture_height(logo)) / 2);
169 }
170
171 void
Game_update()172 Game_update() {
173 char str[40];
174
175 switch (state) {
176 case STATE_PLAYING:
177 UI_clear();
178 Bucket_draw();
179 Network_update();
180 Network_draw();
181 Horde_update(iteration);
182 Horde_draw();
183 update_info();
184 if (Horde_get_counter(HORDE_COUNTER_ON) +
185 Horde_get_counter(HORDE_COUNTER_OFF) == 0) {
186 score += (level * efficiency / iteration);
187 state = STATE_BETWEEN;
188 }
189 if ((Network_get_counter(NETWORK_COUNTER_BASE) +
190 Network_get_counter(NETWORK_COUNTER_OFF)) <= 1)
191 state = STATE_END;
192 break;
193 case STATE_END:
194 UI_set_cursor(defaultcursor);
195 UI_clear();
196 Network_toasters();
197 Network_draw();
198 UI_refresh();
199 UI_popup_dialog(DIALOG_ENDGAME);
200 if (Scorelist_ishighscore(score)) {
201 UI_popup_dialog(DIALOG_ENTERNAME);
202 Scorelist_update();
203 }
204 UI_popup_dialog(DIALOG_HIGHSCORE);
205 draw_logo();
206 UI_kill_timer();
207 UI_set_pausebutton(0);
208 state = STATE_WAITING;
209 break;
210 case STATE_BETWEEN:
211 UI_set_cursor(defaultcursor);
212 sprintf(str, "After Level %d:\nScore: %d", level, score);
213 UI_update_dialog(DIALOG_SCORE, str);
214 UI_popup_dialog(DIALOG_SCORE);
215 state = STATE_PLAYING;
216 setup_level(++level);
217 break;
218 }
219 UI_refresh();
220 iteration++;
221 }
222
223 int
Game_score()224 Game_score() {
225 return score;
226 }
227
228 int
Game_level()229 Game_level() {
230 return level;
231 }
232
233 int
Game_screensize()234 Game_screensize() {
235 return screensize;
236 }
237
238 double
Game_scale(int dimensions)239 Game_scale(int dimensions) {
240 double scale = (double)screensize / SCREENSIZE;
241 double d = 1;
242 for ( ; dimensions > 0; dimensions--)
243 d *= scale;
244 return (d);
245 }
246
247 /*
248 * Note - don't use getopt, since it might reorder the args or do something
249 * that the UI-specific argument parser doesn't like.
250 */
251 static void
parse_args(int argc,char ** argv)252 parse_args(int argc, char **argv) {
253 char *s;
254 char *endp;
255 int i;
256
257 for (i = 1; i < argc; i++) {
258 if (strncasecmp(argv[i], "-l", 2) == 0) {
259 if (strlen(argv[i]) == 2 && i == argc - 1)
260 fatal("-l takes an argument");
261 if (strlen(argv[i]) > 2)
262 s = argv[i] + 2;
263 else
264 s = argv[++i];
265 level = strtol(s, &endp, 10);
266 if (*endp != '\0' || level <= 0)
267 fatal("invalid level '%s'", s);
268 } else if (strcmp(argv[i], "--gui") == 0) {
269 if (i == argc - 1)
270 fatal("--gui takes an argument");
271 gui = argv[++i];
272 } else if (strcmp(argv[i], "--size") == 0) {
273 if (i == argc - 1)
274 fatal("--size takes an argument");
275 s = argv[++i];
276 screensize = strtol(s, &endp, 10);
277 if (*endp != '\0' || screensize <= 0)
278 fatal("invalid screensize '%s'", s);
279 if (screensize < SCREENSIZE)
280 fatal("screensize must be larger than '%d'",
281 SCREENSIZE);
282 } else if (strcmp(argv[1], "-v") == 0 ||
283 strcmp(argv[1], "--version") == 0)
284 {
285 printf ("XLennart version 1.0\n\n");
286 exit(0);
287 } else if (strcmp(argv[1], "-h") == 0 ||
288 strcmp(argv[1], "--help") == 0)
289 {
290 printf("XLennart version 1.0\n");
291 printf("Options:\n");
292 printf("-l <n>\tStart at level n.\n");
293 printf("--gui <gui> \tUse a specific gui "
294 "(athena, motif, gtk)\n");
295 printf("--size <size>\t\tUse a larger playing area.\n");
296 printf("-v\t\tPrint version number and exit.\n");
297 printf("-h\t\tPrint help and exit.\n");
298 printf("All standard toolkit options are also ");
299 printf("supported.\n\n");
300 exit(0);
301 }
302 }
303 }
304
305 int
main(int argc,char ** argv)306 main(int argc, char **argv) {
307 srand(time(NULL));
308 parse_args(argc, argv);
309 UI_initialize(gui, &argc, argv);
310 UI_make_main_window(screensize);
311 UI_graphics_init();
312 UI_load_picture("logo", 0, &logo);
313 UI_load_picture("icon", 0, &icon);
314 UI_load_picture("about", 0, &about);
315 draw_logo();
316 UI_refresh();
317 UI_make_dialogs(logo, icon, about);
318 UI_set_icon(icon);
319
320 Scorelist_read();
321 Scorelist_update();
322
323 UI_load_cursor("hand_up", CURSOR_SEP_MASK, &defaultcursor);
324 UI_load_cursor("hand_down", CURSOR_SEP_MASK, &downcursor);
325 UI_set_cursor(defaultcursor);
326
327 Bill_load_pix();
328 OS_load_pix();
329 Computer_load_pix();
330 Bucket_load_pix();
331 Spark_load_pix();
332
333 state = STATE_WAITING;
334 if (level)
335 Game_start(level);
336 else
337 UI_set_pausebutton(0);
338 UI_main_loop();
339 exit(0);
340 }
341