Proper ball shadow removal in poser mode. Patch from Elviz.
[neverball] / ball / game.c
index be79fa0..e66021b 100644 (file)
@@ -65,8 +65,8 @@ static float jump_dt;                   /* Jump duration                     */
 static float jump_p[3];                 /* Jump destination                  */
 static float fade_k = 0.0;              /* Fade in/out level                 */
 static float fade_d = 0.0;              /* Fade in/out direction             */
-static int   drawball = 1;              /* Should the ball be drawn?         */
-static int   ball_b = 0;                /* Is the ball a bonus ball?         */
+
+/*---------------------------------------------------------------------------*/
 
 static int   grow = 0;                  /* Should the ball be changing size? */
 static float grow_orig = 0;             /* the original ball size            */
@@ -79,46 +79,63 @@ static int   got_orig = 0;              /* Do we know original ball size?    */
 #define GROW_BIG   1.5f                 /* large factor                      */
 #define GROW_SMALL 0.5f                 /* small factor                      */
 
-/*---------------------------------------------------------------------------*/
+static int   grow_state = 0;            /* Current state (values -1, 0, +1)  */
 
-static void grow_set(const struct s_file *fp, int type)
-{    
+static void grow_init(const struct s_file *fp, int type)
+{
     if (!got_orig)
     {
-        grow_orig = fp->uv->r;
-        grow_goal = grow_orig;
-        grow_strt = grow_orig;
-        got_orig  = 1;
+        grow_orig  = fp->uv->r;
+        grow_goal  = grow_orig;
+        grow_strt  = grow_orig;
+
+        grow_state = 0;
+
+        got_orig   = 1;
     }
 
     if (type == ITEM_SHRINK)
     {
-        if (grow_goal == grow_orig * GROW_SMALL)
-            return;
-        else if (grow_goal == grow_orig * GROW_BIG)
+        audio_play(AUD_SHRINK, 1.f);
+
+        switch (grow_state)
         {
+        case -1:
+            break;
+
+        case  0:
+            grow_goal = grow_orig * GROW_SMALL;
+            grow_state = -1;
             grow = 1;
+            break;
+
+        case +1:
             grow_goal = grow_orig;
-        }
-        else
-        {
-            grow_goal = grow_orig * GROW_SMALL;
+            grow_state = 0;
             grow = 1;
+            break;
         }
     }
-    if (type == ITEM_GROW)
+    else if (type == ITEM_GROW)
     {
-        if (grow_goal == grow_orig * GROW_BIG)
-            return;
-        else if (grow_goal == grow_orig * GROW_SMALL)
+        audio_play(AUD_GROW, 1.f);
+
+        switch (grow_state)
         {
-            grow = 1;
+        case -1:
             grow_goal = grow_orig;
-        }
-        else
-        {
+            grow_state = 0;
+            grow = 1;
+            break;
+
+        case  0:
             grow_goal = grow_orig * GROW_BIG;
+            grow_state = +1;
             grow = 1;
+            break;
+
+        case +1:
+            break;
         }
     }
 
@@ -129,10 +146,13 @@ static void grow_set(const struct s_file *fp, int type)
     }
 }
 
-static void grow_ball(const struct s_file *fp, float dt)
+static void grow_step(const struct s_file *fp, float dt)
 {
     float dr;
 
+    if (!grow)
+        return;
+
     /* Calculate new size based on how long since you touched the coin... */
 
     grow_t += dt;
@@ -150,6 +170,8 @@ static void grow_ball(const struct s_file *fp, float dt)
     fp->uv->r = dr;
 }
 
+/*---------------------------------------------------------------------------*/
+
 static void view_init(void)
 {
     view_a  = 0.f;
@@ -201,8 +223,6 @@ int game_init(const struct level *level, int t, int g)
     game_rx = 0.f;
     game_rz = 0.f;
 
-    drawball = 1;
-
     /* Initialize jump and goal states. */
 
     jump_e = 1;
@@ -211,8 +231,6 @@ int game_init(const struct level *level, int t, int g)
     goal_c = g;
     goal_k = (g == 0) ? 1.0f : 0.0f;
 
-    ball_b = level->is_bonus;
-
     /* Initialise the level, background, particles, fade, and view. */
 
     fade_k =  1.0f;
@@ -228,6 +246,7 @@ int game_init(const struct level *level, int t, int g)
     /* Initialize ball size tracking... */
 
     got_orig = 0;
+    grow = 0;
 
     return game_state;
 }
@@ -280,8 +299,7 @@ static void game_draw_balls(const struct s_file *fp)
                  fp->uv[0].r);
 
         glColor4fv(c);
-
-        ball_draw(ball_b);
+        ball_draw();
     }
     glPopMatrix();
 }
@@ -291,10 +309,9 @@ static void game_draw_items(const struct s_file *fp)
     float r = 360.f * SDL_GetTicks() / 1000.f;
     int hi;
 
-    /* FIXME:  Draw items of different types in one pass. */
+    /* FIXME:  Draw items of different types in one pass? */
 
-    item_push();
-    item_push_text(ITEM_COIN);
+    item_push(ITEM_COIN);
     {
         for (hi = 0; hi < fp->hc; hi++)
 
@@ -313,8 +330,7 @@ static void game_draw_items(const struct s_file *fp)
     }
     item_pull();
 
-    item_push();
-    item_push_text(ITEM_SHRINK);
+    item_push(ITEM_SHRINK);
     {
         for (hi = 0; hi < fp->hc; hi++)
 
@@ -333,8 +349,7 @@ static void game_draw_items(const struct s_file *fp)
     }
     item_pull();
 
-    item_push();
-    item_push_text(ITEM_GROW);
+    item_push(ITEM_GROW);
     {
         for (hi = 0; hi < fp->hc; hi++)
 
@@ -367,7 +382,7 @@ static void game_draw_goals(const struct s_file *fp, float rx, float ry)
                              fp->zv[zi].p[1],
                              fp->zv[zi].p[2]);
 
-                part_draw_goal(rx, ry, fp->zv[zi].r, goal_k, fp->zv[zi].c);
+                part_draw_goal(rx, ry, fp->zv[zi].r, goal_k);
 
                 glScalef(fp->zv[zi].r, goal_k, fp->zv[zi].r);
                 goal_draw();
@@ -403,6 +418,7 @@ static void game_draw_swchs(const struct s_file *fp)
     {
         if (fp->xv[xi].i)
             continue;
+
         glPushMatrix();
         {
             glTranslatef(fp->xv[xi].p[0],
@@ -443,8 +459,8 @@ static void game_refl_all(int s)
 static void game_draw_light(void)
 {
     const float light_p[2][4] = {
-        { -8.0f, +32.0f, -8.0f, 1.0f },
-        { +8.0f, +32.0f, +8.0f, 1.0f },
+        { -8.0f, +32.0f, -8.0f, 0.0f },
+        { +8.0f, +32.0f, +8.0f, 0.0f },
     };
     const float light_c[2][4] = {
         { 1.0f, 0.8f, 0.8f, 1.0f },
@@ -530,7 +546,7 @@ static void game_draw_fore(int pose, float rx, float ry, int d, const float p[3]
 
             sol_draw(&file);
 
-            if (config_get_d(CONFIG_SHADOW) && drawball)
+            if (pose == 0 && config_get_d(CONFIG_SHADOW))
             {
                 shad_draw_set(ball_p, ball_r);
                 sol_shad(&file);
@@ -546,8 +562,7 @@ static void game_draw_fore(int pose, float rx, float ry, int d, const float p[3]
             {
                 part_draw_coin(-rx * d, -ry);
                 game_draw_items(&file);
-                if (drawball)
-                    game_draw_balls(&file);
+                game_draw_balls(&file);
             }
             game_draw_goals(&file, -rx * d, -ry);
             game_draw_jumps(&file);
@@ -758,7 +773,7 @@ static void game_update_time(float dt, int b)
     }
 }
 
-static int game_update_state(int *state_value)
+static int game_update_state(int bt)
 {
     struct s_file *fp = &file;
     struct s_goal *zp;
@@ -767,8 +782,6 @@ static int game_update_state(int *state_value)
     float p[3];
     float c[3];
 
-    int bt = state_value != NULL;
-
     /* Test for an item. */
     if (bt && (hp = sol_item_test(fp, p, COIN_RADIUS)))
     {
@@ -777,7 +790,7 @@ static int game_update_state(int *state_value)
         item_color(hp, c);
         part_burst(p, c);
 
-        grow_set(fp, hp->t);
+        grow_init(fp, hp->t);
 
         if (hp->t == ITEM_COIN)
         {
@@ -821,24 +834,14 @@ static int game_update_state(int *state_value)
 
     if (bt && goal_c == 0 && (zp = sol_goal_test(fp, p, 0)))
     {
-        *state_value = zp->s;
         audio_play(AUD_GOAL, 1.0f);
-        return zp->c ? GAME_SPEC : GAME_GOAL;
+        return GAME_GOAL;
     }
 
     /* Test for time-out. */
 
     if (bt && clock_down && clock <= 0.f)
     {
-        const GLfloat *p = fp->uv->p;
-        const GLfloat c[5] = {1.0f, 1.0f, 0.0f, 0.0f, 1.0f};
-        part_burst(p, c);
-        part_burst(p, c+1);
-        part_burst(p, c+2);
-        part_burst(p, c);
-        part_burst(p, c+1);
-        part_burst(p, c+2);
-        drawball = 0;
         audio_play(AUD_TIME, 1.0f);
         return GAME_TIME;
     }
@@ -865,11 +868,11 @@ static int game_update_state(int *state_value)
  * the measured  frame time  exceeds this  maximum, we cut  the time  step in
  * half, and  do two updates.  If THIS  time step exceeds the  maximum, we do
  * four updates.  And  so on.  In this way, the physics  system is allowed to
- * seek an optimal update rate independant of, yet in integral sync with, the
+ * seek an optimal update rate independent of, yet in integral sync with, the
  * graphics frame rate.
  */
 
-int game_step(const float g[3], float dt, int *state_value)
+int game_step(const float g[3], float dt, int bt)
 {
     struct s_file *fp = &file;
 
@@ -896,15 +899,12 @@ int game_step(const float g[3], float dt, int *state_value)
             game_rz = game_iz;
         }
 
-        if (grow)
-            grow_ball(fp, dt);
+        grow_step(fp, dt);
 
         game_update_grav(h, g);
         part_step(h, t);
 
-        if (!drawball)
-                /* nothing */;
-        else if (jump_b)
+        if (jump_b)
         {
             jump_dt += t;
 
@@ -936,14 +936,24 @@ int game_step(const float g[3], float dt, int *state_value)
             /* Mix the sound of a ball bounce. */
 
             if (b > 0.5)
-                audio_play(AUD_BUMP, (b - 0.5f) * 2.0f);
+            {
+                float k = (b - 0.5f) * 2.0f;
+                
+                if (got_orig)
+                {
+                    if      (fp->uv->r > grow_orig) audio_play(AUD_BUMPL, k);
+                    else if (fp->uv->r < grow_orig) audio_play(AUD_BUMPS, k);
+                    else                            audio_play(AUD_BUMPM, k);
+                }
+                else audio_play(AUD_BUMPM, k);
+            }
         }
 
         game_step_fade(dt);
         game_update_view(dt);
-        game_update_time(dt, state_value != NULL);
+        game_update_time(dt, bt);
 
-        return game_update_state(state_value);
+        return game_update_state(bt);
     }
     return GAME_NONE;
 }