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.
26 #include <sys/types.h> //for opendir et al.
47 static int interrupted
= 0;
87 typedef struct hsentry_s
*hsentry_ptr
;
88 typedef struct hsentry_s hsentry_t
[1];
90 hsentry_t hstable
[level_max
];
91 char *level_name
[level_max
];
93 static config_t config
;
97 int lastmousex
, lastmousey
;
103 struct widget_s widget
;
107 typedef struct button_s button_t
[1];
108 typedef struct button_s
*button_ptr
;
111 struct widget_s widget
;
115 typedef struct label_s label_t
[1];
116 typedef struct label_s
*label_ptr
;
119 struct widget_s widget
;
124 typedef struct textbox_s textbox_t
[1];
125 typedef struct textbox_s
*textbox_ptr
;
128 struct widget_s widget
;
130 typedef struct arena_s arena_t
[1];
131 typedef struct arena_s
*arena_ptr
;
134 struct widget_s widget
;
137 struct menu_s
*submenu
;
139 typedef struct menuitem_s menuitem_t
[1];
140 typedef struct menuitem_s
*menuitem_ptr
;
143 struct widget_s widget
;
144 menuitem_ptr item_list
[64];
147 typedef struct menu_s menu_t
[1];
148 typedef struct menu_s
*menu_ptr
;
151 struct widget_s widget
;
152 menuitem_ptr item_list
[64];
155 typedef struct menubar_s menubar_t
[1];
156 typedef struct menubar_s
*menubar_ptr
;
159 struct widget_s widget
;
160 struct widget_s
*widget_list
[64];
164 typedef struct window_s window_t
[1];
165 typedef struct window_s
*window_ptr
;
172 typedef struct hsw_s
*hsw_ptr
;
173 typedef struct hsw_s hsw_t
[1];
175 hsw_t hsw
[level_max
];
182 menuitem_ptr openedmenu
;
183 window_ptr modalwindow
;
184 window_t about_window
;
186 window_t enter_name_window
;
199 SDL_Surface
*font_render(char *s
, int c
)
201 return TTF_RenderText_Solid(font
, s
, rgbtable
[c
]);
204 void statusbar_update(widget_ptr w
)
206 widget_lowered_background(w
);
209 void menu_init(menu_ptr m
)
211 widget_init((widget_ptr
) m
);
215 void menu_update(menu_ptr m
)
221 widget_fill((widget_ptr
) m
, c_background
);
222 for (i
=0; i
<m
->item_count
; i
++) {
223 it
= m
->item_list
[i
];
224 if (in_widget((widget_ptr
) it
, lastmousex
, lastmousey
)) {
227 rect
.w
= ((widget_ptr
) it
)->w
- 4;
229 widget_fillrect((widget_ptr
) m
, &rect
, c_menubg
);
232 rect
.y
= vsize
* i
+ 4;
233 widget_blit((widget_ptr
) m
, it
->img
, NULL
, &rect
);
237 void menu_add_item(menu_ptr m
, menuitem_ptr it
)
239 m
->item_list
[m
->item_count
] = it
;
243 void menuitem_init(menuitem_ptr m
)
245 widget_init((widget_ptr
) m
);
251 menuitem_ptr
menuitem_new()
253 menuitem_ptr it
= (menuitem_ptr
) malloc(sizeof(menuitem_t
));
258 void menuitem_put_text(menuitem_ptr m
, char *s
)
263 if (m
->img
) SDL_FreeSurface(m
->img
);
264 tmp
= font_render(s
, c_text
);
265 m
->img
= SDL_DisplayFormat(tmp
);
266 SDL_FreeSurface(tmp
);
269 void open_submenu(widget_ptr p
, void *data
)
275 openedmenu
= (menuitem_ptr
) p
;
276 menu_ptr m
= openedmenu
->submenu
;
278 for (i
=0; i
<m
->item_count
; i
++) {
279 it
= m
->item_list
[i
];
280 if (w
< it
->img
->w
) w
= it
->img
->w
;
284 m
->widget
.x
= m
->widget
.parent
->x
;
285 m
->widget
.y
= m
->widget
.parent
->y
+ vsize
;
288 m
->widget
.h
= vsize
* m
->item_count
+ 1;
290 for (i
=0; i
<m
->item_count
; i
++) {
291 it
= m
->item_list
[i
];
292 it
->widget
.x
= 0 + m
->widget
.x
;
293 it
->widget
.y
= vsize
* i
+ 4 + m
->widget
.y
;
295 it
->widget
.h
= vsize
;
299 void menuitem_set_submenu(menuitem_ptr it
, menu_ptr m
)
302 widget_put_handler((widget_ptr
) it
, open_submenu
, signal_activate
);
303 m
->widget
.parent
= (widget_ptr
) it
;
306 void menubar_update(widget_ptr wid
)
309 menubar_ptr m
= (menubar_ptr
) wid
;
313 widget_raised_background(wid
);
315 for (i
=0; i
<m
->item_count
; i
++) {
316 it
= m
->item_list
[i
];
317 if (it
== openedmenu
) {
318 dst
.x
= it
->widget
.x
+ 2;
319 dst
.y
= it
->widget
.y
+ 2;
320 dst
.w
= it
->widget
.w
- 4;
322 widget_fillrect(wid
, &dst
, c_menubg
);
325 dst
.x
= it
->widget
.x
+ 5;
326 dst
.y
= it
->widget
.y
+ 2;
327 widget_blit(m
, it
->img
, NULL
, &dst
);
332 void menubar_handle_click(widget_ptr p
, int button
, int x
, int y
)
334 menubar_ptr m
= (menubar_ptr
) p
;
337 for (i
=0; i
<m
->item_count
; i
++) {
338 it
= m
->item_list
[i
];
339 if (in_widget((widget_ptr
) it
, x
, y
)) {
340 widget_raise_signal((widget_ptr
) it
, signal_activate
);
346 void menubar_init(menubar_ptr m
)
348 widget_init((widget_ptr
) m
);
349 m
->widget
.update
= menubar_update
;
351 m
->widget
.handle_click
= menubar_handle_click
;
354 void menubar_add_item(menubar_ptr m
, menuitem_ptr it
)
356 m
->item_list
[m
->item_count
] = it
;
358 it
->widget
.parent
= (widget_ptr
) m
;
361 void menubar_auto_layout(menubar_ptr m
)
366 for (i
=0; i
<m
->item_count
; i
++) {
367 it
= m
->item_list
[i
];
371 it
->widget
.w
= it
->img
->w
+ 10;
372 it
->widget
.h
= it
->img
->h
;
373 x
+= it
->img
->w
+ 10;
378 void label_update(widget_ptr p
)
381 label_ptr l
= (label_ptr
) p
;
386 widget_blit(l
, l
->img
, NULL
, &dst
);
390 void label_init(label_ptr l
)
392 widget_init((widget_ptr
) l
);
395 l
->widget
.update
= label_update
;
398 void label_put_text(label_ptr l
, char *s
)
402 if (l
->img
) SDL_FreeSurface(l
->img
);
403 if (l
->text
) free(l
->text
);
404 l
->text
= clonestr(s
);
405 tmp
= font_render(s
, c_text
);
406 l
->img
= SDL_DisplayFormat(tmp
);
407 SDL_FreeSurface(tmp
);
410 void textbox_update_img(textbox_ptr tb
)
414 if (tb
->img
) SDL_FreeSurface(tb
->img
);
415 tmp
= font_render(tb
->text
, c_text
);
417 tb
->img
= SDL_DisplayFormat(tmp
);
418 SDL_FreeSurface(tmp
);
424 void textbox_left(textbox_ptr tb
)
426 if (tb
->i
> 0) tb
->i
--;
429 void textbox_right(textbox_ptr tb
)
431 if (tb
->i
< strlen(tb
->text
)) tb
->i
++;
434 void textbox_delete(textbox_ptr tb
)
439 textbox_update_img(tb
);
443 void textbox_backspace(textbox_ptr tb
)
445 char *s
= &tb
->text
[tb
->i
];
447 memmove(s
- 1, s
, strlen(s
) + 1);
449 textbox_update_img(tb
);
453 void textbox_insert(textbox_ptr tb
, char c
)
455 char *s
= &tb
->text
[tb
->i
];
456 memmove(s
+ 1, s
, strlen(s
) + 1);
459 textbox_update_img(tb
);
462 void textbox_update(widget_ptr p
)
464 textbox_ptr tb
= (textbox_ptr
) p
;
471 widget_fillrect(p
, &dst
, c_text
);
476 widget_fillrect(p
, &dst
, c_canvas
);
481 widget_blit(tb
, tb
->img
, NULL
, &dst
);
488 strncpy(s
, tb
->text
, tb
->i
);
490 TTF_SizeText(font
, s
, &w
, &h
);
496 widget_fillrect(p
, &dst
, c_text
);
500 void textbox_init(textbox_ptr l
)
502 widget_init((widget_ptr
) l
);
504 l
->widget
.update
= textbox_update
;
507 void textbox_put_text(textbox_ptr tb
, char *s
)
511 textbox_update_img(tb
);
514 static widget_ptr button_selection
;
516 void button_handle_click(widget_ptr p
, int button
, int x
, int y
)
518 state
= state_button
;
519 button_selection
= p
;
522 void button_update(widget_ptr p
)
525 label_ptr l
= (label_ptr
) p
;
527 if (state
== state_button
&& button_selection
== p
528 && in_widget(p
, lastmousex
, lastmousey
)) {
529 widget_lowered_background(p
);
531 widget_raised_background(p
);
536 widget_blit(l
, l
->img
, NULL
, &dst
);
540 void button_init(button_ptr b
)
542 widget_init((widget_ptr
) b
);
545 b
->widget
.update
= button_update
;
546 b
->widget
.handle_click
= button_handle_click
;
549 void button_put_text(button_ptr b
, char *s
)
553 if (b
->img
) SDL_FreeSurface(b
->img
);
554 if (b
->text
) free(b
->text
);
555 b
->text
= clonestr(s
);
556 tmp
= font_render(s
, c_text
);
557 b
->img
= SDL_DisplayFormat(tmp
);
558 SDL_FreeSurface(tmp
);
561 void set_video(int w
, int h
)
563 int flags
= SDL_DOUBLEBUF
;
564 screen
= SDL_SetVideoMode(w
, h
, 0, flags
);
565 // flags = SDL_FULLSCREEN;
566 // screen = SDL_SetVideoMode(0, 0, 0, flags);
567 init_ctable(screen
->format
);
569 fprintf(stderr
, "Can't set video mode: %s\n", SDL_GetError());
572 //SDL_ShowCursor(SDL_DISABLE);
575 void set_interrupted(int i
)
583 signal(SIGINT
, set_interrupted
);
584 signal(SIGTERM
, set_interrupted
);
585 if (SDL_Init(SDL_INIT_VIDEO
|SDL_INIT_TIMER
) < 0) {
586 fprintf(stderr
, "Can't init SDL: %s\n", SDL_GetError());
592 fprintf(stderr
, "Can't init SDL_ttf\n");
596 SDL_WM_SetCaption("NetWalk", "NetWalk");
597 SDL_EnableKeyRepeat(150, 50);
600 SDL_Surface
*unmarked_tileimg
[64];
601 SDL_Surface
*marked_tileimg
[64];
602 int level
= level_medium
;
612 void draw_tile(widget_ptr wid
, int i
, int j
)
615 rect
.x
= padding
+ border
+ i
* (cellw
+ border
);
616 rect
.y
= padding
+ border
+ j
* (cellh
+ border
);
617 int const marked
= flags
[i
][j
] & 0x1;
618 int index
= board
[i
][j
] - 1;
620 (marked
?marked_tileimg
:unmarked_tileimg
)[index
],
631 pulse_s pulse_list
[pulse_max
];
634 void new_pulse(int x
, int y
, int d
)
638 if (pulse_count
>= pulse_max
) return;
640 //stop incoming server pulses
641 if (x
== sourcex
&& (y
== sourceybottom
|| y
==sourceytop
) && d
!= -1) {
646 for (j
=0; j
<4; j
++) {
647 if ((j
!= d
) && (i
& (1 << j
))) {
648 pulse_list
[pulse_count
].x
= x
;
649 pulse_list
[pulse_count
].y
= y
;
650 pulse_list
[pulse_count
].dir
= j
;
651 pulse_list
[pulse_count
].tick
= tick
;
653 if (pulse_count
>= pulse_max
) return;
660 new_pulse(sourcex
, sourceybottom
, -1);
661 new_pulse(sourcex
, sourceytop
, -1);
664 void animate_pulse(widget_ptr wid
)
678 while (i
<pulse_count
) {
681 d
= pulse_list
[i
].dir
;
682 dt
= tick
- pulse_list
[i
].tick
;
685 memmove(&pulse_list
[i
], &pulse_list
[i
+1], sizeof(pulse_s
) * (pulse_count
- i
));
687 add_dir(&x
, &y
, x
, y
, d
);
688 new_pulse(x
, y
, (d
+ 2) % 4);
691 if (dir
[d
].x
== -1 && 2 * dt
> speed
&& !x
) {
694 if (dir
[d
].x
== 1 && 2 * dt
> speed
&& x
== boardw
- 1) {
697 if (dir
[d
].y
== -1 && 2 * dt
> speed
&& !y
) {
700 if (dir
[d
].y
== 1 && 2 * dt
> speed
&& y
== boardh
- 1) {
704 rect
.x
= x
* (cellw
+ border
) + pipex
- 1;
705 rect
.x
+= dir
[d
].x
* (cellw
+ border
) * dt
/ speed
;
706 rect
.x
+= border
+ padding
;
708 rect
.y
= y
* (cellh
+ border
) + border
+ padding
;
709 rect
.y
+= dir
[d
].y
* (cellh
+ border
) * dt
/ speed
;
711 widget_fillrect(wid
, &rect
, c_pulse
);
717 /** \brief Determine which cell of the arena the mouse is currently
718 * pointing at, if any.
719 * \param wid The arena widget.
720 * \param mousex The mouse X position.
721 * \param mousey The mouse Y position.
722 * \param[out] col_p Returns the current cell's column in the arena.
723 * \param[out] row_p Returns the current cell's row in the arena.
724 * \retval 0 The mouse is over the arena and the cell index is returned
725 * through \a row_p and \a col_p.
726 * \retval -1 The mouse is not over the area.
729 int get_cell_from_mouse_position(widget_ptr
const wid
,
730 int const mousex
,int const mousey
,
731 unsigned int * const col_p
,unsigned int * const row_p
)
733 if((mousex
< wid
->x
) || (mousey
< wid
->y
))
736 unsigned int const col
=
737 (mousex
- padding
- border
- wid
->x
) / (cellw
+ border
);
738 unsigned int const row
=
739 (mousey
- padding
- border
- wid
->y
) / (cellh
+ border
);
741 if((col
>= boardw
) || (row
>= boardh
))
749 /** \brief Fill a cell (including border) in the arena with a color.
750 * \param wid The arena widget.
751 * \param col The column of the cell to be filled.
752 * \param row The row of the cell to be filled.
753 * \param coloridx The index of the color to use when filling.
756 void fill_arena_cell(widget_ptr
const wid
,
757 unsigned int const col
,unsigned int const row
,int const coloridx
)
760 .x
= (cellw
+ border
) * col
+ padding
,
761 .y
= (cellh
+ border
) * row
+ padding
,
762 .w
= cellw
+ 2 * border
,
763 .h
= cellh
+ 2 * border
765 widget_fillrect(wid
, &rect
, coloridx
);
768 void arena_update(widget_ptr wid
)
772 int bc
= game_won
? c_borderwon
: c_border
;
773 int c
= game_won
? c_serverwon
: c_server
;
778 rect
.w
= cellw
* boardw
+ (boardw
+ 1) * border
;
781 for (i
=0; i
<=boardh
; i
++) {
782 widget_fillrect(wid
, &rect
, bc
);
783 rect
.y
+= cellh
+ border
;
788 rect
.h
= cellh
* boardh
+ (boardh
+ 1) * border
;
789 for (i
=0; i
<=boardw
; i
++) {
790 widget_fillrect(wid
, &rect
, bc
);
791 rect
.x
+= cellw
+ border
;
797 if(get_cell_from_mouse_position(wid
,lastmousex
,lastmousey
,&col
,&row
) == 0)
799 /* highlight the cell the mouse is pointing at */
800 fill_arena_cell(wid
,col
,row
,c_highlight
);
805 * If the highlighted cell is an edge cell, also
806 * highlight the corresponding cells on opposite
807 * edges. This will make it easier to work with large
811 fill_arena_cell(wid
,boardw
- 1,row
,c_edgematch
);
813 if(col
== boardw
- 1)
814 fill_arena_cell(wid
,0,row
,c_edgematch
);
817 fill_arena_cell(wid
,col
,boardh
- 1,c_edgematch
);
819 if(row
== boardh
- 1)
820 fill_arena_cell(wid
,col
,0,c_edgematch
);
825 for (i
=0; i
<boardw
; i
++) {
826 for (j
=0; j
<boardh
; j
++) {
828 draw_tile(wid
, i
, j
);
834 rect
.x
= padding
+ border
+ (cellw
+ border
) * sourcex
;
835 rect
.y
= padding
+ border
+ (cellh
+ border
) * sourceytop
;
841 widget_fillrect(wid
, &rect
, c
);
843 rect
.y
= padding
+ border
+ (cellh
+ border
) * sourceybottom
;
844 widget_fillrect(wid
, &rect
, c
);
852 char* read_field(FILE *fp
)
854 char *r
= (char *) malloc(1024);
883 for (i
=0; i
<level_max
; i
++) {
884 if (hstable
[i
]->name
) {
885 label_put_text(hsw
[i
]->name
, hstable
[i
]->name
);
887 label_put_text(hsw
[i
]->name
, "None");
889 if (hstable
[i
]->time
!= -1) {
892 sprintf(s
, "%d", hstable
[i
]->time
);
893 label_put_text(hsw
[i
]->time
, s
);
895 label_put_text(hsw
[i
]->name
, "None");
905 for (i
=0; i
<level_max
; i
++) {
906 hstable
[i
]->name
= NULL
;
907 hstable
[i
]->time
= -1;
910 fp
= fopen(config
->hsfile
, "r");
913 for (i
=0; i
<level_max
; i
++) {
918 hstable
[i
]->name
= s
;
923 hstable
[i
]->time
= atoi(s
);
933 FILE *fp
= fopen(config
->hsfile
, "w");
936 for (i
=0; i
<level_max
; i
++) {
937 fprintf(fp
, "%s,%d\n", hstable
[i
]->name
, hstable
[i
]->time
);
944 void enter_name_open()
946 modalwindow
= enter_name_window
;
950 void enter_name_close()
955 player_name
= tb_en1
->text
;
957 if (hstable
[level
]->name
) {
958 free(hstable
[level
]->name
);
960 hstable
[level
]->name
= clonestr(player_name
);
961 hstable
[level
]->time
= second_count
;
968 if (hstable
[level
]->time
== -1 || second_count
< hstable
[level
]->time
) {
973 void init_tileimg(SDL_Surface
* tileimg
[64],int bgcolor
)
976 SDL_PixelFormat
*fmt
= screen
->format
;
980 pipex
= cellw
/ 2 - pipet
/ 2;
981 pipey
= cellw
/ 2 - pipet
/ 2;
982 pipew
= cellw
/ 2 + pipet
/ 2;
983 pipeh
= cellh
/ 2 + pipet
/ 2;
985 SDL_Rect entirecell
= (SDL_Rect
){
992 for (i
=0; i
<64; i
++) {
993 tileimg
[i
] = SDL_CreateRGBSurface(0, cellw
, cellh
, fmt
->BitsPerPixel
,
994 fmt
->Rmask
, fmt
->Gmask
, fmt
->Bmask
, fmt
->Amask
);
996 SDL_FillRect(tileimg
[i
], &entirecell
, ctable
[bgcolor
]);
998 for (j
=0; j
<4; j
++) {
999 if ((i
+ 1) & (1 << j
)) {
1028 } else c
= ctable
[c_off
];
1029 SDL_FillRect(tileimg
[i
], &rect
, c
);
1034 for (i
=1; i
<32; i
*=2) {
1035 rect
.x
= cellw
/ 2 - 2 * pipet
;
1036 rect
.y
= cellh
/ 2 - 2 * pipet
;
1043 SDL_FillRect(tileimg
[i
-1], &rect
, ctable
[c_down
]);
1044 SDL_FillRect(tileimg
[i
-1+16], &rect
, ctable
[c_up
]);
1048 void reset_move_count()
1051 label_put_text(l_moves
, "moves: 0");
1054 void increment_move_count()
1058 sprintf(s
, "moves: %d", move_count
);
1059 label_put_text(l_moves
, s
);
1064 label_put_text(l_time
, "time: 0");
1071 ms_count
+= tick
- tick_old
;
1072 while (ms_count
>= 1000) {
1075 sprintf(s
, "time: %d", second_count
);
1076 label_put_text(l_time
, s
);
1081 //position everything based on board size
1083 sourcex
= boardw
/ 2 - 1;
1084 sourceytop
= boardh
/ 2;
1085 sourceybottom
= sourceytop
+ 1;
1086 int w
= cellw
* boardw
+ (boardw
+ 1) * border
+ 2 * padding
;
1087 int h
= cellh
* boardh
+ (boardh
+ 1) * border
+ 2 * padding
;
1088 widget_put_geometry(arena
, 0, vsize
, w
, h
);
1089 set_video(w
, h
+ 2 * vsize
);
1090 widget_put_geometry(root
, 0, 0, w
, h
+ 2 * vsize
);
1091 widget_put_geometry(menu
, 0, 0, w
, vsize
);
1092 menubar_auto_layout(menu
);
1093 widget_put_geometry(statusbar
, 0, h
+ vsize
, w
, vsize
);
1095 widget_put_geometry(l_moves
, 8, h
+ vsize
, 64, vsize
);
1096 widget_put_geometry(l_time
, w
- 48, h
+ vsize
, 64, vsize
);
1098 widget_put_geometry((widget_ptr
) about_window
,
1099 w
/2 - 50, h
/2 - 50, 100, 100);
1100 widget_put_geometry((widget_ptr
) l_about1
, 10, 10, 60, vsize
);
1101 widget_put_geometry((widget_ptr
) l_about2
, 10, 30, 60, vsize
);
1102 widget_put_geometry((widget_ptr
) b_about1
, 30, 80, 30, vsize
);
1104 /* vertical sizes and positions for the high score window */
1105 int const hslabely
= 5;
1106 int const hslabelheight
= vsize
;
1107 int const hslisty
= hslabely
+ hslabelheight
+ 8;
1108 int const hslisteachheight
= vsize
;
1109 int const hslistheight
= hslisteachheight
* level_max
;
1110 int const hsoky
= hslisty
+ hslistheight
+ 8;
1111 int const hsokheight
= vsize
;
1112 int const hswindowheight
= hsoky
+ hsokheight
+ 5;
1114 widget_put_geometry((widget_ptr
) hs_window
,
1115 w
/2 - 75, h
/2 - 60, 170, hswindowheight
);
1116 widget_put_geometry((widget_ptr
) l_hs1
, 10, hslabely
, 60, hslabelheight
);
1117 widget_put_geometry((widget_ptr
) b_hs1
, 100, hsoky
, 30, hsokheight
);
1121 for (i
=0; i
<level_max
; i
++) {
1122 int y
= hslisty
+ (hslisteachheight
* i
);
1123 widget_put_geometry((widget_ptr
) hsw
[i
]->level
,
1124 10, y
, 20, hslisteachheight
);
1125 widget_put_geometry((widget_ptr
) hsw
[i
]->time
,
1126 60, y
, 20, hslisteachheight
);
1127 widget_put_geometry((widget_ptr
) hsw
[i
]->name
,
1128 90, y
, 20, hslisteachheight
);
1132 widget_put_geometry((widget_ptr
) enter_name_window
,
1133 10, h
/2 - 30, w
- 20, 67);
1134 widget_put_geometry((widget_ptr
) l_en1
, 10, 0, 60, vsize
);
1135 widget_put_geometry((widget_ptr
) tb_en1
, 5, vsize
+ 5, w
- 30, vsize
);
1136 widget_put_geometry((widget_ptr
) b_en1
, w
- 60, 45, 30, vsize
);
1138 ((widget_ptr
) root
)->computexy((widget_ptr
) root
);
1139 ((widget_ptr
) about_window
)->computexy((widget_ptr
) about_window
);
1140 ((widget_ptr
) hs_window
)->computexy((widget_ptr
) hs_window
);
1141 ((widget_ptr
) enter_name_window
)->computexy((widget_ptr
) enter_name_window
);
1147 strcpy(s
,"NetWalk - ");
1148 strcat(s
,level_name
[level
]);
1149 SDL_WM_SetCaption(s
,s
);
1153 boardw
= 5; boardh
= 5;
1158 boardw
= 10; boardh
= 9;
1163 boardw
= 10; boardh
= 9;
1167 case level_veryhard
:
1168 boardw
= 20; boardh
= 18;
1173 boardw
= 50; boardh
= 50;
1178 boardw
= 50; boardh
= 50;
1194 tick
= SDL_GetTicks();
1198 void handle_mousebuttonup(SDL_Event
*event
)
1200 int x
= event
->button
.x
;
1201 int y
= event
->button
.y
;
1207 m
= openedmenu
->submenu
;
1208 for (i
=0; i
<m
->item_count
; i
++) {
1209 it
= m
->item_list
[i
];
1210 if (in_widget((widget_ptr
) it
, x
, y
)) {
1211 widget_raise_signal((widget_ptr
) it
, signal_activate
);
1218 } else if (state
== state_button
) {
1220 if (in_widget(button_selection
, x
, y
)) {
1221 widget_raise_signal(button_selection
, signal_activate
);
1227 void handle_click(int button
, int x
, int y
)
1232 wid
= (widget_ptr
) modalwindow
;
1233 if (in_widget(wid
, x
, y
) && (wid
->handle_click
)) {
1234 wid
->handle_click(wid
, button
, x
, y
);
1239 wid
= (widget_ptr
) root
;
1240 wid
->handle_click(wid
, button
, x
, y
);
1243 void arena_handle_click(widget_ptr p
, int button
, int x
, int y
)
1248 if (state
!= state_game
) return;
1250 i
= (x
- padding
- border
) / (cellw
+ border
);
1251 j
= (y
- padding
- border
) / (cellh
+ border
);
1252 if (i
>= boardw
|| j
>= boardh
) return;
1255 if (i
== sourcex
&& (j
== sourceytop
|| j
== sourceybottom
)) {
1256 new_pulse(sourcex
, sourceybottom
, -1);
1257 new_pulse(sourcex
, sourceytop
, -1);
1259 new_pulse(i
, j
, -1);
1264 //temporarily merge server squares
1265 board
[sourcex
][sourceybottom
] |= board
[sourcex
][sourceytop
] & 1;
1266 if (i
== sourcex
&& j
== sourceytop
) {
1269 d
= board
[i
][j
] & 15;
1271 case SDL_BUTTON_LEFT
:
1273 increment_move_count();
1275 case SDL_BUTTON_RIGHT
:
1277 increment_move_count();
1283 board
[sourcex
][sourceytop
] &= ~1;
1284 board
[sourcex
][sourceytop
] |= board
[sourcex
][sourceybottom
] & 1;
1285 board
[sourcex
][sourceybottom
] &= ~1;
1287 if(button
== SDL_BUTTON_MIDDLE
)
1303 void quit_menu(widget_ptr w
, void *data
)
1308 void new_game_menu(widget_ptr w
, void *data
)
1313 void about_open(widget_ptr w
, void *data
)
1315 modalwindow
= about_window
;
1318 void about_close(widget_ptr w
, void *data
)
1323 void hs_open(widget_ptr w
, void *data
)
1325 modalwindow
= hs_window
;
1328 void hs_close(widget_ptr w
, void *data
)
1333 void set_level(widget_ptr w
, void *data
)
1335 level
= (intptr_t) data
;
1339 void handle_key(int key
, int mod
)
1352 textbox_left(tb_en1
);
1355 textbox_right(tb_en1
);
1358 textbox_delete(tb_en1
);
1360 case SDLK_BACKSPACE
:
1361 textbox_backspace(tb_en1
);
1364 if (key
< 256 && key
>= 32) {
1365 if (mod
& KMOD_SHIFT
) {
1366 textbox_insert(tb_en1
, shifttable
[key
]);
1368 textbox_insert(tb_en1
, key
);
1390 void update_screen()
1392 SDL_FillRect(screen
, NULL
, 0);
1393 widget_update((widget_ptr
) root
);
1398 for (i
=0; i
<menu
->item_count
; i
++) {
1399 it
= menu
->item_list
[i
];
1400 if (in_widget((widget_ptr
) it
, lastmousex
, lastmousey
)) {
1401 open_submenu((widget_ptr
) it
, NULL
);
1404 menu_update(openedmenu
->submenu
);
1407 widget_update((widget_ptr
) modalwindow
);
1412 void window_update(widget_ptr p
)
1414 window_ptr w
= (window_ptr
) p
;
1419 if (p
!= (widget_ptr
) root
) {
1424 widget_fillrect(p
, &dst
, c_windowborder
);
1425 widget_fill(p
, c_background
);
1428 for (i
=0; i
<w
->widget_count
; i
++) {
1429 wid
= w
->widget_list
[i
];
1434 void window_handle_click(widget_ptr p
, int button
, int x
, int y
)
1437 window_ptr window
= (window_ptr
) p
;
1440 for (i
=0; i
<window
->widget_count
; i
++) {
1441 wid
= window
->widget_list
[i
];
1442 if (in_widget(wid
, x
, y
) && (wid
->handle_click
)) {
1443 wid
->handle_click(wid
, button
, x
- wid
->x
, y
- wid
->y
);
1449 void window_add_widget(window_ptr r
, void *p
)
1451 widget_ptr wid
= (widget_ptr
) p
;
1452 r
->widget_list
[r
->widget_count
] = wid
;
1454 wid
->parent
= (widget_ptr
) r
;
1455 wid
->x
+= r
->widget
.x
;
1456 wid
->y
+= r
->widget
.y
;
1459 void window_computexy(widget_ptr wid
)
1462 window_ptr w
= (window_ptr
) wid
;
1464 widget_computexy(wid
);
1465 for (i
=0; i
<w
->widget_count
; i
++) {
1466 w
->widget_list
[i
]->computexy(w
->widget_list
[i
]);
1470 void window_init(window_ptr w
)
1472 widget_init((widget_ptr
) w
);
1473 w
->widget_count
= 0;
1474 w
->widget
.update
= window_update
;
1475 w
->widget
.handle_click
= window_handle_click
;
1476 w
->widget
.computexy
= window_computexy
;
1479 static void add_shiftstring(char *s1
, char *s2
)
1482 for (i
=0; i
<strlen(s1
); i
++) {
1483 shifttable
[(int) s1
[i
]] = s2
[i
];
1487 int main(int argc
, char *argv
[])
1492 level_name
[level_easy
] = "Newbie";
1493 level_name
[level_medium
] = "Normal";
1494 level_name
[level_hard
] = "Nerd";
1495 level_name
[level_veryhard
] = "Nutcase";
1496 level_name
[level_giant
] = "Nonsense";
1497 level_name
[level_absurd
] = "No Sleep";
1503 for (i
=0; i
<256; i
++) shifttable
[i
] = i
;
1505 for (i
='a'; i
<='z'; i
++) {
1506 shifttable
[i
] = i
- 32;
1509 add_shiftstring("1234567890-=", "!@#$%^&*()_+");
1510 add_shiftstring("[]\\;',./`", "{}|:\"<>?~");
1513 config_load(config
);
1519 font
= TTF_OpenFont(config
->fontname
, config
->fontsize
);
1521 fprintf(stderr
, "error loading font %s\n", config
->fontname
);
1527 //need to set video mode here to initialize colour table
1528 set_video(100, 100);
1530 //setup enter name box
1532 window_init(enter_name_window
);
1535 label_put_text(l_en1
, "Enter name:");
1536 window_add_widget(enter_name_window
, l_en1
);
1538 textbox_init(tb_en1
);
1539 textbox_put_text(tb_en1
, "Anonymous");
1540 window_add_widget(enter_name_window
, tb_en1
);
1543 button_put_text(b_en1
, "Ok");
1544 window_add_widget(enter_name_window
, b_en1
);
1545 widget_put_handler((widget_ptr
) b_en1
, enter_name_close
, signal_activate
);
1548 //setup the "arena": where the action is
1550 widget_init((widget_ptr
) arena
);
1551 arena
->widget
.update
= arena_update
;
1552 arena
->widget
.handle_click
= arena_handle_click
;
1553 window_add_widget(root
, arena
);
1556 //status bar: mainly for showing the time
1558 widget_init((widget_ptr
) statusbar
);
1559 statusbar
->update
= statusbar_update
;
1560 window_add_widget(root
, statusbar
);
1562 //setup moves and time
1563 label_init(l_moves
);
1564 if (config
->showmoves
) {
1565 window_add_widget(root
, l_moves
);
1569 window_add_widget(root
, l_time
);
1573 menuitem_t it1
, it2
;
1581 window_add_widget(root
, menu
);
1583 menuitem_put_text(it1
, "Game");
1584 menubar_add_item(menu
, it1
);
1586 menuitem_put_text(it2
, "Help");
1587 menubar_add_item(menu
, it2
);
1591 it
= menuitem_new();
1592 menuitem_put_text(it
, "New game");
1593 widget_put_handler((widget_ptr
) it
, new_game_menu
, signal_activate
);
1594 menu_add_item(m1
, it
);
1596 for (i
=0; i
<level_max
; i
++) {
1597 it
= menuitem_new();
1598 menuitem_put_text(it
, level_name
[i
]);
1599 widget_put_handler_data((widget_ptr
) it
,
1600 set_level
, (void *) i
, signal_activate
);
1601 menu_add_item(m1
, it
);
1603 it
= menuitem_new();
1604 menuitem_put_text(it
, "High Scores");
1605 widget_put_handler((widget_ptr
) it
, hs_open
, signal_activate
);
1606 menu_add_item(m1
, it
);
1607 it
= menuitem_new();
1608 menuitem_put_text(it
, "Quit");
1609 widget_put_handler((widget_ptr
) it
, quit_menu
, signal_activate
);
1610 menu_add_item(m1
, it
);
1612 menuitem_set_submenu(it1
, m1
);
1616 it
= menuitem_new();
1617 menuitem_put_text(it
, "About");
1618 widget_put_handler((widget_ptr
) it
, about_open
, signal_activate
);
1619 menu_add_item(m2
, it
);
1621 menuitem_set_submenu(it2
, m2
);
1626 window_init(about_window
);
1628 label_init(l_about1
);
1629 label_put_text(l_about1
, "NetWalk " VERSION_STRING
);
1630 window_add_widget(about_window
, l_about1
);
1632 label_init(l_about2
);
1633 label_put_text(l_about2
, "Ben Lynn");
1634 window_add_widget(about_window
, l_about2
);
1636 button_init(b_about1
);
1637 button_put_text(b_about1
, "Ok");
1638 window_add_widget(about_window
, b_about1
);
1639 widget_put_handler((widget_ptr
) b_about1
, about_close
, signal_activate
);
1642 //setup hiscores box
1645 window_init(hs_window
);
1648 label_put_text(l_hs1
, "High Scores");
1649 window_add_widget(hs_window
, l_hs1
);
1652 button_put_text(b_hs1
, "Ok");
1653 window_add_widget(hs_window
, b_hs1
);
1654 widget_put_handler((widget_ptr
) b_hs1
, hs_close
, signal_activate
);
1656 for (i
=0; i
<level_max
; i
++) {
1657 label_init(hsw
[i
]->level
);
1658 label_put_text(hsw
[i
]->level
, level_name
[i
]);
1659 window_add_widget(hs_window
, hsw
[i
]->level
);
1660 label_init(hsw
[i
]->name
);
1661 window_add_widget(hs_window
, hsw
[i
]->name
);
1662 label_init(hsw
[i
]->time
);
1663 window_add_widget(hs_window
, hsw
[i
]->time
);
1671 init_tileimg(unmarked_tileimg
,c_unmarkedbg
);
1672 init_tileimg(marked_tileimg
,c_markedbg
);
1675 while (state
!= state_quit
&& !interrupted
) {
1677 tick
= SDL_GetTicks();
1681 SDL_GetMouseState(&lastmousex
, &lastmousey
);
1682 while (SDL_PollEvent(&event
)) {
1683 switch (event
.type
) {
1685 handle_key(event
.key
.keysym
.sym
, SDL_GetModState());
1687 case SDL_MOUSEBUTTONDOWN
:
1688 handle_click(event
.button
.button
, event
.button
.x
, event
.button
.y
);
1690 case SDL_MOUSEBUTTONUP
:
1691 handle_mousebuttonup(&event
);