Applied my "bidirectional dt scaling" patch. Accordingly, the game can
[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 paused = 0;
463
464 static struct state *st_continue;
465 static struct state *st_quit;
466
467 #define PAUSE_CONTINUE 1
468 #define PAUSE_QUIT     2
469
470 int goto_pause(struct state *s, int e)
471 {
472     if (e && (SDL_GetModState() & (KMOD_SHIFT | KMOD_CTRL | KMOD_ALT | KMOD_META)))
473         return goto_state(s);
474     st_continue = curr_state();
475     st_quit = s;
476     paused = 1;
477     return goto_state(&st_pause);
478 }
479
480 static int pause_action(int i)
481 {
482     audio_play(AUD_MENU, 1.0f);
483
484     switch(i)
485     {
486     case PAUSE_CONTINUE:
487         return goto_state(st_continue ? st_continue : &st_title);
488
489     case PAUSE_QUIT:
490         return goto_state(st_quit);
491     }
492     return 1;
493 }
494
495 static int pause_enter(void)
496 {
497     int id, jd, td;
498
499     audio_music_fade_out(0.2f);
500
501     if ((id = gui_vstack(0)))
502     {
503         td = gui_label(id, _("Paused"), GUI_LRG, GUI_ALL, 0, 0);
504         gui_space(id);
505
506         if ((jd = gui_harray(id)))
507         {
508             gui_state(jd, _("Quit"), GUI_SML, PAUSE_QUIT, 0);
509             gui_start(jd, _("Continue"), GUI_SML, PAUSE_CONTINUE, 1);
510         }
511
512         gui_pulse(td, 1.2f);
513         gui_layout(id, 0, 0);
514     }
515
516     hud_init();
517     return id;
518 }
519
520 static void pause_leave(int id)
521 {
522     gui_delete(id);
523     hud_free();
524     audio_music_fade_in(0.5f);
525 }
526
527 static void pause_paint(int id, float st)
528 {
529     game_draw(0);
530     gui_paint(id);
531     hud_paint();
532 }
533
534 static void pause_timer(int id, float dt)
535 {
536     gui_timer(id, dt);
537     audio_timer(dt);
538 }
539
540 static void pause_point(int id, int x, int y, int dx, int dy)
541 {
542     gui_pulse(gui_point(id, x, y), 1.2f);
543 }
544
545 static int pause_click(int b, int d)
546 {
547     return (d && b < 0) ? pause_action(gui_token(gui_click())) : 1;
548 }
549
550 static int pause_keybd(int c, int d)
551 {
552     if (d && (c == SDLK_ESCAPE || config_tst_d(CONFIG_KEY_PAUSE, c)))
553         return pause_action(PAUSE_CONTINUE);
554     return 1;
555 }
556
557 /*---------------------------------------------------------------------------*/
558
559 static int shared_keybd(int c, int d)
560 {
561     if (d)
562     {
563         if (c == SDLK_ESCAPE)
564             return goto_pause(&st_over, 1);
565         if (config_tst_d(CONFIG_KEY_PAUSE, c))
566             return goto_pause(&st_over, 0);
567     }
568     return 1;
569 }
570
571 /*---------------------------------------------------------------------------*/
572
573 static int num = 0;
574
575 static int next_enter(void)
576 {
577     int id;
578     char str[MAXSTR];
579
580     sprintf(str, _("Hole %02d"), curr_hole());
581
582     if ((id = gui_vstack(0)))
583     {
584         gui_label(id, str, GUI_MED, GUI_ALL, 0, 0);
585         gui_space(id);
586
587         gui_label(id, _("Player"), GUI_SML, GUI_TOP, 0, 0);
588
589         switch (curr_player())
590         {
591         case 1:
592             gui_label(id, "1", GUI_LRG, GUI_BOT, gui_red, gui_wht);
593             if (curr_party() > 1) audio_play(AUD_PLAYER1, 1.f);
594             break;
595         case 2:
596             gui_label(id, "2", GUI_LRG, GUI_BOT, gui_grn, gui_wht);
597             if (curr_party() > 1) audio_play(AUD_PLAYER2, 1.f);
598             break;
599         case 3:
600             gui_label(id, "3", GUI_LRG, GUI_BOT, gui_blu, gui_wht);
601             if (curr_party() > 1) audio_play(AUD_PLAYER3, 1.f);
602             break;
603         case 4:
604             gui_label(id, "4", GUI_LRG, GUI_BOT, gui_yel, gui_wht);
605             if (curr_party() > 1) audio_play(AUD_PLAYER4, 1.f);
606             break;
607         }
608         gui_layout(id, 0, 0);
609     }
610
611     hud_init();
612     game_set_fly(1.f);
613
614     if (paused)
615         paused = 0;
616
617     return id;
618 }
619
620 static void next_leave(int id)
621 {
622     hud_free();
623     gui_delete(id);
624 }
625
626 static void next_paint(int id, float st)
627 {
628     game_draw(0);
629     hud_paint();
630     gui_paint(id);
631 }
632
633 static void next_timer(int id, float dt)
634 {
635     gui_timer(id, dt);
636     audio_timer(dt);
637 }
638
639 static void next_point(int id, int x, int y, int dx, int dy)
640 {
641     gui_pulse(gui_point(id, x, y), 1.2f);
642 }
643
644 static int next_click(int b, int d)
645 {
646     return (d && b < 0) ? goto_state(&st_flyby) : 1;
647 }
648
649 static int next_keybd(int c, int d)
650 {
651     if (d)
652     {
653         if (c == SDLK_F12)
654             return goto_state(&st_poser);
655         if (c == SDLK_ESCAPE)
656             return goto_pause(&st_over, 1);
657         if (config_tst_d(CONFIG_KEY_PAUSE, c))
658             return goto_pause(&st_over, 0);
659         if (c == SDLK_RETURN)
660         {
661             hole_goto(num, -1);
662             num = 0;
663             return goto_state(&st_next);
664         }
665         if ('0' <= c && c <= '9')
666             num = num * 10 + c - '0';
667     }
668     return 1;
669 }
670
671 /*---------------------------------------------------------------------------*/
672
673 static int poser_enter(void)
674 {
675     game_set_fly(-1.f);
676     return 0;
677 }
678
679 static void poser_paint(int id, float st)
680 {
681     game_draw(1);
682 }
683
684 static int poser_keybd(int c, int d)
685 {
686     return (d && c == SDLK_ESCAPE) ? goto_state(&st_next) : 1;
687 }
688
689 /*---------------------------------------------------------------------------*/
690
691 static int flyby_enter(void)
692 {
693     if (paused)
694         paused = 0;
695     else
696         hud_init();
697
698     return 0;
699 }
700
701 static void flyby_leave(int id)
702 {
703     hud_free();
704 }
705
706 static void flyby_paint(int id, float st)
707 {
708     game_draw(0);
709     hud_paint();
710 }
711
712 static void flyby_timer(int id, float dt)
713 {
714     float t = time_state();
715
716     if (dt > 0.f && t > 1.f)
717         goto_state(&st_stroke);
718     else
719         game_set_fly(1.f - t);
720
721     gui_timer(id, dt);
722     audio_timer(dt);
723 }
724
725 static int flyby_click(int b, int d)
726 {
727     if (d && b < 0)
728     {
729         game_set_fly(0.f);
730         return goto_state(&st_stroke);
731     }
732     return 1;
733 }
734
735 /*---------------------------------------------------------------------------*/
736
737 static int stroke_enter(void)
738 {
739     hud_init();
740     game_clr_mag();
741     config_set_d(CONFIG_CAMERA, 2);
742     config_set_grab(!paused);
743
744     if (paused)
745         paused = 0;
746
747     return 0;
748 }
749
750 static void stroke_leave(int id)
751 {
752     hud_free();
753     config_clr_grab();
754     config_set_d(CONFIG_CAMERA, 0);
755 }
756
757 static void stroke_paint(int id, float st)
758 {
759     game_draw(0);
760     hud_paint();
761 }
762
763 static void stroke_timer(int id, float dt)
764 {
765     float g[3] = { 0.f, 0.f, 0.f };
766
767     game_update_view(dt);
768     game_step(g, dt);
769     audio_timer(dt);
770 }
771
772 static void stroke_point(int id, int x, int y, int dx, int dy)
773 {
774     game_set_rot(dx);
775     game_set_mag(dy);
776 }
777
778 static int stroke_click(int b, int d)
779 {
780     return (d && b < 0) ? goto_state(&st_roll) : 1;
781 }
782
783 /*---------------------------------------------------------------------------*/
784
785 static int roll_enter(void)
786 {
787     hud_init();
788
789     if (paused)
790         paused = 0;
791     else
792         game_putt();
793
794     return 0;
795 }
796
797 static void roll_leave(int id)
798 {
799     hud_free();
800 }
801
802 static void roll_paint(int id, float st)
803 {
804     game_draw(0);
805     hud_paint();
806 }
807
808 static void roll_timer(int id, float dt)
809 {
810     float g[3] = { 0.0f, -9.8f, 0.0f };
811
812     switch (game_step(g, dt))
813     {
814     case GAME_STOP: goto_state(&st_stop); break;
815     case GAME_GOAL: goto_state(&st_goal); break;
816     case GAME_FALL: goto_state(&st_fall); break;
817     }
818     audio_timer(dt);
819 }
820
821 /*---------------------------------------------------------------------------*/
822
823 static int goal_enter(void)
824 {
825     int id;
826
827     if ((id = gui_label(0, _("It's In!"), GUI_MED, GUI_ALL, gui_grn, gui_grn)))
828         gui_layout(id, 0, 0);
829
830     if (paused)
831         paused = 0;
832     else
833         hole_goal();
834
835     hud_init();
836
837     return id;
838 }
839
840 static void goal_leave(int id)
841 {
842     gui_delete(id);
843     hud_free();
844 }
845
846 static void goal_paint(int id, float st)
847 {
848     game_draw(0);
849     gui_paint(id);
850     hud_paint();
851 }
852
853 static void goal_timer(int id, float dt)
854 {
855     if (time_state() > 3)
856     {
857         if (hole_next())
858             goto_state(&st_next);
859         else
860             goto_state(&st_score);
861     }
862     audio_timer(dt);
863 }
864
865 static int goal_click(int b, int d)
866 {
867     if (b < 0 && d == 1)
868     {
869         if (hole_next())
870             goto_state(&st_next);
871         else
872             goto_state(&st_score);
873     }
874     return 1;
875 }
876
877 /*---------------------------------------------------------------------------*/
878
879 static int stop_enter(void)
880 {
881     if (paused)
882         paused = 0;
883     else
884         hole_stop();
885
886     hud_init();
887
888     return 0;
889 }
890
891 static void stop_leave(int id)
892 {
893     hud_free();
894 }
895
896 static void stop_paint(int id, float st)
897 {
898     game_draw(0);
899     hud_paint();
900 }
901
902 static void stop_timer(int id, float dt)
903 {
904     float g[3] = { 0.f, 0.f, 0.f };
905
906     game_update_view(dt);
907     game_step(g, dt);
908     audio_timer(dt);
909
910     if (time_state() > 1)
911     {
912         if (hole_next())
913             goto_state(&st_next);
914         else
915             goto_state(&st_score);
916     }
917 }
918
919 static int stop_click(int b, int d)
920 {
921     if (b < 0 && d == 1)
922     {
923         if (hole_next())
924             goto_state(&st_next);
925         else
926             goto_state(&st_score);
927     }
928     return 1;
929 }
930
931 /*---------------------------------------------------------------------------*/
932
933 static int fall_enter(void)
934 {
935     int id;
936
937     if ((id = gui_label(0, _("1 Stroke Penalty"), GUI_MED, GUI_ALL, gui_blk, gui_red)))
938         gui_layout(id, 0, 0);
939
940     if (paused)
941         paused = 0;
942     else
943     {
944         hole_fall();
945         game_draw(0); /*TODO: is this call ok? */
946     }
947
948     hud_init();
949
950     return id;
951 }
952
953 static void fall_leave(int id)
954 {
955     gui_delete(id);
956     hud_free();
957 }
958
959 static void fall_paint(int id, float st)
960 {
961     game_draw(0);
962     gui_paint(id);
963     hud_paint();
964 }
965
966 static void fall_timer(int id, float dt)
967 {
968     if (time_state() > 3)
969     {
970         if (hole_next())
971             goto_state(&st_next);
972         else
973             goto_state(&st_score);
974     }
975     audio_timer(dt);
976 }
977
978 static int fall_click(int b, int d)
979 {
980     if (b < 0 && d == 1)
981     {
982         if (hole_next())
983             goto_state(&st_next);
984         else
985             goto_state(&st_score);
986     }
987     return 1;
988 }
989
990 /*---------------------------------------------------------------------------*/
991
992 static int score_enter(void)
993 {
994     audio_music_fade_out(2.f);
995
996     if (paused)
997         paused = 0;
998
999     return score_card(_("Scores"), gui_yel, gui_red);
1000 }
1001
1002 static void score_leave(int id)
1003 {
1004     gui_delete(id);
1005 }
1006
1007 static void score_paint(int id, float st)
1008 {
1009     game_draw(0);
1010     gui_paint(id);
1011 }
1012
1013 static void score_timer(int id, float dt)
1014 {
1015     gui_timer(id, dt);
1016     audio_timer(dt);
1017 }
1018
1019 static int score_click(int b, int d)
1020 {
1021     if (b < 0 && d == 1)
1022     {
1023         if (hole_move())
1024             return goto_state(&st_next);
1025         else
1026             return goto_state(&st_title);
1027     }
1028     return 1;
1029 }
1030
1031 static int score_keybd(int c, int d)
1032 {
1033     if (d)
1034     {
1035         if (c == SDLK_ESCAPE)
1036             return goto_pause(&st_title, 1);
1037         if (config_tst_d(CONFIG_KEY_PAUSE, c))
1038             return goto_pause(&st_title, 0);
1039     }
1040     return 1;
1041 }
1042
1043 /*---------------------------------------------------------------------------*/
1044
1045 static int over_enter(void)
1046 {
1047     audio_music_fade_out(2.f);
1048     return score_card(_("Final Scores"), gui_yel, gui_red);
1049 }
1050
1051 static void over_leave(int id)
1052 {
1053     gui_delete(id);
1054 }
1055
1056 static void over_paint(int id, float st)
1057 {
1058     game_draw(0);
1059     gui_paint(id);
1060 }
1061
1062 static void over_timer(int id, float dt)
1063 {
1064     gui_timer(id, dt);
1065     audio_timer(dt);
1066 }
1067
1068 static int over_click(int b, int d)
1069 {
1070     return (d && b < 0) ? goto_state(&st_title) : 1;
1071 }
1072
1073 static int over_keybd(int c, int d)
1074 {
1075     return (d && c == SDLK_ESCAPE) ? goto_state(&st_title) : 1;
1076 }
1077
1078 /*---------------------------------------------------------------------------*/
1079
1080 struct state st_title = {
1081     title_enter,
1082     title_leave,
1083     title_paint,
1084     title_timer,
1085     title_point,
1086     NULL,
1087     title_click,
1088     title_keybd,
1089     NULL,
1090     1, 0
1091 };
1092
1093 struct state st_course = {
1094     course_enter,
1095     course_leave,
1096     course_paint,
1097     course_timer,
1098     course_point,
1099     NULL,
1100     course_click,
1101     course_keybd,
1102     NULL,
1103     1, 0
1104 };
1105
1106 struct state st_party = {
1107     party_enter,
1108     party_leave,
1109     party_paint,
1110     party_timer,
1111     party_point,
1112     NULL,
1113     party_click,
1114     party_keybd,
1115     NULL,
1116     1, 0
1117 };
1118
1119 struct state st_next = {
1120     next_enter,
1121     next_leave,
1122     next_paint,
1123     next_timer,
1124     next_point,
1125     NULL,
1126     next_click,
1127     next_keybd,
1128     NULL,
1129     1, 0
1130 };
1131
1132 struct state st_poser = {
1133     poser_enter,
1134     NULL,
1135     poser_paint,
1136     NULL,
1137     NULL,
1138     NULL,
1139     NULL,
1140     poser_keybd,
1141     NULL,
1142     1, 0
1143 };
1144
1145 struct state st_flyby = {
1146     flyby_enter,
1147     flyby_leave,
1148     flyby_paint,
1149     flyby_timer,
1150     NULL,
1151     NULL,
1152     flyby_click,
1153     shared_keybd,
1154     NULL,
1155     1, 0
1156 };
1157
1158 struct state st_stroke = {
1159     stroke_enter,
1160     stroke_leave,
1161     stroke_paint,
1162     stroke_timer,
1163     stroke_point,
1164     NULL,
1165     stroke_click,
1166     shared_keybd,
1167     NULL,
1168     0, 0
1169 };
1170
1171 struct state st_roll = {
1172     roll_enter,
1173     roll_leave,
1174     roll_paint,
1175     roll_timer,
1176     NULL,
1177     NULL,
1178     NULL,
1179     shared_keybd,
1180     NULL,
1181     0, 0
1182 };
1183
1184 struct state st_goal = {
1185     goal_enter,
1186     goal_leave,
1187     goal_paint,
1188     goal_timer,
1189     NULL,
1190     NULL,
1191     goal_click,
1192     shared_keybd,
1193     NULL,
1194     0, 0
1195 };
1196
1197 struct state st_stop = {
1198     stop_enter,
1199     stop_leave,
1200     stop_paint,
1201     stop_timer,
1202     NULL,
1203     NULL,
1204     stop_click,
1205     shared_keybd,
1206     NULL,
1207     0, 0
1208 };
1209
1210 struct state st_fall = {
1211     fall_enter,
1212     fall_leave,
1213     fall_paint,
1214     fall_timer,
1215     NULL,
1216     NULL,
1217     fall_click,
1218     shared_keybd,
1219     NULL,
1220     0, 0
1221 };
1222
1223 struct state st_score = {
1224     score_enter,
1225     score_leave,
1226     score_paint,
1227     score_timer,
1228     NULL,
1229     NULL,
1230     score_click,
1231     score_keybd,
1232     NULL,
1233     0, 0
1234 };
1235
1236 struct state st_over = {
1237     over_enter,
1238     over_leave,
1239     over_paint,
1240     over_timer,
1241     NULL,
1242     NULL,
1243     over_click,
1244     over_keybd,
1245     NULL,
1246     1, 0
1247 };
1248
1249 struct state st_pause = {
1250     pause_enter,
1251     pause_leave,
1252     pause_paint,
1253     pause_timer,
1254     pause_point,
1255     NULL,
1256     pause_click,
1257     pause_keybd,
1258     NULL,
1259     1, 0
1260 };