Call SDL_WM_SetIcon before SDL_SetVideoMode as suggested by the docs.
[neverball] / putt / st_all.c
1 /*
2  * Copyright (C) 2003 Robert Kooima
3  *
4  * NEVERPUTT is  free software; you can redistribute  it and/or modify
5  * it under the  terms of the GNU General  Public License as published
6  * by the Free  Software Foundation; either version 2  of the License,
7  * or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
11  * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
12  * General Public License for more details.
13  */
14
15 #include <math.h>
16
17 #include "hud.h"
18 #include "back.h"
19 #include "geom.h"
20 #include "gui.h"
21 #include "vec3.h"
22 #include "game.h"
23 #include "hole.h"
24 #include "audio.h"
25 #include "course.h"
26 #include "config.h"
27
28 #include "st_all.h"
29 #include "st_conf.h"
30
31 /*---------------------------------------------------------------------------*/
32
33 static char *number(int i)
34 {
35     static char str[MAXSTR];
36
37     sprintf(str, "%02d", i);
38
39     return str;
40 }
41
42 static int score_card(const char  *title,
43                       const float *c0,
44                       const float *c1)
45 {
46     int id, jd, kd, ld;
47
48     int p1 = (curr_party() >= 1) ? 1 : 0, l1 = (curr_party() == 1) ? 1 : 0;
49     int p2 = (curr_party() >= 2) ? 1 : 0, l2 = (curr_party() == 2) ? 1 : 0;
50     int p3 = (curr_party() >= 3) ? 1 : 0, l3 = (curr_party() == 3) ? 1 : 0;
51     int p4 = (curr_party() >= 4) ? 1 : 0, l4 = (curr_party() == 4) ? 1 : 0;
52
53     int i;
54     int n = curr_count() - 1;
55     int m = curr_count() / 2;
56
57     if ((id = gui_vstack(0)))
58     {
59         gui_label(id, title, GUI_MED, GUI_ALL, c0, c1);
60         gui_space(id);
61
62         if ((jd = gui_hstack(id)))
63         {
64             if ((kd = gui_varray(jd)))
65             {
66                 if (p1) gui_label(kd, _("O"),         0, GUI_NE, 0, 0);
67                 if (p1) gui_label(kd, hole_out(0), 0, 0,           gui_wht, gui_wht);
68                 if (p1) gui_label(kd, hole_out(1), 0, GUI_SE * l1, gui_red, gui_wht);
69                 if (p2) gui_label(kd, hole_out(2), 0, GUI_SE * l2, gui_grn, gui_wht);
70                 if (p3) gui_label(kd, hole_out(3), 0, GUI_SE * l3, gui_blu, gui_wht);
71                 if (p4) gui_label(kd, hole_out(4), 0, GUI_SE * l4, gui_yel, gui_wht);
72             }
73
74             if ((kd = gui_harray(jd)))
75                 for (i = m; i > 0; i--)
76                     if ((ld = gui_varray(kd)))
77                     {
78                         if (p1) gui_label(ld, number(i), 0, (i == 1) ? GUI_NW : 0, 0, 0);
79                         if (p1) gui_label(ld, hole_score(i, 0), 0, 0, gui_wht, gui_wht);
80                         if (p1) gui_label(ld, hole_score(i, 1), 0, 0, gui_red, gui_wht);
81                         if (p2) gui_label(ld, hole_score(i, 2), 0, 0, gui_grn, gui_wht);
82                         if (p3) gui_label(ld, hole_score(i, 3), 0, 0, gui_blu, gui_wht);
83                         if (p4) gui_label(ld, hole_score(i, 4), 0, 0, gui_yel, gui_wht);
84                     }
85             if ((kd = gui_varray(jd)))
86             {
87                 gui_filler(kd);
88                 if (p1) gui_label(kd, _("Par"), 0, GUI_NW,      gui_wht, gui_wht);
89                 if (p1) gui_label(kd, _("P1"),  0, GUI_SW * l1, gui_red, gui_wht);
90                 if (p2) gui_label(kd, _("P2"),  0, GUI_SW * l2, gui_grn, gui_wht);
91                 if (p3) gui_label(kd, _("P3"),  0, GUI_SW * l3, gui_blu, gui_wht);
92                 if (p4) gui_label(kd, _("P4"),  0, GUI_SW * l4, gui_yel, gui_wht);
93             }
94         }
95
96         gui_space(id);
97
98         if ((jd = gui_hstack(id)))
99         {
100             if ((kd = gui_varray(jd)))
101             {
102                 if (p1) gui_label(kd, _("Tot"),    0, GUI_TOP, 0, 0);
103                 if (p1) gui_label(kd, hole_tot(0), 0, 0,           gui_wht, gui_wht);
104                 if (p1) gui_label(kd, hole_tot(1), 0, GUI_BOT * l1, gui_red, gui_wht);
105                 if (p2) gui_label(kd, hole_tot(2), 0, GUI_BOT * l2, gui_grn, gui_wht);
106                 if (p3) gui_label(kd, hole_tot(3), 0, GUI_BOT * l3, gui_blu, gui_wht);
107                 if (p4) gui_label(kd, hole_tot(4), 0, GUI_BOT * l4, gui_yel, gui_wht);
108             }
109             if ((kd = gui_varray(jd)))
110             {
111                 if (p1) gui_label(kd, _("I"),     0, GUI_NE, 0, 0);
112                 if (p1) gui_label(kd, hole_in(0), 0, 0,           gui_wht, gui_wht);
113                 if (p1) gui_label(kd, hole_in(1), 0, GUI_SE * l1, gui_red, gui_wht);
114                 if (p2) gui_label(kd, hole_in(2), 0, GUI_SE * l2, gui_grn, gui_wht);
115                 if (p3) gui_label(kd, hole_in(3), 0, GUI_SE * l3, gui_blu, gui_wht);
116                 if (p4) gui_label(kd, hole_in(4), 0, GUI_SE * l4, gui_yel, gui_wht);
117             }
118             if ((kd = gui_harray(jd)))
119                 for (i = n; i > m; i--)
120                     if ((ld = gui_varray(kd)))
121                     {
122                         if (p1) gui_label(ld, number(i), 0, (i == m+1) ? GUI_NW : 0, 0, 0);
123                         if (p1) gui_label(ld, hole_score(i, 0), 0, 0, gui_wht, gui_wht);
124                         if (p1) gui_label(ld, hole_score(i, 1), 0, 0, gui_red, gui_wht);
125                         if (p2) gui_label(ld, hole_score(i, 2), 0, 0, gui_grn, gui_wht);
126                         if (p3) gui_label(ld, hole_score(i, 3), 0, 0, gui_blu, gui_wht);
127                         if (p4) gui_label(ld, hole_score(i, 4), 0, 0, gui_yel, gui_wht);
128                     }
129             if ((kd = gui_varray(jd)))
130             {
131                 gui_filler(kd);
132                 if (p1) gui_label(kd, _("Par"), 0, GUI_NW,      gui_wht, gui_wht);
133                 if (p1) gui_label(kd, _("P1"),  0, GUI_SW * l1, gui_red, gui_wht);
134                 if (p2) gui_label(kd, _("P2"),  0, GUI_SW * l2, gui_grn, gui_wht);
135                 if (p3) gui_label(kd, _("P3"),  0, GUI_SW * l3, gui_blu, gui_wht);
136                 if (p4) gui_label(kd, _("P4"),  0, GUI_SW * l4, gui_yel, gui_wht);
137             }
138         }
139
140         gui_layout(id, 0, 0);
141     }
142
143     return id;
144 }
145
146 /*---------------------------------------------------------------------------*/
147
148 #define TITLE_PLAY 1
149 #define TITLE_CONF 2
150 #define TITLE_EXIT 3
151
152 static int title_action(int i)
153 {
154     audio_play(AUD_MENU, 1.0f);
155
156     switch (i)
157     {
158     case TITLE_PLAY: return goto_state(&st_course);
159     case TITLE_CONF: return goto_state(&st_conf);
160     case TITLE_EXIT: return 0;
161     }
162     return 1;
163 }
164
165 static int title_enter(void)
166 {
167     int id, jd, kd;
168
169     /* Build the title GUI. */
170
171     if ((id = gui_vstack(0)))
172     {
173         gui_label(id, "Neverputt", GUI_LRG, GUI_ALL, 0, 0);
174         gui_space(id);
175
176         if ((jd = gui_harray(id)))
177         {
178             gui_filler(jd);
179
180             if ((kd = gui_varray(jd)))
181             {
182                 gui_start(kd, sgettext("menu^Play"),    GUI_MED, TITLE_PLAY, 1);
183                 gui_state(kd, sgettext("menu^Options"), GUI_MED, TITLE_CONF, 0);
184                 gui_state(kd, sgettext("menu^Exit"),    GUI_MED, TITLE_EXIT, 0);
185             }
186
187             gui_filler(jd);
188         }
189         gui_layout(id, 0, 0);
190     }
191
192     course_init();
193     course_rand();
194
195     return id;
196 }
197
198 static void title_leave(int id)
199 {
200     gui_delete(id);
201 }
202
203 static void title_paint(int id, float st)
204 {
205     game_draw(0);
206     gui_paint(id);
207 }
208
209 static void title_timer(int id, float dt)
210 {
211     float g[3] = { 0.f, 0.f, 0.f };
212
213     game_step(g, dt);
214     game_set_fly(fcosf(time_state() / 10.f));
215
216     gui_timer(id, dt);
217     audio_timer(dt);
218 }
219
220 static void title_point(int id, int x, int y, int dx, int dy)
221 {
222     gui_pulse(gui_point(id, x, y), 1.2f);
223 }
224
225 static int title_click(int b, int d)
226 {
227     return (d && b < 0) ? title_action(gui_token(gui_click())) : 1;
228 }
229
230 static int title_keybd(int c, int d)
231 {
232     return (d && c == SDLK_ESCAPE) ? 0 : 1;
233 }
234
235 /*---------------------------------------------------------------------------*/
236
237 static int desc_id;
238 static int shot_id;
239
240 static int course_action(int i)
241 {
242     if (course_exists(i))
243     {
244         course_goto(i);
245         goto_state(&st_party);
246     }
247     if (i < 0)
248         goto_state(&st_title);
249
250     return 1;
251 }
252
253 static int course_enter(void)
254 {
255     int w = config_get_d(CONFIG_WIDTH);
256     int h = config_get_d(CONFIG_HEIGHT);
257
258     int id, jd, kd, ld, i = 0, j, n = course_count();
259     int m = (int)(sqrt(n/2.0)*2);
260
261     if ((id = gui_vstack(0)))
262     {
263         gui_label(id, _("Select Course"), GUI_MED, GUI_ALL, 0, 0);
264         gui_space(id);
265
266         if ((jd = gui_hstack(id)))
267         {
268             shot_id = gui_image(jd, course_shot(0), w / 3, h / 3);
269             gui_filler(jd);
270             if ((kd = gui_varray(jd)))
271             {
272                 for(i = 0; i < n; i += m)
273                 {
274                     if ((ld = gui_harray(kd)))
275                     {
276                         for (j = (m - 1); j >= 0; j--)
277                         {
278                             if (i + j < n)
279                                 gui_active(gui_image(ld, course_shot(i + j),
280                                                      w / 3 / m, h / 3 / m),
281                                            i + j, 0);
282                             else
283                                 gui_space(ld);
284                         }
285                     }
286                 }
287             }
288         }
289
290         gui_space(id);
291         desc_id = gui_multi(id, _(course_desc(0)), GUI_SML, GUI_ALL, gui_yel, gui_wht);
292         gui_space(id);
293
294         if ((jd = gui_hstack(id)))
295         {
296             gui_filler(jd);
297             gui_state(jd, _("Back"), GUI_SML, -1, 0);
298         }
299
300         gui_layout(id, 0, 0);
301     }
302
303     audio_music_fade_to(0.5f, "bgm/inter.ogg");
304
305     return id;
306 }
307
308 static void course_leave(int id)
309 {
310     gui_delete(id);
311 }
312
313 static void course_paint(int id, float st)
314 {
315     game_draw(0);
316     gui_paint(id);
317 }
318
319 static void course_timer(int id, float dt)
320 {
321     gui_timer(id, dt);
322     audio_timer(dt);
323 }
324
325 static void course_point(int id, int x, int y, int dx, int dy)
326 {
327     int jd;
328
329     if ((jd = gui_point(id, x, y)))
330     {
331         int i = gui_token(jd);
332         if (course_exists(i))
333         {
334             gui_set_image(shot_id, course_shot(i));
335             gui_set_multi(desc_id, _(course_desc(i)));
336         }
337         gui_pulse(jd, 1.2f);
338     }
339 }
340
341 static int course_click(int b, int d)
342 {
343     return (d && b < 0) ? course_action(gui_token(gui_click())) : 1;
344 }
345
346 static int course_keybd(int c, int d)
347 {
348     return (d && c == SDLK_ESCAPE) ? goto_state(&st_title) : 1;
349 }
350
351 /*---------------------------------------------------------------------------*/
352
353 #define PARTY_T 0
354 #define PARTY_1 1
355 #define PARTY_2 2
356 #define PARTY_3 3
357 #define PARTY_4 4
358 #define PARTY_B 5
359
360 static int party_action(int i)
361 {
362     switch (i)
363     {
364     case PARTY_1:
365         audio_play(AUD_MENU, 1.f);
366         hole_goto(1, 1);
367         goto_state(&st_next);
368         break;
369     case PARTY_2:
370         audio_play(AUD_MENU, 1.f);
371         hole_goto(1, 2);
372         goto_state(&st_next);
373         break;
374     case PARTY_3:
375         audio_play(AUD_MENU, 1.f);
376         hole_goto(1, 3);
377         goto_state(&st_next);
378         break;
379     case PARTY_4:
380         audio_play(AUD_MENU, 1.f);
381         hole_goto(1, 4);
382         goto_state(&st_next);
383         break;
384     case PARTY_B:
385         audio_play(AUD_MENU, 1.f);
386         goto_state(&st_course);
387         break;
388     }
389     return 1;
390 }
391
392 static int party_enter(void)
393 {
394     int id, jd;
395
396     if ((id = gui_vstack(0)))
397     {
398         gui_label(id, _("Players?"), GUI_MED, GUI_ALL, 0, 0);
399         gui_space(id);
400
401         if ((jd = gui_harray(id)))
402         {
403             int p4 = gui_state(jd, "4", GUI_LRG, PARTY_4, 0);
404             int p3 = gui_state(jd, "3", GUI_LRG, PARTY_3, 0);
405             int p2 = gui_state(jd, "2", GUI_LRG, PARTY_2, 0);
406             int p1 = gui_state(jd, "1", GUI_LRG, PARTY_1, 0);
407
408             gui_set_color(p1, gui_red, gui_wht);
409             gui_set_color(p2, gui_grn, gui_wht);
410             gui_set_color(p3, gui_blu, gui_wht);
411             gui_set_color(p4, gui_yel, gui_wht);
412         }
413
414         gui_space(id);
415
416         if ((jd = gui_hstack(id)))
417         {
418             gui_filler(jd);
419             gui_state(jd, _("Back"), GUI_SML, PARTY_B, 0);
420         }
421
422         gui_layout(id, 0, 0);
423     }
424
425     return id;
426 }
427
428 static void party_leave(int id)
429 {
430     gui_delete(id);
431 }
432
433 static void party_paint(int id, float st)
434 {
435     game_draw(0);
436     gui_paint(id);
437 }
438
439 static void party_timer(int id, float dt)
440 {
441     gui_timer(id, dt);
442     audio_timer(dt);
443 }
444
445 static void party_point(int id, int x, int y, int dx, int dy)
446 {
447     gui_pulse(gui_point(id, x, y), 1.2f);
448 }
449
450 static int party_click(int b, int d)
451 {
452     return (d && b < 0) ? party_action(gui_token(gui_click())) : 1;
453 }
454
455 static int party_keybd(int c, int d)
456 {
457     return (d && c == SDLK_ESCAPE) ? goto_state(&st_course) : 1;
458 }
459
460 /*---------------------------------------------------------------------------*/
461
462 static int num = 0;
463
464 static int next_enter(void)
465 {
466     int id;
467     char str[MAXSTR];
468
469     sprintf(str, _("Hole %02d"), curr_hole());
470
471     if ((id = gui_vstack(0)))
472     {
473         gui_label(id, str, GUI_MED, GUI_ALL, 0, 0);
474         gui_space(id);
475
476         gui_label(id, _("Player"), GUI_SML, GUI_TOP, 0, 0);
477
478         switch (curr_player())
479         {
480         case 1:
481             gui_label(id, "1", GUI_LRG, GUI_BOT, gui_red, gui_wht);
482             if (curr_party() > 1) audio_play(AUD_PLAYER1, 1.f);
483             break;
484         case 2:
485             gui_label(id, "2", GUI_LRG, GUI_BOT, gui_grn, gui_wht);
486             if (curr_party() > 1) audio_play(AUD_PLAYER2, 1.f);
487             break;
488         case 3:
489             gui_label(id, "3", GUI_LRG, GUI_BOT, gui_blu, gui_wht);
490             if (curr_party() > 1) audio_play(AUD_PLAYER3, 1.f);
491             break;
492         case 4:
493             gui_label(id, "4", GUI_LRG, GUI_BOT, gui_yel, gui_wht);
494             if (curr_party() > 1) audio_play(AUD_PLAYER4, 1.f);
495             break;
496         }
497         gui_layout(id, 0, 0);
498     }
499
500     hud_init();
501     game_set_fly(1.f);
502
503     return id;
504 }
505
506 static void next_leave(int id)
507 {
508     hud_free();
509     gui_delete(id);
510 }
511
512 static void next_paint(int id, float st)
513 {
514     game_draw(0);
515     hud_paint();
516     gui_paint(id);
517 }
518
519 static void next_timer(int id, float dt)
520 {
521     gui_timer(id, dt);
522     audio_timer(dt);
523 }
524
525 static void next_point(int id, int x, int y, int dx, int dy)
526 {
527     gui_pulse(gui_point(id, x, y), 1.2f);
528 }
529
530 static int next_click(int b, int d)
531 {
532     return (d && b < 0) ? goto_state(&st_flyby) : 1;
533 }
534
535 static int next_keybd(int c, int d)
536 {
537     if (d)
538     {
539         if (c == SDLK_F12)
540             return goto_state(&st_poser);
541         if (c == SDLK_ESCAPE)
542             return goto_state(&st_over);
543         if (c == SDLK_RETURN)
544         {
545             hole_goto(num, -1);
546             num = 0;
547             return goto_state(&st_next);
548         }
549         if ('0' <= c && c <= '9')
550             num = num * 10 + c - '0';
551     }
552     return 1;
553 }
554
555 /*---------------------------------------------------------------------------*/
556
557 static int poser_enter(void)
558 {
559     game_set_fly(-1.f);
560     return 0;
561 }
562
563 static void poser_paint(int id, float st)
564 {
565     game_draw(1);
566 }
567
568 static int poser_keybd(int c, int d)
569 {
570     return (d && c == SDLK_ESCAPE) ? goto_state(&st_next) : 1;
571 }
572
573 /*---------------------------------------------------------------------------*/
574
575 static int flyby_enter(void)
576 {
577     hud_init();
578     return 0;
579 }
580
581 static void flyby_leave(int id)
582 {
583     hud_free();
584 }
585
586 static void flyby_paint(int id, float st)
587 {
588     game_draw(0);
589     hud_paint();
590 }
591
592 static void flyby_timer(int id, float dt)
593 {
594     float t = time_state();
595
596     if (dt > 0.f && t > 1.f)
597         goto_state(&st_stroke);
598     else
599         game_set_fly(1.f - t);
600
601     gui_timer(id, dt);
602     audio_timer(dt);
603 }
604
605 static int flyby_click(int b, int d)
606 {
607     if (d && b < 0)
608     {
609         game_set_fly(0.f);
610         return goto_state(&st_stroke);
611     }
612     return 1;
613 }
614
615 static int flyby_keybd(int c, int d)
616 {
617     return (d && c == SDLK_ESCAPE) ? goto_state(&st_over) : 1;
618 }
619
620 /*---------------------------------------------------------------------------*/
621
622 static int stroke_enter(void)
623 {
624     hud_init();
625     game_clr_mag();
626     config_set_d(CONFIG_CAMERA, 2);
627     config_set_grab();
628     return 0;
629 }
630
631 static void stroke_leave(int id)
632 {
633     hud_free();
634     config_clr_grab();
635     config_set_d(CONFIG_CAMERA, 0);
636 }
637
638 static void stroke_paint(int id, float st)
639 {
640     game_draw(0);
641     hud_paint();
642 }
643
644 static void stroke_timer(int id, float dt)
645 {
646     float g[3] = { 0.f, 0.f, 0.f };
647
648     game_update_view(dt);
649     game_step(g, dt);
650     audio_timer(dt);
651 }
652
653 static void stroke_point(int id, int x, int y, int dx, int dy)
654 {
655     game_set_rot(dx);
656     game_set_mag(dy);
657 }
658
659 static int stroke_click(int b, int d)
660 {
661     return (d && b < 0) ? goto_state(&st_roll) : 1;
662 }
663
664 static int stroke_keybd(int c, int d)
665 {
666     return (d && c == SDLK_ESCAPE) ? goto_state(&st_over) : 1;
667 }
668
669 /*---------------------------------------------------------------------------*/
670
671 static int roll_enter(void)
672 {
673     hud_init();
674     game_putt();
675     return 0;
676 }
677
678 static void roll_leave(int id)
679 {
680     hud_free();
681 }
682
683 static void roll_paint(int id, float st)
684 {
685     game_draw(0);
686     hud_paint();
687 }
688
689 static void roll_timer(int id, float dt)
690 {
691     float g[3] = { 0.0f, -9.8f, 0.0f };
692
693     switch (game_step(g, dt))
694     {
695     case GAME_STOP: goto_state(&st_stop); break;
696     case GAME_GOAL: goto_state(&st_goal); break;
697     case GAME_FALL: goto_state(&st_fall); break;
698     }
699     audio_timer(dt);
700 }
701
702 static int roll_keybd(int c, int d)
703 {
704     return (d && c == SDLK_ESCAPE) ? goto_state(&st_over) : 1;
705 }
706
707 /*---------------------------------------------------------------------------*/
708
709 static int goal_enter(void)
710 {
711     int id;
712
713     if ((id = gui_label(0, _("It's In!"), GUI_MED, GUI_ALL, gui_grn, gui_grn)))
714         gui_layout(id, 0, 0);
715
716     hole_goal();
717     hud_init();
718
719     return id;
720 }
721
722 static void goal_leave(int id)
723 {
724     gui_delete(id);
725     hud_free();
726 }
727
728 static void goal_paint(int id, float st)
729 {
730     game_draw(0);
731     gui_paint(id);
732     hud_paint();
733 }
734
735 static void goal_timer(int id, float dt)
736 {
737     if (time_state() > 3)
738     {
739         if (hole_next())
740             goto_state(&st_next);
741         else
742             goto_state(&st_score);
743     }
744     audio_timer(dt);
745 }
746
747 static int goal_click(int b, int d)
748 {
749     if (b < 0 && d == 1)
750     {
751         if (hole_next())
752             goto_state(&st_next);
753         else
754             goto_state(&st_score);
755     }
756     return 1;
757 }
758
759 static int goal_keybd(int c, int d)
760 {
761     return (d && c == SDLK_ESCAPE) ? goto_state(&st_over) : 1;
762 }
763
764 /*---------------------------------------------------------------------------*/
765
766 static int stop_enter(void)
767 {
768     hole_stop();
769     hud_init();
770     return 0;
771 }
772
773 static void stop_leave(int id)
774 {
775     hud_free();
776 }
777
778 static void stop_paint(int id, float st)
779 {
780     game_draw(0);
781     hud_paint();
782 }
783
784 static void stop_timer(int id, float dt)
785 {
786     float g[3] = { 0.f, 0.f, 0.f };
787
788     game_update_view(dt);
789     game_step(g, dt);
790     audio_timer(dt);
791
792     if (time_state() > 1)
793     {
794         if (hole_next())
795             goto_state(&st_next);
796         else
797             goto_state(&st_score);
798     }
799 }
800
801 static int stop_click(int b, int d)
802 {
803     if (b < 0 && d == 1)
804     {
805         if (hole_next())
806             goto_state(&st_next);
807         else
808             goto_state(&st_score);
809     }
810     return 1;
811 }
812
813 static int stop_keybd(int c, int d)
814 {
815     return (d && c == SDLK_ESCAPE) ? goto_state(&st_over) : 1;
816 }
817
818 /*---------------------------------------------------------------------------*/
819
820 static int fall_enter(void)
821 {
822     int id;
823
824     if ((id = gui_label(0, _("1 Stroke Penalty"), GUI_MED, GUI_ALL, gui_blk, gui_red)))
825         gui_layout(id, 0, 0);
826
827     hole_fall();
828     hud_init();
829
830     return id;
831 }
832
833 static void fall_leave(int id)
834 {
835     gui_delete(id);
836     hud_free();
837 }
838
839 static void fall_paint(int id, float st)
840 {
841     game_draw(0);
842     gui_paint(id);
843     hud_paint();
844 }
845
846 static void fall_timer(int id, float dt)
847 {
848     if (time_state() > 3)
849     {
850         if (hole_next())
851             goto_state(&st_next);
852         else
853             goto_state(&st_score);
854     }
855     audio_timer(dt);
856 }
857
858 static int fall_click(int b, int d)
859 {
860     if (b < 0 && d == 1)
861     {
862         if (hole_next())
863             goto_state(&st_next);
864         else
865             goto_state(&st_score);
866     }
867     return 1;
868 }
869
870 static int fall_keybd(int c, int d)
871 {
872     return (d && c == SDLK_ESCAPE) ? goto_state(&st_over) : 1;
873 }
874
875 /*---------------------------------------------------------------------------*/
876
877 static int score_enter(void)
878 {
879     audio_music_fade_out(2.f);
880     return score_card(_("Scores"), gui_yel, gui_red);
881 }
882
883 static void score_leave(int id)
884 {
885     gui_delete(id);
886 }
887
888 static void score_paint(int id, float st)
889 {
890     game_draw(0);
891     gui_paint(id);
892 }
893
894 static void score_timer(int id, float dt)
895 {
896     gui_timer(id, dt);
897     audio_timer(dt);
898 }
899
900 static int score_click(int b, int d)
901 {
902     if (b < 0 && d == 1)
903     {
904         if (hole_move())
905             return goto_state(&st_next);
906         else
907             return goto_state(&st_title);
908     }
909     return 1;
910 }
911
912 static int score_keybd(int c, int d)
913 {
914     return (d && c == SDLK_ESCAPE) ? goto_state(&st_title) : 1;
915 }
916
917 /*---------------------------------------------------------------------------*/
918
919 static int over_enter(void)
920 {
921     audio_music_fade_out(2.f);
922     return score_card(_("Final Scores"), gui_yel, gui_red);
923 }
924
925 static void over_leave(int id)
926 {
927     gui_delete(id);
928 }
929
930 static void over_paint(int id, float st)
931 {
932     game_draw(0);
933     gui_paint(id);
934 }
935
936 static void over_timer(int id, float dt)
937 {
938     gui_timer(id, dt);
939     audio_timer(dt);
940 }
941
942 static int over_click(int b, int d)
943 {
944     return (d && b < 0) ? goto_state(&st_title) : 1;
945 }
946
947 static int over_keybd(int c, int d)
948 {
949     return (d && c == SDLK_ESCAPE) ? goto_state(&st_title) : 1;
950 }
951
952 /*---------------------------------------------------------------------------*/
953
954 struct state st_title = {
955     title_enter,
956     title_leave,
957     title_paint,
958     title_timer,
959     title_point,
960     NULL,
961     title_click,
962     title_keybd,
963     NULL,
964     1, 0
965 };
966
967 struct state st_course = {
968     course_enter,
969     course_leave,
970     course_paint,
971     course_timer,
972     course_point,
973     NULL,
974     course_click,
975     course_keybd,
976     NULL,
977     1, 0
978 };
979
980 struct state st_party = {
981     party_enter,
982     party_leave,
983     party_paint,
984     party_timer,
985     party_point,
986     NULL,
987     party_click,
988     party_keybd,
989     NULL,
990     1, 0
991 };
992
993 struct state st_next = {
994     next_enter,
995     next_leave,
996     next_paint,
997     next_timer,
998     next_point,
999     NULL,
1000     next_click,
1001     next_keybd,
1002     NULL,
1003     1, 0
1004 };
1005
1006 struct state st_poser = {
1007     poser_enter,
1008     NULL,
1009     poser_paint,
1010     NULL,
1011     NULL,
1012     NULL,
1013     NULL,
1014     poser_keybd,
1015     NULL,
1016     1, 0
1017 };
1018
1019 struct state st_flyby = {
1020     flyby_enter,
1021     flyby_leave,
1022     flyby_paint,
1023     flyby_timer,
1024     NULL,
1025     NULL,
1026     flyby_click,
1027     flyby_keybd,
1028     NULL,
1029     1, 0
1030 };
1031
1032 struct state st_stroke = {
1033     stroke_enter,
1034     stroke_leave,
1035     stroke_paint,
1036     stroke_timer,
1037     stroke_point,
1038     NULL,
1039     stroke_click,
1040     stroke_keybd,
1041     NULL,
1042     0, 0
1043 };
1044
1045 struct state st_roll = {
1046     roll_enter,
1047     roll_leave,
1048     roll_paint,
1049     roll_timer,
1050     NULL,
1051     NULL,
1052     NULL,
1053     roll_keybd,
1054     NULL,
1055     0, 0
1056 };
1057
1058 struct state st_goal = {
1059     goal_enter,
1060     goal_leave,
1061     goal_paint,
1062     goal_timer,
1063     NULL,
1064     NULL,
1065     goal_click,
1066     goal_keybd,
1067     NULL,
1068     0, 0
1069 };
1070
1071 struct state st_stop = {
1072     stop_enter,
1073     stop_leave,
1074     stop_paint,
1075     stop_timer,
1076     NULL,
1077     NULL,
1078     stop_click,
1079     stop_keybd,
1080     NULL,
1081     0, 0
1082 };
1083
1084 struct state st_fall = {
1085     fall_enter,
1086     fall_leave,
1087     fall_paint,
1088     fall_timer,
1089     NULL,
1090     NULL,
1091     fall_click,
1092     fall_keybd,
1093     NULL,
1094     0, 0
1095 };
1096
1097 struct state st_score = {
1098     score_enter,
1099     score_leave,
1100     score_paint,
1101     score_timer,
1102     NULL,
1103     NULL,
1104     score_click,
1105     score_keybd,
1106     NULL,
1107     0, 0
1108 };
1109
1110 struct state st_over = {
1111     over_enter,
1112     over_leave,
1113     over_paint,
1114     over_timer,
1115     NULL,
1116     NULL,
1117     over_click,
1118     over_keybd,
1119     NULL,
1120     1, 0
1121 };