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 //TODO use this somehow
98 typedef struct gameparm_s
*gameparm_ptr
;
99 typedef struct gameparm_s gameparm_t
[1];
103 static config_t config
;
107 int lastmousex
, lastmousey
;
113 struct widget_s widget
;
117 typedef struct button_s button_t
[1];
118 typedef struct button_s
*button_ptr
;
121 struct widget_s widget
;
125 typedef struct label_s label_t
[1];
126 typedef struct label_s
*label_ptr
;
129 struct widget_s widget
;
134 typedef struct textbox_s textbox_t
[1];
135 typedef struct textbox_s
*textbox_ptr
;
138 struct widget_s widget
;
140 typedef struct arena_s arena_t
[1];
141 typedef struct arena_s
*arena_ptr
;
144 struct widget_s widget
;
147 struct menu_s
*submenu
;
149 typedef struct menuitem_s menuitem_t
[1];
150 typedef struct menuitem_s
*menuitem_ptr
;
153 struct widget_s widget
;
154 //TODO: replace array with list
155 menuitem_ptr item_list
[64];
158 typedef struct menu_s menu_t
[1];
159 typedef struct menu_s
*menu_ptr
;
162 struct widget_s widget
;
163 //TODO: replace array with list
164 menuitem_ptr item_list
[64];
167 typedef struct menubar_s menubar_t
[1];
168 typedef struct menubar_s
*menubar_ptr
;
171 struct widget_s widget
;
172 //TODO: replace array with list
173 struct widget_s
*widget_list
[64];
177 typedef struct window_s window_t
[1];
178 typedef struct window_s
*window_ptr
;
185 typedef struct hsw_s
*hsw_ptr
;
186 typedef struct hsw_s hsw_t
[1];
188 hsw_t hsw
[level_max
];
195 menuitem_ptr openedmenu
;
196 window_ptr modalwindow
;
197 window_t about_window
;
199 window_t enter_name_window
;
212 SDL_Surface
*font_render(char *s
, int c
)
214 return TTF_RenderText_Solid(font
, s
, rgbtable
[c
]);
217 void statusbar_update(widget_ptr w
)
219 widget_lowered_background(w
);
222 void menu_init(menu_ptr m
)
224 widget_init((widget_ptr
) m
);
228 void menu_update(menu_ptr m
)
234 widget_fill((widget_ptr
) m
, c_background
);
235 for (i
=0; i
<m
->item_count
; i
++) {
236 it
= m
->item_list
[i
];
237 if (in_widget((widget_ptr
) it
, lastmousex
, lastmousey
)) {
240 rect
.w
= ((widget_ptr
) it
)->w
- 4;
242 widget_fillrect((widget_ptr
) m
, &rect
, c_menubg
);
245 rect
.y
= vsize
* i
+ 4;
246 widget_blit((widget_ptr
) m
, it
->img
, NULL
, &rect
);
250 void menu_add_item(menu_ptr m
, menuitem_ptr it
)
252 m
->item_list
[m
->item_count
] = it
;
256 void menuitem_init(menuitem_ptr m
)
258 widget_init((widget_ptr
) m
);
264 menuitem_ptr
menuitem_new()
268 it
= (menuitem_ptr
) malloc(sizeof(menuitem_t
));
274 void menuitem_put_text(menuitem_ptr m
, char *s
)
279 if (m
->img
) SDL_FreeSurface(m
->img
);
280 tmp
= font_render(s
, c_text
);
281 m
->img
= SDL_DisplayFormat(tmp
);
282 SDL_FreeSurface(tmp
);
285 void open_submenu(widget_ptr p
, void *data
)
291 openedmenu
= (menuitem_ptr
) p
;
292 menu_ptr m
= openedmenu
->submenu
;
294 for (i
=0; i
<m
->item_count
; i
++) {
295 it
= m
->item_list
[i
];
296 if (w
< it
->img
->w
) w
= it
->img
->w
;
300 m
->widget
.x
= m
->widget
.parent
->x
;
301 m
->widget
.y
= m
->widget
.parent
->y
+ vsize
;
304 m
->widget
.h
= vsize
* m
->item_count
+ 1;
306 for (i
=0; i
<m
->item_count
; i
++) {
307 it
= m
->item_list
[i
];
308 it
->widget
.x
= 0 + m
->widget
.x
;
309 it
->widget
.y
= vsize
* i
+ 4 + m
->widget
.y
;
311 it
->widget
.h
= vsize
;
315 void menuitem_set_submenu(menuitem_ptr it
, menu_ptr m
)
318 //it->widget.signal_handler[signal_activate] = open_submenu;
319 widget_put_handler((widget_ptr
) it
, open_submenu
, signal_activate
);
320 m
->widget
.parent
= (widget_ptr
) it
;
323 void menubar_update(widget_ptr wid
)
326 menubar_ptr m
= (menubar_ptr
) wid
;
330 widget_raised_background(wid
);
332 for (i
=0; i
<m
->item_count
; i
++) {
333 it
= m
->item_list
[i
];
334 if (it
== openedmenu
) {
335 dst
.x
= it
->widget
.x
+ 2;
336 dst
.y
= it
->widget
.y
+ 2;
337 dst
.w
= it
->widget
.w
- 4;
339 widget_fillrect(wid
, &dst
, c_menubg
);
342 dst
.x
= it
->widget
.x
+ 5;
343 dst
.y
= it
->widget
.y
+ 2;
344 widget_blit(m
, it
->img
, NULL
, &dst
);
349 void menubar_handle_click(widget_ptr p
, int button
, int x
, int y
)
352 menubar_ptr m
= (menubar_ptr
) p
;
355 for (i
=0; i
<m
->item_count
; i
++) {
356 it
= m
->item_list
[i
];
357 if (in_widget((widget_ptr
) it
, x
, y
)) {
358 widget_raise_signal((widget_ptr
) it
, signal_activate
);
364 void menubar_init(menubar_ptr m
)
366 widget_init((widget_ptr
) m
);
367 m
->widget
.update
= menubar_update
;
369 m
->widget
.handle_click
= menubar_handle_click
;
372 void menubar_add_item(menubar_ptr m
, menuitem_ptr it
)
374 m
->item_list
[m
->item_count
] = it
;
376 it
->widget
.parent
= (widget_ptr
) m
;
379 void menubar_auto_layout(menubar_ptr m
)
386 for (i
=0; i
<m
->item_count
; i
++) {
387 it
= m
->item_list
[i
];
391 it
->widget
.w
= it
->img
->w
+ 10;
392 it
->widget
.h
= it
->img
->h
;
393 x
+= it
->img
->w
+ 10;
398 void label_update(widget_ptr p
)
401 label_ptr l
= (label_ptr
) p
;
406 widget_blit(l
, l
->img
, NULL
, &dst
);
410 void label_init(label_ptr l
)
412 widget_init((widget_ptr
) l
);
415 l
->widget
.update
= label_update
;
418 void label_put_text(label_ptr l
, char *s
)
422 if (l
->img
) SDL_FreeSurface(l
->img
);
423 if (l
->text
) free(l
->text
);
424 l
->text
= clonestr(s
);
425 tmp
= font_render(s
, c_text
);
426 l
->img
= SDL_DisplayFormat(tmp
);
427 SDL_FreeSurface(tmp
);
430 void textbox_update_img(textbox_ptr tb
)
434 if (tb
->img
) SDL_FreeSurface(tb
->img
);
435 tmp
= font_render(tb
->text
, c_text
);
437 tb
->img
= SDL_DisplayFormat(tmp
);
438 SDL_FreeSurface(tmp
);
444 void textbox_left(textbox_ptr tb
)
446 if (tb
->i
> 0) tb
->i
--;
449 void textbox_right(textbox_ptr tb
)
451 if (tb
->i
< strlen(tb
->text
)) tb
->i
++;
454 void textbox_delete(textbox_ptr tb
)
459 textbox_update_img(tb
);
463 void textbox_backspace(textbox_ptr tb
)
465 char *s
= &tb
->text
[tb
->i
];
467 memmove(s
- 1, s
, strlen(s
) + 1);
469 textbox_update_img(tb
);
473 void textbox_insert(textbox_ptr tb
, char c
)
475 char *s
= &tb
->text
[tb
->i
];
476 memmove(s
+ 1, s
, strlen(s
) + 1);
479 textbox_update_img(tb
);
482 void textbox_update(widget_ptr p
)
485 textbox_ptr tb
= (textbox_ptr
) p
;
491 widget_fillrect(p
, &dst
, c_text
);
496 widget_fillrect(p
, &dst
, c_canvas
);
501 widget_blit(tb
, tb
->img
, NULL
, &dst
);
508 strncpy(s
, tb
->text
, tb
->i
);
510 TTF_SizeText(font
, s
, &w
, &h
);
516 widget_fillrect(p
, &dst
, c_text
);
520 void textbox_init(textbox_ptr l
)
522 widget_init((widget_ptr
) l
);
524 l
->widget
.update
= textbox_update
;
527 void textbox_put_text(textbox_ptr tb
, char *s
)
531 textbox_update_img(tb
);
534 static widget_ptr button_selection
;
536 void button_handle_click(widget_ptr p
, int button
, int x
, int y
)
538 state
= state_button
;
539 button_selection
= p
;
542 void button_update(widget_ptr p
)
545 label_ptr l
= (label_ptr
) p
;
547 if (state
== state_button
&& button_selection
== p
548 && in_widget(p
, lastmousex
, lastmousey
)) {
549 widget_lowered_background(p
);
551 widget_raised_background(p
);
556 widget_blit(l
, l
->img
, NULL
, &dst
);
560 void button_init(button_ptr b
)
562 widget_init((widget_ptr
) b
);
565 b
->widget
.update
= button_update
;
566 b
->widget
.handle_click
= button_handle_click
;
569 void button_put_text(button_ptr b
, char *s
)
573 if (b
->img
) SDL_FreeSurface(b
->img
);
574 if (b
->text
) free(b
->text
);
575 b
->text
= clonestr(s
);
576 tmp
= font_render(s
, c_text
);
577 b
->img
= SDL_DisplayFormat(tmp
);
578 SDL_FreeSurface(tmp
);
581 void set_video(int w
, int h
)
584 flags
= SDL_DOUBLEBUF
;
586 screen
= SDL_SetVideoMode(w
, h
, 0, flags
);
587 // flags = SDL_FULLSCREEN;
588 // screen = SDL_SetVideoMode(0, 0, 0, flags);
589 init_ctable(screen
->format
);
592 fprintf(stderr
, "Can't set video mode: %s\n", SDL_GetError());
596 //SDL_ShowCursor(SDL_DISABLE);
599 void set_interrupted(int i
)
608 signal(SIGINT
, set_interrupted
);
609 signal(SIGTERM
, set_interrupted
);
611 //if (SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO|SDL_INIT_TIMER) < 0) {
612 if (SDL_Init(SDL_INIT_VIDEO
|SDL_INIT_TIMER
) < 0) {
613 fprintf(stderr
, "Can't init SDL: %s\n", SDL_GetError());
619 fprintf(stderr
, "Can't init SDL_ttf\n");
624 SDL_WM_SetCaption("NetWalk", "NetWalk");
626 SDL_EnableKeyRepeat(150, 50);
629 SDL_Surface
*unmarked_tileimg
[64];
630 SDL_Surface
*marked_tileimg
[64];
631 int level
= level_medium
;
641 void draw_tile(widget_ptr wid
, int i
, int j
)
646 rect
.x
= padding
+ border
+ i
* (cellw
+ border
);
647 rect
.y
= padding
+ border
+ j
* (cellh
+ border
);
649 int const marked
= flags
[i
][j
] & 0x1;
650 index
= board
[i
][j
] - 1;
652 (marked
?marked_tileimg
:unmarked_tileimg
)[index
],
663 pulse_s pulse_list
[pulse_max
];
666 void new_pulse(int x
, int y
, int d
)
670 if (pulse_count
>= pulse_max
) return;
672 //stop incoming server pulses
673 if (x
== sourcex
&& (y
== sourceybottom
|| y
==sourceytop
) && d
!= -1) {
678 for (j
=0; j
<4; j
++) {
679 if ((j
!= d
) && (i
& (1 << j
))) {
680 pulse_list
[pulse_count
].x
= x
;
681 pulse_list
[pulse_count
].y
= y
;
682 pulse_list
[pulse_count
].dir
= j
;
683 pulse_list
[pulse_count
].tick
= tick
;
685 if (pulse_count
>= pulse_max
) return;
692 new_pulse(sourcex
, sourceybottom
, -1);
693 new_pulse(sourcex
, sourceytop
, -1);
696 void animate_pulse(widget_ptr wid
)
710 while (i
<pulse_count
) {
713 d
= pulse_list
[i
].dir
;
714 dt
= tick
- pulse_list
[i
].tick
;
717 memmove(&pulse_list
[i
], &pulse_list
[i
+1], sizeof(pulse_s
) * (pulse_count
- i
));
719 add_dir(&x
, &y
, x
, y
, d
);
720 new_pulse(x
, y
, (d
+ 2) % 4);
723 if (dir
[d
].x
== -1 && 2 * dt
> speed
&& !x
) {
726 if (dir
[d
].x
== 1 && 2 * dt
> speed
&& x
== boardw
- 1) {
729 if (dir
[d
].y
== -1 && 2 * dt
> speed
&& !y
) {
732 if (dir
[d
].y
== 1 && 2 * dt
> speed
&& y
== boardh
- 1) {
736 rect
.x
= x
* (cellw
+ border
) + pipex
- 1;
737 rect
.x
+= dir
[d
].x
* (cellw
+ border
) * dt
/ speed
;
738 rect
.x
+= border
+ padding
;
740 rect
.y
= y
* (cellh
+ border
) + border
+ padding
;
741 rect
.y
+= dir
[d
].y
* (cellh
+ border
) * dt
/ speed
;
743 widget_fillrect(wid
, &rect
, c_pulse
);
749 /** \brief Determine which cell of the arena the mouse is currently
750 * pointing at, if any.
751 * \param wid The arena widget.
752 * \param mousex The mouse X position.
753 * \param mousey The mouse Y position.
754 * \param[out] col_p Returns the current cell's column in the arena.
755 * \param[out] row_p Returns the current cell's row in the arena.
756 * \retval 0 The mouse is over the arena and the cell index is returned
757 * through \a row_p and \a col_p.
758 * \retval -1 The mouse is not over the area.
761 int get_cell_from_mouse_position(widget_ptr
const wid
,
762 int const mousex
,int const mousey
,
763 unsigned int * const col_p
,unsigned int * const row_p
)
765 if((mousex
< wid
->x
) || (mousey
< wid
->y
))
768 unsigned int const col
=
769 (mousex
- padding
- border
- wid
->x
) / (cellw
+ border
);
770 unsigned int const row
=
771 (mousey
- padding
- border
- wid
->y
) / (cellh
+ border
);
773 if((col
>= boardw
) || (row
>= boardh
))
781 /** \brief Fill a cell (including border) in the arena with a color.
782 * \param wid The arena widget.
783 * \param col The column of the cell to be filled.
784 * \param row The row of the cell to be filled.
785 * \param coloridx The index of the color to use when filling.
788 void fill_arena_cell(widget_ptr
const wid
,
789 unsigned int const col
,unsigned int const row
,int const coloridx
)
792 .x
= (cellw
+ border
) * col
+ padding
,
793 .y
= (cellh
+ border
) * row
+ padding
,
794 .w
= cellw
+ 2 * border
,
795 .h
= cellh
+ 2 * border
797 widget_fillrect(wid
, &rect
, coloridx
);
800 void arena_update(widget_ptr wid
)
810 rect
.w
= cellw
* boardw
+ (boardw
+ 1) * border
;
813 if (game_won
) bc
= c_borderwon
;
816 for (i
=0; i
<=boardh
; i
++) {
817 widget_fillrect(wid
, &rect
, bc
);
818 rect
.y
+= cellh
+ border
;
823 rect
.h
= cellh
* boardh
+ (boardh
+ 1) * border
;
824 for (i
=0; i
<=boardw
; i
++) {
825 widget_fillrect(wid
, &rect
, bc
);
826 rect
.x
+= cellw
+ border
;
832 if(get_cell_from_mouse_position(wid
,lastmousex
,lastmousey
,&col
,&row
) == 0)
834 /* highlight the cell the mouse is pointing at */
835 fill_arena_cell(wid
,col
,row
,c_highlight
);
840 * If the highlighted cell is an edge cell, also
841 * highlight the corresponding cells on opposite
842 * edges. This will make it easier to work with large
846 fill_arena_cell(wid
,boardw
- 1,row
,c_edgematch
);
848 if(col
== boardw
- 1)
849 fill_arena_cell(wid
,0,row
,c_edgematch
);
852 fill_arena_cell(wid
,col
,boardh
- 1,c_edgematch
);
854 if(row
== boardh
- 1)
855 fill_arena_cell(wid
,col
,0,c_edgematch
);
860 for (i
=0; i
<boardw
; i
++) {
861 for (j
=0; j
<boardh
; j
++) {
863 draw_tile(wid
, i
, j
);
868 if (game_won
) c
= c_serverwon
;
871 rect
.x
= padding
+ border
+ (cellw
+ border
) * sourcex
;
872 rect
.y
= padding
+ border
+ (cellh
+ border
) * sourceytop
;
878 widget_fillrect(wid
, &rect
, c
);
880 rect
.y
= padding
+ border
+ (cellh
+ border
) * sourceybottom
;
881 widget_fillrect(wid
, &rect
, c
);
889 char* read_field(FILE *fp
)
895 r
= (char *) malloc(1024);
924 for (i
=0; i
<level_max
; i
++) {
925 if (hstable
[i
]->name
) {
926 label_put_text(hsw
[i
]->name
, hstable
[i
]->name
);
928 label_put_text(hsw
[i
]->name
, "None");
930 if (hstable
[i
]->time
!= -1) {
933 sprintf(s
, "%d", hstable
[i
]->time
);
934 label_put_text(hsw
[i
]->time
, s
);
936 label_put_text(hsw
[i
]->name
, "None");
946 for (i
=0; i
<level_max
; i
++) {
947 hstable
[i
]->name
= NULL
;
948 hstable
[i
]->time
= -1;
951 fp
= fopen(config
->hsfile
, "r");
954 for(i
=0; i
<level_max
; i
++) {
959 hstable
[i
]->name
= s
;
964 hstable
[i
]->time
= atoi(s
);
977 fp
= fopen(config
->hsfile
, "w");
980 for(i
=0; i
<level_max
; i
++) {
981 fprintf(fp
, "%s,%d\n", hstable
[i
]->name
, hstable
[i
]->time
);
989 void enter_name_open()
991 modalwindow
= enter_name_window
;
995 void enter_name_close()
1000 player_name
= tb_en1
->text
;
1002 if (hstable
[level
]->name
) {
1003 free(hstable
[level
]->name
);
1005 hstable
[level
]->name
= clonestr(player_name
);
1006 hstable
[level
]->time
= second_count
;
1013 if (hstable
[level
]->time
== -1 || second_count
< hstable
[level
]->time
) {
1018 void init_tileimg(SDL_Surface
* tileimg
[64],int bgcolor
)
1021 SDL_PixelFormat
*fmt
= screen
->format
;
1025 pipex
= cellw
/ 2 - pipet
/ 2;
1026 pipey
= cellw
/ 2 - pipet
/ 2;
1027 pipew
= cellw
/ 2 + pipet
/ 2;
1028 pipeh
= cellh
/ 2 + pipet
/ 2;
1030 SDL_Rect entirecell
= (SDL_Rect
){
1037 for (i
=0; i
<64; i
++) {
1038 tileimg
[i
] = SDL_CreateRGBSurface(0, cellw
, cellh
, fmt
->BitsPerPixel
,
1039 fmt
->Rmask
, fmt
->Gmask
, fmt
->Bmask
, fmt
->Amask
);
1041 SDL_FillRect(tileimg
[i
], &entirecell
, ctable
[bgcolor
]);
1043 for (j
=0; j
<4; j
++) {
1044 if ((i
+ 1) & (1 << j
)) {
1073 } else c
= ctable
[c_off
];
1074 SDL_FillRect(tileimg
[i
], &rect
, c
);
1079 for (i
=1; i
<32; i
*=2) {
1080 rect
.x
= cellw
/ 2 - 2 * pipet
;
1081 rect
.y
= cellh
/ 2 - 2 * pipet
;
1089 SDL_FillRect(tileimg[i-1], &rect, ctable[c_off]);
1090 SDL_FillRect(tileimg[i-1+16], &rect, ctable[c_on]);
1096 SDL_FillRect(tileimg
[i
-1], &rect
, ctable
[c_down
]);
1097 SDL_FillRect(tileimg
[i
-1+16], &rect
, ctable
[c_up
]);
1101 void reset_move_count()
1104 label_put_text(l_moves
, "moves: 0");
1107 void increment_move_count()
1111 sprintf(s
, "moves: %d", move_count
);
1112 label_put_text(l_moves
, s
);
1117 label_put_text(l_time
, "time: 0");
1124 ms_count
+= tick
- tick_old
;
1125 while (ms_count
>= 1000) {
1128 sprintf(s
, "time: %d", second_count
);
1129 label_put_text(l_time
, s
);
1134 //position everything based on board size
1138 sourcex
= boardw
/ 2 - 1;
1139 sourceytop
= boardh
/ 2;
1140 sourceybottom
= sourceytop
+ 1;
1142 w
= cellw
* boardw
+ (boardw
+ 1) * border
+ 2 * padding
;
1143 h
= cellh
* boardh
+ (boardh
+ 1) * border
+ 2 * padding
;
1144 widget_put_geometry(arena
, 0, vsize
, w
, h
);
1145 set_video(w
, h
+ 2 * vsize
);
1146 widget_put_geometry(root
, 0, 0, w
, h
+ 2 * vsize
);
1147 widget_put_geometry(menu
, 0, 0, w
, vsize
);
1148 menubar_auto_layout(menu
);
1149 widget_put_geometry(statusbar
, 0, h
+ vsize
, w
, vsize
);
1151 widget_put_geometry(l_moves
, 8, h
+ vsize
, 64, vsize
);
1152 widget_put_geometry(l_time
, w
- 48, h
+ vsize
, 64, vsize
);
1154 widget_put_geometry((widget_ptr
) about_window
,
1155 w
/2 - 50, h
/2 - 50, 100, 100);
1156 widget_put_geometry((widget_ptr
) l_about1
, 10, 10, 60, vsize
);
1157 widget_put_geometry((widget_ptr
) l_about2
, 10, 30, 60, vsize
);
1158 widget_put_geometry((widget_ptr
) b_about1
, 30, 80, 30, vsize
);
1160 /* vertical sizes and positions for the high score window */
1161 int const hslabely
= 5;
1162 int const hslabelheight
= vsize
;
1163 int const hslisty
= hslabely
+ hslabelheight
+ 8;
1164 int const hslisteachheight
= vsize
;
1165 int const hslistheight
= hslisteachheight
* level_max
;
1166 int const hsoky
= hslisty
+ hslistheight
+ 8;
1167 int const hsokheight
= vsize
;
1168 int const hswindowheight
= hsoky
+ hsokheight
+ 5;
1170 widget_put_geometry((widget_ptr
) hs_window
,
1171 w
/2 - 75, h
/2 - 60, 170, hswindowheight
);
1172 widget_put_geometry((widget_ptr
) l_hs1
, 10, hslabely
, 60, hslabelheight
);
1173 widget_put_geometry((widget_ptr
) b_hs1
, 100, hsoky
, 30, hsokheight
);
1177 for (i
=0; i
<level_max
; i
++) {
1178 int y
= hslisty
+ (hslisteachheight
* i
);
1179 widget_put_geometry((widget_ptr
) hsw
[i
]->level
,
1180 10, y
, 20, hslisteachheight
);
1181 widget_put_geometry((widget_ptr
) hsw
[i
]->time
,
1182 60, y
, 20, hslisteachheight
);
1183 widget_put_geometry((widget_ptr
) hsw
[i
]->name
,
1184 90, y
, 20, hslisteachheight
);
1188 widget_put_geometry((widget_ptr
) enter_name_window
,
1189 10, h
/2 - 30, w
- 20, 67);
1190 widget_put_geometry((widget_ptr
) l_en1
, 10, 0, 60, vsize
);
1191 widget_put_geometry((widget_ptr
) tb_en1
, 5, vsize
+ 5, w
- 30, vsize
);
1192 widget_put_geometry((widget_ptr
) b_en1
, w
- 60, 45, 30, vsize
);
1194 ((widget_ptr
) root
)->computexy((widget_ptr
) root
);
1195 ((widget_ptr
) about_window
)->computexy((widget_ptr
) about_window
);
1196 ((widget_ptr
) hs_window
)->computexy((widget_ptr
) hs_window
);
1197 ((widget_ptr
) enter_name_window
)->computexy((widget_ptr
) enter_name_window
);
1203 strcpy(s
,"NetWalk - ");
1204 strcat(s
,level_name
[level
]);
1205 SDL_WM_SetCaption(s
,s
);
1209 boardw
= 5; boardh
= 5;
1214 boardw
= 10; boardh
= 9;
1219 boardw
= 10; boardh
= 9;
1223 case level_veryhard
:
1224 boardw
= 20; boardh
= 18;
1229 boardw
= 50; boardh
= 50;
1234 boardw
= 50; boardh
= 50;
1250 tick
= SDL_GetTicks();
1254 void handle_mousebuttonup(SDL_Event
*event
)
1256 int x
= event
->button
.x
;
1257 int y
= event
->button
.y
;
1263 m
= openedmenu
->submenu
;
1264 for (i
=0; i
<m
->item_count
; i
++) {
1265 it
= m
->item_list
[i
];
1266 if (in_widget((widget_ptr
) it
, x
, y
)) {
1267 widget_raise_signal((widget_ptr
) it
, signal_activate
);
1274 } else if (state
== state_button
) {
1276 if (in_widget(button_selection
, x
, y
)) {
1277 widget_raise_signal(button_selection
, signal_activate
);
1283 void handle_click(int button
, int x
, int y
)
1288 wid
= (widget_ptr
) modalwindow
;
1289 if (in_widget(wid
, x
, y
) && (wid
->handle_click
)) {
1290 wid
->handle_click(wid
, button
, x
, y
);
1295 wid
= (widget_ptr
) root
;
1296 wid
->handle_click(wid
, button
, x
, y
);
1299 void arena_handle_click(widget_ptr p
, int button
, int x
, int y
)
1304 if (state
!= state_game
) return;
1306 i
= (x
- padding
- border
) / (cellw
+ border
);
1307 j
= (y
- padding
- border
) / (cellh
+ border
);
1308 if (i
>= boardw
|| j
>= boardh
) return;
1311 if (i
== sourcex
&& (j
== sourceytop
|| j
== sourceybottom
)) {
1312 new_pulse(sourcex
, sourceybottom
, -1);
1313 new_pulse(sourcex
, sourceytop
, -1);
1315 new_pulse(i
, j
, -1);
1320 //temporarily merge server squares
1321 board
[sourcex
][sourceybottom
] |= board
[sourcex
][sourceytop
] & 1;
1322 if (i
== sourcex
&& j
== sourceytop
) {
1325 d
= board
[i
][j
] & 15;
1327 case SDL_BUTTON_LEFT
:
1329 increment_move_count();
1331 case SDL_BUTTON_RIGHT
:
1333 increment_move_count();
1339 board
[sourcex
][sourceytop
] &= ~1;
1340 board
[sourcex
][sourceytop
] |= board
[sourcex
][sourceybottom
] & 1;
1341 board
[sourcex
][sourceybottom
] &= ~1;
1343 if(button
== SDL_BUTTON_MIDDLE
)
1359 void quit_menu(widget_ptr w
, void *data
)
1364 void new_game_menu(widget_ptr w
, void *data
)
1369 void about_open(widget_ptr w
, void *data
)
1371 modalwindow
= about_window
;
1374 void about_close(widget_ptr w
, void *data
)
1379 void hs_open(widget_ptr w
, void *data
)
1381 modalwindow
= hs_window
;
1384 void hs_close(widget_ptr w
, void *data
)
1389 void set_level(widget_ptr w
, void *data
)
1391 level
= (intptr_t) data
;
1395 void handle_key(int key
, int mod
)
1408 textbox_left(tb_en1
);
1411 textbox_right(tb_en1
);
1414 textbox_delete(tb_en1
);
1416 case SDLK_BACKSPACE
:
1417 textbox_backspace(tb_en1
);
1420 if (key
< 256 && key
>= 32) {
1421 if (mod
& KMOD_SHIFT
) {
1422 textbox_insert(tb_en1
, shifttable
[key
]);
1424 textbox_insert(tb_en1
, key
);
1446 void update_screen()
1448 SDL_FillRect(screen
, NULL
, 0);
1449 widget_update((widget_ptr
) root
);
1454 for (i
=0; i
<menu
->item_count
; i
++) {
1455 it
= menu
->item_list
[i
];
1456 if (in_widget((widget_ptr
) it
, lastmousex
, lastmousey
)) {
1457 open_submenu((widget_ptr
) it
, NULL
);
1460 menu_update(openedmenu
->submenu
);
1463 widget_update((widget_ptr
) modalwindow
);
1468 void window_update(widget_ptr p
)
1470 window_ptr w
= (window_ptr
) p
;
1475 if (p
!= (widget_ptr
) root
) {
1480 widget_fillrect(p
, &dst
, c_windowborder
);
1481 widget_fill(p
, c_background
);
1484 for (i
=0; i
<w
->widget_count
; i
++) {
1485 wid
= w
->widget_list
[i
];
1490 void window_handle_click(widget_ptr p
, int button
, int x
, int y
)
1493 window_ptr window
= (window_ptr
) p
;
1496 for (i
=0; i
<window
->widget_count
; i
++) {
1497 wid
= window
->widget_list
[i
];
1498 if (in_widget(wid
, x
, y
) && (wid
->handle_click
)) {
1499 wid
->handle_click(wid
, button
, x
- wid
->x
, y
- wid
->y
);
1505 void window_add_widget(window_ptr r
, void *p
)
1507 widget_ptr wid
= (widget_ptr
) p
;
1508 r
->widget_list
[r
->widget_count
] = wid
;
1510 wid
->parent
= (widget_ptr
) r
;
1511 wid
->x
+= r
->widget
.x
;
1512 wid
->y
+= r
->widget
.y
;
1515 void window_computexy(widget_ptr wid
)
1518 window_ptr w
= (window_ptr
) wid
;
1520 widget_computexy(wid
);
1521 for (i
=0; i
<w
->widget_count
; i
++) {
1522 w
->widget_list
[i
]->computexy(w
->widget_list
[i
]);
1526 void window_init(window_ptr w
)
1528 widget_init((widget_ptr
) w
);
1529 w
->widget_count
= 0;
1530 w
->widget
.update
= window_update
;
1531 w
->widget
.handle_click
= window_handle_click
;
1532 w
->widget
.computexy
= window_computexy
;
1535 static void add_shiftstring(char *s1
, char *s2
)
1539 for (i
=0; i
<strlen(s1
); i
++) {
1540 shifttable
[(int) s1
[i
]] = s2
[i
];
1544 int main(int argc
, char *argv
[])
1549 level_name
[level_easy
] = "Newbie";
1550 level_name
[level_medium
] = "Normal";
1551 level_name
[level_hard
] = "Nerd";
1552 level_name
[level_veryhard
] = "Nutcase";
1553 level_name
[level_giant
] = "Nonsense";
1554 level_name
[level_absurd
] = "No Sleep";
1560 for (i
=0; i
<256; i
++) shifttable
[i
] = i
;
1562 for (i
='a'; i
<='z'; i
++) {
1563 shifttable
[i
] = i
- 32;
1566 add_shiftstring("1234567890-=", "!@#$%^&*()_+");
1567 add_shiftstring("[]\\;',./`", "{}|:\"<>?~");
1570 config_load(config
);
1576 font
= TTF_OpenFont(config
->fontname
, config
->fontsize
);
1578 fprintf(stderr
, "error loading font %s\n", config
->fontname
);
1584 //need to set video mode here to initialize colour table
1585 set_video(100, 100);
1587 //setup enter name box
1589 window_init(enter_name_window
);
1592 label_put_text(l_en1
, "Enter name:");
1593 window_add_widget(enter_name_window
, l_en1
);
1595 textbox_init(tb_en1
);
1596 textbox_put_text(tb_en1
, "Anonymous");
1597 window_add_widget(enter_name_window
, tb_en1
);
1600 button_put_text(b_en1
, "Ok");
1601 window_add_widget(enter_name_window
, b_en1
);
1602 widget_put_handler((widget_ptr
) b_en1
, enter_name_close
, signal_activate
);
1605 //setup the "arena": where the action is
1607 widget_init((widget_ptr
) arena
);
1608 arena
->widget
.update
= arena_update
;
1609 arena
->widget
.handle_click
= arena_handle_click
;
1610 window_add_widget(root
, arena
);
1613 //status bar: mainly for showing the time
1615 widget_init((widget_ptr
) statusbar
);
1616 statusbar
->update
= statusbar_update
;
1617 window_add_widget(root
, statusbar
);
1619 //setup moves and time
1620 label_init(l_moves
);
1621 if (config
->showmoves
) {
1622 window_add_widget(root
, l_moves
);
1626 window_add_widget(root
, l_time
);
1631 menuitem_t it1
, it2
;
1638 window_add_widget(root
, menu
);
1640 menuitem_put_text(it1
, "Game");
1641 menubar_add_item(menu
, it1
);
1643 menuitem_put_text(it2
, "Help");
1644 menubar_add_item(menu
, it2
);
1648 it
= menuitem_new();
1649 menuitem_put_text(it
, "New game");
1650 widget_put_handler((widget_ptr
) it
, new_game_menu
, signal_activate
);
1651 menu_add_item(m1
, it
);
1653 for (i
=0; i
<level_max
; i
++) {
1654 it
= menuitem_new();
1655 menuitem_put_text(it
, level_name
[i
]);
1656 widget_put_handler_data((widget_ptr
) it
,
1657 set_level
, (void *) i
, signal_activate
);
1658 menu_add_item(m1
, it
);
1660 it
= menuitem_new();
1661 menuitem_put_text(it
, "High Scores");
1662 widget_put_handler((widget_ptr
) it
, hs_open
, signal_activate
);
1663 menu_add_item(m1
, it
);
1664 it
= menuitem_new();
1665 menuitem_put_text(it
, "Quit");
1666 widget_put_handler((widget_ptr
) it
, quit_menu
, signal_activate
);
1667 menu_add_item(m1
, it
);
1669 menuitem_set_submenu(it1
, m1
);
1673 it
= menuitem_new();
1674 menuitem_put_text(it
, "About");
1675 widget_put_handler((widget_ptr
) it
, about_open
, signal_activate
);
1676 menu_add_item(m2
, it
);
1678 menuitem_set_submenu(it2
, m2
);
1683 window_init(about_window
);
1685 label_init(l_about1
);
1686 label_put_text(l_about1
, "NetWalk " VERSION_STRING
);
1687 window_add_widget(about_window
, l_about1
);
1689 label_init(l_about2
);
1690 label_put_text(l_about2
, "Ben Lynn");
1691 window_add_widget(about_window
, l_about2
);
1693 button_init(b_about1
);
1694 button_put_text(b_about1
, "Ok");
1695 window_add_widget(about_window
, b_about1
);
1696 widget_put_handler((widget_ptr
) b_about1
, about_close
, signal_activate
);
1699 //setup hiscores box
1702 window_init(hs_window
);
1705 label_put_text(l_hs1
, "High Scores");
1706 window_add_widget(hs_window
, l_hs1
);
1709 button_put_text(b_hs1
, "Ok");
1710 window_add_widget(hs_window
, b_hs1
);
1711 widget_put_handler((widget_ptr
) b_hs1
, hs_close
, signal_activate
);
1713 for (i
=0; i
<level_max
; i
++) {
1714 label_init(hsw
[i
]->level
);
1715 label_put_text(hsw
[i
]->level
, level_name
[i
]);
1716 window_add_widget(hs_window
, hsw
[i
]->level
);
1717 label_init(hsw
[i
]->name
);
1718 window_add_widget(hs_window
, hsw
[i
]->name
);
1719 label_init(hsw
[i
]->time
);
1720 window_add_widget(hs_window
, hsw
[i
]->time
);
1728 init_tileimg(unmarked_tileimg
,c_unmarkedbg
);
1729 init_tileimg(marked_tileimg
,c_markedbg
);
1732 while (state
!= state_quit
&& !interrupted
) {
1734 tick
= SDL_GetTicks();
1738 SDL_GetMouseState(&lastmousex
, &lastmousey
);
1739 while (SDL_PollEvent(&event
)) {
1740 switch (event
.type
) {
1742 handle_key(event
.key
.keysym
.sym
, SDL_GetModState());
1744 case SDL_MOUSEBUTTONDOWN
:
1745 handle_click(event
.button
.button
, event
.button
.x
, event
.button
.y
);
1747 case SDL_MOUSEBUTTONUP
:
1748 handle_mousebuttonup(&event
);