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;
88 typedef struct hsentry_s
*hsentry_ptr
;
89 typedef struct hsentry_s hsentry_t
[1];
91 hsentry_t hstable
[level_max
];
92 char *level_name
[level_max
];
94 //TODO use this somehow
99 typedef struct gameparm_s
*gameparm_ptr
;
100 typedef struct gameparm_s gameparm_t
[1];
104 static config_t config
;
108 int lastmousex
, lastmousey
;
114 struct widget_s widget
;
118 typedef struct button_s button_t
[1];
119 typedef struct button_s
*button_ptr
;
122 struct widget_s widget
;
126 typedef struct label_s label_t
[1];
127 typedef struct label_s
*label_ptr
;
130 struct widget_s widget
;
135 typedef struct textbox_s textbox_t
[1];
136 typedef struct textbox_s
*textbox_ptr
;
139 struct widget_s widget
;
141 typedef struct arena_s arena_t
[1];
142 typedef struct arena_s
*arena_ptr
;
145 struct widget_s widget
;
148 struct menu_s
*submenu
;
150 typedef struct menuitem_s menuitem_t
[1];
151 typedef struct menuitem_s
*menuitem_ptr
;
154 struct widget_s widget
;
155 //TODO: replace array with list
156 menuitem_ptr item_list
[64];
159 typedef struct menu_s menu_t
[1];
160 typedef struct menu_s
*menu_ptr
;
163 struct widget_s widget
;
164 //TODO: replace array with list
165 menuitem_ptr item_list
[64];
168 typedef struct menubar_s menubar_t
[1];
169 typedef struct menubar_s
*menubar_ptr
;
172 struct widget_s widget
;
173 //TODO: replace array with list
174 struct widget_s
*widget_list
[64];
178 typedef struct window_s window_t
[1];
179 typedef struct window_s
*window_ptr
;
186 typedef struct hsw_s
*hsw_ptr
;
187 typedef struct hsw_s hsw_t
[1];
189 hsw_t hsw
[level_max
];
196 menuitem_ptr openedmenu
;
197 window_ptr modalwindow
;
198 window_t about_window
;
200 window_t enter_name_window
;
213 SDL_Surface
*font_render(char *s
, int c
)
215 return TTF_RenderText_Solid(font
, s
, rgbtable
[c
]);
218 void statusbar_update(widget_ptr w
)
220 widget_lowered_background(w
);
223 void menu_init(menu_ptr m
)
225 widget_init((widget_ptr
) m
);
229 void menu_update(menu_ptr m
)
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
)) {
241 rect
.w
= ((widget_ptr
) it
)->w
- 4;
243 widget_fillrect((widget_ptr
) m
, &rect
, c_menubg
);
246 rect
.y
= vsize
* i
+ 4;
247 widget_blit((widget_ptr
) m
, it
->img
, NULL
, &rect
);
251 void menu_add_item(menu_ptr m
, menuitem_ptr it
)
253 m
->item_list
[m
->item_count
] = it
;
257 void menuitem_init(menuitem_ptr m
)
259 widget_init((widget_ptr
) m
);
265 menuitem_ptr
menuitem_new()
269 it
= (menuitem_ptr
) malloc(sizeof(menuitem_t
));
275 void menuitem_put_text(menuitem_ptr m
, char *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
);
286 void open_submenu(widget_ptr p
, void *data
)
292 openedmenu
= (menuitem_ptr
) p
;
293 menu_ptr m
= openedmenu
->submenu
;
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
;
301 m
->widget
.x
= m
->widget
.parent
->x
;
302 m
->widget
.y
= m
->widget
.parent
->y
+ vsize
;
305 m
->widget
.h
= vsize
* m
->item_count
+ 1;
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
;
312 it
->widget
.h
= vsize
;
316 void menuitem_set_submenu(menuitem_ptr it
, menu_ptr 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
;
324 void menubar_update(widget_ptr wid
)
327 menubar_ptr m
= (menubar_ptr
) wid
;
331 widget_raised_background(wid
);
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;
340 widget_fillrect(wid
, &dst
, c_menubg
);
343 dst
.x
= it
->widget
.x
+ 5;
344 dst
.y
= it
->widget
.y
+ 2;
345 widget_blit(m
, it
->img
, NULL
, &dst
);
350 void menubar_handle_click(widget_ptr p
, int button
, int x
, int y
)
353 menubar_ptr m
= (menubar_ptr
) p
;
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
);
365 void menubar_init(menubar_ptr m
)
367 widget_init((widget_ptr
) m
);
368 m
->widget
.update
= menubar_update
;
370 m
->widget
.handle_click
= menubar_handle_click
;
373 void menubar_add_item(menubar_ptr m
, menuitem_ptr it
)
375 m
->item_list
[m
->item_count
] = it
;
377 it
->widget
.parent
= (widget_ptr
) m
;
380 void menubar_auto_layout(menubar_ptr m
)
387 for (i
=0; i
<m
->item_count
; i
++) {
388 it
= m
->item_list
[i
];
392 it
->widget
.w
= it
->img
->w
+ 10;
393 it
->widget
.h
= it
->img
->h
;
394 x
+= it
->img
->w
+ 10;
399 void label_update(widget_ptr p
)
402 label_ptr l
= (label_ptr
) p
;
407 widget_blit(l
, l
->img
, NULL
, &dst
);
411 void label_init(label_ptr l
)
413 widget_init((widget_ptr
) l
);
416 l
->widget
.update
= label_update
;
419 void label_put_text(label_ptr l
, char *s
)
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
);
431 void textbox_update_img(textbox_ptr tb
)
435 if (tb
->img
) SDL_FreeSurface(tb
->img
);
436 tmp
= font_render(tb
->text
, c_text
);
438 tb
->img
= SDL_DisplayFormat(tmp
);
439 SDL_FreeSurface(tmp
);
445 void textbox_left(textbox_ptr tb
)
447 if (tb
->i
> 0) tb
->i
--;
450 void textbox_right(textbox_ptr tb
)
452 if (tb
->i
< strlen(tb
->text
)) tb
->i
++;
455 void textbox_delete(textbox_ptr tb
)
460 textbox_update_img(tb
);
464 void textbox_backspace(textbox_ptr tb
)
466 char *s
= &tb
->text
[tb
->i
];
468 memmove(s
- 1, s
, strlen(s
) + 1);
470 textbox_update_img(tb
);
474 void textbox_insert(textbox_ptr tb
, char c
)
476 char *s
= &tb
->text
[tb
->i
];
477 memmove(s
+ 1, s
, strlen(s
) + 1);
480 textbox_update_img(tb
);
483 void textbox_update(widget_ptr p
)
486 textbox_ptr tb
= (textbox_ptr
) p
;
492 widget_fillrect(p
, &dst
, c_text
);
497 widget_fillrect(p
, &dst
, c_canvas
);
502 widget_blit(tb
, tb
->img
, NULL
, &dst
);
509 strncpy(s
, tb
->text
, tb
->i
);
511 TTF_SizeText(font
, s
, &w
, &h
);
517 widget_fillrect(p
, &dst
, c_text
);
521 void textbox_init(textbox_ptr l
)
523 widget_init((widget_ptr
) l
);
525 l
->widget
.update
= textbox_update
;
528 void textbox_put_text(textbox_ptr tb
, char *s
)
532 textbox_update_img(tb
);
535 static widget_ptr button_selection
;
537 void button_handle_click(widget_ptr p
, int button
, int x
, int y
)
539 state
= state_button
;
540 button_selection
= p
;
543 void button_update(widget_ptr p
)
546 label_ptr l
= (label_ptr
) p
;
548 if (state
== state_button
&& button_selection
== p
549 && in_widget(p
, lastmousex
, lastmousey
)) {
550 widget_lowered_background(p
);
552 widget_raised_background(p
);
557 widget_blit(l
, l
->img
, NULL
, &dst
);
561 void button_init(button_ptr b
)
563 widget_init((widget_ptr
) b
);
566 b
->widget
.update
= button_update
;
567 b
->widget
.handle_click
= button_handle_click
;
570 void button_put_text(button_ptr b
, char *s
)
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
);
582 void set_video(int w
, int h
)
585 flags
= SDL_DOUBLEBUF
;
587 screen
= SDL_SetVideoMode(w
, h
, 0, flags
);
588 init_ctable(screen
->format
);
591 fprintf(stderr
, "Can't set video mode: %s\n", SDL_GetError());
595 //SDL_ShowCursor(SDL_DISABLE);
598 void set_interrupted(int i
)
607 signal(SIGINT
, set_interrupted
);
608 signal(SIGTERM
, set_interrupted
);
610 //if (SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO|SDL_INIT_TIMER) < 0) {
611 if (SDL_Init(SDL_INIT_VIDEO
|SDL_INIT_TIMER
) < 0) {
612 fprintf(stderr
, "Can't init SDL: %s\n", SDL_GetError());
618 fprintf(stderr
, "Can't init SDL_ttf\n");
623 SDL_WM_SetCaption("NetWalk", "NetWalk");
625 SDL_EnableKeyRepeat(150, 50);
628 SDL_Surface
*unmarked_tileimg
[64];
629 SDL_Surface
*marked_tileimg
[64];
630 int level
= level_medium
;
640 void draw_tile(widget_ptr wid
, int i
, int j
)
645 rect
.x
= padding
+ border
+ i
* (cellw
+ border
);
646 rect
.y
= padding
+ border
+ j
* (cellh
+ border
);
648 int const marked
= flags
[i
][j
] & 0x1;
649 index
= board
[i
][j
] - 1;
651 (marked
?marked_tileimg
:unmarked_tileimg
)[index
],
662 pulse_s pulse_list
[pulse_max
];
665 void new_pulse(int x
, int y
, int d
)
669 if (pulse_count
>= pulse_max
) return;
671 //stop incoming server pulses
672 if (x
== sourcex
&& (y
== sourceybottom
|| y
==sourceytop
) && d
!= -1) {
677 for (j
=0; j
<4; j
++) {
678 if ((j
!= d
) && (i
& (1 << j
))) {
679 pulse_list
[pulse_count
].x
= x
;
680 pulse_list
[pulse_count
].y
= y
;
681 pulse_list
[pulse_count
].dir
= j
;
682 pulse_list
[pulse_count
].tick
= tick
;
684 if (pulse_count
>= pulse_max
) return;
691 new_pulse(sourcex
, sourceybottom
, -1);
692 new_pulse(sourcex
, sourceytop
, -1);
695 void animate_pulse(widget_ptr wid
)
709 while (i
<pulse_count
) {
712 d
= pulse_list
[i
].dir
;
713 dt
= tick
- pulse_list
[i
].tick
;
716 memmove(&pulse_list
[i
], &pulse_list
[i
+1], sizeof(pulse_s
) * (pulse_count
- i
));
718 add_dir(&x
, &y
, x
, y
, d
);
719 new_pulse(x
, y
, (d
+ 2) % 4);
722 if (dir
[d
].x
== -1 && 2 * dt
> speed
&& !x
) {
725 if (dir
[d
].x
== 1 && 2 * dt
> speed
&& x
== boardw
- 1) {
728 if (dir
[d
].y
== -1 && 2 * dt
> speed
&& !y
) {
731 if (dir
[d
].y
== 1 && 2 * dt
> speed
&& y
== boardh
- 1) {
735 rect
.x
= x
* (cellw
+ border
) + pipex
- 1;
736 rect
.x
+= dir
[d
].x
* (cellw
+ border
) * dt
/ speed
;
737 rect
.x
+= border
+ padding
;
739 rect
.y
= y
* (cellh
+ border
) + border
+ padding
;
740 rect
.y
+= dir
[d
].y
* (cellh
+ border
) * dt
/ speed
;
742 widget_fillrect(wid
, &rect
, c_pulse
);
748 /** \brief Determine which cell of the arena the mouse is currently
749 * pointing at, if any.
750 * \param wid The arena widget.
751 * \param mousex The mouse X position.
752 * \param mousey The mouse Y position.
753 * \param[out] col_p Returns the current cell's column in the arena.
754 * \param[out] row_p Returns the current cell's row in the arena.
755 * \retval 0 The mouse is over the arena and the cell index is returned
756 * through \a row_p and \a col_p.
757 * \retval -1 The mouse is not over the area.
760 int get_cell_from_mouse_position(widget_ptr
const wid
,
761 int const mousex
,int const mousey
,
762 unsigned int * const col_p
,unsigned int * const row_p
)
764 if((mousex
< wid
->x
) || (mousey
< wid
->y
))
767 unsigned int const col
=
768 (mousex
- padding
- border
- wid
->x
) / (cellw
+ border
);
769 unsigned int const row
=
770 (mousey
- padding
- border
- wid
->y
) / (cellh
+ border
);
772 if((col
>= boardw
) || (row
>= boardh
))
780 /** \brief Fill a cell (including border) in the arena with a color.
781 * \param wid The arena widget.
782 * \param col The column of the cell to be filled.
783 * \param row The row of the cell to be filled.
784 * \param coloridx The index of the color to use when filling.
787 void fill_arena_cell(widget_ptr
const wid
,
788 unsigned int const col
,unsigned int const row
,int const coloridx
)
791 .x
= (cellw
+ border
) * col
+ padding
,
792 .y
= (cellh
+ border
) * row
+ padding
,
793 .w
= cellw
+ 2 * border
,
794 .h
= cellh
+ 2 * border
796 widget_fillrect(wid
, &rect
, coloridx
);
799 void arena_update(widget_ptr wid
)
809 rect
.w
= cellw
* boardw
+ (boardw
+ 1) * border
;
812 if (game_won
) bc
= c_borderwon
;
815 for (i
=0; i
<=boardh
; i
++) {
816 widget_fillrect(wid
, &rect
, bc
);
817 rect
.y
+= cellh
+ border
;
822 rect
.h
= cellh
* boardh
+ (boardh
+ 1) * border
;
823 for (i
=0; i
<=boardw
; i
++) {
824 widget_fillrect(wid
, &rect
, bc
);
825 rect
.x
+= cellw
+ border
;
831 if(get_cell_from_mouse_position(wid
,lastmousex
,lastmousey
,&col
,&row
) == 0)
833 /* highlight the cell the mouse is pointing at */
834 fill_arena_cell(wid
,col
,row
,c_highlight
);
839 * If the highlighted cell is an edge cell, also
840 * highlight the corresponding cells on opposite
841 * edges. This will make it easier to work with large
845 fill_arena_cell(wid
,boardw
- 1,row
,c_edgematch
);
847 if(col
== boardw
- 1)
848 fill_arena_cell(wid
,0,row
,c_edgematch
);
851 fill_arena_cell(wid
,col
,boardh
- 1,c_edgematch
);
853 if(row
== boardh
- 1)
854 fill_arena_cell(wid
,col
,0,c_edgematch
);
859 for (i
=0; i
<boardw
; i
++) {
860 for (j
=0; j
<boardh
; j
++) {
862 draw_tile(wid
, i
, j
);
867 if (game_won
) c
= c_serverwon
;
870 rect
.x
= padding
+ border
+ (cellw
+ border
) * sourcex
;
871 rect
.y
= padding
+ border
+ (cellh
+ border
) * sourceytop
;
877 widget_fillrect(wid
, &rect
, c
);
879 rect
.y
= padding
+ border
+ (cellh
+ border
) * sourceybottom
;
880 widget_fillrect(wid
, &rect
, c
);
888 char* read_field(FILE *fp
)
894 r
= (char *) malloc(1024);
923 for (i
=0; i
<level_max
; i
++) {
924 if (hstable
[i
]->name
) {
925 label_put_text(hsw
[i
]->name
, hstable
[i
]->name
);
927 label_put_text(hsw
[i
]->name
, "None");
929 if (hstable
[i
]->time
!= -1) {
932 sprintf(s
, "%d", hstable
[i
]->time
);
933 label_put_text(hsw
[i
]->time
, s
);
935 label_put_text(hsw
[i
]->name
, "None");
945 for (i
=0; i
<level_max
; i
++) {
946 hstable
[i
]->name
= NULL
;
947 hstable
[i
]->time
= -1;
950 fp
= fopen(config
->hsfile
, "r");
953 for(i
=0; i
<level_max
; i
++) {
958 hstable
[i
]->name
= s
;
963 hstable
[i
]->time
= atoi(s
);
976 fp
= fopen(config
->hsfile
, "w");
979 for(i
=0; i
<level_max
; i
++) {
980 fprintf(fp
, "%s,%d\n", hstable
[i
]->name
, hstable
[i
]->time
);
988 void enter_name_open()
990 modalwindow
= enter_name_window
;
994 void enter_name_close()
999 player_name
= tb_en1
->text
;
1001 if (hstable
[level
]->name
) {
1002 free(hstable
[level
]->name
);
1004 hstable
[level
]->name
= clonestr(player_name
);
1005 hstable
[level
]->time
= second_count
;
1012 if (hstable
[level
]->time
== -1 || second_count
< hstable
[level
]->time
) {
1017 void init_tileimg(SDL_Surface
* tileimg
[64],int bgcolor
)
1020 SDL_PixelFormat
*fmt
= screen
->format
;
1024 pipex
= cellw
/ 2 - pipet
/ 2;
1025 pipey
= cellw
/ 2 - pipet
/ 2;
1026 pipew
= cellw
/ 2 + pipet
/ 2;
1027 pipeh
= cellh
/ 2 + pipet
/ 2;
1029 SDL_Rect entirecell
= (SDL_Rect
){
1036 for (i
=0; i
<64; i
++) {
1037 tileimg
[i
] = SDL_CreateRGBSurface(0, cellw
, cellh
, fmt
->BitsPerPixel
,
1038 fmt
->Rmask
, fmt
->Gmask
, fmt
->Bmask
, fmt
->Amask
);
1040 SDL_FillRect(tileimg
[i
], &entirecell
, ctable
[bgcolor
]);
1042 for (j
=0; j
<4; j
++) {
1043 if ((i
+ 1) & (1 << j
)) {
1072 } else c
= ctable
[c_off
];
1073 SDL_FillRect(tileimg
[i
], &rect
, c
);
1078 for (i
=1; i
<32; i
*=2) {
1079 rect
.x
= cellw
/ 2 - 2 * pipet
;
1080 rect
.y
= cellh
/ 2 - 2 * pipet
;
1088 SDL_FillRect(tileimg[i-1], &rect, ctable[c_off]);
1089 SDL_FillRect(tileimg[i-1+16], &rect, ctable[c_on]);
1095 SDL_FillRect(tileimg
[i
-1], &rect
, ctable
[c_down
]);
1096 SDL_FillRect(tileimg
[i
-1+16], &rect
, ctable
[c_up
]);
1100 void reset_move_count()
1103 label_put_text(l_moves
, "moves: 0");
1106 void increment_move_count()
1110 sprintf(s
, "moves: %d", move_count
);
1111 label_put_text(l_moves
, s
);
1116 label_put_text(l_time
, "time: 0");
1123 ms_count
+= tick
- tick_old
;
1124 while (ms_count
>= 1000) {
1127 sprintf(s
, "time: %d", second_count
);
1128 label_put_text(l_time
, s
);
1133 //position everything based on board size
1137 sourcex
= boardw
/ 2 - 1;
1138 sourceytop
= boardh
/ 2;
1139 sourceybottom
= sourceytop
+ 1;
1141 w
= cellw
* boardw
+ (boardw
+ 1) * border
+ 2 * padding
;
1142 h
= cellh
* boardh
+ (boardh
+ 1) * border
+ 2 * padding
;
1143 widget_put_geometry(arena
, 0, vsize
, w
, h
);
1144 set_video(w
, h
+ 2 * vsize
);
1145 widget_put_geometry(root
, 0, 0, w
, h
+ 2 * vsize
);
1146 widget_put_geometry(menu
, 0, 0, w
, vsize
);
1147 menubar_auto_layout(menu
);
1148 widget_put_geometry(statusbar
, 0, h
+ vsize
, w
, vsize
);
1150 widget_put_geometry(l_moves
, 8, h
+ vsize
, 64, vsize
);
1151 widget_put_geometry(l_time
, w
- 48, h
+ vsize
, 64, vsize
);
1153 widget_put_geometry((widget_ptr
) about_window
,
1154 w
/2 - 50, h
/2 - 50, 100, 100);
1155 widget_put_geometry((widget_ptr
) l_about1
, 10, 10, 60, vsize
);
1156 widget_put_geometry((widget_ptr
) l_about2
, 10, 30, 60, vsize
);
1157 widget_put_geometry((widget_ptr
) b_about1
, 30, 80, 30, vsize
);
1159 /* vertical sizes and positions for the high score window */
1160 int const hslabely
= 5;
1161 int const hslabelheight
= vsize
;
1162 int const hslisty
= hslabely
+ hslabelheight
+ 8;
1163 int const hslisteachheight
= vsize
;
1164 int const hslistheight
= hslisteachheight
* level_max
;
1165 int const hsoky
= hslisty
+ hslistheight
+ 8;
1166 int const hsokheight
= vsize
;
1167 int const hswindowheight
= hsoky
+ hsokheight
+ 5;
1169 widget_put_geometry((widget_ptr
) hs_window
,
1170 w
/2 - 75, h
/2 - 60, 170, hswindowheight
);
1171 widget_put_geometry((widget_ptr
) l_hs1
, 10, hslabely
, 60, hslabelheight
);
1172 widget_put_geometry((widget_ptr
) b_hs1
, 100, hsoky
, 30, hsokheight
);
1176 for (i
=0; i
<level_max
; i
++) {
1177 int y
= hslisty
+ (hslisteachheight
* i
);
1178 widget_put_geometry((widget_ptr
) hsw
[i
]->level
,
1179 10, y
, 20, hslisteachheight
);
1180 widget_put_geometry((widget_ptr
) hsw
[i
]->time
,
1181 60, y
, 20, hslisteachheight
);
1182 widget_put_geometry((widget_ptr
) hsw
[i
]->name
,
1183 90, y
, 20, hslisteachheight
);
1187 widget_put_geometry((widget_ptr
) enter_name_window
,
1188 10, h
/2 - 30, w
- 20, 67);
1189 widget_put_geometry((widget_ptr
) l_en1
, 10, 0, 60, vsize
);
1190 widget_put_geometry((widget_ptr
) tb_en1
, 5, vsize
+ 5, w
- 30, vsize
);
1191 widget_put_geometry((widget_ptr
) b_en1
, w
- 60, 45, 30, vsize
);
1193 ((widget_ptr
) root
)->computexy((widget_ptr
) root
);
1194 ((widget_ptr
) about_window
)->computexy((widget_ptr
) about_window
);
1195 ((widget_ptr
) hs_window
)->computexy((widget_ptr
) hs_window
);
1196 ((widget_ptr
) enter_name_window
)->computexy((widget_ptr
) enter_name_window
);
1202 strcpy(s
,"NetWalk - ");
1203 strcat(s
,level_name
[level
]);
1204 SDL_WM_SetCaption(s
,s
);
1208 boardw
= 5; boardh
= 5;
1213 boardw
= 10; boardh
= 9;
1218 boardw
= 10; boardh
= 9;
1222 case level_veryhard
:
1223 boardw
= 20; boardh
= 18;
1228 boardw
= 50; boardh
= 50;
1233 boardw
= 50; boardh
= 50;
1249 tick
= SDL_GetTicks();
1253 void handle_mousebuttonup(SDL_Event
*event
)
1255 int x
= event
->button
.x
;
1256 int y
= event
->button
.y
;
1262 m
= openedmenu
->submenu
;
1263 for (i
=0; i
<m
->item_count
; i
++) {
1264 it
= m
->item_list
[i
];
1265 if (in_widget((widget_ptr
) it
, x
, y
)) {
1266 widget_raise_signal((widget_ptr
) it
, signal_activate
);
1273 } else if (state
== state_button
) {
1275 if (in_widget(button_selection
, x
, y
)) {
1276 widget_raise_signal(button_selection
, signal_activate
);
1282 void handle_click(int button
, int x
, int y
)
1287 wid
= (widget_ptr
) modalwindow
;
1288 if (in_widget(wid
, x
, y
) && (wid
->handle_click
)) {
1289 wid
->handle_click(wid
, button
, x
, y
);
1294 wid
= (widget_ptr
) root
;
1295 wid
->handle_click(wid
, button
, x
, y
);
1298 void arena_handle_click(widget_ptr p
, int button
, int x
, int y
)
1303 if (state
!= state_game
) return;
1305 i
= (x
- padding
- border
) / (cellw
+ border
);
1306 j
= (y
- padding
- border
) / (cellh
+ border
);
1307 if (i
>= boardw
|| j
>= boardh
) return;
1310 if (i
== sourcex
&& (j
== sourceytop
|| j
== sourceybottom
)) {
1311 new_pulse(sourcex
, sourceybottom
, -1);
1312 new_pulse(sourcex
, sourceytop
, -1);
1314 new_pulse(i
, j
, -1);
1319 //temporarily merge server squares
1320 board
[sourcex
][sourceybottom
] |= board
[sourcex
][sourceytop
] & 1;
1321 if (i
== sourcex
&& j
== sourceytop
) {
1324 d
= board
[i
][j
] & 15;
1326 case SDL_BUTTON_LEFT
:
1328 increment_move_count();
1330 case SDL_BUTTON_RIGHT
:
1332 increment_move_count();
1338 board
[sourcex
][sourceytop
] &= ~1;
1339 board
[sourcex
][sourceytop
] |= board
[sourcex
][sourceybottom
] & 1;
1340 board
[sourcex
][sourceybottom
] &= ~1;
1342 if(button
== SDL_BUTTON_MIDDLE
)
1358 void quit_menu(widget_ptr w
, void *data
)
1363 void new_game_menu(widget_ptr w
, void *data
)
1368 void about_open(widget_ptr w
, void *data
)
1370 modalwindow
= about_window
;
1373 void about_close(widget_ptr w
, void *data
)
1378 void hs_open(widget_ptr w
, void *data
)
1380 modalwindow
= hs_window
;
1383 void hs_close(widget_ptr w
, void *data
)
1388 void set_level(widget_ptr w
, void *data
)
1394 void handle_key(int key
, int mod
)
1407 textbox_left(tb_en1
);
1410 textbox_right(tb_en1
);
1413 textbox_delete(tb_en1
);
1415 case SDLK_BACKSPACE
:
1416 textbox_backspace(tb_en1
);
1419 if (key
< 256 && key
>= 32) {
1420 if (mod
& KMOD_SHIFT
) {
1421 textbox_insert(tb_en1
, shifttable
[key
]);
1423 textbox_insert(tb_en1
, key
);
1445 void update_screen()
1447 SDL_FillRect(screen
, NULL
, 0);
1448 widget_update((widget_ptr
) root
);
1453 for (i
=0; i
<menu
->item_count
; i
++) {
1454 it
= menu
->item_list
[i
];
1455 if (in_widget((widget_ptr
) it
, lastmousex
, lastmousey
)) {
1456 open_submenu((widget_ptr
) it
, NULL
);
1459 menu_update(openedmenu
->submenu
);
1462 widget_update((widget_ptr
) modalwindow
);
1467 void window_update(widget_ptr p
)
1469 window_ptr w
= (window_ptr
) p
;
1474 if (p
!= (widget_ptr
) root
) {
1479 widget_fillrect(p
, &dst
, c_windowborder
);
1480 widget_fill(p
, c_background
);
1483 for (i
=0; i
<w
->widget_count
; i
++) {
1484 wid
= w
->widget_list
[i
];
1489 void window_handle_click(widget_ptr p
, int button
, int x
, int y
)
1492 window_ptr window
= (window_ptr
) p
;
1495 for (i
=0; i
<window
->widget_count
; i
++) {
1496 wid
= window
->widget_list
[i
];
1497 if (in_widget(wid
, x
, y
) && (wid
->handle_click
)) {
1498 wid
->handle_click(wid
, button
, x
- wid
->x
, y
- wid
->y
);
1504 void window_add_widget(window_ptr r
, void *p
)
1506 widget_ptr wid
= (widget_ptr
) p
;
1507 r
->widget_list
[r
->widget_count
] = wid
;
1509 wid
->parent
= (widget_ptr
) r
;
1510 wid
->x
+= r
->widget
.x
;
1511 wid
->y
+= r
->widget
.y
;
1514 void window_computexy(widget_ptr wid
)
1517 window_ptr w
= (window_ptr
) wid
;
1519 widget_computexy(wid
);
1520 for (i
=0; i
<w
->widget_count
; i
++) {
1521 w
->widget_list
[i
]->computexy(w
->widget_list
[i
]);
1525 void window_init(window_ptr w
)
1527 widget_init((widget_ptr
) w
);
1528 w
->widget_count
= 0;
1529 w
->widget
.update
= window_update
;
1530 w
->widget
.handle_click
= window_handle_click
;
1531 w
->widget
.computexy
= window_computexy
;
1534 static void add_shiftstring(char *s1
, char *s2
)
1538 for (i
=0; i
<strlen(s1
); i
++) {
1539 shifttable
[(int) s1
[i
]] = s2
[i
];
1543 int main(int argc
, char *argv
[])
1548 level_name
[level_easy
] = "Newbie";
1549 level_name
[level_medium
] = "Normal";
1550 level_name
[level_hard
] = "Nerd";
1551 level_name
[level_veryhard
] = "Nutcase";
1552 level_name
[level_giant
] = "Nonsense";
1553 level_name
[level_absurd
] = "No Sleep";
1559 for (i
=0; i
<256; i
++) shifttable
[i
] = i
;
1561 for (i
='a'; i
<='z'; i
++) {
1562 shifttable
[i
] = i
- 32;
1565 add_shiftstring("1234567890-=", "!@#$%^&*()_+");
1566 add_shiftstring("[]\\;',./`", "{}|:\"<>?~");
1569 config_load(config
);
1575 font
= TTF_OpenFont(config
->fontname
, config
->fontsize
);
1577 fprintf(stderr
, "error loading font %s\n", config
->fontname
);
1583 //need to set video mode here to initialize colour table
1584 set_video(100, 100);
1586 //setup enter name box
1588 window_init(enter_name_window
);
1591 label_put_text(l_en1
, "Enter name:");
1592 window_add_widget(enter_name_window
, l_en1
);
1594 textbox_init(tb_en1
);
1595 textbox_put_text(tb_en1
, "Anonymous");
1596 window_add_widget(enter_name_window
, tb_en1
);
1599 button_put_text(b_en1
, "Ok");
1600 window_add_widget(enter_name_window
, b_en1
);
1601 widget_put_handler((widget_ptr
) b_en1
, enter_name_close
, signal_activate
);
1604 //setup the "arena": where the action is
1606 widget_init((widget_ptr
) arena
);
1607 arena
->widget
.update
= arena_update
;
1608 arena
->widget
.handle_click
= arena_handle_click
;
1609 window_add_widget(root
, arena
);
1612 //status bar: mainly for showing the time
1614 widget_init((widget_ptr
) statusbar
);
1615 statusbar
->update
= statusbar_update
;
1616 window_add_widget(root
, statusbar
);
1618 //setup moves and time
1619 label_init(l_moves
);
1620 if (config
->showmoves
) {
1621 window_add_widget(root
, l_moves
);
1625 window_add_widget(root
, l_time
);
1630 menuitem_t it1
, it2
;
1637 window_add_widget(root
, menu
);
1639 menuitem_put_text(it1
, "Game");
1640 menubar_add_item(menu
, it1
);
1642 menuitem_put_text(it2
, "Help");
1643 menubar_add_item(menu
, it2
);
1647 it
= menuitem_new();
1648 menuitem_put_text(it
, "New game");
1649 widget_put_handler((widget_ptr
) it
, new_game_menu
, signal_activate
);
1650 menu_add_item(m1
, it
);
1652 for (i
=0; i
<level_max
; i
++) {
1653 it
= menuitem_new();
1654 menuitem_put_text(it
, level_name
[i
]);
1655 widget_put_handler_data((widget_ptr
) it
,
1656 set_level
, (void *) i
, signal_activate
);
1657 menu_add_item(m1
, it
);
1659 it
= menuitem_new();
1660 menuitem_put_text(it
, "High Scores");
1661 widget_put_handler((widget_ptr
) it
, hs_open
, signal_activate
);
1662 menu_add_item(m1
, it
);
1663 it
= menuitem_new();
1664 menuitem_put_text(it
, "Quit");
1665 widget_put_handler((widget_ptr
) it
, quit_menu
, signal_activate
);
1666 menu_add_item(m1
, it
);
1668 menuitem_set_submenu(it1
, m1
);
1672 it
= menuitem_new();
1673 menuitem_put_text(it
, "About");
1674 widget_put_handler((widget_ptr
) it
, about_open
, signal_activate
);
1675 menu_add_item(m2
, it
);
1677 menuitem_set_submenu(it2
, m2
);
1682 window_init(about_window
);
1684 label_init(l_about1
);
1685 label_put_text(l_about1
, "NetWalk " VERSION_STRING
);
1686 window_add_widget(about_window
, l_about1
);
1688 label_init(l_about2
);
1689 label_put_text(l_about2
, "Ben Lynn");
1690 window_add_widget(about_window
, l_about2
);
1692 button_init(b_about1
);
1693 button_put_text(b_about1
, "Ok");
1694 window_add_widget(about_window
, b_about1
);
1695 widget_put_handler((widget_ptr
) b_about1
, about_close
, signal_activate
);
1698 //setup hiscores box
1701 window_init(hs_window
);
1704 label_put_text(l_hs1
, "High Scores");
1705 window_add_widget(hs_window
, l_hs1
);
1708 button_put_text(b_hs1
, "Ok");
1709 window_add_widget(hs_window
, b_hs1
);
1710 widget_put_handler((widget_ptr
) b_hs1
, hs_close
, signal_activate
);
1712 for (i
=0; i
<level_max
; i
++) {
1713 label_init(hsw
[i
]->level
);
1714 label_put_text(hsw
[i
]->level
, level_name
[i
]);
1715 window_add_widget(hs_window
, hsw
[i
]->level
);
1716 label_init(hsw
[i
]->name
);
1717 window_add_widget(hs_window
, hsw
[i
]->name
);
1718 label_init(hsw
[i
]->time
);
1719 window_add_widget(hs_window
, hsw
[i
]->time
);
1727 init_tileimg(unmarked_tileimg
,c_unmarkedbg
);
1728 init_tileimg(marked_tileimg
,c_markedbg
);
1731 while (state
!= state_quit
&& !interrupted
) {
1733 tick
= SDL_GetTicks();
1737 SDL_GetMouseState(&lastmousex
, &lastmousey
);
1738 while (SDL_PollEvent(&event
)) {
1739 switch (event
.type
) {
1741 handle_key(event
.key
.keysym
.sym
, SDL_GetModState());
1743 case SDL_MOUSEBUTTONDOWN
:
1744 handle_click(event
.button
.button
, event
.button
.x
, event
.button
.y
);
1746 case SDL_MOUSEBUTTONUP
:
1747 handle_mousebuttonup(&event
);