Merge branch 'gles'
[neverball] / putt / game.c
index 960439b..70ce43c 100644 (file)
 #include "vec3.h"
 #include "geom.h"
 #include "ball.h"
-#include "back.h"
 #include "hole.h"
 #include "hud.h"
 #include "image.h"
 #include "audio.h"
-#include "solid_gl.h"
 #include "config.h"
+#include "video.h"
+
+#include "solid_draw.h"
+#include "solid_sim.h"
+#include "solid_all.h"
 
 /*---------------------------------------------------------------------------*/
 
-static struct s_file file;
+static struct s_full file;
 static int           ball;
 
+static int state;
+
 static float view_a;                    /* Ideal view rotation about Y axis  */
 static float view_m;
 static float view_ry;                   /* Angular velocity about Y axis     */
@@ -46,10 +51,11 @@ static float view_e[3][3];              /* Current view orientation          */
 
 static float jump_e = 1;                /* Jumping enabled flag              */
 static float jump_b = 0;                /* Jump-in-progress flag             */
-static int   jump_u = 0;                /* Which ball is jumping?            */
 static float jump_dt;                   /* Jump duration                     */
 static float jump_p[3];                 /* Jump destination                  */
 
+static float idle_t;                    /* Idling timeout                    */
+
 /*---------------------------------------------------------------------------*/
 
 static void view_init(void)
@@ -79,258 +85,107 @@ static void view_init(void)
     view_e[2][2] = 1.f;
 }
 
-void game_init(const char *s)
+int game_init(const char *s)
 {
+    int i;
+
     jump_e = 1;
     jump_b = 0;
-    jump_u = 0;
-
-    view_init();
-    sol_load_gl(&file, config_data(s), config_get_d(CONFIG_TEXTURES),
-                                    config_get_d(CONFIG_SHADOW));
-}
-
-void game_free(void)
-{
-    sol_free_gl(&file);
-}
 
-/*---------------------------------------------------------------------------*/
+    idle_t = 1.0f;
 
-int game_check_balls(struct s_file *fp)
-{
-    float z[3] = {0.0f, 0.0f, 0.0f};
-    int i, j;
-
-    for (i = 1; i < fp->uc && config_get_d(CONFIG_BALL_COLLISIONS); i++)
-    {
-        struct s_ball *up = fp->uv + i;
-
-       /*
-        * If a ball falls out, return the ball to the camera marker
-        * and reset the play state for fair play
-        */
-        if (i != ball && up->p[1] < -10.f && (up->p[1] > -199.9f || up->p[1] < -599.9f))
-        {
-            up->P = 0;
-            v_cpy(up->p, fp->uv->p);
-            v_cpy(up->v, z);
-            v_cpy(up->w, z);
-        }
+    view_init();
 
-        if (i == ball && up->p[1] < -30.0f)
-        {
-            v_cpy(up->p, fp->uv->p);
-            v_cpy(up->v, z);
-            v_cpy(up->w, z);
-        }
+    if (!(state = sol_load_full(&file, s, config_get_d(CONFIG_SHADOW))))
+        return 0;
 
-       /*
-        * If an OTHER ball stops in a hole, mark it as done
-        * and drop it -200.0 units to allow room for more balls
-        */
-        if (i != ball && !(v_len(up->v) > 0.0f))
-        {
-            const float *ball_p = up->p;
-            const float  ball_r = up->r;
-            int zi;
-            for (zi = 0; zi < fp->zc; zi++)
-            {
-                float r[3];
-
-                r[0] = ball_p[0] - fp->zv[zi].p[0];
-                r[1] = ball_p[2] - fp->zv[zi].p[2];
-                r[2] = 0;
-
-                if (v_len(r) < fp->zv[zi].r * 1.1 - ball_r &&
-                    ball_p[1] > fp->zv[zi].p[1] &&
-                    ball_p[1] < fp->zv[zi].p[1] + GOAL_HEIGHT / 2)
-                {
-                    up->p[1] = -200.0f;
-                    v_cpy(up->v, z);
-                    v_cpy(up->w, z);
-                    return i;
-                }
-            }
-        }
+    sol_init_sim(&file.vary);
 
-       /*
-        * Check for intesecting balls.
-        * If there are any, reset the proper
-        * ball's play state
-        */
-        for (j = i + 1; j < fp->uc && config_get_d(CONFIG_BALL_COLLISIONS); j++)
-        {
-            struct s_ball *u2p = fp->uv + j;
-            float d[3];
-            v_sub(d, up->p, u2p->p);
-            if (v_len(up->v) > 0.005f || v_len(u2p->v) > 0.005f)
-                continue;
-            if (v_len(d) < (fsqrtf((up->r + u2p->r) * (up->r + u2p->r))) * 1.0f && i != ball)
-                up->P = 0;
-            else if (v_len(d) < (fsqrtf((up->r + u2p->r) * (up->r + u2p->r)) *  1.0f))
-                u2p->P = 0;
-        }
-    }
-
-    for (i = 0; i < fp->yc; i++)
+    for (i = 0; i < file.base.dc; i++)
     {
-        struct s_ball *yp = fp->yv + i;
+        const char *k = file.base.av + file.base.dv[i].ai;
+        const char *v = file.base.av + file.base.dv[i].aj;
 
-        if (yp->p[1] < -20.0f && yp->n)
+        if (strcmp(k, "idle") == 0)
         {
-            v_cpy(yp->p, yp->O);
-            v_cpy(yp->v, z);
-            v_cpy(yp->w, z);
-        }
+            sscanf(v, "%f", &idle_t);
 
-        if (!(v_len(yp->v) > 0.0f))
-        {
-            const float *ball_p = yp->p;
-            const float  ball_r = yp->r;
-            int zi;
-            for (zi = 0; zi < fp->zc; zi++)
-            {
-                float r[3];
-
-                r[0] = ball_p[0] - fp->zv[zi].p[0];
-                r[1] = ball_p[2] - fp->zv[zi].p[2];
-                r[2] = 0;
-
-                if (v_len(r) < fp->zv[zi].r * 1.1 - ball_r &&
-                    ball_p[1] > fp->zv[zi].p[1] &&
-                    ball_p[1] < fp->zv[zi].p[1] + GOAL_HEIGHT / 2)
-                {
-                    v_cpy(yp->p, yp->O);
-                    v_cpy(yp->v, z);
-                    v_cpy(yp->w, z);
-                }
-            }
+            if (idle_t < 1.0f)
+                idle_t = 1.0f;
         }
     }
-
-    return 0;
+    return 1;
 }
 
-static void game_draw_vect_prim(const struct s_file *fp, GLenum mode)
+void game_free(void)
 {
-    float p[3];
-    float x[3];
-    float z[3];
-    float r;
-
-    v_cpy(p, fp->uv[ball].p);
-    v_cpy(x, view_e[0]);
-    v_cpy(z, view_e[2]);
-
-    r = fp->uv[ball].r;
-
-    glBegin(mode);
-    {
-        glColor4f(1.0f, 1.0f, 0.5f, 0.5f);
-        glVertex3f(p[0] - x[0] * r,
-                   p[1] - x[1] * r,
-                   p[2] - x[2] * r);
-
-        glColor4f(1.0f, 0.0f, 0.0f, 0.5f);
-        glVertex3f(p[0] + z[0] * view_m,
-                   p[1] + z[1] * view_m,
-                   p[2] + z[2] * view_m);
-
-        glColor4f(1.0f, 1.0f, 0.0f, 0.5f);
-        glVertex3f(p[0] + x[0] * r,
-                   p[1] + x[1] * r,
-                   p[2] + x[2] * r);
-    }
-    glEnd();
+    sol_quit_sim();
+    sol_free_full(&file);
 }
 
-static void game_draw_vect(const struct s_file *fp)
+/*---------------------------------------------------------------------------*/
+
+static void game_draw_vect(struct s_rend *rend, const struct s_vary *fp)
 {
     if (view_m > 0.f)
     {
-        glPushAttrib(GL_TEXTURE_BIT);
-        glPushAttrib(GL_POLYGON_BIT);
-        glPushAttrib(GL_LIGHTING_BIT);
-        glPushAttrib(GL_DEPTH_BUFFER_BIT);
+        glDisable(GL_LIGHTING);
+        glPushMatrix();
         {
-            glEnable(GL_COLOR_MATERIAL);
-            glDisable(GL_LIGHTING);
-            glDisable(GL_TEXTURE_2D);
-            glDepthMask(GL_FALSE);
-
-            glEnable(GL_DEPTH_TEST);
-            game_draw_vect_prim(fp, GL_TRIANGLES);
-
-            glDisable(GL_DEPTH_TEST);
-            game_draw_vect_prim(fp, GL_LINE_STRIP);
+            glTranslatef(fp->uv[ball].p[0],
+                         fp->uv[ball].p[1],
+                         fp->uv[ball].p[2]);
+            glRotatef(view_a, 0.0f, 1.0f, 0.0f);
+            glScalef(fp->uv[ball].r,
+                     fp->uv[ball].r * 0.1f, view_m);
+
+            vect_draw(rend);
         }
-        glPopAttrib();
-        glPopAttrib();
-        glPopAttrib();
-        glPopAttrib();
+        glPopMatrix();
+        glEnable(GL_LIGHTING);
     }
 }
 
-static void game_draw_balls(const struct s_file *fp,
+static void game_draw_balls(struct s_rend *rend,
+                            const struct s_vary *fp,
                             const float *bill_M, float t)
 {
-    static const GLfloat color[6][4] = {
+    static const GLfloat color[5][4] = {
         { 1.0f, 1.0f, 1.0f, 0.7f },
         { 1.0f, 0.0f, 0.0f, 1.0f },
         { 0.0f, 1.0f, 0.0f, 1.0f },
         { 0.0f, 0.0f, 1.0f, 1.0f },
         { 1.0f, 1.0f, 0.0f, 1.0f },
-        { 0.1f, 0.1f, 0.1f, 1.0f },
     };
 
-    int ui, yi;
-
-    for (yi = 0; yi < fp->yc; yi++)
-    {
-        float M[16];
-
-        if (!config_get_d(CONFIG_BALL_COLLISIONS) && fp->yv[yi].c)
-            continue;
-
-        m_basis(M, fp->yv[yi].e[0], fp->yv[yi].e[1], fp->yv[yi].e[2]);
+    int ui;
 
-        glPushMatrix();
-        {
-            glTranslatef(fp->yv[yi].p[0],
-                         fp->yv[yi].p[1] + BALL_FUDGE,
-                         fp->yv[yi].p[2]);
-            glMultMatrixf(M);
-            glScalef(fp->yv[yi].r,
-                     fp->yv[yi].r,
-                     fp->yv[yi].r);
-
-            glColor4fv(color[5]);
-            oldball_draw(1);
-        }
-        glPopMatrix();
-    }
+    glEnable(GL_COLOR_MATERIAL);
 
     for (ui = curr_party(); ui > 0; ui--)
     {
-        if (ui == ball || (config_get_d(CONFIG_BALL_COLLISIONS) && fp->uv[ui].P))
+        if (ui == ball)
         {
-            float M[16];
+            float ball_M[16];
+            float pend_M[16];
 
-            m_basis(M, fp->uv[ui].e[0], fp->uv[ui].e[1], fp->uv[ui].e[2]);
+            m_basis(ball_M, fp->uv[ui].e[0], fp->uv[ui].e[1], fp->uv[ui].e[2]);
+            m_basis(pend_M, fp->uv[ui].E[0], fp->uv[ui].E[1], fp->uv[ui].E[2]);
 
             glPushMatrix();
             {
                 glTranslatef(fp->uv[ui].p[0],
                              fp->uv[ui].p[1] + BALL_FUDGE,
                              fp->uv[ui].p[2]);
-                glMultMatrixf(M);
                 glScalef(fp->uv[ui].r,
                          fp->uv[ui].r,
                          fp->uv[ui].r);
 
-                glColor4fv(color[ui]);
-                oldball_draw(0);
+                glColor4f(color[ui][0],
+                          color[ui][1],
+                          color[ui][2],
+                          color[ui][3]);
+                ball_draw(rend, ball_M, pend_M, bill_M, t);
             }
             glPopMatrix();
         }
@@ -349,15 +204,17 @@ static void game_draw_balls(const struct s_file *fp,
                           color[ui][1],
                           color[ui][2], 0.5f);
 
-                mark_draw();
+                mark_draw(rend);
             }
             glPopMatrix();
         }
     }
+
     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+    glDisable(GL_COLOR_MATERIAL);
 }
 
-static void game_draw_goals(const struct s_file *fp)
+static void game_draw_goals(struct s_rend *rend, const struct s_base *fp)
 {
     int zi;
 
@@ -368,14 +225,15 @@ static void game_draw_goals(const struct s_file *fp)
             glTranslatef(fp->zv[zi].p[0],
                          fp->zv[zi].p[1],
                          fp->zv[zi].p[2]);
-            flag_draw();
+            flag_draw(rend);
         }
         glPopMatrix();
     }
 }
 
-static void game_draw_jumps(const struct s_file *fp)
+static void game_draw_jumps(struct s_rend *rend, const struct s_base *fp)
 {
+    float t = 0.001f * SDL_GetTicks();
     int ji;
 
     for (ji = 0; ji < fp->jc; ji++)
@@ -387,26 +245,31 @@ static void game_draw_jumps(const struct s_file *fp)
                          fp->jv[ji].p[2]);
 
             glScalef(fp->jv[ji].r, 1.f, fp->jv[ji].r);
-            jump_draw(!jump_e);
+            jump_draw(rend, t, !jump_e);
         }
         glPopMatrix();
     }
 }
 
-static void game_draw_swchs(const struct s_file *fp)
+static void game_draw_swchs(struct s_rend *rend, const struct s_vary *fp)
 {
     int xi;
 
     for (xi = 0; xi < fp->xc; xi++)
     {
+        struct v_swch *xp = fp->xv + xi;
+
+        if (xp->base->i)
+            continue;
+
         glPushMatrix();
         {
-            glTranslatef(fp->xv[xi].p[0],
-                         fp->xv[xi].p[1],
-                         fp->xv[xi].p[2]);
+            glTranslatef(xp->base->p[0],
+                         xp->base->p[1],
+                         xp->base->p[2]);
 
-            glScalef(fp->xv[xi].r, 1.f, fp->xv[xi].r);
-            swch_draw(fp->xv[xi].f, fp->xv[xi].e);
+            glScalef(xp->base->r, 1.f, xp->base->r);
+            swch_draw(rend, xp->f, xp->e);
         }
         glPopMatrix();
     }
@@ -416,27 +279,23 @@ static void game_draw_swchs(const struct s_file *fp)
 
 void game_draw(int pose, float t)
 {
-    static const float a[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
-    static const float s[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
-    static const float e[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
-    static const float h[1] = { 0.0f };
-    
-    const float light_p[4] = { 8.f, 32.f, 8.f, 1.f };
+    const float light_p[4] = { 8.f, 32.f, 8.f, 0.f };
 
-    const struct s_file *fp = &file;
+    struct s_draw *fp = &file.draw;
+    struct s_rend rend = { NULL };
 
     float fov = FOV;
 
-    int i = 0;
+    if (!state)
+        return;
 
-    if (config_get_d(CONFIG_BALL_COLLISIONS) && jump_b && jump_u != ball * 2)
-        fov /= 1.9f * fabsf(jump_dt - 0.5f);
+    fp->shadow_ui = ball;
 
-    else if (jump_b)
-        fov *= 2.0f * fabsf(jump_dt - 0.5f);
+    sol_draw_enable(&rend);
 
-    config_push_persp(fov, 0.1f, FAR_DIST);
-    glPushAttrib(GL_LIGHTING_BIT);
+    if (jump_b) fov *= 2.0f * fabsf(jump_dt - 0.5f);
+
+    video_push_persp(fov, 0.1f, FAR_DIST);
     glPushMatrix();
     {
         float T[16], M[16], v[3], rx, ry;
@@ -458,7 +317,7 @@ void game_draw(int pose, float t)
         glPushMatrix();
         {
             glTranslatef(view_p[0], view_p[1], view_p[2]);
-            back_draw(0);
+            back_draw(&rend, 0);
         }
         glPopMatrix();
 
@@ -467,31 +326,7 @@ void game_draw(int pose, float t)
 
         /* Draw the floor. */
 
-        sol_draw(fp, 0, 1);
-
-        if (config_get_d(CONFIG_SHADOW) && !pose)
-        {
-            for (i = 0; i < fp->yc; i++)
-            {
-                shad_draw_set(fp->yv[i].p, fp->yv[i].r);
-                sol_shad(fp);
-                shad_draw_clr();
-            }
-
-            for (i = 0; i < fp->uc; i++)
-            {
-                if (fp->uv[i].P)
-                {
-                    shad_draw_set(fp->uv[i].p, fp->uv[i].r);
-                    sol_shad(fp);
-                    shad_draw_clr();
-                }
-            }
-
-            shad_draw_set(fp->uv[ball].p, fp->uv[ball].r);
-            sol_shad(fp);
-            shad_draw_clr();
-        }
+        sol_draw(fp, &rend, 0, 1);
 
         /* Draw the game elements. */
 
@@ -500,33 +335,26 @@ void game_draw(int pose, float t)
 
         if (pose == 0)
         {
-            game_draw_balls(fp, T, t);
-            game_draw_vect(fp);
+            game_draw_balls(&rend, fp->vary, T, t);
+            game_draw_vect(&rend, fp->vary);
         }
 
-        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,   a);
-        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,  s);
-        glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION,  e);
-        glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, h);
-
-        game_draw_goals(fp);
-
         glEnable(GL_COLOR_MATERIAL);
         glDisable(GL_LIGHTING);
-        glDisable(GL_TEXTURE_2D);
         glDepthMask(GL_FALSE);
         {
-            game_draw_jumps(fp);
-            game_draw_swchs(fp);
+            game_draw_goals(&rend, fp->base);
+            game_draw_jumps(&rend, fp->base);
+            game_draw_swchs(&rend, fp->vary);
         }
         glDepthMask(GL_TRUE);
-        glEnable(GL_TEXTURE_2D);
         glEnable(GL_LIGHTING);
         glDisable(GL_COLOR_MATERIAL);
     }
     glPopMatrix();
-    glPopAttrib();
-    config_pop_matrix();
+    video_pop_matrix();
+
+    sol_draw_disable(&rend);
 }
 
 /*---------------------------------------------------------------------------*/
@@ -542,10 +370,13 @@ void game_update_view(float dt)
     float d[3];
     float s = 2.f * dt;
 
+    if (!state)
+        return;
+
     /* Center the view about the ball. */
 
-    v_cpy(view_c, file.uv[ball].p);
-    v_inv(view_v, file.uv[ball].v);
+    v_cpy(view_c, file.vary.uv[ball].p);
+    v_inv(view_v, file.vary.uv[ball].v);
 
     switch (config_get_d(CONFIG_CAMERA))
     {
@@ -602,127 +433,56 @@ static int game_update_state(float dt)
 {
     static float t = 0.f;
 
-    struct s_file *fp = &file;
+    struct s_vary *fp = &file.vary;
     float p[3];
 
-    int i;
-
     if (dt > 0.f)
         t += dt;
     else
         t = 0.f;
 
     /* Test for a switch. */
-    if (sol_swch_test(fp))
+
+    if (sol_swch_test(fp, ball) == SWCH_INSIDE)
         audio_play(AUD_SWITCH, 1.f);
 
     /* Test for a jump. */
 
-    if (config_get_d(CONFIG_BALL_COLLISIONS))
+    if (jump_e == 1 && jump_b == 0 && (sol_jump_test(fp, jump_p, ball) ==
+                                       JUMP_INSIDE))
     {
-        for (i = 1; i < curr_party() + 1; i++)
-        {
-            if (!jump_u && jump_e == 1 && jump_b == 0 && sol_jump_test(fp, jump_p, i) == 1)
-            {
-                jump_b  = 1;
-                jump_e  = 0;
-                jump_dt = 0.f;
-                jump_u  = i * 2;
+        jump_b  = 1;
+        jump_e  = 0;
+        jump_dt = 0.f;
 
-                audio_play(AUD_JUMP, 1.f);
-            }
-            if (jump_e == 0 && jump_b == 0 && sol_jump_test(fp, jump_p, i) == 0)
-                jump_e = 1;
-            if (!jump_b && jump_u && i == jump_u / 2 && sol_jump_test(fp, jump_p, i) == 0)
-                jump_u = 0;
-        }
-
-        for (i = 0; i < fp->yc; i++)
-        {
-            if (!jump_u && jump_e == 1 && jump_b == 0 && sol_jump_test(fp, jump_p, fp->yv + i - fp->uv) == 1)
-            {
-                jump_b  = 1;
-                jump_e  = 0;
-                jump_dt = 0.f;
-                jump_u  = i * 2 + 1;
-
-                audio_play(AUD_JUMP, 1.f);
-            }
-            if (jump_e == 0 && jump_b == 0 && sol_jump_test(fp, jump_p, fp->yv + i - fp->uv) == 0)
-                jump_e = 1;
-            if (!jump_b && jump_u && i == jump_u / 2 && sol_jump_test(fp, jump_p, fp->yv + i - fp->uv) == 0)
-                jump_u = 0;
-        }
+        audio_play(AUD_JUMP, 1.f);
     }
-    else
+    if (jump_e == 0 && jump_b == 0 && (sol_jump_test(fp, jump_p, ball) ==
+                                       JUMP_OUTSIDE))
     {
-        if (jump_e == 1 && jump_b == 0 && sol_jump_test(fp, jump_p, ball) == 1)
-        {
-            jump_b  = 1;
-            jump_e  = 0;
-            jump_dt = 0.f;
-
-            audio_play(AUD_JUMP, 1.f);
-        }
-        if (jump_e == 0 && jump_b == 0 && sol_jump_test(fp, jump_p, ball) == 0)
-            jump_e = 1;
+        jump_e = 1;
     }
 
     /* Test for fall-out. */
 
-    if (fp->uv[ball].p[1] < -10.0f)
+    if (fp->uv[ball].p[1] < -10.f)
         return GAME_FALL;
 
     /* Test for a goal or stop. */
 
-    if (t > 1.0f)
+    if (t > 1.f && sol_goal_test(fp, p, ball))
     {
-        t = 0.0f;
-
-        if (config_get_d(CONFIG_BALL_COLLISIONS))
-        {
-            switch (sol_goal_test(fp, p, ball))
-            {
-                case 2:  /* The player's ball landed in the goal and the all of the other balls have stopped */
-                    t = 0.0f;
-                    return GAME_GOAL;
-                    break;
-                case 1:  /* All balls have stopped */
-                    t = 0.0f;
-                    return GAME_STOP;
-                    break;
-                case 0:  /* Game still running; there may be a ball that has not yet stopped */
-                    return GAME_NONE;
-                    break;
-                default: /* Should never reach this */
-                    break;
-            }
-        }
-
-        else
-        {
-            if (sol_goal_test(fp, p, ball))
-                return GAME_GOAL;
-            else
-                return GAME_STOP;
-        }
+        t = 0.f;
+        return GAME_GOAL;
     }
 
-    return GAME_NONE;
-}
-
-void game_set_played(int b)
-{
-    if (ball)
-        file.uv[ball].P = b;
-    if (!b)
+    if (t > idle_t)
     {
-        file.uv[0].P = 0;
-        file.uv[1].P = 0;
-        file.uv[2].P = 0;
-        file.uv[3].P = 0;
-        file.uv[4].P = 0;
+        t = 0.f;
+        return GAME_STOP;
     }
+
+    return GAME_NONE;
 }
 
 /*
@@ -742,7 +502,7 @@ void game_set_played(int b)
 
 int game_step(const float g[3], float dt)
 {
-    struct s_file *fp = &file;
+    struct s_vary *fp = &file.vary;
 
     static float s = 0.f;
     static float t = 0.f;
@@ -752,54 +512,26 @@ int game_step(const float g[3], float dt)
     float st = 0.f;
     int i, n = 1, m = 0;
 
+    if (!state)
+        return GAME_NONE;
+
     s = (7.f * s + dt) / 8.f;
     t = s;
 
     if (jump_b)
     {
-        if (config_get_d(CONFIG_BALL_COLLISIONS))
-        {
-            jump_dt += dt;
-
-            /* Handle a jump. */
+        jump_dt += dt;
 
-            if (0.5 < jump_dt)
-            {
-                if (jump_u % 2)
-                {
-                    fp->yv[jump_u / 2].p[0] = jump_p[0];
-                    fp->yv[jump_u / 2].p[1] = jump_p[1];
-                    fp->yv[jump_u / 2].p[2] = jump_p[2];
-                }
-
-                else
-                {
-                    fp->uv[jump_u / 2].p[0] = jump_p[0];
-                    fp->uv[jump_u / 2].p[1] = jump_p[1];
-                    fp->uv[jump_u / 2].p[2] = jump_p[2];
-                }
-            }
-            if (1.f < jump_dt)
-            {
-                jump_b = 0;
-            }
-        }
+        /* Handle a jump. */
 
-        else
+        if (0.5 < jump_dt)
         {
-            jump_dt += dt;
-
-            /* Handle a jump. */
-
-            if (0.5 < jump_dt)
-            {
-                fp->uv[ball].p[0] = jump_p[0];
-                fp->uv[ball].p[1] = jump_p[1];
-                fp->uv[ball].p[2] = jump_p[2];
-            }
-            if (1.f < jump_dt)
-                jump_b = 0;
+            fp->uv[ball].p[0] = jump_p[0];
+            fp->uv[ball].p[1] = jump_p[1];
+            fp->uv[ball].p[2] = jump_p[2];
         }
+        if (1.f < jump_dt)
+            jump_b = 0;
     }
     else
     {
@@ -813,13 +545,8 @@ int game_step(const float g[3], float dt)
 
         for (i = 0; i < n; i++)
         {
-            int ball_in_hole = 0;
-
             d = sol_step(fp, g, t, ball, &m);
 
-            if ((ball_in_hole = game_check_balls(fp)))
-                hole_goal(ball_in_hole);
-
             if (b < d)
                 b = d;
             if (m)
@@ -844,19 +571,9 @@ void game_putt(void)
      * friction too early and stopping the ball prematurely.
      */
 
-    if (config_get_d(CONFIG_BALL_COLLISIONS))
-    {
-        file.uv[ball].v[0] = -4.f * view_e[2][0] * view_m;
-        file.uv[ball].v[1] = -4.f * view_e[2][1] * view_m + BALL_FUDGE;
-        file.uv[ball].v[2] = -4.f * view_e[2][2] * view_m;
-    }
-
-    else
-    {
-        file.uv[ball].v[0] = -4.f * view_e[2][0] * view_m;
-        file.uv[ball].v[1] = -4.f * view_e[2][1] * view_m + BALL_FUDGE;
-        file.uv[ball].v[2] = -4.f * view_e[2][2] * view_m;
-    }
+    file.vary.uv[ball].v[0] = -4.f * view_e[2][0] * view_m;
+    file.vary.uv[ball].v[1] = -4.f * view_e[2][1] * view_m + BALL_FUDGE;
+    file.vary.uv[ball].v[2] = -4.f * view_e[2][2] * view_m;
 
     view_m = 0.f;
 }
@@ -883,7 +600,7 @@ void game_set_mag(int d)
 
 void game_set_fly(float k)
 {
-    struct s_file *fp = &file;
+    struct s_vary *fp = &file.vary;
 
     float  x[3] = { 1.f, 0.f, 0.f };
     float  y[3] = { 0.f, 1.f, 0.f };
@@ -894,9 +611,12 @@ void game_set_fly(float k)
     float p1[3] = { 0.f, 0.f, 0.f };
     float  v[3];
 
+    if (!state)
+        return;
+
     v_cpy(view_e[0], x);
     v_cpy(view_e[1], y);
-    v_sub(view_e[2], fp->uv[ball].p, fp->zv[0].p);
+    v_sub(view_e[2], fp->uv[ball].p, fp->base->zv[0].p);
 
     if (fabs(v_dot(view_e[1], view_e[2])) > 0.999)
         v_cpy(view_e[2], z);
@@ -920,18 +640,18 @@ void game_set_fly(float k)
 
     /* k = +1.0 view is s_view 0 */
 
-    if (k >= 0 && fp->wc > 0)
+    if (k >= 0 && fp->base->wc > 0)
     {
-        v_cpy(p1, fp->wv[0].p);
-        v_cpy(c1, fp->wv[0].q);
+        v_cpy(p1, fp->base->wv[0].p);
+        v_cpy(c1, fp->base->wv[0].q);
     }
 
     /* k = -1.0 view is s_view 1 */
 
-    if (k <= 0 && fp->wc > 1)
+    if (k <= 0 && fp->base->wc > 1)
     {
-        v_cpy(p1, fp->wv[1].p);
-        v_cpy(c1, fp->wv[1].q);
+        v_cpy(p1, fp->base->wv[1].p);
+        v_cpy(c1, fp->base->wv[1].q);
     }
 
     /* Interpolate the views. */
@@ -962,32 +682,32 @@ void game_ball(int i)
     jump_e = 1;
     jump_b = 0;
 
-    for (ui = 0; ui < file.uc; ui++)
+    for (ui = 0; ui < file.vary.uc; ui++)
     {
-        file.uv[ui].v[0] = 0.f;
-        file.uv[ui].v[1] = 0.f;
-        file.uv[ui].v[2] = 0.f;
+        file.vary.uv[ui].v[0] = 0.f;
+        file.vary.uv[ui].v[1] = 0.f;
+        file.vary.uv[ui].v[2] = 0.f;
 
-        file.uv[ui].w[0] = 0.f;
-        file.uv[ui].w[1] = 0.f;
-        file.uv[ui].w[2] = 0.f;
+        file.vary.uv[ui].w[0] = 0.f;
+        file.vary.uv[ui].w[1] = 0.f;
+        file.vary.uv[ui].w[2] = 0.f;
     }
 }
 
 void game_get_pos(float p[3], float e[3][3])
 {
-    v_cpy(p,    file.uv[ball].p);
-    v_cpy(e[0], file.uv[ball].e[0]);
-    v_cpy(e[1], file.uv[ball].e[1]);
-    v_cpy(e[2], file.uv[ball].e[2]);
+    v_cpy(p,    file.vary.uv[ball].p);
+    v_cpy(e[0], file.vary.uv[ball].e[0]);
+    v_cpy(e[1], file.vary.uv[ball].e[1]);
+    v_cpy(e[2], file.vary.uv[ball].e[2]);
 }
 
 void game_set_pos(float p[3], float e[3][3])
 {
-    v_cpy(file.uv[ball].p,    p);
-    v_cpy(file.uv[ball].e[0], e[0]);
-    v_cpy(file.uv[ball].e[1], e[1]);
-    v_cpy(file.uv[ball].e[2], e[2]);
+    v_cpy(file.vary.uv[ball].p,    p);
+    v_cpy(file.vary.uv[ball].e[0], e[0]);
+    v_cpy(file.vary.uv[ball].e[1], e[1]);
+    v_cpy(file.vary.uv[ball].e[2], e[2]);
 }
 
 /*---------------------------------------------------------------------------*/