1 /* NetWalk main program
2 * Ben Lynn
3 */
4 /*
5 Copyright (C) 2004 Benjamin Lynn (blynn@cs.stanford.edu)
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21 #include <assert.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <math.h>
25 #include <time.h>
26
27 #include <sys/types.h> //for opendir et al.
28 #include <dirent.h>
29
30 #include <sys/stat.h>
31 #include <unistd.h>
32
33 #include <stdlib.h>
34 #include <signal.h>
35
36 #include <SDL.h>
37 #include <SDL_ttf.h>
38
39 #include "version.h"
40
41 #include "widget.h"
42 #include "colour.h"
43 #include "game.h"
44
45 #include "config.h"
46 #include "util.h"
47
48 static int interrupted = 0;
49
50 enum {
51 vsize = 18
52 };
53
54 enum {
55 pulse_max = 1024
56 };
57
58 enum {
59 state_game,
60 state_button,
61 state_quit
62 };
63
64 enum {
65 level_easy = 0,
66 level_medium,
67 level_hard,
68 level_veryhard,
69 level_giant,
70 level_absurd,
71 level_max,
72 level_custom
73 };
74
75 enum {
76 cellw = 24,
77 cellh = 24,
78 border = 1,
79 padding = 10
80 };
81
82 char shifttable[256];
83
84 struct hsentry_s {
85 char *name;
86 int time;
87 };
88 typedef struct hsentry_s *hsentry_ptr;
89 typedef struct hsentry_s hsentry_t[1];
90
91 hsentry_t hstable[level_max];
92 char *level_name[level_max];
93
94 //TODO use this somehow
95 struct gameparm_s {
96 int boardw, boardh;
97 int wrap;
98 };
99 typedef struct gameparm_s *gameparm_ptr;
100 typedef struct gameparm_s gameparm_t[1];
101
102 gameparm_t gp;
103
104 static config_t config;
105
106 SDL_Surface *screen;
107 TTF_Font *font;
108 int lastmousex, lastmousey;
109 char *player_name;
110 extern int game_won;
111 int state;
112
113 struct button_s {
114 struct widget_s widget;
115 char *text;
116 SDL_Surface *img;
117 };
118 typedef struct button_s button_t[1];
119 typedef struct button_s *button_ptr;
120
121 struct label_s {
122 struct widget_s widget;
123 char *text;
124 SDL_Surface *img;
125 };
126 typedef struct label_s label_t[1];
127 typedef struct label_s *label_ptr;
128
129 struct textbox_s {
130 struct widget_s widget;
131 char text[1024];
132 int i;
133 SDL_Surface *img;
134 };
135 typedef struct textbox_s textbox_t[1];
136 typedef struct textbox_s *textbox_ptr;
137
138 struct arena_s {
139 struct widget_s widget;
140 };
141 typedef struct arena_s arena_t[1];
142 typedef struct arena_s *arena_ptr;
143
144 struct menuitem_s {
145 struct widget_s widget;
146 char *text;
147 SDL_Surface *img;
148 struct menu_s *submenu;
149 };
150 typedef struct menuitem_s menuitem_t[1];
151 typedef struct menuitem_s *menuitem_ptr;
152
153 struct menu_s {
154 struct widget_s widget;
155 //TODO: replace array with list
156 menuitem_ptr item_list[64];
157 int item_count;
158 };
159 typedef struct menu_s menu_t[1];
160 typedef struct menu_s *menu_ptr;
161
162 struct menubar_s {
163 struct widget_s widget;
164 //TODO: replace array with list
165 menuitem_ptr item_list[64];
166 int item_count;
167 };
168 typedef struct menubar_s menubar_t[1];
169 typedef struct menubar_s *menubar_ptr;
170
171 struct window_s {
172 struct widget_s widget;
173 //TODO: replace array with list
174 struct widget_s *widget_list[64];
175 int widget_count;
176
177 };
178 typedef struct window_s window_t[1];
179 typedef struct window_s *window_ptr;
180
181 struct hsw_s {
182 label_t level;
183 label_t time;
184 label_t name;
185 };
186 typedef struct hsw_s *hsw_ptr;
187 typedef struct hsw_s hsw_t[1];
188
189 hsw_t hsw[level_max];
190
191 arena_t arena;
192 window_t root;
193 label_t l_moves;
194 label_t l_time;
195 menubar_t menu;
196 menuitem_ptr openedmenu;
197 window_ptr modalwindow;
198 window_t about_window;
199 window_t hs_window;
200 window_t enter_name_window;
201 label_t l_about1;
202 label_t l_about2;
203 button_t b_about1;
204 widget_t statusbar;
205
206 label_t l_hs1;
207 button_t b_hs1;
208
209 label_t l_en1;
210 textbox_t tb_en1;
211 button_t b_en1;
212
font_render(char * s,int c)213 SDL_Surface *font_render(char *s, int c)
214 {
215 return TTF_RenderText_Solid(font, s, rgbtable[c]);
216 }
217
statusbar_update(widget_ptr w)218 void statusbar_update(widget_ptr w)
219 {
220 widget_lowered_background(w);
221 }
222
menu_init(menu_ptr m)223 void menu_init(menu_ptr m)
224 {
225 widget_init((widget_ptr) m);
226 m->item_count = 0;
227 }
228
menu_update(menu_ptr m)229 void menu_update(menu_ptr m)
230 {
231 int i;
232 menuitem_ptr it;
233 SDL_Rect rect;
234
235 widget_fill((widget_ptr) m, c_background);
236 for (i=0; i<m->item_count; i++) {
237 it = m->item_list[i];
238 if (in_widget((widget_ptr) it, lastmousex, lastmousey)) {
239 rect.x = 2;
240 rect.y = vsize * i;
241 rect.w = ((widget_ptr) it)->w - 4;
242 rect.h = vsize;
243 widget_fillrect((widget_ptr) m, &rect, c_menubg);
244 }
245 rect.x = 8;
246 rect.y = vsize * i + 4;
247 widget_blit((widget_ptr) m, it->img, NULL, &rect);
248 }
249 }
250
menu_add_item(menu_ptr m,menuitem_ptr it)251 void menu_add_item(menu_ptr m, menuitem_ptr it)
252 {
253 m->item_list[m->item_count] = it;
254 m->item_count++;
255 }
256
menuitem_init(menuitem_ptr m)257 void menuitem_init(menuitem_ptr m)
258 {
259 widget_init((widget_ptr) m);
260 m->text = NULL;
261 m->img = NULL;
262 m->submenu = NULL;
263 }
264
menuitem_new()265 menuitem_ptr menuitem_new()
266 {
267 menuitem_ptr it;
268
269 it = (menuitem_ptr) malloc(sizeof(menuitem_t));
270 menuitem_init(it);
271
272 return it;
273 }
274
menuitem_put_text(menuitem_ptr m,char * s)275 void menuitem_put_text(menuitem_ptr m, char *s)
276 {
277 SDL_Surface *tmp;
278
279 m->text = s;
280 if (m->img) SDL_FreeSurface(m->img);
281 tmp = font_render(s, c_text);
282 m->img = SDL_DisplayFormat(tmp);
283 SDL_FreeSurface(tmp);
284 }
285
open_submenu(widget_ptr p,void * data)286 void open_submenu(widget_ptr p, void *data)
287 {
288 int i;
289 int w = 0;
290 menuitem_ptr it;
291
292 openedmenu = (menuitem_ptr) p;
293 menu_ptr m = openedmenu->submenu;
294
295 for (i=0; i<m->item_count; i++) {
296 it = m->item_list[i];
297 if (w < it->img->w) w = it->img->w;
298 }
299 w += 12;
300
301 m->widget.x = m->widget.parent->x;
302 m->widget.y = m->widget.parent->y + vsize;
303
304 m->widget.w = w;
305 m->widget.h = vsize * m->item_count + 1;
306
307 for (i=0; i<m->item_count; i++) {
308 it = m->item_list[i];
309 it->widget.x = 0 + m->widget.x;
310 it->widget.y = vsize * i + 4 + m->widget.y;
311 it->widget.w = w;
312 it->widget.h = vsize;
313 }
314 }
315
menuitem_set_submenu(menuitem_ptr it,menu_ptr m)316 void menuitem_set_submenu(menuitem_ptr it, menu_ptr m)
317 {
318 it->submenu = m;
319 //it->widget.signal_handler[signal_activate] = open_submenu;
320 widget_put_handler((widget_ptr) it, open_submenu, signal_activate);
321 m->widget.parent = (widget_ptr) it;
322 }
323
menubar_update(widget_ptr wid)324 void menubar_update(widget_ptr wid)
325 {
326 SDL_Rect dst;
327 menubar_ptr m = (menubar_ptr) wid;
328 menuitem_ptr it;
329 int i;
330
331 widget_raised_background(wid);
332
333 for (i=0; i<m->item_count; i++) {
334 it = m->item_list[i];
335 if (it == openedmenu) {
336 dst.x = it->widget.x + 2;
337 dst.y = it->widget.y + 2;
338 dst.w = it->widget.w - 4;
339 dst.h = vsize - 2;
340 widget_fillrect(wid, &dst, c_menubg);
341 }
342 if (it->img) {
343 dst.x = it->widget.x + 5;
344 dst.y = it->widget.y + 2;
345 widget_blit(m, it->img, NULL, &dst);
346 }
347 }
348 }
349
menubar_handle_click(widget_ptr p,int button,int x,int y)350 void menubar_handle_click(widget_ptr p, int button, int x, int y)
351 {
352 int i;
353 menubar_ptr m = (menubar_ptr) p;
354 menuitem_ptr it;
355
356 for (i=0; i<m->item_count; i++) {
357 it = m->item_list[i];
358 if (in_widget((widget_ptr) it, x, y)) {
359 widget_raise_signal((widget_ptr) it, signal_activate);
360 return;
361 }
362 }
363 }
364
menubar_init(menubar_ptr m)365 void menubar_init(menubar_ptr m)
366 {
367 widget_init((widget_ptr) m);
368 m->widget.update = menubar_update;
369 m->item_count = 0;
370 m->widget.handle_click = menubar_handle_click;
371 }
372
menubar_add_item(menubar_ptr m,menuitem_ptr it)373 void menubar_add_item(menubar_ptr m, menuitem_ptr it)
374 {
375 m->item_list[m->item_count] = it;
376 m->item_count++;
377 it->widget.parent = (widget_ptr) m;
378 }
379
menubar_auto_layout(menubar_ptr m)380 void menubar_auto_layout(menubar_ptr m)
381 {
382 int i, x, y;
383 menuitem_ptr it;
384
385 x = 0;
386 y = 0;
387 for (i=0; i<m->item_count; i++) {
388 it = m->item_list[i];
389 if (it->img) {
390 it->widget.x = x;
391 it->widget.y = y;
392 it->widget.w = it->img->w + 10;
393 it->widget.h = it->img->h;
394 x += it->img->w + 10;
395 }
396 }
397 }
398
label_update(widget_ptr p)399 void label_update(widget_ptr p)
400 {
401 SDL_Rect dst;
402 label_ptr l = (label_ptr) p;
403
404 if (l->img) {
405 dst.x = 0;
406 dst.y = 4;
407 widget_blit(l, l->img, NULL, &dst);
408 }
409 }
410
label_init(label_ptr l)411 void label_init(label_ptr l)
412 {
413 widget_init((widget_ptr) l);
414 l->text = NULL;
415 l->img = NULL;
416 l->widget.update = label_update;
417 }
418
label_put_text(label_ptr l,char * s)419 void label_put_text(label_ptr l, char *s)
420 {
421 SDL_Surface *tmp;
422
423 if (l->img) SDL_FreeSurface(l->img);
424 if (l->text) free(l->text);
425 l->text = clonestr(s);
426 tmp = font_render(s, c_text);
427 l->img = SDL_DisplayFormat(tmp);
428 SDL_FreeSurface(tmp);
429 }
430
textbox_update_img(textbox_ptr tb)431 void textbox_update_img(textbox_ptr tb)
432 {
433 SDL_Surface *tmp;
434
435 if (tb->img) SDL_FreeSurface(tb->img);
436 tmp = font_render(tb->text, c_text);
437 if (tmp) {
438 tb->img = SDL_DisplayFormat(tmp);
439 SDL_FreeSurface(tmp);
440 } else {
441 tb->img = NULL;
442 }
443 }
444
textbox_left(textbox_ptr tb)445 void textbox_left(textbox_ptr tb)
446 {
447 if (tb->i > 0) tb->i--;
448 }
449
textbox_right(textbox_ptr tb)450 void textbox_right(textbox_ptr tb)
451 {
452 if (tb->i < strlen(tb->text)) tb->i++;
453 }
454
textbox_delete(textbox_ptr tb)455 void textbox_delete(textbox_ptr tb)
456 {
457 if (tb->i > 0) {
458 tb->i--;
459 tb->text[tb->i] = 0;
460 textbox_update_img(tb);
461 }
462 }
463
textbox_backspace(textbox_ptr tb)464 void textbox_backspace(textbox_ptr tb)
465 {
466 char *s = &tb->text[tb->i];
467 if (tb->i) {
468 memmove(s - 1, s, strlen(s) + 1);
469 tb->i--;
470 textbox_update_img(tb);
471 }
472 }
473
textbox_insert(textbox_ptr tb,char c)474 void textbox_insert(textbox_ptr tb, char c)
475 {
476 char *s = &tb->text[tb->i];
477 memmove(s + 1, s, strlen(s) + 1);
478 tb->text[tb->i] = c;
479 tb->i++;
480 textbox_update_img(tb);
481 }
482
textbox_update(widget_ptr p)483 void textbox_update(widget_ptr p)
484 {
485 SDL_Rect dst;
486 textbox_ptr tb = (textbox_ptr) p;
487
488 dst.x = 0;
489 dst.y = 0;
490 dst.w = p->w;
491 dst.h = p->h;
492 widget_fillrect(p, &dst, c_text);
493 dst.x++;
494 dst.y++;
495 dst.w-=2;
496 dst.h-=2;
497 widget_fillrect(p, &dst, c_canvas);
498
499 if (tb->img) {
500 dst.x = 1;
501 dst.y = 3;
502 widget_blit(tb, tb->img, NULL, &dst);
503 }
504
505 {
506 char s[1024];
507 int w, h;
508
509 strncpy(s, tb->text, tb->i);
510 s[tb->i] = 0;
511 TTF_SizeText(font, s, &w, &h);
512
513 dst.x = w;
514 dst.y = 2;
515 dst.w = 1;
516 dst.h = vsize - 2;
517 widget_fillrect(p, &dst, c_text);
518 }
519 }
520
textbox_init(textbox_ptr l)521 void textbox_init(textbox_ptr l)
522 {
523 widget_init((widget_ptr) l);
524 l->img = NULL;
525 l->widget.update = textbox_update;
526 }
527
textbox_put_text(textbox_ptr tb,char * s)528 void textbox_put_text(textbox_ptr tb, char *s)
529 {
530 strcpy(tb->text, s);
531 tb->i = strlen(s);
532 textbox_update_img(tb);
533 }
534
535 static widget_ptr button_selection;
536
button_handle_click(widget_ptr p,int button,int x,int y)537 void button_handle_click(widget_ptr p, int button, int x, int y)
538 {
539 state = state_button;
540 button_selection = p;
541 }
542
button_update(widget_ptr p)543 void button_update(widget_ptr p)
544 {
545 SDL_Rect dst;
546 label_ptr l = (label_ptr) p;
547
548 if (state == state_button && button_selection == p
549 && in_widget(p, lastmousex, lastmousey)) {
550 widget_lowered_background(p);
551 } else {
552 widget_raised_background(p);
553 }
554 if (l->img) {
555 dst.x = 5;
556 dst.y = 2;
557 widget_blit(l, l->img, NULL, &dst);
558 }
559 }
560
button_init(button_ptr b)561 void button_init(button_ptr b)
562 {
563 widget_init((widget_ptr) b);
564 b->text = NULL;
565 b->img = NULL;
566 b->widget.update = button_update;
567 b->widget.handle_click = button_handle_click;
568 }
569
button_put_text(button_ptr b,char * s)570 void button_put_text(button_ptr b, char *s)
571 {
572 SDL_Surface *tmp;
573
574 if (b->img) SDL_FreeSurface(b->img);
575 if (b->text) free(b->text);
576 b->text = clonestr(s);
577 tmp = font_render(s, c_text);
578 b->img = SDL_DisplayFormat(tmp);
579 SDL_FreeSurface(tmp);
580 }
581
set_video(int w,int h)582 void set_video(int w, int h)
583 {
584 int flags;
585 flags = SDL_DOUBLEBUF;
586
587 screen = SDL_SetVideoMode(w, h, 0, flags);
588 // flags = SDL_FULLSCREEN;
589 // screen = SDL_SetVideoMode(0, 0, 0, flags);
590 init_ctable(screen->format);
591
592 if (!screen) {
593 fprintf(stderr, "Can't set video mode: %s\n", SDL_GetError());
594 exit(1);
595 }
596
597 //SDL_ShowCursor(SDL_DISABLE);
598 }
599
set_interrupted(int i)600 void set_interrupted(int i)
601 {
602 interrupted = 1;
603 }
604
init()605 void init()
606 {
607 int status;
608
609 signal(SIGINT, set_interrupted);
610 signal(SIGTERM, set_interrupted);
611
612 //if (SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO|SDL_INIT_TIMER) < 0) {
613 if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) < 0) {
614 fprintf(stderr, "Can't init SDL: %s\n", SDL_GetError());
615 exit(1);
616 }
617 atexit(SDL_Quit);
618 status = TTF_Init();
619 if (status) {
620 fprintf(stderr, "Can't init SDL_ttf\n");
621 exit(-1);
622 }
623 atexit(TTF_Quit);
624
625 SDL_WM_SetCaption("NetWalk", "NetWalk");
626
627 SDL_EnableKeyRepeat(150, 50);
628 }
629
630 SDL_Surface *unmarked_tileimg[64];
631 SDL_Surface *marked_tileimg[64];
632 int level = level_medium;
633 int tick;
634 int tick_old;
635 int pipey, pipex;
636 int pipew, pipeh;
637 int pipet = 4;
638 int move_count;
639 int ms_count;
640 int second_count;
641
draw_tile(widget_ptr wid,int i,int j)642 void draw_tile(widget_ptr wid, int i, int j)
643 {
644 SDL_Rect rect;
645 int index;
646
647 rect.x = padding + border + i * (cellw + border);
648 rect.y = padding + border + j * (cellh + border);
649
650 int const marked = flags[i][j] & 0x1;
651 index = board[i][j] - 1;
652 widget_blit(wid,
653 (marked?marked_tileimg:unmarked_tileimg)[index],
654 NULL,
655 &rect);
656 }
657
658 typedef struct {
659 int x, y;
660 int dir;
661 int tick;
662 } pulse_s;
663
664 pulse_s pulse_list[pulse_max];
665 int pulse_count;
666
new_pulse(int x,int y,int d)667 void new_pulse(int x, int y, int d)
668 {
669 int i, j;
670
671 if (pulse_count >= pulse_max) return;
672
673 //stop incoming server pulses
674 if (x == sourcex && (y == sourceybottom || y ==sourceytop) && d != -1) {
675 return;
676 }
677
678 i = board[x][y];
679 for (j=0; j<4; j++) {
680 if ((j != d) && (i & (1 << j))) {
681 pulse_list[pulse_count].x = x;
682 pulse_list[pulse_count].y = y;
683 pulse_list[pulse_count].dir = j;
684 pulse_list[pulse_count].tick = tick;
685 pulse_count++;
686 if (pulse_count >= pulse_max) return;
687 }
688 }
689 }
690
server_pulse()691 void server_pulse()
692 {
693 new_pulse(sourcex, sourceybottom, -1);
694 new_pulse(sourcex, sourceytop, -1);
695 }
696
animate_pulse(widget_ptr wid)697 void animate_pulse(widget_ptr wid)
698 {
699 int i, dt, d;
700 int x, y;
701 SDL_Rect rect;
702 int speed = 500;
703
704 if (!pulse_count) {
705 server_pulse();
706 }
707
708 rect.w = pipet + 2;
709 rect.h = pipet + 2;
710 i = 0;
711 while (i<pulse_count) {
712 x = pulse_list[i].x;
713 y = pulse_list[i].y;
714 d = pulse_list[i].dir;
715 dt = tick - pulse_list[i].tick;
716 if (dt > speed) {
717 pulse_count--;
718 memmove(&pulse_list[i], &pulse_list[i+1], sizeof(pulse_s) * (pulse_count - i));
719
720 add_dir(&x, &y, x, y, d);
721 new_pulse(x, y, (d + 2) % 4);
722 } else {
723 //wrap cases:
724 if (dir[d].x == -1 && 2 * dt > speed && !x) {
725 x += boardw;
726 }
727 if (dir[d].x == 1 && 2 * dt > speed && x == boardw - 1) {
728 x -= boardw;
729 }
730 if (dir[d].y == -1 && 2 * dt > speed && !y) {
731 y += boardh;
732 }
733 if (dir[d].y == 1 && 2 * dt > speed && y == boardh - 1) {
734 y -= boardh;
735 }
736
737 rect.x = x * (cellw + border) + pipex - 1;
738 rect.x += dir[d].x * (cellw + border) * dt / speed;
739 rect.x += border + padding;
740
741 rect.y = y * (cellh + border) + border + padding;
742 rect.y += dir[d].y * (cellh + border) * dt / speed;
743 rect.y += pipey - 1;
744 widget_fillrect(wid, &rect, c_pulse);
745 i++;
746 }
747 }
748 }
749
750 /** \brief Determine which cell of the arena the mouse is currently
751 * pointing at, if any.
752 * \param wid The arena widget.
753 * \param mousex The mouse X position.
754 * \param mousey The mouse Y position.
755 * \param[out] col_p Returns the current cell's column in the arena.
756 * \param[out] row_p Returns the current cell's row in the arena.
757 * \retval 0 The mouse is over the arena and the cell index is returned
758 * through \a row_p and \a col_p.
759 * \retval -1 The mouse is not over the area.
760 */
761
get_cell_from_mouse_position(widget_ptr const wid,int const mousex,int const mousey,unsigned int * const col_p,unsigned int * const row_p)762 int get_cell_from_mouse_position(widget_ptr const wid,
763 int const mousex,int const mousey,
764 unsigned int * const col_p,unsigned int * const row_p)
765 {
766 if((mousex < wid->x) || (mousey < wid->y))
767 return -1;
768
769 unsigned int const col =
770 (mousex - padding - border - wid->x) / (cellw + border);
771 unsigned int const row =
772 (mousey - padding - border - wid->y) / (cellh + border);
773
774 if((col >= boardw) || (row >= boardh))
775 return -1;
776
777 *col_p = col;
778 *row_p = row;
779 return 0;
780 }
781
782 /** \brief Fill a cell (including border) in the arena with a color.
783 * \param wid The arena widget.
784 * \param col The column of the cell to be filled.
785 * \param row The row of the cell to be filled.
786 * \param coloridx The index of the color to use when filling.
787 */
788
fill_arena_cell(widget_ptr const wid,unsigned int const col,unsigned int const row,int const coloridx)789 void fill_arena_cell(widget_ptr const wid,
790 unsigned int const col,unsigned int const row,int const coloridx)
791 {
792 SDL_Rect rect = {
793 .x = (cellw + border) * col + padding,
794 .y = (cellh + border) * row + padding,
795 .w = cellw + 2 * border,
796 .h = cellh + 2 * border
797 };
798 widget_fillrect(wid, &rect, coloridx);
799 }
800
arena_update(widget_ptr wid)801 void arena_update(widget_ptr wid)
802 {
803 int i, j;
804 SDL_Rect rect;
805 int bc;
806 int c;
807
808 //draw grid
809 rect.x = padding;
810 rect.y = padding;
811 rect.w = cellw * boardw + (boardw + 1) * border;
812 rect.h = border;
813
814 if (game_won) bc = c_borderwon;
815 else bc = c_border;
816
817 for (i=0; i<=boardh; i++) {
818 widget_fillrect(wid, &rect, bc);
819 rect.y += cellh + border;
820 }
821
822 rect.y = padding;
823 rect.w = border;
824 rect.h = cellh * boardh + (boardh + 1) * border;
825 for (i=0; i<=boardw; i++) {
826 widget_fillrect(wid, &rect, bc);
827 rect.x += cellw + border;
828 }
829
830 //highlight cursor
831 unsigned int col;
832 unsigned int row;
833 if(get_cell_from_mouse_position(wid,lastmousex,lastmousey,&col,&row) == 0)
834 {
835 /* highlight the cell the mouse is pointing at */
836 fill_arena_cell(wid,col,row,c_highlight);
837
838 if(wrap_flag)
839 {
840 /*
841 * If the highlighted cell is an edge cell, also
842 * highlight the corresponding cells on opposite
843 * edges. This will make it easier to work with large
844 * wrapped grids.
845 */
846 if(col == 0)
847 fill_arena_cell(wid,boardw - 1,row,c_edgematch);
848 else
849 if(col == boardw - 1)
850 fill_arena_cell(wid,0,row,c_edgematch);
851
852 if(row == 0)
853 fill_arena_cell(wid,col,boardh - 1,c_edgematch);
854 else
855 if(row == boardh - 1)
856 fill_arena_cell(wid,col,0,c_edgematch);
857 }
858 }
859
860 //draw in tiles
861 for (i=0; i<boardw; i++) {
862 for (j=0; j<boardh; j++) {
863 if (board[i][j]) {
864 draw_tile(wid, i, j);
865 }
866 }
867 }
868 //draw server
869 if (game_won) c = c_serverwon;
870 else c = c_server;
871
872 rect.x = padding + border + (cellw + border) * sourcex;
873 rect.y = padding + border + (cellh + border) * sourceytop;
874
875 rect.x += 5;
876 rect.y += 5;
877 rect.w = cellw - 10;
878 rect.h = cellh - 5;
879 widget_fillrect(wid, &rect, c);
880
881 rect.y = padding + border + (cellh + border) * sourceybottom;
882 widget_fillrect(wid, &rect, c);
883
884 //victory animation
885 if (game_won) {
886 animate_pulse(wid);
887 }
888 }
889
read_field(FILE * fp)890 char* read_field(FILE *fp)
891 {
892 char *r;
893 int i;
894 char c;
895
896 r = (char *) malloc(1024);
897 i = 0;
898
899 for(;;) {
900 c = getc(fp);
901
902 if (feof(fp)) {
903 free(r);
904 return NULL;
905 }
906
907 switch(c) {
908 case ',':
909 r[i] = 0;
910 return r;
911 case '\n':
912 r[i] = 0;
913 return r;
914 default:
915 r[i] = c;
916 i++;
917 break;
918 }
919 }
920 }
921
update_hsw()922 void update_hsw()
923 {
924 int i;
925 for (i=0; i<level_max; i++) {
926 if (hstable[i]->name) {
927 label_put_text(hsw[i]->name, hstable[i]->name);
928 } else {
929 label_put_text(hsw[i]->name, "None");
930 }
931 if (hstable[i]->time != -1) {
932 char s[80];
933
934 sprintf(s, "%d", hstable[i]->time);
935 label_put_text(hsw[i]->time, s);
936 } else {
937 label_put_text(hsw[i]->name, "None");
938 }
939 }
940 }
941
read_hstable()942 void read_hstable()
943 {
944 FILE *fp;
945 int i;
946
947 for (i=0; i<level_max; i++) {
948 hstable[i]->name = NULL;
949 hstable[i]->time = -1;
950 }
951
952 fp = fopen(config->hsfile, "r");
953 if (!fp) return;
954
955 for(i=0; i<level_max; i++) {
956 char *s;
957 s = read_field(fp);
958 if (!s) goto done;
959
960 hstable[i]->name = s;
961
962 s = read_field(fp);
963 if (!s) goto done;
964
965 hstable[i]->time = atoi(s);
966 free(s);
967 }
968
969 done:
970 fclose(fp);
971 }
972
write_hstable()973 void write_hstable()
974 {
975 FILE *fp;
976 int i;
977
978 fp = fopen(config->hsfile, "w");
979 if (!fp) return;
980
981 for(i=0; i<level_max; i++) {
982 fprintf(fp, "%s,%d\n", hstable[i]->name, hstable[i]->time);
983 }
984
985 fclose(fp);
986 }
987
988 int enkludge;
989
enter_name_open()990 void enter_name_open()
991 {
992 modalwindow = enter_name_window;
993 enkludge = 1;
994 }
995
enter_name_close()996 void enter_name_close()
997 {
998 modalwindow = NULL;
999 enkludge = 0;
1000
1001 player_name = tb_en1->text;
1002
1003 if (hstable[level]->name) {
1004 free(hstable[level]->name);
1005 }
1006 hstable[level]->name = clonestr(player_name);
1007 hstable[level]->time = second_count;
1008 update_hsw();
1009 write_hstable();
1010 }
1011
check_hs()1012 void check_hs()
1013 {
1014 if (hstable[level]->time == -1 || second_count < hstable[level]->time) {
1015 enter_name_open();
1016 }
1017 }
1018
init_tileimg(SDL_Surface * tileimg[64],int bgcolor)1019 void init_tileimg(SDL_Surface * tileimg[64],int bgcolor)
1020 {
1021 int i, j;
1022 SDL_PixelFormat *fmt = screen->format;
1023 SDL_Rect rect;
1024 int c;
1025
1026 pipex = cellw / 2 - pipet / 2;
1027 pipey = cellw / 2 - pipet / 2;
1028 pipew = cellw / 2 + pipet / 2;
1029 pipeh = cellh / 2 + pipet / 2;
1030
1031 SDL_Rect entirecell = (SDL_Rect){
1032 .x = 0,
1033 .y = 0,
1034 .w = cellw,
1035 .h = cellh
1036 };
1037
1038 for (i=0; i<64; i++) {
1039 tileimg[i] = SDL_CreateRGBSurface(0, cellw, cellh, fmt->BitsPerPixel,
1040 fmt->Rmask, fmt->Gmask, fmt->Bmask, fmt->Amask);
1041
1042 SDL_FillRect(tileimg[i], &entirecell, ctable[bgcolor]);
1043
1044 for (j=0; j<4; j++) {
1045 if ((i + 1) & (1 << j)) {
1046 switch (j) {
1047 case 0:
1048 rect.x = pipex;
1049 rect.y = 0;
1050 rect.w = pipet;
1051 rect.h = pipeh;
1052 break;
1053 case 1:
1054 rect.x = pipex;
1055 rect.y = pipey;
1056 rect.w = pipew;
1057 rect.h = pipet;
1058 break;
1059 case 2:
1060 rect.x = pipex;
1061 rect.y = pipey;
1062 rect.w = pipet;
1063 rect.h = pipeh;
1064 break;
1065 case 3:
1066 rect.x = 0;
1067 rect.y = pipey;
1068 rect.w = pipew;
1069 rect.h = pipet;
1070 break;
1071 }
1072 if (i >= 16) {
1073 c = ctable[c_on];
1074 } else c = ctable[c_off];
1075 SDL_FillRect(tileimg[i], &rect, c);
1076 }
1077 }
1078 }
1079
1080 for (i=1; i<32; i*=2) {
1081 rect.x = cellw / 2 - 2 * pipet;
1082 rect.y = cellh / 2 - 2 * pipet;
1083 rect.w = pipet * 4;
1084 rect.h = pipet * 4;
1085 rect.x++;
1086 rect.w-=2;
1087 rect.y++;
1088 rect.h-=2;
1089 /*
1090 SDL_FillRect(tileimg[i-1], &rect, ctable[c_off]);
1091 SDL_FillRect(tileimg[i-1+16], &rect, ctable[c_on]);
1092 rect.x++;
1093 rect.w-=2;
1094 rect.y++;
1095 rect.h-=2;
1096 */
1097 SDL_FillRect(tileimg[i-1], &rect, ctable[c_down]);
1098 SDL_FillRect(tileimg[i-1+16], &rect, ctable[c_up]);
1099 }
1100 }
1101
reset_move_count()1102 void reset_move_count()
1103 {
1104 move_count = 0;
1105 label_put_text(l_moves, "moves: 0");
1106 }
1107
increment_move_count()1108 void increment_move_count()
1109 {
1110 char s[80];
1111 move_count++;
1112 sprintf(s, "moves: %d", move_count);
1113 label_put_text(l_moves, s);
1114 }
1115
reset_time()1116 void reset_time()
1117 {
1118 label_put_text(l_time, "time: 0");
1119 }
1120
update_time()1121 void update_time()
1122 {
1123 static char s[80];
1124
1125 ms_count += tick - tick_old;
1126 while (ms_count >= 1000) {
1127 ms_count -= 1000;
1128 second_count++;
1129 sprintf(s, "time: %d", second_count);
1130 label_put_text(l_time, s);
1131 }
1132 }
1133
resize()1134 void resize()
1135 //position everything based on board size
1136 {
1137 int w, h;
1138
1139 sourcex = boardw / 2 - 1;
1140 sourceytop = boardh / 2;
1141 sourceybottom = sourceytop + 1;
1142
1143 w = cellw * boardw + (boardw + 1) * border + 2 * padding;
1144 h = cellh * boardh + (boardh + 1) * border + 2 * padding;
1145 widget_put_geometry(arena, 0, vsize, w, h);
1146 set_video(w, h + 2 * vsize);
1147 widget_put_geometry(root, 0, 0, w, h + 2 * vsize);
1148 widget_put_geometry(menu, 0, 0, w, vsize);
1149 menubar_auto_layout(menu);
1150 widget_put_geometry(statusbar, 0, h + vsize, w, vsize);
1151
1152 widget_put_geometry(l_moves, 8, h + vsize, 64, vsize);
1153 widget_put_geometry(l_time, w - 48, h + vsize, 64, vsize);
1154
1155 widget_put_geometry((widget_ptr) about_window,
1156 w/2 - 50, h/2 - 50, 100, 100);
1157 widget_put_geometry((widget_ptr) l_about1, 10, 10, 60, vsize);
1158 widget_put_geometry((widget_ptr) l_about2, 10, 30, 60, vsize);
1159 widget_put_geometry((widget_ptr) b_about1, 30, 80, 30, vsize);
1160
1161 /* vertical sizes and positions for the high score window */
1162 int const hslabely = 5;
1163 int const hslabelheight = vsize;
1164 int const hslisty = hslabely + hslabelheight + 8;
1165 int const hslisteachheight = vsize;
1166 int const hslistheight = hslisteachheight * level_max;
1167 int const hsoky = hslisty + hslistheight + 8;
1168 int const hsokheight = vsize;
1169 int const hswindowheight = hsoky + hsokheight + 5;
1170
1171 widget_put_geometry((widget_ptr) hs_window,
1172 w/2 - 75, h/2 - 60, 170, hswindowheight);
1173 widget_put_geometry((widget_ptr) l_hs1, 10, hslabely, 60, hslabelheight);
1174 widget_put_geometry((widget_ptr) b_hs1, 100, hsoky, 30, hsokheight);
1175
1176 {
1177 int i;
1178 for (i=0; i<level_max; i++) {
1179 int y = hslisty + (hslisteachheight * i);
1180 widget_put_geometry((widget_ptr) hsw[i]->level,
1181 10, y, 20, hslisteachheight);
1182 widget_put_geometry((widget_ptr) hsw[i]->time,
1183 60, y, 20, hslisteachheight);
1184 widget_put_geometry((widget_ptr) hsw[i]->name,
1185 90, y, 20, hslisteachheight);
1186 }
1187 }
1188
1189 widget_put_geometry((widget_ptr) enter_name_window,
1190 10, h/2 - 30, w - 20, 67);
1191 widget_put_geometry((widget_ptr) l_en1, 10, 0, 60, vsize);
1192 widget_put_geometry((widget_ptr) tb_en1, 5, vsize + 5, w - 30, vsize);
1193 widget_put_geometry((widget_ptr) b_en1, w - 60, 45, 30, vsize);
1194
1195 ((widget_ptr) root)->computexy((widget_ptr) root);
1196 ((widget_ptr) about_window)->computexy((widget_ptr) about_window);
1197 ((widget_ptr) hs_window)->computexy((widget_ptr) hs_window);
1198 ((widget_ptr) enter_name_window)->computexy((widget_ptr) enter_name_window);
1199 }
1200
new_game()1201 void new_game()
1202 {
1203 char s[BUFSIZ];
1204 strcpy(s,"NetWalk - ");
1205 strcat(s,level_name[level]);
1206 SDL_WM_SetCaption(s,s);
1207
1208 switch(level) {
1209 case level_easy:
1210 boardw = 5; boardh = 5;
1211 wrap_flag = 0;
1212 no_fourway = 0;
1213 break;
1214 case level_medium:
1215 boardw = 10; boardh = 9;
1216 wrap_flag = 0;
1217 no_fourway = 0;
1218 break;
1219 case level_hard:
1220 boardw = 10; boardh = 9;
1221 wrap_flag = 1;
1222 no_fourway = 1;
1223 break;
1224 case level_veryhard:
1225 boardw = 20; boardh = 18;
1226 wrap_flag = 1;
1227 no_fourway = 1;
1228 break;
1229 case level_giant:
1230 boardw = 50; boardh = 50;
1231 wrap_flag = 0;
1232 no_fourway = 1;
1233 break;
1234 case level_absurd:
1235 boardw = 50; boardh = 50;
1236 wrap_flag = 1;
1237 no_fourway = 1;
1238 break;
1239 default:
1240 break;
1241 }
1242 resize();
1243 srand(time(NULL));
1244 generate_maze();
1245 clear_flags();
1246 scramble();
1247 check_live();
1248 reset_move_count();
1249 reset_time();
1250 ms_count = 0;
1251 tick = SDL_GetTicks();
1252 second_count = 0;
1253 }
1254
handle_mousebuttonup(SDL_Event * event)1255 void handle_mousebuttonup(SDL_Event *event)
1256 {
1257 int x = event->button.x;
1258 int y = event->button.y;
1259 if (openedmenu) {
1260 int i;
1261 menuitem_ptr it;
1262 menu_ptr m;
1263
1264 m = openedmenu->submenu;
1265 for (i=0; i<m->item_count; i++) {
1266 it = m->item_list[i];
1267 if (in_widget((widget_ptr) it, x, y)) {
1268 widget_raise_signal((widget_ptr) it, signal_activate);
1269 break;
1270 }
1271 }
1272 openedmenu = NULL;
1273
1274 return;
1275 } else if (state == state_button) {
1276 state = state_game;
1277 if (in_widget(button_selection, x, y)) {
1278 widget_raise_signal(button_selection, signal_activate);
1279 return;
1280 }
1281 }
1282 }
1283
handle_click(int button,int x,int y)1284 void handle_click(int button, int x, int y)
1285 {
1286 widget_ptr wid;
1287
1288 if (modalwindow) {
1289 wid = (widget_ptr) modalwindow;
1290 if (in_widget(wid, x, y) && (wid->handle_click)) {
1291 wid->handle_click(wid, button, x, y);
1292 }
1293 return;
1294 }
1295
1296 wid = (widget_ptr) root;
1297 wid->handle_click(wid, button, x, y);
1298 }
1299
arena_handle_click(widget_ptr p,int button,int x,int y)1300 void arena_handle_click(widget_ptr p, int button, int x, int y)
1301 {
1302 int i, j;
1303 int d;
1304
1305 if (state != state_game) return;
1306
1307 i = (x - padding - border) / (cellw + border);
1308 j = (y - padding - border) / (cellh + border);
1309 if (i >= boardw || j >= boardh) return;
1310
1311 if (game_won) {
1312 if (i == sourcex && (j == sourceytop || j == sourceybottom)) {
1313 new_pulse(sourcex, sourceybottom, -1);
1314 new_pulse(sourcex, sourceytop, -1);
1315 } else {
1316 new_pulse(i, j, -1);
1317 }
1318 return;
1319 }
1320
1321 //temporarily merge server squares
1322 board[sourcex][sourceybottom] |= board[sourcex][sourceytop] & 1;
1323 if (i == sourcex && j == sourceytop) {
1324 j = sourceybottom;
1325 }
1326 d = board[i][j] & 15;
1327 switch(button) {
1328 case SDL_BUTTON_LEFT:
1329 d = rotatecw(d, 3);
1330 increment_move_count();
1331 break;
1332 case SDL_BUTTON_RIGHT:
1333 d = rotatecw(d, 1);
1334 increment_move_count();
1335 break;
1336 }
1337 board[i][j] &= ~15;
1338 board[i][j] += d;
1339
1340 board[sourcex][sourceytop] &= ~1;
1341 board[sourcex][sourceytop] |= board[sourcex][sourceybottom] & 1;
1342 board[sourcex][sourceybottom] &= ~1;
1343
1344 if(button == SDL_BUTTON_MIDDLE)
1345 flags[i][j] ^= 0x1;
1346
1347 check_live();
1348 if (game_won) {
1349 pulse_count = 0;
1350
1351 check_hs();
1352 }
1353 }
1354
quit()1355 void quit()
1356 {
1357 state = state_quit;
1358 }
1359
quit_menu(widget_ptr w,void * data)1360 void quit_menu(widget_ptr w, void *data)
1361 {
1362 quit();
1363 }
1364
new_game_menu(widget_ptr w,void * data)1365 void new_game_menu(widget_ptr w, void *data)
1366 {
1367 new_game();
1368 }
1369
about_open(widget_ptr w,void * data)1370 void about_open(widget_ptr w, void *data)
1371 {
1372 modalwindow = about_window;
1373 }
1374
about_close(widget_ptr w,void * data)1375 void about_close(widget_ptr w, void *data)
1376 {
1377 modalwindow = NULL;
1378 }
1379
hs_open(widget_ptr w,void * data)1380 void hs_open(widget_ptr w, void *data)
1381 {
1382 modalwindow = hs_window;
1383 }
1384
hs_close(widget_ptr w,void * data)1385 void hs_close(widget_ptr w, void *data)
1386 {
1387 modalwindow = NULL;
1388 }
1389
set_level(widget_ptr w,void * data)1390 void set_level(widget_ptr w, void *data)
1391 {
1392 level = (int) data;
1393 new_game();
1394 }
1395
handle_key(int key,int mod)1396 void handle_key(int key, int mod)
1397 {
1398 if (openedmenu) {
1399 switch(key) {
1400 case SDLK_ESCAPE:
1401 openedmenu = NULL;
1402 }
1403 return;
1404 }
1405
1406 if (enkludge) {
1407 switch(key) {
1408 case SDLK_LEFT:
1409 textbox_left(tb_en1);
1410 break;
1411 case SDLK_RIGHT:
1412 textbox_right(tb_en1);
1413 break;
1414 case SDLK_DELETE:
1415 textbox_delete(tb_en1);
1416 break;
1417 case SDLK_BACKSPACE:
1418 textbox_backspace(tb_en1);
1419 break;
1420 default:
1421 if (key < 256 && key >= 32) {
1422 if (mod & KMOD_SHIFT) {
1423 textbox_insert(tb_en1, shifttable[key]);
1424 } else {
1425 textbox_insert(tb_en1, key);
1426 }
1427 }
1428 break;
1429 }
1430 return;
1431 }
1432
1433 switch(key) {
1434 case SDLK_d:
1435 enter_name_open();
1436 break;
1437 case SDLK_ESCAPE:
1438 case SDLK_q:
1439 quit();
1440 break;
1441 case SDLK_F2:
1442 new_game();
1443 break;
1444 }
1445 }
1446
update_screen()1447 void update_screen()
1448 {
1449 SDL_FillRect(screen, NULL, 0);
1450 widget_update((widget_ptr) root);
1451 if (openedmenu) {
1452 int i;
1453 menuitem_ptr it;
1454
1455 for (i=0; i<menu->item_count; i++) {
1456 it = menu->item_list[i];
1457 if (in_widget((widget_ptr) it, lastmousex, lastmousey)) {
1458 open_submenu((widget_ptr) it, NULL);
1459 }
1460 }
1461 menu_update(openedmenu->submenu);
1462 }
1463 if (modalwindow) {
1464 widget_update((widget_ptr) modalwindow);
1465 }
1466 SDL_Flip(screen);
1467 }
1468
window_update(widget_ptr p)1469 void window_update(widget_ptr p)
1470 {
1471 window_ptr w = (window_ptr) p;
1472 widget_ptr wid;
1473 int i;
1474 SDL_Rect dst;
1475
1476 if (p != (widget_ptr) root) {
1477 dst.x = -1;
1478 dst.y = -1;
1479 dst.w = p->w + 2;
1480 dst.h = p->h + 2;
1481 widget_fillrect(p, &dst, c_windowborder);
1482 widget_fill(p, c_background);
1483 }
1484
1485 for (i=0; i<w->widget_count; i++) {
1486 wid = w->widget_list[i];
1487 widget_update(wid);
1488 }
1489 }
1490
window_handle_click(widget_ptr p,int button,int x,int y)1491 void window_handle_click(widget_ptr p, int button, int x, int y)
1492 {
1493 widget_ptr wid;
1494 window_ptr window = (window_ptr) p;
1495 int i;
1496
1497 for (i=0; i<window->widget_count; i++) {
1498 wid = window->widget_list[i];
1499 if (in_widget(wid, x, y) && (wid->handle_click)) {
1500 wid->handle_click(wid, button, x - wid->x, y - wid->y);
1501 return;
1502 }
1503 }
1504 }
1505
window_add_widget(window_ptr r,void * p)1506 void window_add_widget(window_ptr r, void *p)
1507 {
1508 widget_ptr wid = (widget_ptr) p;
1509 r->widget_list[r->widget_count] = wid;
1510 r->widget_count++;
1511 wid->parent = (widget_ptr) r;
1512 wid->x += r->widget.x;
1513 wid->y += r->widget.y;
1514 }
1515
window_computexy(widget_ptr wid)1516 void window_computexy(widget_ptr wid)
1517 {
1518 int i;
1519 window_ptr w = (window_ptr) wid;
1520
1521 widget_computexy(wid);
1522 for (i=0; i<w->widget_count; i++) {
1523 w->widget_list[i]->computexy(w->widget_list[i]);
1524 }
1525 }
1526
window_init(window_ptr w)1527 void window_init(window_ptr w)
1528 {
1529 widget_init((widget_ptr) w);
1530 w->widget_count = 0;
1531 w->widget.update = window_update;
1532 w->widget.handle_click = window_handle_click;
1533 w->widget.computexy = window_computexy;
1534 }
1535
add_shiftstring(char * s1,char * s2)1536 static void add_shiftstring(char *s1, char *s2)
1537 {
1538 int i;
1539
1540 for (i=0; i<strlen(s1); i++) {
1541 shifttable[(int) s1[i]] = s2[i];
1542 }
1543 }
1544
main(int argc,char * argv[])1545 int main(int argc, char *argv[])
1546 {
1547 SDL_Event event;
1548
1549 //setup names
1550 level_name[level_easy] = "Newbie";
1551 level_name[level_medium] = "Normal";
1552 level_name[level_hard] = "Nerd";
1553 level_name[level_veryhard] = "Nutcase";
1554 level_name[level_giant] = "Nonsense";
1555 level_name[level_absurd] = "No Sleep";
1556
1557 //setup shifttable
1558 {
1559 int i;
1560
1561 for (i=0; i<256; i++) shifttable[i] = i;
1562
1563 for (i='a'; i<='z'; i++) {
1564 shifttable[i] = i - 32;
1565 }
1566
1567 add_shiftstring("1234567890-=", "!@#$%^&*()_+");
1568 add_shiftstring("[]\\;',./`", "{}|:\"<>?~");
1569 }
1570
1571 config_load(config);
1572 read_hstable();
1573 init();
1574
1575 init_rgbtable();
1576
1577 font = TTF_OpenFont(config->fontname, config->fontsize);
1578 if (!font) {
1579 fprintf(stderr, "error loading font %s\n", config->fontname);
1580 exit(1);
1581 }
1582
1583 window_init(root);
1584
1585 //need to set video mode here to initialize colour table
1586 set_video(100, 100);
1587
1588 //setup enter name box
1589 {
1590 window_init(enter_name_window);
1591
1592 label_init(l_en1);
1593 label_put_text(l_en1, "Enter name:");
1594 window_add_widget(enter_name_window, l_en1);
1595
1596 textbox_init(tb_en1);
1597 textbox_put_text(tb_en1, "Anonymous");
1598 window_add_widget(enter_name_window, tb_en1);
1599
1600 button_init(b_en1);
1601 button_put_text(b_en1, "Ok");
1602 window_add_widget(enter_name_window, b_en1);
1603 widget_put_handler((widget_ptr) b_en1, enter_name_close, signal_activate);
1604 }
1605
1606 //setup the "arena": where the action is
1607 {
1608 widget_init((widget_ptr) arena);
1609 arena->widget.update = arena_update;
1610 arena->widget.handle_click = arena_handle_click;
1611 window_add_widget(root, arena);
1612 }
1613
1614 //status bar: mainly for showing the time
1615 {
1616 widget_init((widget_ptr) statusbar);
1617 statusbar->update = statusbar_update;
1618 window_add_widget(root, statusbar);
1619
1620 //setup moves and time
1621 label_init(l_moves);
1622 if (config->showmoves) {
1623 window_add_widget(root, l_moves);
1624 }
1625
1626 label_init(l_time);
1627 window_add_widget(root, l_time);
1628 }
1629
1630 //setup the menus
1631 {
1632 menuitem_t it1, it2;
1633 menuitem_ptr it;
1634 menu_t m1, m2;
1635
1636 int i;
1637
1638 menubar_init(menu);
1639 window_add_widget(root, menu);
1640 menuitem_init(it1);
1641 menuitem_put_text(it1, "Game");
1642 menubar_add_item(menu, it1);
1643 menuitem_init(it2);
1644 menuitem_put_text(it2, "Help");
1645 menubar_add_item(menu, it2);
1646
1647 menu_init(m1);
1648
1649 it = menuitem_new();
1650 menuitem_put_text(it, "New game");
1651 widget_put_handler((widget_ptr) it, new_game_menu, signal_activate);
1652 menu_add_item(m1, it);
1653
1654 for (i=0; i<level_max; i++) {
1655 it = menuitem_new();
1656 menuitem_put_text(it, level_name[i]);
1657 widget_put_handler_data((widget_ptr) it,
1658 set_level, (void *) i, signal_activate);
1659 menu_add_item(m1, it);
1660 }
1661 it = menuitem_new();
1662 menuitem_put_text(it, "High Scores");
1663 widget_put_handler((widget_ptr) it, hs_open, signal_activate);
1664 menu_add_item(m1, it);
1665 it = menuitem_new();
1666 menuitem_put_text(it, "Quit");
1667 widget_put_handler((widget_ptr) it, quit_menu, signal_activate);
1668 menu_add_item(m1, it);
1669
1670 menuitem_set_submenu(it1, m1);
1671
1672 menu_init(m2);
1673
1674 it = menuitem_new();
1675 menuitem_put_text(it, "About");
1676 widget_put_handler((widget_ptr) it, about_open, signal_activate);
1677 menu_add_item(m2, it);
1678
1679 menuitem_set_submenu(it2, m2);
1680 }
1681
1682 //setup about box
1683 {
1684 window_init(about_window);
1685
1686 label_init(l_about1);
1687 label_put_text(l_about1, "NetWalk " VERSION_STRING);
1688 window_add_widget(about_window, l_about1);
1689
1690 label_init(l_about2);
1691 label_put_text(l_about2, "Ben Lynn");
1692 window_add_widget(about_window, l_about2);
1693
1694 button_init(b_about1);
1695 button_put_text(b_about1, "Ok");
1696 window_add_widget(about_window, b_about1);
1697 widget_put_handler((widget_ptr) b_about1, about_close, signal_activate);
1698 }
1699
1700 //setup hiscores box
1701 {
1702 int i;
1703 window_init(hs_window);
1704
1705 label_init(l_hs1);
1706 label_put_text(l_hs1, "High Scores");
1707 window_add_widget(hs_window, l_hs1);
1708
1709 button_init(b_hs1);
1710 button_put_text(b_hs1, "Ok");
1711 window_add_widget(hs_window, b_hs1);
1712 widget_put_handler((widget_ptr) b_hs1, hs_close, signal_activate);
1713
1714 for (i=0; i<level_max; i++) {
1715 label_init(hsw[i]->level);
1716 label_put_text(hsw[i]->level, level_name[i]);
1717 window_add_widget(hs_window, hsw[i]->level);
1718 label_init(hsw[i]->name);
1719 window_add_widget(hs_window, hsw[i]->name);
1720 label_init(hsw[i]->time);
1721 window_add_widget(hs_window, hsw[i]->time);
1722 }
1723 }
1724
1725 resize();
1726
1727 update_hsw();
1728
1729 init_tileimg(unmarked_tileimg,c_unmarkedbg);
1730 init_tileimg(marked_tileimg,c_markedbg);
1731 new_game();
1732
1733 while (state != state_quit && !interrupted) {
1734 tick_old = tick;
1735 tick = SDL_GetTicks();
1736 if (!game_won) {
1737 update_time();
1738 }
1739 SDL_GetMouseState(&lastmousex, &lastmousey);
1740 while (SDL_PollEvent(&event)) {
1741 switch (event.type) {
1742 case SDL_KEYDOWN:
1743 handle_key(event.key.keysym.sym, SDL_GetModState());
1744 break;
1745 case SDL_MOUSEBUTTONDOWN:
1746 handle_click(event.button.button, event.button.x, event.button.y);
1747 break;
1748 case SDL_MOUSEBUTTONUP:
1749 handle_mousebuttonup(&event);
1750 break;
1751 case SDL_QUIT:
1752 quit();
1753 break;
1754 }
1755 }
1756 update_screen();
1757 SDL_Delay(20);
1758 }
1759 return 0;
1760 }
1761