1 /* NetWalk main program
5 Copyright (C) 2004 Benjamin Lynn (blynn@cs.stanford.edu)
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.
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.
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.
27 #include <sys/types.h> //for opendir et al.
45 char *config_file
= "config";
47 static int interrupted
= 0;
80 int show_moves_flag
= 0;
87 typedef struct config_s
*config_ptr
;
88 typedef struct config_s config_t
[1];
94 typedef struct hsentry_s
*hsentry_ptr
;
95 typedef struct hsentry_s hsentry_t
[1];
97 hsentry_t hstable
[level_max
];
98 char *level_name
[level_max
];
100 //TODO use this somehow
105 typedef struct gameparm_s
*gameparm_ptr
;
106 typedef struct gameparm_s gameparm_t
[1];
112 int lastmousex
, lastmousey
;
119 struct widget_s widget
;
123 typedef struct button_s button_t
[1];
124 typedef struct button_s
*button_ptr
;
127 struct widget_s widget
;
131 typedef struct label_s label_t
[1];
132 typedef struct label_s
*label_ptr
;
135 struct widget_s widget
;
140 typedef struct textbox_s textbox_t
[1];
141 typedef struct textbox_s
*textbox_ptr
;
144 struct widget_s widget
;
146 typedef struct arena_s arena_t
[1];
147 typedef struct arena_s
*arena_ptr
;
150 struct widget_s widget
;
153 struct menu_s
*submenu
;
155 typedef struct menuitem_s menuitem_t
[1];
156 typedef struct menuitem_s
*menuitem_ptr
;
159 struct widget_s widget
;
160 //TODO: replace array with list
161 menuitem_ptr item_list
[64];
164 typedef struct menu_s menu_t
[1];
165 typedef struct menu_s
*menu_ptr
;
168 struct widget_s widget
;
169 //TODO: replace array with list
170 menuitem_ptr item_list
[64];
173 typedef struct menubar_s menubar_t
[1];
174 typedef struct menubar_s
*menubar_ptr
;
177 struct widget_s widget
;
178 //TODO: replace array with list
179 struct widget_s
*widget_list
[64];
183 typedef struct window_s window_t
[1];
184 typedef struct window_s
*window_ptr
;
191 typedef struct hsw_s
*hsw_ptr
;
192 typedef struct hsw_s hsw_t
[1];
194 hsw_t hsw
[level_max
];
201 menuitem_ptr openedmenu
;
202 window_ptr modalwindow
;
203 window_t about_window
;
205 window_t enter_name_window
;
218 char *clonestr(char *s
)
220 char *res
= malloc(sizeof(char) * strlen(s
) + 1);
225 SDL_Surface
*font_render(char *s
, int c
)
227 return TTF_RenderText_Solid(font
, s
, rgbtable
[c
]);
230 void statusbar_update(widget_ptr w
)
232 widget_lowered_background(w
);
235 void menu_init(menu_ptr m
)
237 widget_init((widget_ptr
) m
);
241 void menu_update(menu_ptr m
)
247 widget_fill((widget_ptr
) m
, c_background
);
248 for (i
=0; i
<m
->item_count
; i
++) {
249 it
= m
->item_list
[i
];
250 if (in_widget((widget_ptr
) it
, lastmousex
, lastmousey
)) {
253 rect
.w
= ((widget_ptr
) it
)->w
- 4;
255 widget_fillrect((widget_ptr
) m
, &rect
, c_menubg
);
258 rect
.y
= vsize
* i
+ 4;
259 widget_blit((widget_ptr
) m
, it
->img
, NULL
, &rect
);
263 void menu_add_item(menu_ptr m
, menuitem_ptr it
)
265 m
->item_list
[m
->item_count
] = it
;
269 void menuitem_init(menuitem_ptr m
)
271 widget_init((widget_ptr
) m
);
277 menuitem_ptr
menuitem_new()
281 it
= (menuitem_ptr
) malloc(sizeof(menuitem_t
));
287 void menuitem_put_text(menuitem_ptr m
, char *s
)
292 if (m
->img
) SDL_FreeSurface(m
->img
);
293 tmp
= font_render(s
, c_text
);
294 m
->img
= SDL_DisplayFormat(tmp
);
295 SDL_FreeSurface(tmp
);
298 void open_submenu(widget_ptr p
, void *data
)
304 openedmenu
= (menuitem_ptr
) p
;
305 menu_ptr m
= openedmenu
->submenu
;
307 for (i
=0; i
<m
->item_count
; i
++) {
308 it
= m
->item_list
[i
];
309 if (w
< it
->img
->w
) w
= it
->img
->w
;
313 m
->widget
.x
= m
->widget
.parent
->x
;
314 m
->widget
.y
= m
->widget
.parent
->y
+ vsize
;
317 m
->widget
.h
= vsize
* m
->item_count
+ 1;
319 for (i
=0; i
<m
->item_count
; i
++) {
320 it
= m
->item_list
[i
];
321 it
->widget
.x
= 0 + m
->widget
.x
;
322 it
->widget
.y
= vsize
* i
+ 4 + m
->widget
.y
;
324 it
->widget
.h
= vsize
;
328 void menuitem_set_submenu(menuitem_ptr it
, menu_ptr m
)
331 //it->widget.signal_handler[signal_activate] = open_submenu;
332 widget_put_handler((widget_ptr
) it
, open_submenu
, signal_activate
);
333 m
->widget
.parent
= (widget_ptr
) it
;
336 void menubar_update(widget_ptr wid
)
339 menubar_ptr m
= (menubar_ptr
) wid
;
343 widget_raised_background(wid
);
345 for (i
=0; i
<m
->item_count
; i
++) {
346 it
= m
->item_list
[i
];
347 if (it
== openedmenu
) {
348 dst
.x
= it
->widget
.x
+ 2;
349 dst
.y
= it
->widget
.y
+ 2;
350 dst
.w
= it
->widget
.w
- 4;
352 widget_fillrect(wid
, &dst
, c_menubg
);
355 dst
.x
= it
->widget
.x
+ 5;
356 dst
.y
= it
->widget
.y
+ 2;
357 widget_blit(m
, it
->img
, NULL
, &dst
);
362 void menubar_handle_click(widget_ptr p
, int button
, int x
, int y
)
365 menubar_ptr m
= (menubar_ptr
) p
;
368 for (i
=0; i
<m
->item_count
; i
++) {
369 it
= m
->item_list
[i
];
370 if (in_widget((widget_ptr
) it
, x
, y
)) {
371 widget_raise_signal((widget_ptr
) it
, signal_activate
);
377 void menubar_init(menubar_ptr m
)
379 widget_init((widget_ptr
) m
);
380 m
->widget
.update
= menubar_update
;
382 m
->widget
.handle_click
= menubar_handle_click
;
385 void menubar_add_item(menubar_ptr m
, menuitem_ptr it
)
387 m
->item_list
[m
->item_count
] = it
;
389 it
->widget
.parent
= (widget_ptr
) m
;
392 void menubar_auto_layout(menubar_ptr m
)
399 for (i
=0; i
<m
->item_count
; i
++) {
400 it
= m
->item_list
[i
];
404 it
->widget
.w
= it
->img
->w
+ 10;
405 it
->widget
.h
= it
->img
->h
;
406 x
+= it
->img
->w
+ 10;
411 void label_update(widget_ptr p
)
414 label_ptr l
= (label_ptr
) p
;
419 widget_blit(l
, l
->img
, NULL
, &dst
);
423 void label_init(label_ptr l
)
425 widget_init((widget_ptr
) l
);
428 l
->widget
.update
= label_update
;
431 void label_put_text(label_ptr l
, char *s
)
435 if (l
->img
) SDL_FreeSurface(l
->img
);
436 if (l
->text
) free(l
->text
);
437 l
->text
= clonestr(s
);
438 tmp
= font_render(s
, c_text
);
439 l
->img
= SDL_DisplayFormat(tmp
);
440 SDL_FreeSurface(tmp
);
443 void textbox_update_img(textbox_ptr tb
)
447 if (tb
->img
) SDL_FreeSurface(tb
->img
);
448 tmp
= font_render(tb
->text
, c_text
);
450 tb
->img
= SDL_DisplayFormat(tmp
);
451 SDL_FreeSurface(tmp
);
457 void textbox_left(textbox_ptr tb
)
459 if (tb
->i
> 0) tb
->i
--;
462 void textbox_right(textbox_ptr tb
)
464 if (tb
->i
< strlen(tb
->text
)) tb
->i
++;
467 void textbox_delete(textbox_ptr tb
)
472 textbox_update_img(tb
);
476 void textbox_backspace(textbox_ptr tb
)
478 char *s
= &tb
->text
[tb
->i
];
480 memmove(s
- 1, s
, strlen(s
) + 1);
482 textbox_update_img(tb
);
486 void textbox_insert(textbox_ptr tb
, char c
)
488 char *s
= &tb
->text
[tb
->i
];
489 memmove(s
+ 1, s
, strlen(s
) + 1);
492 textbox_update_img(tb
);
495 void textbox_update(widget_ptr p
)
498 textbox_ptr tb
= (textbox_ptr
) p
;
504 widget_fillrect(p
, &dst
, c_text
);
509 widget_fillrect(p
, &dst
, c_canvas
);
514 widget_blit(tb
, tb
->img
, NULL
, &dst
);
521 strncpy(s
, tb
->text
, tb
->i
);
523 TTF_SizeText(font
, s
, &w
, &h
);
529 widget_fillrect(p
, &dst
, c_text
);
533 void textbox_init(textbox_ptr l
)
535 widget_init((widget_ptr
) l
);
537 l
->widget
.update
= textbox_update
;
540 void textbox_put_text(textbox_ptr tb
, char *s
)
544 textbox_update_img(tb
);
547 static widget_ptr button_selection
;
549 void button_handle_click(widget_ptr p
, int button
, int x
, int y
)
551 state
= state_button
;
552 button_selection
= p
;
555 void button_update(widget_ptr p
)
558 label_ptr l
= (label_ptr
) p
;
560 if (state
== state_button
&& button_selection
== p
561 && in_widget(p
, lastmousex
, lastmousey
)) {
562 widget_lowered_background(p
);
564 widget_raised_background(p
);
569 widget_blit(l
, l
->img
, NULL
, &dst
);
573 void button_init(button_ptr b
)
575 widget_init((widget_ptr
) b
);
578 b
->widget
.update
= button_update
;
579 b
->widget
.handle_click
= button_handle_click
;
582 void button_put_text(button_ptr b
, char *s
)
586 if (b
->img
) SDL_FreeSurface(b
->img
);
587 if (b
->text
) free(b
->text
);
588 b
->text
= clonestr(s
);
589 tmp
= font_render(s
, c_text
);
590 b
->img
= SDL_DisplayFormat(tmp
);
591 SDL_FreeSurface(tmp
);
594 void set_video(int w
, int h
)
597 flags
= SDL_DOUBLEBUF
;
599 screen
= SDL_SetVideoMode(w
, h
, 0, flags
);
600 init_ctable(screen
->format
);
603 fprintf(stderr
, "Can't set video mode: %s\n", SDL_GetError());
607 //SDL_ShowCursor(SDL_DISABLE);
610 void set_interrupted(int i
)
619 signal(SIGINT
, set_interrupted
);
620 signal(SIGTERM
, set_interrupted
);
622 //if (SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO|SDL_INIT_TIMER) < 0) {
623 if (SDL_Init(SDL_INIT_VIDEO
|SDL_INIT_TIMER
) < 0) {
624 fprintf(stderr
, "Can't init SDL: %s\n", SDL_GetError());
630 fprintf(stderr
, "Can't init SDL_ttf\n");
635 SDL_WM_SetCaption("NetWalk", "NetWalk");
638 SDL_Surface
*tileimg
[64];
639 int level
= level_medium
;
649 void draw_tile(widget_ptr wid
, int i
, int j
)
654 rect
.x
= padding
+ border
+ i
* (cellw
+ border
);
655 rect
.y
= padding
+ border
+ j
* (cellh
+ border
);
657 index
= board
[i
][j
] - 1;
658 widget_blit(wid
, tileimg
[index
], NULL
, &rect
);
667 pulse_s pulse_list
[pulse_max
];
670 void new_pulse(int x
, int y
, int d
)
674 if (pulse_count
>= pulse_max
) return;
676 //stop incoming server pulses
677 if (x
== sourcex
&& (y
== sourceybottom
|| y
==sourceytop
) && d
!= -1) {
682 for (j
=0; j
<4; j
++) {
683 if ((j
!= d
) && (i
& (1 << j
))) {
684 pulse_list
[pulse_count
].x
= x
;
685 pulse_list
[pulse_count
].y
= y
;
686 pulse_list
[pulse_count
].dir
= j
;
687 pulse_list
[pulse_count
].tick
= tick
;
689 if (pulse_count
>= pulse_max
) return;
696 new_pulse(sourcex
, sourceybottom
, -1);
697 new_pulse(sourcex
, sourceytop
, -1);
700 void animate_pulse(widget_ptr wid
)
714 while (i
<pulse_count
) {
717 d
= pulse_list
[i
].dir
;
718 dt
= tick
- pulse_list
[i
].tick
;
721 memmove(&pulse_list
[i
], &pulse_list
[i
+1], sizeof(pulse_s
) * (pulse_count
- i
));
723 add_dir(&x
, &y
, x
, y
, d
);
724 new_pulse(x
, y
, (d
+ 2) % 4);
727 if (dir
[d
].x
== -1 && 2 * dt
> speed
&& !x
) {
730 if (dir
[d
].x
== 1 && 2 * dt
> speed
&& x
== boardw
- 1) {
733 if (dir
[d
].y
== -1 && 2 * dt
> speed
&& !y
) {
736 if (dir
[d
].y
== 1 && 2 * dt
> speed
&& y
== boardh
- 1) {
740 rect
.x
= x
* (cellw
+ border
) + pipex
- 1;
741 rect
.x
+= dir
[d
].x
* (cellw
+ border
) * dt
/ speed
;
742 rect
.x
+= border
+ padding
;
744 rect
.y
= y
* (cellh
+ border
) + border
+ padding
;
745 rect
.y
+= dir
[d
].y
* (cellh
+ border
) * dt
/ speed
;
747 widget_fillrect(wid
, &rect
, c_pulse
);
753 void arena_update(widget_ptr wid
)
763 rect
.w
= cellw
* boardw
+ (boardw
+ 1) * border
;
766 if (game_won
) bc
= c_borderwon
;
769 for (i
=0; i
<=boardh
; i
++) {
770 widget_fillrect(wid
, &rect
, bc
);
771 rect
.y
+= cellh
+ border
;
776 rect
.h
= cellh
* boardh
+ (boardh
+ 1) * border
;
777 for (i
=0; i
<=boardw
; i
++) {
778 widget_fillrect(wid
, &rect
, bc
);
779 rect
.x
+= cellw
+ border
;
783 if (lastmousex
> wid
->x
&& lastmousey
> wid
->y
) {
784 i
= (lastmousex
- padding
- border
- wid
->x
) / (cellw
+ border
);
785 j
= (lastmousey
- padding
- border
- wid
->y
) / (cellh
+ border
);
786 if (i
< boardw
&& j
< boardh
) {
787 rect
.x
= (cellw
+ border
) * i
+ padding
;
788 rect
.y
= (cellh
+ border
) * j
+ padding
;
789 rect
.w
= cellw
+ 2 * border
;
790 rect
.h
= cellh
+ 2 * border
;
791 widget_fillrect(wid
, &rect
, c_highlight
);
796 for (i
=0; i
<boardw
; i
++) {
797 for (j
=0; j
<boardh
; j
++) {
799 draw_tile(wid
, i
, j
);
804 if (game_won
) c
= c_serverwon
;
807 rect
.x
= padding
+ border
+ (cellw
+ border
) * sourcex
;
808 rect
.y
= padding
+ border
+ (cellh
+ border
) * sourceytop
;
814 widget_fillrect(wid
, &rect
, c
);
816 rect
.y
= padding
+ border
+ (cellh
+ border
) * sourceybottom
;
817 widget_fillrect(wid
, &rect
, c
);
825 char* read_field(FILE *fp
)
831 r
= (char *) malloc(1024);
860 for (i
=0; i
<level_max
; i
++) {
861 if (hstable
[i
]->name
) {
862 label_put_text(hsw
[i
]->name
, hstable
[i
]->name
);
864 label_put_text(hsw
[i
]->name
, "None");
866 if (hstable
[i
]->time
!= -1) {
869 sprintf(s
, "%d", hstable
[i
]->time
);
870 label_put_text(hsw
[i
]->time
, s
);
872 label_put_text(hsw
[i
]->name
, "None");
882 for (i
=0; i
<level_max
; i
++) {
883 hstable
[i
]->name
= NULL
;
884 hstable
[i
]->time
= -1;
887 fp
= fopen(config
->hsfile
, "r");
890 for(i
=0; i
<level_max
; i
++) {
895 hstable
[i
]->name
= s
;
900 hstable
[i
]->time
= atoi(s
);
913 fp
= fopen(config
->hsfile
, "w");
916 for(i
=0; i
<level_max
; i
++) {
917 fprintf(fp
, "%s,%d\n", hstable
[i
]->name
, hstable
[i
]->time
);
925 void enter_name_open()
927 modalwindow
= enter_name_window
;
931 void enter_name_close()
936 player_name
= tb_en1
->text
;
938 if (hstable
[level
]->name
) {
939 free(hstable
[level
]->name
);
941 hstable
[level
]->name
= clonestr(player_name
);
942 hstable
[level
]->time
= second_count
;
949 if (hstable
[level
]->time
== -1 || second_count
< hstable
[level
]->time
) {
957 SDL_PixelFormat
*fmt
= screen
->format
;
961 pipex
= cellw
/ 2 - pipet
/ 2;
962 pipey
= cellw
/ 2 - pipet
/ 2;
963 pipew
= cellw
/ 2 + pipet
/ 2;
964 pipeh
= cellh
/ 2 + pipet
/ 2;
966 for (i
=0; i
<64; i
++) {
967 tileimg
[i
] = SDL_CreateRGBSurface(0, cellw
, cellh
, fmt
->BitsPerPixel
,
968 fmt
->Rmask
, fmt
->Gmask
, fmt
->Bmask
, fmt
->Amask
);
969 for (j
=0; j
<4; j
++) {
970 if ((i
+ 1) & (1 << j
)) {
999 } else c
= ctable
[c_off
];
1000 SDL_FillRect(tileimg
[i
], &rect
, c
);
1005 for (i
=1; i
<32; i
*=2) {
1006 rect
.x
= cellw
/ 2 - 2 * pipet
;
1007 rect
.y
= cellh
/ 2 - 2 * pipet
;
1015 SDL_FillRect(tileimg[i-1], &rect, ctable[c_off]);
1016 SDL_FillRect(tileimg[i-1+16], &rect, ctable[c_on]);
1022 SDL_FillRect(tileimg
[i
-1], &rect
, ctable
[c_down
]);
1023 SDL_FillRect(tileimg
[i
-1+16], &rect
, ctable
[c_up
]);
1027 void reset_move_count()
1030 label_put_text(l_moves
, "moves: 0");
1033 void increment_move_count()
1037 sprintf(s
, "moves: %d", move_count
);
1038 label_put_text(l_moves
, s
);
1043 label_put_text(l_time
, "time: 0");
1050 ms_count
+= tick
- tick_old
;
1051 while (ms_count
>= 1000) {
1054 sprintf(s
, "time: %d", second_count
);
1055 label_put_text(l_time
, s
);
1060 //position everything based on board size
1064 sourcex
= boardw
/ 2 - 1;
1065 sourceytop
= boardh
/ 2;
1066 sourceybottom
= sourceytop
+ 1;
1068 w
= cellw
* boardw
+ (boardw
+ 1) * border
+ 2 * padding
;
1069 h
= cellh
* boardh
+ (boardh
+ 1) * border
+ 2 * padding
;
1070 widget_put_geometry(arena
, 0, vsize
, w
, h
);
1071 set_video(w
, h
+ 2 * vsize
);
1072 widget_put_geometry(root
, 0, 0, w
, h
+ 2 * vsize
);
1073 widget_put_geometry(menu
, 0, 0, w
, vsize
);
1074 menubar_auto_layout(menu
);
1075 widget_put_geometry(statusbar
, 0, h
+ vsize
, w
, vsize
);
1077 widget_put_geometry(l_moves
, 8, h
+ vsize
, 64, vsize
);
1078 widget_put_geometry(l_time
, w
- 48, h
+ vsize
, 64, vsize
);
1080 widget_put_geometry((widget_ptr
) about_window
,
1081 w
/2 - 50, h
/2 - 50, 100, 100);
1082 widget_put_geometry((widget_ptr
) l_about1
, 10, 10, 60, vsize
);
1083 widget_put_geometry((widget_ptr
) l_about2
, 10, 30, 60, vsize
);
1084 widget_put_geometry((widget_ptr
) b_about1
, 30, 80, 30, vsize
);
1086 widget_put_geometry((widget_ptr
) hs_window
,
1087 w
/2 - 75, h
/2 - 60, 150, 120);
1088 widget_put_geometry((widget_ptr
) l_hs1
, 10, 5, 60, vsize
);
1089 widget_put_geometry((widget_ptr
) b_hs1
, 100, 100, 30, vsize
);
1093 for (i
=0; i
<level_max
; i
++) {
1094 int y
= vsize
* i
+ 8 + vsize
;
1095 widget_put_geometry((widget_ptr
) hsw
[i
]->level
, 10, y
, 20, vsize
);
1096 widget_put_geometry((widget_ptr
) hsw
[i
]->time
, 60, y
, 20, vsize
);
1097 widget_put_geometry((widget_ptr
) hsw
[i
]->name
, 90, y
, 20, vsize
);
1101 widget_put_geometry((widget_ptr
) enter_name_window
,
1102 10, h
/2 - 30, w
- 20, 67);
1103 widget_put_geometry((widget_ptr
) l_en1
, 10, 0, 60, vsize
);
1104 widget_put_geometry((widget_ptr
) tb_en1
, 5, vsize
+ 5, w
- 30, vsize
);
1105 widget_put_geometry((widget_ptr
) b_en1
, w
- 60, 45, 30, vsize
);
1107 ((widget_ptr
) root
)->computexy((widget_ptr
) root
);
1108 ((widget_ptr
) about_window
)->computexy((widget_ptr
) about_window
);
1109 ((widget_ptr
) hs_window
)->computexy((widget_ptr
) hs_window
);
1110 ((widget_ptr
) enter_name_window
)->computexy((widget_ptr
) enter_name_window
);
1117 boardw
= 5; boardh
= 5;
1122 boardw
= 10; boardh
= 9;
1127 boardw
= 10; boardh
= 9;
1131 case level_veryhard
:
1132 boardw
= 20; boardh
= 18;
1147 tick
= SDL_GetTicks();
1151 void handle_mousebuttonup(SDL_Event
*event
)
1153 int x
= event
->button
.x
;
1154 int y
= event
->button
.y
;
1160 m
= openedmenu
->submenu
;
1161 for (i
=0; i
<m
->item_count
; i
++) {
1162 it
= m
->item_list
[i
];
1163 if (in_widget((widget_ptr
) it
, x
, y
)) {
1164 widget_raise_signal((widget_ptr
) it
, signal_activate
);
1171 } else if (state
== state_button
) {
1173 if (in_widget(button_selection
, x
, y
)) {
1174 widget_raise_signal(button_selection
, signal_activate
);
1180 void handle_click(int button
, int x
, int y
)
1185 wid
= (widget_ptr
) modalwindow
;
1186 if (in_widget(wid
, x
, y
) && (wid
->handle_click
)) {
1187 wid
->handle_click(wid
, button
, x
, y
);
1192 wid
= (widget_ptr
) root
;
1193 wid
->handle_click(wid
, button
, x
, y
);
1196 void arena_handle_click(widget_ptr p
, int button
, int x
, int y
)
1201 if (state
!= state_game
) return;
1203 i
= (x
- padding
- border
) / (cellw
+ border
);
1204 j
= (y
- padding
- border
) / (cellh
+ border
);
1205 if (i
>= boardw
|| j
>= boardh
) return;
1208 if (i
== sourcex
&& (j
== sourceytop
|| j
== sourceybottom
)) {
1209 new_pulse(sourcex
, sourceybottom
, -1);
1210 new_pulse(sourcex
, sourceytop
, -1);
1212 new_pulse(i
, j
, -1);
1217 //temporarily merge server squares
1218 board
[sourcex
][sourceybottom
] |= board
[sourcex
][sourceytop
] & 1;
1219 if (i
== sourcex
&& j
== sourceytop
) {
1222 d
= board
[i
][j
] & 15;
1224 case SDL_BUTTON_LEFT
:
1226 increment_move_count();
1228 case SDL_BUTTON_RIGHT
:
1230 increment_move_count();
1236 board
[sourcex
][sourceytop
] &= ~1;
1237 board
[sourcex
][sourceytop
] |= board
[sourcex
][sourceybottom
] & 1;
1238 board
[sourcex
][sourceybottom
] &= ~1;
1253 void quit_menu(widget_ptr w
, void *data
)
1258 void new_game_menu(widget_ptr w
, void *data
)
1263 void about_open(widget_ptr w
, void *data
)
1265 modalwindow
= about_window
;
1268 void about_close(widget_ptr w
, void *data
)
1273 void hs_open(widget_ptr w
, void *data
)
1275 modalwindow
= hs_window
;
1278 void hs_close(widget_ptr w
, void *data
)
1283 void set_level(widget_ptr w
, void *data
)
1289 void handle_key(int key
, int mod
)
1302 textbox_left(tb_en1
);
1305 textbox_right(tb_en1
);
1308 textbox_delete(tb_en1
);
1310 case SDLK_BACKSPACE
:
1311 textbox_backspace(tb_en1
);
1314 if (key
< 256 && key
>= 32) {
1315 if (mod
& KMOD_SHIFT
) {
1316 textbox_insert(tb_en1
, shifttable
[key
]);
1318 textbox_insert(tb_en1
, key
);
1340 void update_screen()
1342 SDL_FillRect(screen
, NULL
, 0);
1343 widget_update((widget_ptr
) root
);
1348 for (i
=0; i
<menu
->item_count
; i
++) {
1349 it
= menu
->item_list
[i
];
1350 if (in_widget((widget_ptr
) it
, lastmousex
, lastmousey
)) {
1351 open_submenu((widget_ptr
) it
, NULL
);
1354 menu_update(openedmenu
->submenu
);
1357 widget_update((widget_ptr
) modalwindow
);
1362 void window_update(widget_ptr p
)
1364 window_ptr w
= (window_ptr
) p
;
1369 if (p
!= (widget_ptr
) root
) {
1374 widget_fillrect(p
, &dst
, c_windowborder
);
1375 widget_fill(p
, c_background
);
1378 for (i
=0; i
<w
->widget_count
; i
++) {
1379 wid
= w
->widget_list
[i
];
1384 void window_handle_click(widget_ptr p
, int button
, int x
, int y
)
1387 window_ptr window
= (window_ptr
) p
;
1390 for (i
=0; i
<window
->widget_count
; i
++) {
1391 wid
= window
->widget_list
[i
];
1392 if (in_widget(wid
, x
, y
) && (wid
->handle_click
)) {
1393 wid
->handle_click(wid
, button
, x
- wid
->x
, y
- wid
->y
);
1399 void window_add_widget(window_ptr r
, void *p
)
1401 widget_ptr wid
= (widget_ptr
) p
;
1402 r
->widget_list
[r
->widget_count
] = wid
;
1404 wid
->parent
= (widget_ptr
) r
;
1405 wid
->x
+= r
->widget
.x
;
1406 wid
->y
+= r
->widget
.y
;
1409 void window_computexy(widget_ptr wid
)
1412 window_ptr w
= (window_ptr
) wid
;
1414 widget_computexy(wid
);
1415 for (i
=0; i
<w
->widget_count
; i
++) {
1416 w
->widget_list
[i
]->computexy(w
->widget_list
[i
]);
1420 void window_init(window_ptr w
)
1422 widget_init((widget_ptr
) w
);
1423 w
->widget_count
= 0;
1424 w
->widget
.update
= window_update
;
1425 w
->widget
.handle_click
= window_handle_click
;
1426 w
->widget
.computexy
= window_computexy
;
1429 void parse_option(char *s1
, char *s2
)
1431 if (!strcmp(s1
, "showmoves")) {
1432 show_moves_flag
= atoi(s2
);
1434 if (!strcmp(s1
, "fontsize")) {
1435 config
->fontsize
= atoi(s2
);
1437 if (!strcmp(s1
, "font")) {
1438 config
->fontname
= clonestr(s2
);
1440 if (!strcmp(s1
, "hiscores")) {
1441 config
->hsfile
= clonestr(s2
);
1445 int is_whitespace(char c
)
1447 if (strchr(" \t\r\n", c
)) return -1;
1451 void skip_whitespace(FILE *fp
)
1456 if (feof(fp
)) return;
1457 if (!is_whitespace(c
)) {
1464 void read_word(char *s
, FILE *fp
)
1468 skip_whitespace(fp
);
1469 if (feof(fp
)) return;
1474 if (feof(fp
)) return;
1475 if (is_whitespace(c
)) {
1481 if (i
>= 128 - 1) break;
1486 void read_line(char *s
, FILE *fp
)
1493 if (feof(fp
)) return;
1495 //safest thing to do?
1504 if (i
>= 1024 - 1) break;
1513 fp
= fopen(config_file
, "r");
1515 fprintf(stderr
,"Can't open config file %s\n", config_file
);
1523 skip_whitespace(fp
);
1538 if (is_whitespace(s1
[i
])) {
1542 if (!s1
[i
] || !is_whitespace(s1
[i
])) {
1552 parse_option(s1
, s2
);
1558 void add_shiftstring(char *s1
, char *s2
)
1562 for (i
=0; i
<strlen(s1
); i
++) {
1563 shifttable
[(int) s1
[i
]] = s2
[i
];
1567 int main(int argc
, char *argv
[])
1572 level_name
[level_easy
] = "Newbie";
1573 level_name
[level_medium
] = "Normal";
1574 level_name
[level_hard
] = "Nerd";
1575 level_name
[level_veryhard
] = "Nutcase";
1581 for (i
=0; i
<256; i
++) shifttable
[i
] = i
;
1583 for (i
='a'; i
<='z'; i
++) {
1584 shifttable
[i
] = i
- 32;
1587 add_shiftstring("1234567890-=", "!@#$%^&*()_+");
1588 add_shiftstring("[]\\;',./`", "{}|:\"<>?~");
1597 font
= TTF_OpenFont(config
->fontname
, config
->fontsize
);
1599 fprintf(stderr
, "error loading font\n");
1605 //need to set video mode here to initialize colour table
1606 set_video(100, 100);
1608 //setup enter name box
1610 window_init(enter_name_window
);
1613 label_put_text(l_en1
, "Enter name:");
1614 window_add_widget(enter_name_window
, l_en1
);
1616 textbox_init(tb_en1
);
1617 textbox_put_text(tb_en1
, "Anonymous");
1618 window_add_widget(enter_name_window
, tb_en1
);
1621 button_put_text(b_en1
, "Ok");
1622 window_add_widget(enter_name_window
, b_en1
);
1623 widget_put_handler((widget_ptr
) b_en1
, enter_name_close
, signal_activate
);
1626 //setup the "arena": where the action is
1628 widget_init((widget_ptr
) arena
);
1629 arena
->widget
.update
= arena_update
;
1630 arena
->widget
.handle_click
= arena_handle_click
;
1631 window_add_widget(root
, arena
);
1634 //status bar: mainly for showing the time
1636 widget_init((widget_ptr
) statusbar
);
1637 statusbar
->update
= statusbar_update
;
1638 window_add_widget(root
, statusbar
);
1640 //setup moves and time
1641 label_init(l_moves
);
1642 if (show_moves_flag
) {
1643 window_add_widget(root
, l_moves
);
1647 window_add_widget(root
, l_time
);
1652 menuitem_t it1
, it2
;
1659 window_add_widget(root
, menu
);
1661 menuitem_put_text(it1
, "Game");
1662 menubar_add_item(menu
, it1
);
1664 menuitem_put_text(it2
, "Help");
1665 menubar_add_item(menu
, it2
);
1669 it
= menuitem_new();
1670 menuitem_put_text(it
, "New game");
1671 widget_put_handler((widget_ptr
) it
, new_game_menu
, signal_activate
);
1672 menu_add_item(m1
, it
);
1674 for (i
=0; i
<level_max
; i
++) {
1675 it
= menuitem_new();
1676 menuitem_put_text(it
, level_name
[i
]);
1677 widget_put_handler_data((widget_ptr
) it
,
1678 set_level
, (void *) i
, signal_activate
);
1679 menu_add_item(m1
, it
);
1681 it
= menuitem_new();
1682 menuitem_put_text(it
, "High Scores");
1683 widget_put_handler((widget_ptr
) it
, hs_open
, signal_activate
);
1684 menu_add_item(m1
, it
);
1685 it
= menuitem_new();
1686 menuitem_put_text(it
, "Quit");
1687 widget_put_handler((widget_ptr
) it
, quit_menu
, signal_activate
);
1688 menu_add_item(m1
, it
);
1690 menuitem_set_submenu(it1
, m1
);
1694 it
= menuitem_new();
1695 menuitem_put_text(it
, "About");
1696 widget_put_handler((widget_ptr
) it
, about_open
, signal_activate
);
1697 menu_add_item(m2
, it
);
1699 menuitem_set_submenu(it2
, m2
);
1704 window_init(about_window
);
1706 label_init(l_about1
);
1707 label_put_text(l_about1
, "NetWalk " VERSION_STRING
);
1708 window_add_widget(about_window
, l_about1
);
1710 label_init(l_about2
);
1711 label_put_text(l_about2
, "Ben Lynn");
1712 window_add_widget(about_window
, l_about2
);
1714 button_init(b_about1
);
1715 button_put_text(b_about1
, "Ok");
1716 window_add_widget(about_window
, b_about1
);
1717 widget_put_handler((widget_ptr
) b_about1
, about_close
, signal_activate
);
1720 //setup hiscores box
1723 window_init(hs_window
);
1726 label_put_text(l_hs1
, "High Scores");
1727 window_add_widget(hs_window
, l_hs1
);
1730 button_put_text(b_hs1
, "Ok");
1731 window_add_widget(hs_window
, b_hs1
);
1732 widget_put_handler((widget_ptr
) b_hs1
, hs_close
, signal_activate
);
1734 for (i
=0; i
<level_max
; i
++) {
1735 label_init(hsw
[i
]->level
);
1736 label_put_text(hsw
[i
]->level
, level_name
[i
]);
1737 window_add_widget(hs_window
, hsw
[i
]->level
);
1738 label_init(hsw
[i
]->name
);
1739 window_add_widget(hs_window
, hsw
[i
]->name
);
1740 label_init(hsw
[i
]->time
);
1741 window_add_widget(hs_window
, hsw
[i
]->time
);
1752 while (state
!= state_quit
&& !interrupted
) {
1754 tick
= SDL_GetTicks();
1758 SDL_GetMouseState(&lastmousex
, &lastmousey
);
1759 while (SDL_PollEvent(&event
)) {
1760 switch (event
.type
) {
1762 handle_key(event
.key
.keysym
.sym
, SDL_GetModState());
1764 case SDL_MOUSEBUTTONDOWN
:
1765 handle_click(event
.button
.button
, event
.button
.x
, event
.button
.y
);
1767 case SDL_MOUSEBUTTONUP
:
1768 handle_mousebuttonup(&event
);