Mark levels completed when using set cheat
[neverball] / putt / st_all.c
old mode 100755 (executable)
new mode 100644 (file)
index 910ef8c..a4c366e
@@ -1,4 +1,4 @@
-/*   
+/*
  * Copyright (C) 2003 Robert Kooima
  *
  * NEVERPUTT is  free software; you can redistribute  it and/or modify
 
 /*---------------------------------------------------------------------------*/
 
+static SDL_Joystick *joystick = NULL;
+
+void set_joystick(SDL_Joystick *j)
+{
+    joystick = j;
+}
+
+/*---------------------------------------------------------------------------*/
+
 static char *number(int i)
 {
     static char str[MAXSTR];
@@ -62,8 +71,8 @@ static int score_card(const char  *title,
         if ((jd = gui_hstack(id)))
         {
             if ((kd = gui_varray(jd)))
-            { 
-                if (p1) gui_label(kd, "O",         0, GUI_NE, 0, 0);
+            {
+                if (p1) gui_label(kd, _("O"),         0, GUI_NE, 0, 0);
                 if (p1) gui_label(kd, hole_out(0), 0, 0,           gui_wht, gui_wht);
                 if (p1) gui_label(kd, hole_out(1), 0, GUI_SE * l1, gui_red, gui_wht);
                 if (p2) gui_label(kd, hole_out(2), 0, GUI_SE * l2, gui_grn, gui_wht);
@@ -85,11 +94,11 @@ static int score_card(const char  *title,
             if ((kd = gui_varray(jd)))
             {
                 gui_filler(kd);
-                if (p1) gui_label(kd, "Par", 0, GUI_NW,      gui_wht, gui_wht);
-                if (p1) gui_label(kd, "P1",  0, GUI_SW * l1, gui_red, gui_wht);
-                if (p2) gui_label(kd, "P2",  0, GUI_SW * l2, gui_grn, gui_wht);
-                if (p3) gui_label(kd, "P3",  0, GUI_SW * l3, gui_blu, gui_wht);
-                if (p4) gui_label(kd, "P4",  0, GUI_SW * l4, gui_yel, gui_wht);
+                if (p1) gui_label(kd, _("Par"), 0, GUI_NW,      gui_wht, gui_wht);
+                if (p1) gui_label(kd, _("P1"),  0, GUI_SW * l1, gui_red, gui_wht);
+                if (p2) gui_label(kd, _("P2"),  0, GUI_SW * l2, gui_grn, gui_wht);
+                if (p3) gui_label(kd, _("P3"),  0, GUI_SW * l3, gui_blu, gui_wht);
+                if (p4) gui_label(kd, _("P4"),  0, GUI_SW * l4, gui_yel, gui_wht);
             }
         }
 
@@ -99,7 +108,7 @@ static int score_card(const char  *title,
         {
             if ((kd = gui_varray(jd)))
             {
-                if (p1) gui_label(kd, "Tot",       0, GUI_TOP, 0, 0);
+                if (p1) gui_label(kd, _("Tot"),    0, GUI_TOP, 0, 0);
                 if (p1) gui_label(kd, hole_tot(0), 0, 0,           gui_wht, gui_wht);
                 if (p1) gui_label(kd, hole_tot(1), 0, GUI_BOT * l1, gui_red, gui_wht);
                 if (p2) gui_label(kd, hole_tot(2), 0, GUI_BOT * l2, gui_grn, gui_wht);
@@ -108,7 +117,7 @@ static int score_card(const char  *title,
             }
             if ((kd = gui_varray(jd)))
             {
-                if (p1) gui_label(kd, "I",        0, GUI_NE, 0, 0);
+                if (p1) gui_label(kd, _("I"),     0, GUI_NE, 0, 0);
                 if (p1) gui_label(kd, hole_in(0), 0, 0,           gui_wht, gui_wht);
                 if (p1) gui_label(kd, hole_in(1), 0, GUI_SE * l1, gui_red, gui_wht);
                 if (p2) gui_label(kd, hole_in(2), 0, GUI_SE * l2, gui_grn, gui_wht);
@@ -129,11 +138,11 @@ static int score_card(const char  *title,
             if ((kd = gui_varray(jd)))
             {
                 gui_filler(kd);
-                if (p1) gui_label(kd, "Par", 0, GUI_NW,      gui_wht, gui_wht);
-                if (p1) gui_label(kd, "P1",  0, GUI_SW * l1, gui_red, gui_wht);
-                if (p2) gui_label(kd, "P2",  0, GUI_SW * l2, gui_grn, gui_wht);
-                if (p3) gui_label(kd, "P3",  0, GUI_SW * l3, gui_blu, gui_wht);
-                if (p4) gui_label(kd, "P4",  0, GUI_SW * l4, gui_yel, gui_wht);
+                if (p1) gui_label(kd, _("Par"), 0, GUI_NW,      gui_wht, gui_wht);
+                if (p1) gui_label(kd, _("P1"),  0, GUI_SW * l1, gui_red, gui_wht);
+                if (p2) gui_label(kd, _("P2"),  0, GUI_SW * l2, gui_grn, gui_wht);
+                if (p3) gui_label(kd, _("P3"),  0, GUI_SW * l3, gui_blu, gui_wht);
+                if (p4) gui_label(kd, _("P4"),  0, GUI_SW * l4, gui_yel, gui_wht);
             }
         }
 
@@ -145,6 +154,28 @@ static int score_card(const char  *title,
 
 /*---------------------------------------------------------------------------*/
 
+static int shared_stick_basic(int id, int a, int v)
+{
+    int jd = 0;
+
+    if (config_tst_d(CONFIG_JOYSTICK_AXIS_X, a))
+        jd = gui_stick(id, v, 0);
+    else if (config_tst_d(CONFIG_JOYSTICK_AXIS_Y, a))
+        jd = gui_stick(id, 0, v);
+
+    if (jd)
+        gui_pulse(jd, 1.2f);
+
+    return jd;
+}
+
+static void shared_stick(int id, int a, int v)
+{
+    shared_stick_basic(id, a, v);
+}
+
+/*---------------------------------------------------------------------------*/
+
 #define TITLE_PLAY 1
 #define TITLE_CONF 2
 #define TITLE_EXIT 3
@@ -179,9 +210,9 @@ static int title_enter(void)
 
             if ((kd = gui_varray(jd)))
             {
-                gui_start(kd, "Play",    GUI_MED, TITLE_PLAY, 1);
-                gui_state(kd, "Options", GUI_MED, TITLE_CONF, 0);
-                gui_state(kd, "Exit",    GUI_MED, TITLE_EXIT, 0);
+                gui_start(kd, sgettext("menu^Play"),    GUI_MED, TITLE_PLAY, 1);
+                gui_state(kd, sgettext("menu^Options"), GUI_MED, TITLE_CONF, 0);
+                gui_state(kd, sgettext("menu^Exit"),    GUI_MED, TITLE_EXIT, 0);
             }
 
             gui_filler(jd);
@@ -200,9 +231,9 @@ static void title_leave(int id)
     gui_delete(id);
 }
 
-static void title_paint(int id, float st)
+static void title_paint(int id, float t)
 {
-    game_draw(0);
+    game_draw(0, t);
     gui_paint(id);
 }
 
@@ -214,7 +245,6 @@ static void title_timer(int id, float dt)
     game_set_fly(fcosf(time_state() / 10.f));
 
     gui_timer(id, dt);
-    audio_timer(dt);
 }
 
 static void title_point(int id, int x, int y, int dx, int dy)
@@ -227,14 +257,24 @@ static int title_click(int b, int d)
     return (d && b < 0) ? title_action(gui_token(gui_click())) : 1;
 }
 
-static int title_keybd(int c, int d)
+static int title_buttn(int b, int d)
 {
-    return (d && c == SDLK_ESCAPE) ? 0 : 1;
+    if (d)
+    {
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
+            return title_action(gui_token(gui_click()));
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
+            return title_action(TITLE_EXIT);
+    }
+    return 1;
 }
 
 /*---------------------------------------------------------------------------*/
 
 static int desc_id;
+static int shot_id;
+
+#define COURSE_BACK -1
 
 static int course_action(int i)
 {
@@ -243,7 +283,7 @@ static int course_action(int i)
         course_goto(i);
         goto_state(&st_party);
     }
-    if (i < 0)
+    if (i == COURSE_BACK)
         goto_state(&st_title);
 
     return 1;
@@ -254,29 +294,53 @@ static int course_enter(void)
     int w = config_get_d(CONFIG_WIDTH);
     int h = config_get_d(CONFIG_HEIGHT);
 
-    int id, jd, i, n = course_count(), m = n + 2;
+    int id, jd, kd, ld, md, i = 0, j, n = course_count();
+    int m = (int)(sqrt(n/2.0)*2);
 
     if ((id = gui_vstack(0)))
     {
-        gui_label(id, "Select Course", GUI_MED, GUI_ALL, 0, 0);
+        gui_label(id, _("Select Course"), GUI_MED, GUI_ALL, 0, 0);
         gui_space(id);
 
         if ((jd = gui_hstack(id)))
         {
+            shot_id = gui_image(jd, course_shot(0), w / 3, h / 3);
+
             gui_filler(jd);
-            for (i = n - 1; i >= 0; i--)
-                gui_active(gui_image(jd, course_shot(i), w / m, h / m), i, 0);
-            gui_filler(jd);
+
+            if ((kd = gui_varray(jd)))
+            {
+                for(i = 0; i < n; i += m)
+                {
+                    if ((ld = gui_harray(kd)))
+                    {
+                        for (j = (m - 1); j >= 0; j--)
+                        {
+                            if (i + j < n)
+                            {
+                                md = gui_image(ld, course_shot(i + j),
+                                               w / 3 / m, h / 3 / m);
+                                gui_active(md, i + j, 0);
+
+                                if (i + j == 0)
+                                    gui_focus(md);
+                            }
+                            else
+                                gui_space(ld);
+                        }
+                    }
+                }
+            }
         }
 
         gui_space(id);
-        desc_id = gui_multi(id, course_desc(0), GUI_SML, GUI_ALL, gui_yel, gui_wht);
+        desc_id = gui_multi(id, _(course_desc(0)), GUI_SML, GUI_ALL, gui_yel, gui_wht);
         gui_space(id);
 
         if ((jd = gui_hstack(id)))
         {
             gui_filler(jd);
-            gui_state(jd, " Back ", GUI_SML, -1, 0);
+            gui_state(jd, _("Back"), GUI_SML, COURSE_BACK, 0);
         }
 
         gui_layout(id, 0, 0);
@@ -292,16 +356,15 @@ static void course_leave(int id)
     gui_delete(id);
 }
 
-static void course_paint(int id, float st)
+static void course_paint(int id, float t)
 {
-    game_draw(0);
+    game_draw(0, t);
     gui_paint(id);
 }
 
 static void course_timer(int id, float dt)
 {
     gui_timer(id, dt);
-    audio_timer(dt);
 }
 
 static void course_point(int id, int x, int y, int dx, int dy)
@@ -312,7 +375,28 @@ static void course_point(int id, int x, int y, int dx, int dy)
     {
         int i = gui_token(jd);
 
-        gui_set_multi(desc_id, course_desc(i));
+        if (course_exists(i))
+        {
+            gui_set_image(shot_id, course_shot(i));
+            gui_set_multi(desc_id, _(course_desc(i)));
+        }
+        gui_pulse(jd, 1.2f);
+    }
+}
+
+static void course_stick(int id, int a, int v)
+{
+    int jd;
+
+    if ((jd = shared_stick_basic(id, a, v)))
+    {
+        int i = gui_token(jd);
+
+        if (course_exists(i))
+        {
+            gui_set_image(shot_id, course_shot(i));
+            gui_set_multi(desc_id, _(course_desc(i)));
+        }
         gui_pulse(jd, 1.2f);
     }
 }
@@ -322,9 +406,16 @@ static int course_click(int b, int d)
     return (d && b < 0) ? course_action(gui_token(gui_click())) : 1;
 }
 
-static int course_keybd(int c, int d)
+static int course_buttn(int b, int d)
 {
-    return (d && c == SDLK_ESCAPE) ? goto_state(&st_title) : 1;
+    if (d)
+    {
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
+            return course_action(gui_token(gui_click()));
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
+            return course_action(COURSE_BACK);
+    }
+    return 1;
 }
 
 /*---------------------------------------------------------------------------*/
@@ -374,7 +465,7 @@ static int party_enter(void)
 
     if ((id = gui_vstack(0)))
     {
-        gui_label(id, "Players?", GUI_MED, GUI_ALL, 0, 0);
+        gui_label(id, _("Players?"), GUI_MED, GUI_ALL, 0, 0);
         gui_space(id);
 
         if ((jd = gui_harray(id)))
@@ -388,6 +479,8 @@ static int party_enter(void)
             gui_set_color(p2, gui_grn, gui_wht);
             gui_set_color(p3, gui_blu, gui_wht);
             gui_set_color(p4, gui_yel, gui_wht);
+
+            gui_focus(p1);
         }
 
         gui_space(id);
@@ -395,7 +488,7 @@ static int party_enter(void)
         if ((jd = gui_hstack(id)))
         {
             gui_filler(jd);
-            gui_state(jd, " Back ", GUI_SML, PARTY_B, 0);
+            gui_state(jd, _("Back"), GUI_SML, PARTY_B, 0);
         }
 
         gui_layout(id, 0, 0);
@@ -409,16 +502,15 @@ static void party_leave(int id)
     gui_delete(id);
 }
 
-static void party_paint(int id, float st)
+static void party_paint(int id, float t)
 {
-    game_draw(0);
+    game_draw(0, t);
     gui_paint(id);
 }
 
 static void party_timer(int id, float dt)
 {
     gui_timer(id, dt);
-    audio_timer(dt);
 }
 
 static void party_point(int id, int x, int y, int dx, int dy)
@@ -431,9 +523,141 @@ static int party_click(int b, int d)
     return (d && b < 0) ? party_action(gui_token(gui_click())) : 1;
 }
 
-static int party_keybd(int c, int d)
+static int party_buttn(int b, int d)
 {
-    return (d && c == SDLK_ESCAPE) ? goto_state(&st_course) : 1;
+    if (d)
+    {
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
+            return party_action(gui_token(gui_click()));
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
+            return party_action(PARTY_B);
+    }
+    return 1;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static int paused = 0;
+
+static struct state *st_continue;
+static struct state *st_quit;
+
+#define PAUSE_CONTINUE 1
+#define PAUSE_QUIT     2
+
+int goto_pause(struct state *s, int e)
+{
+    if (curr_state() == &st_pause)
+        return 1;
+
+    if (e && !config_tst_d(CONFIG_KEY_PAUSE, SDLK_ESCAPE))
+        return goto_state(s);
+
+    st_continue = curr_state();
+    st_quit = s;
+    paused = 1;
+
+    return goto_state(&st_pause);
+}
+
+static int pause_action(int i)
+{
+    audio_play(AUD_MENU, 1.0f);
+
+    switch(i)
+    {
+    case PAUSE_CONTINUE:
+        return goto_state(st_continue ? st_continue : &st_title);
+
+    case PAUSE_QUIT:
+        return goto_state(st_quit);
+    }
+    return 1;
+}
+
+static int pause_enter(void)
+{
+    int id, jd, td;
+
+    audio_music_fade_out(0.2f);
+
+    if ((id = gui_vstack(0)))
+    {
+        td = gui_label(id, _("Paused"), GUI_LRG, GUI_ALL, 0, 0);
+        gui_space(id);
+
+        if ((jd = gui_harray(id)))
+        {
+            gui_state(jd, _("Quit"), GUI_SML, PAUSE_QUIT, 0);
+            gui_start(jd, _("Continue"), GUI_SML, PAUSE_CONTINUE, 1);
+        }
+
+        gui_pulse(td, 1.2f);
+        gui_layout(id, 0, 0);
+    }
+
+    hud_init();
+    return id;
+}
+
+static void pause_leave(int id)
+{
+    gui_delete(id);
+    hud_free();
+    audio_music_fade_in(0.5f);
+}
+
+static void pause_paint(int id, float t)
+{
+    game_draw(0, t);
+    gui_paint(id);
+    hud_paint();
+}
+
+static void pause_timer(int id, float dt)
+{
+    gui_timer(id, dt);
+}
+
+static void pause_point(int id, int x, int y, int dx, int dy)
+{
+    gui_pulse(gui_point(id, x, y), 1.2f);
+}
+
+static int pause_click(int b, int d)
+{
+    return (d && b < 0) ? pause_action(gui_token(gui_click())) : 1;
+}
+
+static int pause_keybd(int c, int d)
+{
+    if (d && config_tst_d(CONFIG_KEY_PAUSE, c))
+        return pause_action(PAUSE_CONTINUE);
+    return 1;
+}
+
+static int pause_buttn(int b, int d)
+{
+    if (d)
+    {
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
+            return pause_action(gui_token(gui_click()));
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
+            return pause_action(PAUSE_CONTINUE);
+    }
+    return 1;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static int shared_keybd(int c, int d)
+{
+    if (d)
+    {
+        if (config_tst_d(CONFIG_KEY_PAUSE, c))
+            return goto_pause(&st_over, 0);
+    }
+    return 1;
 }
 
 /*---------------------------------------------------------------------------*/
@@ -445,14 +669,14 @@ static int next_enter(void)
     int id;
     char str[MAXSTR];
 
-    sprintf(str, "Hole %02d", curr_hole());
+    sprintf(str, _("Hole %02d"), curr_hole());
 
     if ((id = gui_vstack(0)))
     {
         gui_label(id, str, GUI_MED, GUI_ALL, 0, 0);
         gui_space(id);
 
-        gui_label(id, "Player", GUI_SML, GUI_TOP, 0, 0);
+        gui_label(id, _("Player"), GUI_SML, GUI_TOP, 0, 0);
 
         switch (curr_player())
         {
@@ -479,6 +703,9 @@ static int next_enter(void)
     hud_init();
     game_set_fly(1.f);
 
+    if (paused)
+        paused = 0;
+
     return id;
 }
 
@@ -488,9 +715,9 @@ static void next_leave(int id)
     gui_delete(id);
 }
 
-static void next_paint(int id, float st)
+static void next_paint(int id, float t)
 {
-    game_draw(0);
+    game_draw(0, t);
     hud_paint();
     gui_paint(id);
 }
@@ -498,7 +725,6 @@ static void next_paint(int id, float st)
 static void next_timer(int id, float dt)
 {
     gui_timer(id, dt);
-    audio_timer(dt);
 }
 
 static void next_point(int id, int x, int y, int dx, int dy)
@@ -517,20 +743,34 @@ static int next_keybd(int c, int d)
     {
         if (c == SDLK_F12)
             return goto_state(&st_poser);
-        if (c == SDLK_ESCAPE)
-            return goto_state(&st_over);
-        if (c == SDLK_RETURN)
-        {
-            hole_goto(num, -1);
-            num = 0;
-            return goto_state(&st_next);
-        }
+        if (config_tst_d(CONFIG_KEY_PAUSE, c))
+            return goto_pause(&st_over, 0);
         if ('0' <= c && c <= '9')
             num = num * 10 + c - '0';
     }
     return 1;
 }
 
+static int next_buttn(int b, int d)
+{
+    if (d)
+    {
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
+        {
+            if (num > 0)
+            {
+                hole_goto(num, -1);
+                num = 0;
+                return goto_state(&st_next);
+            }
+            return goto_state(&st_flyby);
+        }
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
+            return goto_pause(&st_over, 1);
+    }
+    return 1;
+}
+
 /*---------------------------------------------------------------------------*/
 
 static int poser_enter(void)
@@ -539,21 +779,32 @@ static int poser_enter(void)
     return 0;
 }
 
-static void poser_paint(int id, float st)
+static void poser_paint(int id, float t)
 {
-    game_draw(1);
+    game_draw(1, t);
 }
 
-static int poser_keybd(int c, int d)
+static int poser_buttn(int b, int d)
 {
-    return (d && c == SDLK_ESCAPE) ? goto_state(&st_next) : 1;
+    if (d)
+    {
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
+            return goto_state(&st_next);
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
+            return goto_state(&st_next);
+    }
+    return 1;
 }
 
 /*---------------------------------------------------------------------------*/
 
 static int flyby_enter(void)
 {
-    hud_init();
+    if (paused)
+        paused = 0;
+    else
+        hud_init();
+
     return 0;
 }
 
@@ -562,9 +813,9 @@ static void flyby_leave(int id)
     hud_free();
 }
 
-static void flyby_paint(int id, float st)
+static void flyby_paint(int id, float t)
 {
-    game_draw(0);
+    game_draw(0, t);
     hud_paint();
 }
 
@@ -578,7 +829,6 @@ static void flyby_timer(int id, float dt)
         game_set_fly(1.f - t);
 
     gui_timer(id, dt);
-    audio_timer(dt);
 }
 
 static int flyby_click(int b, int d)
@@ -591,19 +841,36 @@ static int flyby_click(int b, int d)
     return 1;
 }
 
-static int flyby_keybd(int c, int d)
+static int flyby_buttn(int b, int d)
 {
-    return (d && c == SDLK_ESCAPE) ? goto_state(&st_over) : 1;
+    if (d)
+    {
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
+        {
+            game_set_fly(0.f);
+            return goto_state(&st_stroke);
+        }
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
+            return goto_pause(&st_over, 1);
+    }
+    return 1;
 }
 
 /*---------------------------------------------------------------------------*/
 
+static int stroke_rotate = 0;
+static int stroke_mag    = 0;
+
 static int stroke_enter(void)
 {
     hud_init();
     game_clr_mag();
     config_set_d(CONFIG_CAMERA, 2);
-    config_set_grab();
+    config_set_grab(!paused);
+
+    if (paused)
+        paused = 0;
+
     return 0;
 }
 
@@ -614,9 +881,9 @@ static void stroke_leave(int id)
     config_set_d(CONFIG_CAMERA, 0);
 }
 
-static void stroke_paint(int id, float st)
+static void stroke_paint(int id, float t)
 {
-    game_draw(0);
+    game_draw(0, t);
     hud_paint();
 }
 
@@ -624,9 +891,20 @@ static void stroke_timer(int id, float dt)
 {
     float g[3] = { 0.f, 0.f, 0.f };
 
+    float k;
+
+    if (SDL_GetModState() & KMOD_SHIFT ||
+        (joystick && SDL_JoystickGetButton(joystick,
+                                           config_get_d(CONFIG_JOYSTICK_BUTTON_B))))
+        k = 0.25;
+    else
+        k = 1.0;
+
+    game_set_rot(stroke_rotate * k);
+    game_set_mag(stroke_mag * k);
+
     game_update_view(dt);
     game_step(g, dt);
-    audio_timer(dt);
 }
 
 static void stroke_point(int id, int x, int y, int dx, int dy)
@@ -635,14 +913,32 @@ static void stroke_point(int id, int x, int y, int dx, int dy)
     game_set_mag(dy);
 }
 
+static void stroke_stick(int id, int a, int v)
+{
+    if (v == 1) /* See 'loop' in main.c */
+        v = 0;
+
+    if (config_tst_d(CONFIG_JOYSTICK_AXIS_X, a))
+        stroke_rotate = (6 * v) / JOY_MAX;
+    else if (config_tst_d(CONFIG_JOYSTICK_AXIS_Y, a))
+        stroke_mag = -((6 * v) / JOY_MAX);
+}
+
 static int stroke_click(int b, int d)
 {
     return (d && b < 0) ? goto_state(&st_roll) : 1;
 }
 
-static int stroke_keybd(int c, int d)
+static int stroke_buttn(int b, int d)
 {
-    return (d && c == SDLK_ESCAPE) ? goto_state(&st_over) : 1;
+    if (d)
+    {
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
+            return goto_state(&st_roll);
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
+            return goto_pause(&st_over, 1);
+    }
+    return 1;
 }
 
 /*---------------------------------------------------------------------------*/
@@ -650,7 +946,12 @@ static int stroke_keybd(int c, int d)
 static int roll_enter(void)
 {
     hud_init();
-    game_putt();
+
+    if (paused)
+        paused = 0;
+    else
+        game_putt();
+
     return 0;
 }
 
@@ -659,9 +960,9 @@ static void roll_leave(int id)
     hud_free();
 }
 
-static void roll_paint(int id, float st)
+static void roll_paint(int id, float t)
 {
-    game_draw(0);
+    game_draw(0, t);
     hud_paint();
 }
 
@@ -675,12 +976,16 @@ static void roll_timer(int id, float dt)
     case GAME_GOAL: goto_state(&st_goal); break;
     case GAME_FALL: goto_state(&st_fall); break;
     }
-    audio_timer(dt);
 }
 
-static int roll_keybd(int c, int d)
+static int roll_buttn(int b, int d)
 {
-    return (d && c == SDLK_ESCAPE) ? goto_state(&st_over) : 1;
+    if (d)
+    {
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
+            return goto_pause(&st_over, 1);
+    }
+    return 1;
 }
 
 /*---------------------------------------------------------------------------*/
@@ -688,11 +993,15 @@ static int roll_keybd(int c, int d)
 static int goal_enter(void)
 {
     int id;
-    
-    if ((id = gui_label(0, "It's In!", GUI_MED, GUI_ALL, gui_grn, gui_grn)))
+
+    if ((id = gui_label(0, _("It's In!"), GUI_MED, GUI_ALL, gui_grn, gui_grn)))
         gui_layout(id, 0, 0);
 
-    hole_goal();
+    if (paused)
+        paused = 0;
+    else
+        hole_goal();
+
     hud_init();
 
     return id;
@@ -704,9 +1013,9 @@ static void goal_leave(int id)
     hud_free();
 }
 
-static void goal_paint(int id, float st)
+static void goal_paint(int id, float t)
 {
-    game_draw(0);
+    game_draw(0, t);
     gui_paint(id);
     hud_paint();
 }
@@ -720,7 +1029,6 @@ static void goal_timer(int id, float dt)
         else
             goto_state(&st_score);
     }
-    audio_timer(dt);
 }
 
 static int goal_click(int b, int d)
@@ -735,17 +1043,34 @@ static int goal_click(int b, int d)
     return 1;
 }
 
-static int goal_keybd(int c, int d)
+static int goal_buttn(int b, int d)
 {
-    return (d && c == SDLK_ESCAPE) ? goto_state(&st_over) : 1;
+    if (d)
+    {
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
+        {
+            if (hole_next())
+                goto_state(&st_next);
+            else
+                goto_state(&st_score);
+        }
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
+            return goto_pause(&st_over, 1);
+    }
+    return 1;
 }
 
 /*---------------------------------------------------------------------------*/
 
 static int stop_enter(void)
 {
-    hole_stop();
+    if (paused)
+        paused = 0;
+    else
+        hole_stop();
+
     hud_init();
+
     return 0;
 }
 
@@ -754,9 +1079,9 @@ static void stop_leave(int id)
     hud_free();
 }
 
-static void stop_paint(int id, float st)
+static void stop_paint(int id, float t)
 {
-    game_draw(0);
+    game_draw(0, t);
     hud_paint();
 }
 
@@ -766,7 +1091,6 @@ static void stop_timer(int id, float dt)
 
     game_update_view(dt);
     game_step(g, dt);
-    audio_timer(dt);
 
     if (time_state() > 1)
     {
@@ -789,9 +1113,21 @@ static int stop_click(int b, int d)
     return 1;
 }
 
-static int stop_keybd(int c, int d)
+static int stop_buttn(int b, int d)
 {
-    return (d && c == SDLK_ESCAPE) ? goto_state(&st_over) : 1;
+    if (d)
+    {
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
+        {
+            if (hole_next())
+                goto_state(&st_next);
+            else
+                goto_state(&st_score);
+        }
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
+            return goto_pause(&st_over, 1);
+    }
+    return 1;
 }
 
 /*---------------------------------------------------------------------------*/
@@ -799,11 +1135,18 @@ static int stop_keybd(int c, int d)
 static int fall_enter(void)
 {
     int id;
-    
-    if ((id = gui_label(0, "1 Stroke Penalty", GUI_MED, GUI_ALL, gui_blk, gui_red)))
+
+    if ((id = gui_label(0, _("1 Stroke Penalty"), GUI_MED, GUI_ALL, gui_blk, gui_red)))
         gui_layout(id, 0, 0);
 
-    hole_fall();
+    if (paused)
+        paused = 0;
+    else
+    {
+        hole_fall();
+/*        game_draw(0);*/ /*TODO: is this call ok? */  /* No, it's not. */
+    }
+
     hud_init();
 
     return id;
@@ -815,9 +1158,9 @@ static void fall_leave(int id)
     hud_free();
 }
 
-static void fall_paint(int id, float st)
+static void fall_paint(int id, float t)
 {
-    game_draw(0);
+    game_draw(0, t);
     gui_paint(id);
     hud_paint();
 }
@@ -831,7 +1174,6 @@ static void fall_timer(int id, float dt)
         else
             goto_state(&st_score);
     }
-    audio_timer(dt);
 }
 
 static int fall_click(int b, int d)
@@ -846,9 +1188,21 @@ static int fall_click(int b, int d)
     return 1;
 }
 
-static int fall_keybd(int c, int d)
+static int fall_buttn(int b, int d)
 {
-    return (d && c == SDLK_ESCAPE) ? goto_state(&st_over) : 1;
+    if (d)
+    {
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
+        {
+            if (hole_next())
+                goto_state(&st_next);
+            else
+                goto_state(&st_score);
+        }
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
+            return goto_pause(&st_over, 1);
+    }
+    return 1;
 }
 
 /*---------------------------------------------------------------------------*/
@@ -856,7 +1210,11 @@ static int fall_keybd(int c, int d)
 static int score_enter(void)
 {
     audio_music_fade_out(2.f);
-    return score_card("Scores", gui_yel, gui_red);
+
+    if (paused)
+        paused = 0;
+
+    return score_card(_("Scores"), gui_yel, gui_red);
 }
 
 static void score_leave(int id)
@@ -864,16 +1222,15 @@ static void score_leave(int id)
     gui_delete(id);
 }
 
-static void score_paint(int id, float st)
+static void score_paint(int id, float t)
 {
-    game_draw(0);
+    game_draw(0, t);
     gui_paint(id);
 }
 
 static void score_timer(int id, float dt)
 {
     gui_timer(id, dt);
-    audio_timer(dt);
 }
 
 static int score_click(int b, int d)
@@ -888,9 +1245,21 @@ static int score_click(int b, int d)
     return 1;
 }
 
-static int score_keybd(int c, int d)
+static int score_buttn(int b, int d)
 {
-    return (d && c == SDLK_ESCAPE) ? goto_state(&st_title) : 1;
+    if (d)
+    {
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
+        {
+            if (hole_move())
+                goto_state(&st_next);
+            else
+                goto_state(&st_score);
+        }
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
+            return goto_pause(&st_over, 1);
+    }
+    return 1;
 }
 
 /*---------------------------------------------------------------------------*/
@@ -898,7 +1267,7 @@ static int score_keybd(int c, int d)
 static int over_enter(void)
 {
     audio_music_fade_out(2.f);
-    return score_card("Final Scores", gui_yel, gui_red);
+    return score_card(_("Final Scores"), gui_yel, gui_red);
 }
 
 static void over_leave(int id)
@@ -906,16 +1275,15 @@ static void over_leave(int id)
     gui_delete(id);
 }
 
-static void over_paint(int id, float st)
+static void over_paint(int id, float t)
 {
-    game_draw(0);
+    game_draw(0, t);
     gui_paint(id);
 }
 
 static void over_timer(int id, float dt)
 {
     gui_timer(id, dt);
-    audio_timer(dt);
 }
 
 static int over_click(int b, int d)
@@ -923,9 +1291,16 @@ static int over_click(int b, int d)
     return (d && b < 0) ? goto_state(&st_title) : 1;
 }
 
-static int over_keybd(int c, int d)
+static int over_buttn(int b, int d)
 {
-    return (d && c == SDLK_ESCAPE) ? goto_state(&st_title) : 1;
+    if (d)
+    {
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
+            return goto_state(&st_title);
+        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
+            return goto_state(&st_title);
+    }
+    return 1;
 }
 
 /*---------------------------------------------------------------------------*/
@@ -936,10 +1311,11 @@ struct state st_title = {
     title_paint,
     title_timer,
     title_point,
+    shared_stick,
     NULL,
     title_click,
-    title_keybd,
     NULL,
+    title_buttn,
     1, 0
 };
 
@@ -949,10 +1325,11 @@ struct state st_course = {
     course_paint,
     course_timer,
     course_point,
+    course_stick,
     NULL,
     course_click,
-    course_keybd,
     NULL,
+    course_buttn,
     1, 0
 };
 
@@ -962,10 +1339,11 @@ struct state st_party = {
     party_paint,
     party_timer,
     party_point,
+    shared_stick,
     NULL,
     party_click,
-    party_keybd,
     NULL,
+    party_buttn,
     1, 0
 };
 
@@ -975,10 +1353,11 @@ struct state st_next = {
     next_paint,
     next_timer,
     next_point,
+    shared_stick,
     NULL,
     next_click,
     next_keybd,
-    NULL,
+    next_buttn,
     1, 0
 };
 
@@ -990,8 +1369,9 @@ struct state st_poser = {
     NULL,
     NULL,
     NULL,
-    poser_keybd,
     NULL,
+    NULL,
+    poser_buttn,
     1, 0
 };
 
@@ -1002,9 +1382,10 @@ struct state st_flyby = {
     flyby_timer,
     NULL,
     NULL,
-    flyby_click,
-    flyby_keybd,
     NULL,
+    flyby_click,
+    shared_keybd,
+    flyby_buttn,
     1, 0
 };
 
@@ -1014,10 +1395,11 @@ struct state st_stroke = {
     stroke_paint,
     stroke_timer,
     stroke_point,
+    stroke_stick,
     NULL,
     stroke_click,
-    stroke_keybd,
-    NULL,
+    shared_keybd,
+    stroke_buttn,
     0, 0
 };
 
@@ -1029,8 +1411,9 @@ struct state st_roll = {
     NULL,
     NULL,
     NULL,
-    roll_keybd,
     NULL,
+    shared_keybd,
+    roll_buttn,
     0, 0
 };
 
@@ -1041,9 +1424,10 @@ struct state st_goal = {
     goal_timer,
     NULL,
     NULL,
-    goal_click,
-    goal_keybd,
     NULL,
+    goal_click,
+    shared_keybd,
+    goal_buttn,
     0, 0
 };
 
@@ -1054,9 +1438,10 @@ struct state st_stop = {
     stop_timer,
     NULL,
     NULL,
-    stop_click,
-    stop_keybd,
     NULL,
+    stop_click,
+    shared_keybd,
+    stop_buttn,
     0, 0
 };
 
@@ -1067,9 +1452,10 @@ struct state st_fall = {
     fall_timer,
     NULL,
     NULL,
-    fall_click,
-    fall_keybd,
     NULL,
+    fall_click,
+    shared_keybd,
+    fall_buttn,
     0, 0
 };
 
@@ -1080,9 +1466,10 @@ struct state st_score = {
     score_timer,
     NULL,
     NULL,
-    score_click,
-    score_keybd,
     NULL,
+    score_click,
+    shared_keybd,
+    score_buttn,
     0, 0
 };
 
@@ -1093,8 +1480,23 @@ struct state st_over = {
     over_timer,
     NULL,
     NULL,
+    NULL,
     over_click,
-    over_keybd,
     NULL,
+    over_buttn,
+    1, 0
+};
+
+struct state st_pause = {
+    pause_enter,
+    pause_leave,
+    pause_paint,
+    pause_timer,
+    pause_point,
+    shared_stick,
+    NULL,
+    pause_click,
+    pause_keybd,
+    pause_buttn,
     1, 0
 };