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.
48 static int interrupted
= 0;
86 typedef struct hsentry_s
*hsentry_ptr
;
87 typedef struct hsentry_s hsentry_t
[1];
89 hsentry_t hstable
[level_max
];
90 char *level_name
[level_max
];
92 //TODO use this somehow
97 typedef struct gameparm_s
*gameparm_ptr
;
98 typedef struct gameparm_s gameparm_t
[1];
102 static config_t config
;
106 int lastmousex
, lastmousey
;
112 struct widget_s widget
;
116 typedef struct button_s button_t
[1];
117 typedef struct button_s
*button_ptr
;
120 struct widget_s widget
;
124 typedef struct label_s label_t
[1];
125 typedef struct label_s
*label_ptr
;
128 struct widget_s widget
;
133 typedef struct textbox_s textbox_t
[1];
134 typedef struct textbox_s
*textbox_ptr
;
137 struct widget_s widget
;
139 typedef struct arena_s arena_t
[1];
140 typedef struct arena_s
*arena_ptr
;
143 struct widget_s widget
;
146 struct menu_s
*submenu
;
148 typedef struct menuitem_s menuitem_t
[1];
149 typedef struct menuitem_s
*menuitem_ptr
;
152 struct widget_s widget
;
153 //TODO: replace array with list
154 menuitem_ptr item_list
[64];
157 typedef struct menu_s menu_t
[1];
158 typedef struct menu_s
*menu_ptr
;
161 struct widget_s widget
;
162 //TODO: replace array with list
163 menuitem_ptr item_list
[64];
166 typedef struct menubar_s menubar_t
[1];
167 typedef struct menubar_s
*menubar_ptr
;
170 struct widget_s widget
;
171 //TODO: replace array with list
172 struct widget_s
*widget_list
[64];
176 typedef struct window_s window_t
[1];
177 typedef struct window_s
*window_ptr
;
184 typedef struct hsw_s
*hsw_ptr
;
185 typedef struct hsw_s hsw_t
[1];
187 hsw_t hsw
[level_max
];
194 menuitem_ptr openedmenu
;
195 window_ptr modalwindow
;
196 window_t about_window
;
198 window_t enter_name_window
;
211 SDL_Surface
*font_render(char *s
, int c
)
213 return TTF_RenderText_Solid(font
, s
, rgbtable
[c
]);
216 void statusbar_update(widget_ptr w
)
218 widget_lowered_background(w
);
221 void menu_init(menu_ptr m
)
223 widget_init((widget_ptr
) m
);
227 void menu_update(menu_ptr m
)
233 widget_fill((widget_ptr
) m
, c_background
);
234 for (i
=0; i
<m
->item_count
; i
++) {
235 it
= m
->item_list
[i
];
236 if (in_widget((widget_ptr
) it
, lastmousex
, lastmousey
)) {
239 rect
.w
= ((widget_ptr
) it
)->w
- 4;
241 widget_fillrect((widget_ptr
) m
, &rect
, c_menubg
);
244 rect
.y
= vsize
* i
+ 4;
245 widget_blit((widget_ptr
) m
, it
->img
, NULL
, &rect
);
249 void menu_add_item(menu_ptr m
, menuitem_ptr it
)
251 m
->item_list
[m
->item_count
] = it
;
255 void menuitem_init(menuitem_ptr m
)
257 widget_init((widget_ptr
) m
);
263 menuitem_ptr
menuitem_new()
267 it
= (menuitem_ptr
) malloc(sizeof(menuitem_t
));
273 void menuitem_put_text(menuitem_ptr m
, char *s
)
278 if (m
->img
) SDL_FreeSurface(m
->img
);
279 tmp
= font_render(s
, c_text
);
280 m
->img
= SDL_DisplayFormat(tmp
);
281 SDL_FreeSurface(tmp
);
284 void open_submenu(widget_ptr p
, void *data
)
290 openedmenu
= (menuitem_ptr
) p
;
291 menu_ptr m
= openedmenu
->submenu
;
293 for (i
=0; i
<m
->item_count
; i
++) {
294 it
= m
->item_list
[i
];
295 if (w
< it
->img
->w
) w
= it
->img
->w
;
299 m
->widget
.x
= m
->widget
.parent
->x
;
300 m
->widget
.y
= m
->widget
.parent
->y
+ vsize
;
303 m
->widget
.h
= vsize
* m
->item_count
+ 1;
305 for (i
=0; i
<m
->item_count
; i
++) {
306 it
= m
->item_list
[i
];
307 it
->widget
.x
= 0 + m
->widget
.x
;
308 it
->widget
.y
= vsize
* i
+ 4 + m
->widget
.y
;
310 it
->widget
.h
= vsize
;
314 void menuitem_set_submenu(menuitem_ptr it
, menu_ptr m
)
317 //it->widget.signal_handler[signal_activate] = open_submenu;
318 widget_put_handler((widget_ptr
) it
, open_submenu
, signal_activate
);
319 m
->widget
.parent
= (widget_ptr
) it
;
322 void menubar_update(widget_ptr wid
)
325 menubar_ptr m
= (menubar_ptr
) wid
;
329 widget_raised_background(wid
);
331 for (i
=0; i
<m
->item_count
; i
++) {
332 it
= m
->item_list
[i
];
333 if (it
== openedmenu
) {
334 dst
.x
= it
->widget
.x
+ 2;
335 dst
.y
= it
->widget
.y
+ 2;
336 dst
.w
= it
->widget
.w
- 4;
338 widget_fillrect(wid
, &dst
, c_menubg
);
341 dst
.x
= it
->widget
.x
+ 5;
342 dst
.y
= it
->widget
.y
+ 2;
343 widget_blit(m
, it
->img
, NULL
, &dst
);
348 void menubar_handle_click(widget_ptr p
, int button
, int x
, int y
)
351 menubar_ptr m
= (menubar_ptr
) p
;
354 for (i
=0; i
<m
->item_count
; i
++) {
355 it
= m
->item_list
[i
];
356 if (in_widget((widget_ptr
) it
, x
, y
)) {
357 widget_raise_signal((widget_ptr
) it
, signal_activate
);
363 void menubar_init(menubar_ptr m
)
365 widget_init((widget_ptr
) m
);
366 m
->widget
.update
= menubar_update
;
368 m
->widget
.handle_click
= menubar_handle_click
;
371 void menubar_add_item(menubar_ptr m
, menuitem_ptr it
)
373 m
->item_list
[m
->item_count
] = it
;
375 it
->widget
.parent
= (widget_ptr
) m
;
378 void menubar_auto_layout(menubar_ptr m
)
385 for (i
=0; i
<m
->item_count
; i
++) {
386 it
= m
->item_list
[i
];
390 it
->widget
.w
= it
->img
->w
+ 10;
391 it
->widget
.h
= it
->img
->h
;
392 x
+= it
->img
->w
+ 10;
397 void label_update(widget_ptr p
)
400 label_ptr l
= (label_ptr
) p
;
405 widget_blit(l
, l
->img
, NULL
, &dst
);
409 void label_init(label_ptr l
)
411 widget_init((widget_ptr
) l
);
414 l
->widget
.update
= label_update
;
417 void label_put_text(label_ptr l
, char *s
)
421 if (l
->img
) SDL_FreeSurface(l
->img
);
422 if (l
->text
) free(l
->text
);
423 l
->text
= clonestr(s
);
424 tmp
= font_render(s
, c_text
);
425 l
->img
= SDL_DisplayFormat(tmp
);
426 SDL_FreeSurface(tmp
);
429 void textbox_update_img(textbox_ptr tb
)
433 if (tb
->img
) SDL_FreeSurface(tb
->img
);
434 tmp
= font_render(tb
->text
, c_text
);
436 tb
->img
= SDL_DisplayFormat(tmp
);
437 SDL_FreeSurface(tmp
);
443 void textbox_left(textbox_ptr tb
)
445 if (tb
->i
> 0) tb
->i
--;
448 void textbox_right(textbox_ptr tb
)
450 if (tb
->i
< strlen(tb
->text
)) tb
->i
++;
453 void textbox_delete(textbox_ptr tb
)
458 textbox_update_img(tb
);
462 void textbox_backspace(textbox_ptr tb
)
464 char *s
= &tb
->text
[tb
->i
];
466 memmove(s
- 1, s
, strlen(s
) + 1);
468 textbox_update_img(tb
);
472 void textbox_insert(textbox_ptr tb
, char c
)
474 char *s
= &tb
->text
[tb
->i
];
475 memmove(s
+ 1, s
, strlen(s
) + 1);
478 textbox_update_img(tb
);
481 void textbox_update(widget_ptr p
)
484 textbox_ptr tb
= (textbox_ptr
) p
;
490 widget_fillrect(p
, &dst
, c_text
);
495 widget_fillrect(p
, &dst
, c_canvas
);
500 widget_blit(tb
, tb
->img
, NULL
, &dst
);
507 strncpy(s
, tb
->text
, tb
->i
);
509 TTF_SizeText(font
, s
, &w
, &h
);
515 widget_fillrect(p
, &dst
, c_text
);
519 void textbox_init(textbox_ptr l
)
521 widget_init((widget_ptr
) l
);
523 l
->widget
.update
= textbox_update
;
526 void textbox_put_text(textbox_ptr tb
, char *s
)
530 textbox_update_img(tb
);
533 static widget_ptr button_selection
;
535 void button_handle_click(widget_ptr p
, int button
, int x
, int y
)
537 state
= state_button
;
538 button_selection
= p
;
541 void button_update(widget_ptr p
)
544 label_ptr l
= (label_ptr
) p
;
546 if (state
== state_button
&& button_selection
== p
547 && in_widget(p
, lastmousex
, lastmousey
)) {
548 widget_lowered_background(p
);
550 widget_raised_background(p
);
555 widget_blit(l
, l
->img
, NULL
, &dst
);
559 void button_init(button_ptr b
)
561 widget_init((widget_ptr
) b
);
564 b
->widget
.update
= button_update
;
565 b
->widget
.handle_click
= button_handle_click
;
568 void button_put_text(button_ptr b
, char *s
)
572 if (b
->img
) SDL_FreeSurface(b
->img
);
573 if (b
->text
) free(b
->text
);
574 b
->text
= clonestr(s
);
575 tmp
= font_render(s
, c_text
);
576 b
->img
= SDL_DisplayFormat(tmp
);
577 SDL_FreeSurface(tmp
);
580 void set_video(int w
, int h
)
583 flags
= SDL_DOUBLEBUF
;
585 screen
= SDL_SetVideoMode(w
, h
, 0, flags
);
586 init_ctable(screen
->format
);
589 fprintf(stderr
, "Can't set video mode: %s\n", SDL_GetError());
593 //SDL_ShowCursor(SDL_DISABLE);
596 void set_interrupted(int i
)
605 signal(SIGINT
, set_interrupted
);
606 signal(SIGTERM
, set_interrupted
);
608 //if (SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO|SDL_INIT_TIMER) < 0) {
609 if (SDL_Init(SDL_INIT_VIDEO
|SDL_INIT_TIMER
) < 0) {
610 fprintf(stderr
, "Can't init SDL: %s\n", SDL_GetError());
616 fprintf(stderr
, "Can't init SDL_ttf\n");
621 SDL_WM_SetCaption("NetWalk", "NetWalk");
624 SDL_Surface
*tileimg
[64];
625 int level
= level_medium
;
635 void draw_tile(widget_ptr wid
, int i
, int j
)
640 rect
.x
= padding
+ border
+ i
* (cellw
+ border
);
641 rect
.y
= padding
+ border
+ j
* (cellh
+ border
);
643 index
= board
[i
][j
] - 1;
644 widget_blit(wid
, tileimg
[index
], NULL
, &rect
);
653 pulse_s pulse_list
[pulse_max
];
656 void new_pulse(int x
, int y
, int d
)
660 if (pulse_count
>= pulse_max
) return;
662 //stop incoming server pulses
663 if (x
== sourcex
&& (y
== sourceybottom
|| y
==sourceytop
) && d
!= -1) {
668 for (j
=0; j
<4; j
++) {
669 if ((j
!= d
) && (i
& (1 << j
))) {
670 pulse_list
[pulse_count
].x
= x
;
671 pulse_list
[pulse_count
].y
= y
;
672 pulse_list
[pulse_count
].dir
= j
;
673 pulse_list
[pulse_count
].tick
= tick
;
675 if (pulse_count
>= pulse_max
) return;
682 new_pulse(sourcex
, sourceybottom
, -1);
683 new_pulse(sourcex
, sourceytop
, -1);
686 void animate_pulse(widget_ptr wid
)
700 while (i
<pulse_count
) {
703 d
= pulse_list
[i
].dir
;
704 dt
= tick
- pulse_list
[i
].tick
;
707 memmove(&pulse_list
[i
], &pulse_list
[i
+1], sizeof(pulse_s
) * (pulse_count
- i
));
709 add_dir(&x
, &y
, x
, y
, d
);
710 new_pulse(x
, y
, (d
+ 2) % 4);
713 if (dir
[d
].x
== -1 && 2 * dt
> speed
&& !x
) {
716 if (dir
[d
].x
== 1 && 2 * dt
> speed
&& x
== boardw
- 1) {
719 if (dir
[d
].y
== -1 && 2 * dt
> speed
&& !y
) {
722 if (dir
[d
].y
== 1 && 2 * dt
> speed
&& y
== boardh
- 1) {
726 rect
.x
= x
* (cellw
+ border
) + pipex
- 1;
727 rect
.x
+= dir
[d
].x
* (cellw
+ border
) * dt
/ speed
;
728 rect
.x
+= border
+ padding
;
730 rect
.y
= y
* (cellh
+ border
) + border
+ padding
;
731 rect
.y
+= dir
[d
].y
* (cellh
+ border
) * dt
/ speed
;
733 widget_fillrect(wid
, &rect
, c_pulse
);
739 void arena_update(widget_ptr wid
)
749 rect
.w
= cellw
* boardw
+ (boardw
+ 1) * border
;
752 if (game_won
) bc
= c_borderwon
;
755 for (i
=0; i
<=boardh
; i
++) {
756 widget_fillrect(wid
, &rect
, bc
);
757 rect
.y
+= cellh
+ border
;
762 rect
.h
= cellh
* boardh
+ (boardh
+ 1) * border
;
763 for (i
=0; i
<=boardw
; i
++) {
764 widget_fillrect(wid
, &rect
, bc
);
765 rect
.x
+= cellw
+ border
;
769 if (lastmousex
> wid
->x
&& lastmousey
> wid
->y
) {
770 i
= (lastmousex
- padding
- border
- wid
->x
) / (cellw
+ border
);
771 j
= (lastmousey
- padding
- border
- wid
->y
) / (cellh
+ border
);
772 if (i
< boardw
&& j
< boardh
) {
773 rect
.x
= (cellw
+ border
) * i
+ padding
;
774 rect
.y
= (cellh
+ border
) * j
+ padding
;
775 rect
.w
= cellw
+ 2 * border
;
776 rect
.h
= cellh
+ 2 * border
;
777 widget_fillrect(wid
, &rect
, c_highlight
);
782 for (i
=0; i
<boardw
; i
++) {
783 for (j
=0; j
<boardh
; j
++) {
785 draw_tile(wid
, i
, j
);
790 if (game_won
) c
= c_serverwon
;
793 rect
.x
= padding
+ border
+ (cellw
+ border
) * sourcex
;
794 rect
.y
= padding
+ border
+ (cellh
+ border
) * sourceytop
;
800 widget_fillrect(wid
, &rect
, c
);
802 rect
.y
= padding
+ border
+ (cellh
+ border
) * sourceybottom
;
803 widget_fillrect(wid
, &rect
, c
);
811 char* read_field(FILE *fp
)
817 r
= (char *) malloc(1024);
846 for (i
=0; i
<level_max
; i
++) {
847 if (hstable
[i
]->name
) {
848 label_put_text(hsw
[i
]->name
, hstable
[i
]->name
);
850 label_put_text(hsw
[i
]->name
, "None");
852 if (hstable
[i
]->time
!= -1) {
855 sprintf(s
, "%d", hstable
[i
]->time
);
856 label_put_text(hsw
[i
]->time
, s
);
858 label_put_text(hsw
[i
]->name
, "None");
868 for (i
=0; i
<level_max
; i
++) {
869 hstable
[i
]->name
= NULL
;
870 hstable
[i
]->time
= -1;
873 fp
= fopen(config
->hsfile
, "r");
876 for(i
=0; i
<level_max
; i
++) {
881 hstable
[i
]->name
= s
;
886 hstable
[i
]->time
= atoi(s
);
899 fp
= fopen(config
->hsfile
, "w");
902 for(i
=0; i
<level_max
; i
++) {
903 fprintf(fp
, "%s,%d\n", hstable
[i
]->name
, hstable
[i
]->time
);
911 void enter_name_open()
913 modalwindow
= enter_name_window
;
917 void enter_name_close()
922 player_name
= tb_en1
->text
;
924 if (hstable
[level
]->name
) {
925 free(hstable
[level
]->name
);
927 hstable
[level
]->name
= clonestr(player_name
);
928 hstable
[level
]->time
= second_count
;
935 if (hstable
[level
]->time
== -1 || second_count
< hstable
[level
]->time
) {
943 SDL_PixelFormat
*fmt
= screen
->format
;
947 pipex
= cellw
/ 2 - pipet
/ 2;
948 pipey
= cellw
/ 2 - pipet
/ 2;
949 pipew
= cellw
/ 2 + pipet
/ 2;
950 pipeh
= cellh
/ 2 + pipet
/ 2;
952 for (i
=0; i
<64; i
++) {
953 tileimg
[i
] = SDL_CreateRGBSurface(0, cellw
, cellh
, fmt
->BitsPerPixel
,
954 fmt
->Rmask
, fmt
->Gmask
, fmt
->Bmask
, fmt
->Amask
);
955 for (j
=0; j
<4; j
++) {
956 if ((i
+ 1) & (1 << j
)) {
985 } else c
= ctable
[c_off
];
986 SDL_FillRect(tileimg
[i
], &rect
, c
);
991 for (i
=1; i
<32; i
*=2) {
992 rect
.x
= cellw
/ 2 - 2 * pipet
;
993 rect
.y
= cellh
/ 2 - 2 * pipet
;
1001 SDL_FillRect(tileimg[i-1], &rect, ctable[c_off]);
1002 SDL_FillRect(tileimg[i-1+16], &rect, ctable[c_on]);
1008 SDL_FillRect(tileimg
[i
-1], &rect
, ctable
[c_down
]);
1009 SDL_FillRect(tileimg
[i
-1+16], &rect
, ctable
[c_up
]);
1013 void reset_move_count()
1016 label_put_text(l_moves
, "moves: 0");
1019 void increment_move_count()
1023 sprintf(s
, "moves: %d", move_count
);
1024 label_put_text(l_moves
, s
);
1029 label_put_text(l_time
, "time: 0");
1036 ms_count
+= tick
- tick_old
;
1037 while (ms_count
>= 1000) {
1040 sprintf(s
, "time: %d", second_count
);
1041 label_put_text(l_time
, s
);
1046 //position everything based on board size
1050 sourcex
= boardw
/ 2 - 1;
1051 sourceytop
= boardh
/ 2;
1052 sourceybottom
= sourceytop
+ 1;
1054 w
= cellw
* boardw
+ (boardw
+ 1) * border
+ 2 * padding
;
1055 h
= cellh
* boardh
+ (boardh
+ 1) * border
+ 2 * padding
;
1056 widget_put_geometry(arena
, 0, vsize
, w
, h
);
1057 set_video(w
, h
+ 2 * vsize
);
1058 widget_put_geometry(root
, 0, 0, w
, h
+ 2 * vsize
);
1059 widget_put_geometry(menu
, 0, 0, w
, vsize
);
1060 menubar_auto_layout(menu
);
1061 widget_put_geometry(statusbar
, 0, h
+ vsize
, w
, vsize
);
1063 widget_put_geometry(l_moves
, 8, h
+ vsize
, 64, vsize
);
1064 widget_put_geometry(l_time
, w
- 48, h
+ vsize
, 64, vsize
);
1066 widget_put_geometry((widget_ptr
) about_window
,
1067 w
/2 - 50, h
/2 - 50, 100, 100);
1068 widget_put_geometry((widget_ptr
) l_about1
, 10, 10, 60, vsize
);
1069 widget_put_geometry((widget_ptr
) l_about2
, 10, 30, 60, vsize
);
1070 widget_put_geometry((widget_ptr
) b_about1
, 30, 80, 30, vsize
);
1072 widget_put_geometry((widget_ptr
) hs_window
,
1073 w
/2 - 75, h
/2 - 60, 150, 120);
1074 widget_put_geometry((widget_ptr
) l_hs1
, 10, 5, 60, vsize
);
1075 widget_put_geometry((widget_ptr
) b_hs1
, 100, 100, 30, vsize
);
1079 for (i
=0; i
<level_max
; i
++) {
1080 int y
= vsize
* i
+ 8 + vsize
;
1081 widget_put_geometry((widget_ptr
) hsw
[i
]->level
, 10, y
, 20, vsize
);
1082 widget_put_geometry((widget_ptr
) hsw
[i
]->time
, 60, y
, 20, vsize
);
1083 widget_put_geometry((widget_ptr
) hsw
[i
]->name
, 90, y
, 20, vsize
);
1087 widget_put_geometry((widget_ptr
) enter_name_window
,
1088 10, h
/2 - 30, w
- 20, 67);
1089 widget_put_geometry((widget_ptr
) l_en1
, 10, 0, 60, vsize
);
1090 widget_put_geometry((widget_ptr
) tb_en1
, 5, vsize
+ 5, w
- 30, vsize
);
1091 widget_put_geometry((widget_ptr
) b_en1
, w
- 60, 45, 30, vsize
);
1093 ((widget_ptr
) root
)->computexy((widget_ptr
) root
);
1094 ((widget_ptr
) about_window
)->computexy((widget_ptr
) about_window
);
1095 ((widget_ptr
) hs_window
)->computexy((widget_ptr
) hs_window
);
1096 ((widget_ptr
) enter_name_window
)->computexy((widget_ptr
) enter_name_window
);
1103 boardw
= 5; boardh
= 5;
1108 boardw
= 10; boardh
= 9;
1113 boardw
= 10; boardh
= 9;
1117 case level_veryhard
:
1118 boardw
= 20; boardh
= 18;
1133 tick
= SDL_GetTicks();
1137 void handle_mousebuttonup(SDL_Event
*event
)
1139 int x
= event
->button
.x
;
1140 int y
= event
->button
.y
;
1146 m
= openedmenu
->submenu
;
1147 for (i
=0; i
<m
->item_count
; i
++) {
1148 it
= m
->item_list
[i
];
1149 if (in_widget((widget_ptr
) it
, x
, y
)) {
1150 widget_raise_signal((widget_ptr
) it
, signal_activate
);
1157 } else if (state
== state_button
) {
1159 if (in_widget(button_selection
, x
, y
)) {
1160 widget_raise_signal(button_selection
, signal_activate
);
1166 void handle_click(int button
, int x
, int y
)
1171 wid
= (widget_ptr
) modalwindow
;
1172 if (in_widget(wid
, x
, y
) && (wid
->handle_click
)) {
1173 wid
->handle_click(wid
, button
, x
, y
);
1178 wid
= (widget_ptr
) root
;
1179 wid
->handle_click(wid
, button
, x
, y
);
1182 void arena_handle_click(widget_ptr p
, int button
, int x
, int y
)
1187 if (state
!= state_game
) return;
1189 i
= (x
- padding
- border
) / (cellw
+ border
);
1190 j
= (y
- padding
- border
) / (cellh
+ border
);
1191 if (i
>= boardw
|| j
>= boardh
) return;
1194 if (i
== sourcex
&& (j
== sourceytop
|| j
== sourceybottom
)) {
1195 new_pulse(sourcex
, sourceybottom
, -1);
1196 new_pulse(sourcex
, sourceytop
, -1);
1198 new_pulse(i
, j
, -1);
1203 //temporarily merge server squares
1204 board
[sourcex
][sourceybottom
] |= board
[sourcex
][sourceytop
] & 1;
1205 if (i
== sourcex
&& j
== sourceytop
) {
1208 d
= board
[i
][j
] & 15;
1210 case SDL_BUTTON_LEFT
:
1212 increment_move_count();
1214 case SDL_BUTTON_RIGHT
:
1216 increment_move_count();
1222 board
[sourcex
][sourceytop
] &= ~1;
1223 board
[sourcex
][sourceytop
] |= board
[sourcex
][sourceybottom
] & 1;
1224 board
[sourcex
][sourceybottom
] &= ~1;
1239 void quit_menu(widget_ptr w
, void *data
)
1244 void new_game_menu(widget_ptr w
, void *data
)
1249 void about_open(widget_ptr w
, void *data
)
1251 modalwindow
= about_window
;
1254 void about_close(widget_ptr w
, void *data
)
1259 void hs_open(widget_ptr w
, void *data
)
1261 modalwindow
= hs_window
;
1264 void hs_close(widget_ptr w
, void *data
)
1269 void set_level(widget_ptr w
, void *data
)
1275 void handle_key(int key
, int mod
)
1288 textbox_left(tb_en1
);
1291 textbox_right(tb_en1
);
1294 textbox_delete(tb_en1
);
1296 case SDLK_BACKSPACE
:
1297 textbox_backspace(tb_en1
);
1300 if (key
< 256 && key
>= 32) {
1301 if (mod
& KMOD_SHIFT
) {
1302 textbox_insert(tb_en1
, shifttable
[key
]);
1304 textbox_insert(tb_en1
, key
);
1326 void update_screen()
1328 SDL_FillRect(screen
, NULL
, 0);
1329 widget_update((widget_ptr
) root
);
1334 for (i
=0; i
<menu
->item_count
; i
++) {
1335 it
= menu
->item_list
[i
];
1336 if (in_widget((widget_ptr
) it
, lastmousex
, lastmousey
)) {
1337 open_submenu((widget_ptr
) it
, NULL
);
1340 menu_update(openedmenu
->submenu
);
1343 widget_update((widget_ptr
) modalwindow
);
1348 void window_update(widget_ptr p
)
1350 window_ptr w
= (window_ptr
) p
;
1355 if (p
!= (widget_ptr
) root
) {
1360 widget_fillrect(p
, &dst
, c_windowborder
);
1361 widget_fill(p
, c_background
);
1364 for (i
=0; i
<w
->widget_count
; i
++) {
1365 wid
= w
->widget_list
[i
];
1370 void window_handle_click(widget_ptr p
, int button
, int x
, int y
)
1373 window_ptr window
= (window_ptr
) p
;
1376 for (i
=0; i
<window
->widget_count
; i
++) {
1377 wid
= window
->widget_list
[i
];
1378 if (in_widget(wid
, x
, y
) && (wid
->handle_click
)) {
1379 wid
->handle_click(wid
, button
, x
- wid
->x
, y
- wid
->y
);
1385 void window_add_widget(window_ptr r
, void *p
)
1387 widget_ptr wid
= (widget_ptr
) p
;
1388 r
->widget_list
[r
->widget_count
] = wid
;
1390 wid
->parent
= (widget_ptr
) r
;
1391 wid
->x
+= r
->widget
.x
;
1392 wid
->y
+= r
->widget
.y
;
1395 void window_computexy(widget_ptr wid
)
1398 window_ptr w
= (window_ptr
) wid
;
1400 widget_computexy(wid
);
1401 for (i
=0; i
<w
->widget_count
; i
++) {
1402 w
->widget_list
[i
]->computexy(w
->widget_list
[i
]);
1406 void window_init(window_ptr w
)
1408 widget_init((widget_ptr
) w
);
1409 w
->widget_count
= 0;
1410 w
->widget
.update
= window_update
;
1411 w
->widget
.handle_click
= window_handle_click
;
1412 w
->widget
.computexy
= window_computexy
;
1415 static void add_shiftstring(char *s1
, char *s2
)
1419 for (i
=0; i
<strlen(s1
); i
++) {
1420 shifttable
[(int) s1
[i
]] = s2
[i
];
1424 int main(int argc
, char *argv
[])
1429 level_name
[level_easy
] = "Newbie";
1430 level_name
[level_medium
] = "Normal";
1431 level_name
[level_hard
] = "Nerd";
1432 level_name
[level_veryhard
] = "Nutcase";
1438 for (i
=0; i
<256; i
++) shifttable
[i
] = i
;
1440 for (i
='a'; i
<='z'; i
++) {
1441 shifttable
[i
] = i
- 32;
1444 add_shiftstring("1234567890-=", "!@#$%^&*()_+");
1445 add_shiftstring("[]\\;',./`", "{}|:\"<>?~");
1448 config_load(config
);
1454 font
= TTF_OpenFont(config
->fontname
, config
->fontsize
);
1456 fprintf(stderr
, "error loading font %s\n", config
->fontname
);
1462 //need to set video mode here to initialize colour table
1463 set_video(100, 100);
1465 //setup enter name box
1467 window_init(enter_name_window
);
1470 label_put_text(l_en1
, "Enter name:");
1471 window_add_widget(enter_name_window
, l_en1
);
1473 textbox_init(tb_en1
);
1474 textbox_put_text(tb_en1
, "Anonymous");
1475 window_add_widget(enter_name_window
, tb_en1
);
1478 button_put_text(b_en1
, "Ok");
1479 window_add_widget(enter_name_window
, b_en1
);
1480 widget_put_handler((widget_ptr
) b_en1
, enter_name_close
, signal_activate
);
1483 //setup the "arena": where the action is
1485 widget_init((widget_ptr
) arena
);
1486 arena
->widget
.update
= arena_update
;
1487 arena
->widget
.handle_click
= arena_handle_click
;
1488 window_add_widget(root
, arena
);
1491 //status bar: mainly for showing the time
1493 widget_init((widget_ptr
) statusbar
);
1494 statusbar
->update
= statusbar_update
;
1495 window_add_widget(root
, statusbar
);
1497 //setup moves and time
1498 label_init(l_moves
);
1499 if (config
->showmoves
) {
1500 window_add_widget(root
, l_moves
);
1504 window_add_widget(root
, l_time
);
1509 menuitem_t it1
, it2
;
1516 window_add_widget(root
, menu
);
1518 menuitem_put_text(it1
, "Game");
1519 menubar_add_item(menu
, it1
);
1521 menuitem_put_text(it2
, "Help");
1522 menubar_add_item(menu
, it2
);
1526 it
= menuitem_new();
1527 menuitem_put_text(it
, "New game");
1528 widget_put_handler((widget_ptr
) it
, new_game_menu
, signal_activate
);
1529 menu_add_item(m1
, it
);
1531 for (i
=0; i
<level_max
; i
++) {
1532 it
= menuitem_new();
1533 menuitem_put_text(it
, level_name
[i
]);
1534 widget_put_handler_data((widget_ptr
) it
,
1535 set_level
, (void *) i
, signal_activate
);
1536 menu_add_item(m1
, it
);
1538 it
= menuitem_new();
1539 menuitem_put_text(it
, "High Scores");
1540 widget_put_handler((widget_ptr
) it
, hs_open
, signal_activate
);
1541 menu_add_item(m1
, it
);
1542 it
= menuitem_new();
1543 menuitem_put_text(it
, "Quit");
1544 widget_put_handler((widget_ptr
) it
, quit_menu
, signal_activate
);
1545 menu_add_item(m1
, it
);
1547 menuitem_set_submenu(it1
, m1
);
1551 it
= menuitem_new();
1552 menuitem_put_text(it
, "About");
1553 widget_put_handler((widget_ptr
) it
, about_open
, signal_activate
);
1554 menu_add_item(m2
, it
);
1556 menuitem_set_submenu(it2
, m2
);
1561 window_init(about_window
);
1563 label_init(l_about1
);
1564 label_put_text(l_about1
, "NetWalk " VERSION_STRING
);
1565 window_add_widget(about_window
, l_about1
);
1567 label_init(l_about2
);
1568 label_put_text(l_about2
, "Ben Lynn");
1569 window_add_widget(about_window
, l_about2
);
1571 button_init(b_about1
);
1572 button_put_text(b_about1
, "Ok");
1573 window_add_widget(about_window
, b_about1
);
1574 widget_put_handler((widget_ptr
) b_about1
, about_close
, signal_activate
);
1577 //setup hiscores box
1580 window_init(hs_window
);
1583 label_put_text(l_hs1
, "High Scores");
1584 window_add_widget(hs_window
, l_hs1
);
1587 button_put_text(b_hs1
, "Ok");
1588 window_add_widget(hs_window
, b_hs1
);
1589 widget_put_handler((widget_ptr
) b_hs1
, hs_close
, signal_activate
);
1591 for (i
=0; i
<level_max
; i
++) {
1592 label_init(hsw
[i
]->level
);
1593 label_put_text(hsw
[i
]->level
, level_name
[i
]);
1594 window_add_widget(hs_window
, hsw
[i
]->level
);
1595 label_init(hsw
[i
]->name
);
1596 window_add_widget(hs_window
, hsw
[i
]->name
);
1597 label_init(hsw
[i
]->time
);
1598 window_add_widget(hs_window
, hsw
[i
]->time
);
1609 while (state
!= state_quit
&& !interrupted
) {
1611 tick
= SDL_GetTicks();
1615 SDL_GetMouseState(&lastmousex
, &lastmousey
);
1616 while (SDL_PollEvent(&event
)) {
1617 switch (event
.type
) {
1619 handle_key(event
.key
.keysym
.sym
, SDL_GetModState());
1621 case SDL_MOUSEBUTTONDOWN
:
1622 handle_click(event
.button
.button
, event
.button
.x
, event
.button
.y
);
1624 case SDL_MOUSEBUTTONUP
:
1625 handle_mousebuttonup(&event
);