Revert "Merged progression and putt-collisions"
authorparasti <parasti@78b8d119-cf0a-0410-b17c-f493084dd1d7>
Sat, 1 Mar 2008 14:19:39 +0000 (14:19 +0000)
committerparasti <parasti@78b8d119-cf0a-0410-b17c-f493084dd1d7>
Sat, 1 Mar 2008 14:19:39 +0000 (14:19 +0000)
git-svn-id: https://s.snth.net/svn/neverball/trunk@1850 78b8d119-cf0a-0410-b17c-f493084dd1d7

44 files changed:
Makefile
ball/demo.c
ball/demo.h
ball/game.c
ball/game.h
ball/hud.c
ball/level.c
ball/level.h
ball/main.c
ball/set.c
ball/set.h
ball/st_demo.c
ball/st_done.c
ball/st_fall_out.c
ball/st_goal.c
ball/st_help.c
ball/st_level.c
ball/st_over.c
ball/st_pause.c
ball/st_play.c
ball/st_save.c
ball/st_set.c
ball/st_start.c
ball/st_time_out.c
ball/st_title.c
ball/util.c
ball/util.h
doc/AUTHORS
doc/MANUAL
putt/game.c
putt/game.h
putt/hole.c
putt/hole.h
putt/st_all.c
putt/st_balt.c [deleted file]
putt/st_balt.h [deleted file]
putt/st_conf.c
share/ball.c
share/ball.h
share/config.c
share/config.h
share/mapc.c
share/solid.c
share/solid.h

index 7ce23f3..de2a853 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -125,8 +125,6 @@ MAPC_OBJS := \
        share/solid.o       \
        share/binary.o      \
        share/base_config.o \
-       share/config.o      \
-       share/sync.o        \
        share/mapc.o
 BALL_OBJS := \
        share/lang.o        \
@@ -151,10 +149,11 @@ BALL_OBJS := \
        share/tilt.o        \
        share/common.o      \
        ball/hud.o          \
+       ball/mode.o         \
        ball/game.o         \
        ball/score.o        \
        ball/level.o        \
-       ball/progress.o     \
+       ball/levels.o       \
        ball/set.o          \
        ball/demo.o         \
        ball/util.o         \
@@ -201,7 +200,6 @@ PUTT_OBJS := \
        putt/hole.o         \
        putt/course.o       \
        putt/st_all.o       \
-    putt/st_balt.o      \
        putt/st_conf.o      \
        putt/main.o
 
@@ -232,7 +230,7 @@ $(PUTT_TARG) : $(PUTT_OBJS)
        $(CC) $(ALL_CFLAGS) -o $(PUTT_TARG) $(PUTT_OBJS) $(LDFLAGS) $(ALL_LIBS)
 
 $(MAPC_TARG) : $(MAPC_OBJS)
-       $(CC) $(ALL_CFLAGS) -o $(MAPC_TARG) $(MAPC_OBJS) $(LDFLAGS) $(ALL_LIBS)
+       $(CC) $(ALL_CFLAGS) -o $(MAPC_TARG) $(MAPC_OBJS) $(LDFLAGS) $(BASE_LIBS)
 
 # Work around some extremely helpful sdl-config scripts.
 
index d466163..39aceaf 100644 (file)
 #include "binary.h"
 #include "text.h"
 #include "common.h"
-#include "level.h"
 
 /*---------------------------------------------------------------------------*/
 
 #define MAGIC           0x52424EAF
-#define DEMO_VERSION    6
+#define DEMO_VERSION    5
 
 #define DATELEN 20
 
@@ -53,17 +52,19 @@ void demo_dump_info(const struct demo *d)
            "Player:       %s\n"
            "Shot:         %s\n"
            "Level:        %s\n"
+           "  Back:       %s\n"
+           "  Grad:       %s\n"
+           "  Song:       %s\n"
            "Time:         %d\n"
            "Goal:         %d\n"
-           "Goal enabled: %d\n"
            "Score:        %d\n"
            "Balls:        %d\n"
            "Total Time:   %d\n",
            d->name, d->filename,
            d->timer, d->coins, d->mode, d->status, ctime(&d->date),
            d->player,
-           d->shot, d->file,
-           d->time, d->goal, d->goal_e, d->score, d->balls, d->times);
+           d->shot, d->file, d->back, d->grad, d->song,
+           d->time, d->goal, d->score, d->balls, d->times);
 }
 
 static int demo_header_read(FILE *fp, struct demo *d)
@@ -111,7 +112,6 @@ static int demo_header_read(FILE *fp, struct demo *d)
 
         get_index(fp, &d->time);
         get_index(fp, &d->goal);
-        get_index(fp, &d->goal_e);
         get_index(fp, &d->score);
         get_index(fp, &d->balls);
         get_index(fp, &d->times);
@@ -146,7 +146,6 @@ static void demo_header_write(FILE *fp, struct demo *d)
 
     put_index(fp, &d->time);
     put_index(fp, &d->goal);
-    put_index(fp, &d->goal_e);
     put_index(fp, &d->score);
     put_index(fp, &d->balls);
     put_index(fp, &d->times);
@@ -263,8 +262,9 @@ void demo_unique(char *name)
 
 /*---------------------------------------------------------------------------*/
 
-int demo_play_init(const char *name, const struct level *level,
-                   int mode, int t, int g, int e, int s, int b, int tt)
+int demo_play_init(const char *name,
+                   const struct level *level,
+                   const struct level_game *lg)
 {
     struct demo demo;
 
@@ -273,26 +273,28 @@ int demo_play_init(const char *name, const struct level *level,
     strncpy(demo.filename, config_user(name), MAXSTR);
     strcat(demo.filename, REPLAY_EXT);
 
-    demo.mode = mode;
+    demo.mode = lg->mode;
     demo.date = time(NULL);
 
     config_get_s(CONFIG_PLAYER, demo.player, MAXNAM);
 
     strncpy(demo.shot, level->shot, PATHMAX);
     strncpy(demo.file, level->file, PATHMAX);
+    strncpy(demo.back, level->back, PATHMAX);
+    strncpy(demo.grad, level->grad, PATHMAX);
+    strncpy(demo.song, level->song, PATHMAX);
 
-    demo.time   = t;
-    demo.goal   = g;
-    demo.goal_e = e;
-    demo.score  = s;
-    demo.balls  = b;
-    demo.times  = tt;
+    demo.time  = lg->time;
+    demo.goal  = lg->goal;
+    demo.score = lg->score;
+    demo.balls = lg->balls;
+    demo.times = lg->times;
 
     if ((demo_fp = fopen(demo.filename, FMODE_WB)))
     {
         demo_header_write(demo_fp, &demo);
         audio_music_fade_to(2.0f, level->song);
-        return game_init(level->file, t, e);
+        return game_init(level, lg->time, lg->goal);
     }
     return 0;
 }
@@ -303,7 +305,7 @@ void demo_play_step()
         input_put(demo_fp);
 }
 
-void demo_play_stat(int status, int coins, int timer)
+void demo_play_stat(const struct level_game *lg)
 {
     if (demo_fp)
     {
@@ -311,9 +313,9 @@ void demo_play_stat(int status, int coins, int timer)
 
         fseek(demo_fp, 8, SEEK_SET);
 
-        put_index(demo_fp, &timer);
-        put_index(demo_fp, &coins);
-        put_index(demo_fp, &status);
+        put_index(demo_fp, &lg->timer);
+        put_index(demo_fp, &lg->coins);
+        put_index(demo_fp, &lg->status);
 
         fseek(demo_fp, pos, SEEK_SET);
     }
@@ -354,6 +356,17 @@ void demo_rename(const char *name)
 
 /*---------------------------------------------------------------------------*/
 
+static int demo_load_level(const struct demo *demo, struct level *level)
+{
+    if (level_load(demo->file, level))
+    {
+        level->time = demo->time;
+        level->goal = demo->goal;
+        return 1;
+    }
+    return 0;
+}
+
 static struct demo  demo_replay;       /* The current demo */
 static struct level demo_level_replay; /* The current level demo-ed*/
 
@@ -364,7 +377,7 @@ const struct demo *curr_demo_replay(void)
 
 static int demo_status = GAME_NONE;
 
-int demo_replay_init(const char *name, int *g, int *m, int *b, int *s, int *tt)
+int demo_replay_init(const char *name, struct level_game *lg)
 {
     demo_status = GAME_NONE;
     demo_fp     = fopen(name, FMODE_RB);
@@ -376,31 +389,24 @@ int demo_replay_init(const char *name, int *g, int *m, int *b, int *s, int *tt)
                 base_name(text_from_locale(demo_replay.filename), REPLAY_EXT),
                 PATHMAX);
 
-        if (level_load(demo_replay.file, &demo_level_replay))
-        {
-            demo_level_replay.time = demo_replay.time;
-            demo_level_replay.goal = demo_replay.goal;
-        }
-        else
+        if (!demo_load_level(&demo_replay, &demo_level_replay))
             return 0;
 
-        if (g)  *g  = demo_replay.goal;
-        if (m)  *m  = demo_replay.mode;
-        if (b)  *b  = demo_replay.balls;
-        if (s)  *s  = demo_replay.score;
-        if (tt) *tt = demo_replay.times;
-
-        if (g)
+        if (lg)
         {
-            audio_music_fade_to(0.5f, demo_level_replay.song);
+            lg->mode  = demo_replay.mode;
+            lg->score = demo_replay.score;
+            lg->times = demo_replay.times;
+            lg->time  = demo_replay.time;
+            lg->goal  = demo_replay.goal;
 
-            return game_init(demo_level_replay.file,
-                             demo_level_replay.time,
-                             demo_replay.goal_e);
+            /* A normal replay demo */
+            audio_music_fade_to(0.5f, demo_level_replay.song);
+            return game_init(&demo_level_replay, demo_replay.time,
+                             demo_replay.goal);
         }
-        else
-            return game_init(demo_level_replay.file,
-                             demo_level_replay.time, 1);
+        else /* A title screen demo */
+            return game_init(&demo_level_replay, demo_replay.time, 0);
     }
     return 0;
 }
index 55590e1..ee7ee1f 100644 (file)
@@ -9,26 +9,25 @@
 
 struct demo
 {
-    char   name[PATHMAX];     /* demo basename    */
-    char   filename[MAXSTR];  /* demo path        */
-
-    char   player[MAXNAM];
-    time_t date;
-
-    int    timer;
-    int    coins;
-    int    status;
-    int    mode;
-
+    char   name[PATHMAX];      /* demo basename */
+    char   filename[MAXSTR];  /* demo path */
+
+    int    timer;           /* elapsed time */
+    int    coins;           /* coin number */
+    int    status;          /* how the replay end */
+    int    mode;            /* game mode */
+    time_t date;            /* date of creation */
+    char   player[MAXNAM];  /* player name */
     char   shot[PATHMAX];   /* image filename */
     char   file[PATHMAX];   /* level filename */
-
-    int    time;            /* time limit        */
-    int    goal;            /* coin limit        */
-    int    goal_e;          /* goal enabled flag */
-    int    score;           /* total coins       */
-    int    balls;           /* number of balls   */
-    int    times;           /* total time        */
+    char   back[PATHMAX];   /* level bg filename */
+    char   grad[PATHMAX];   /* level gradient filename */
+    char   song[PATHMAX];   /* level song filename */
+    int    time;            /* time limit (! training mode) */
+    int    goal;            /* coin to open the goal (! training mode) */
+    int    score;           /* sum of coins (challenge mode) */
+    int    balls;           /* number of balls (challenge mode) */
+    int    times;           /* total time (challenge mode) */
 };
 
 /*---------------------------------------------------------------------------*/
@@ -47,9 +46,9 @@ void demo_unique(char *);
 /*---------------------------------------------------------------------------*/
 
 int  demo_play_init(const char *, const struct level *,
-                    int, int, int, int, int, int, int);
+                    const struct level_game *);
 void demo_play_step(void);
-void demo_play_stat(int, int, int);
+void demo_play_stat(const struct level_game *);
 void demo_play_stop(void);
 
 int  demo_saved (void);
@@ -57,7 +56,7 @@ void demo_rename(const char *);
 
 /*---------------------------------------------------------------------------*/
 
-int  demo_replay_init(const char *, int *, int *, int *, int *, int *);
+int  demo_replay_init(const char *, struct level_game *);
 int  demo_replay_step(float);
 void demo_replay_stop(int);
 void demo_replay_dump_info(void);
index 20991f5..618f6d2 100644 (file)
@@ -55,12 +55,11 @@ static float view_e[3][3];              /* Current view reference frame      */
 static float view_k;
 
 static int   coins  = 0;                /* Collected coins                   */
-static int   goal_e = 0;                /* Goal enabled flag                 */
+static int   goal_c = 0;                /* Goal coins remaining (0 = open)   */
 static float goal_k = 0;                /* Goal animation                    */
 static int   jump_e = 1;                /* Jumping enabled flag              */
 static int   jump_b = 0;                /* Jump-in-progress flag             */
 static float jump_dt;                   /* Jump duration                     */
-static int   jump_y = 0;                /* Which arbitrary ball is jumping?  */
 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             */
@@ -313,12 +312,8 @@ static void view_init(void)
     view_e[2][2] = 1.f;
 }
 
-int game_init(const char *file_name, int t, int e)
+int game_init(const struct level *level, int t, int g)
 {
-    char *back_name = NULL, *grad_name = NULL;
-
-    int i;
-
     timer      = (float) t / 100.f;
     timer_down = (t > 0);
     coins      = 0;
@@ -326,7 +321,7 @@ int game_init(const char *file_name, int t, int e)
     if (game_state)
         game_free();
 
-    if (!sol_load_gl(&file, config_data(file_name),
+    if (!sol_load_gl(&file, config_data(level->file),
                      config_get_d(CONFIG_TEXTURES),
                      config_get_d(CONFIG_SHADOW)))
         return (game_state = 0);
@@ -342,30 +337,20 @@ int game_init(const char *file_name, int t, int e)
 
     jump_e = 1;
     jump_b = 0;
-    jump_y = 0;
 
-    goal_e = e ? 1    : 0;
-    goal_k = e ? 1.0f : 0.0f;
+    goal_c = g;
+    goal_k = (g == 0) ? 1.0f : 0.0f;
 
     /* Initialise the level, background, particles, fade, and view. */
 
     fade_k =  1.0f;
     fade_d = -2.0f;
 
-    for (i = 0; i < file.dc; i++)
-    {
-        char *k = file.av + file.dv[i].ai;
-        char *v = file.av + file.dv[i].aj;
-
-        if (strcmp(k, "back") == 0) back_name = v;
-        if (strcmp(k, "grad") == 0) grad_name = v;
-    }
-
     part_reset(GOAL_HEIGHT);
     view_init();
-    back_init(grad_name, config_get_d(CONFIG_GEOMETRY));
+    back_init(level->grad, config_get_d(CONFIG_GEOMETRY));
 
-    sol_load_gl(&back, config_data(back_name),
+    sol_load_gl(&back, config_data(level->back),
                 config_get_d(CONFIG_TEXTURES), 0);
 
     /* Initialize ball size tracking... */
@@ -399,62 +384,21 @@ int curr_coins(void)
     return coins;
 }
 
-/*---------------------------------------------------------------------------*/
-
-void game_check_balls(struct s_file *fp)
+int curr_goal(void)
 {
-    float z[3] = {0.0f, 0.0f, 0.0f};
-    int i;
-
-    for (i = 0; i < fp->yc; i++)
-    {
-        struct s_ball *yp = fp->yv + i;
-
-       /*
-        * Test and deal with any fall-outs
-        */
-        if (yp->p[1] < fp->vv[0].p[1] && yp->n)
-        {
-            v_cpy(yp->p, yp->O);
-            v_cpy(yp->v, z);
-            v_cpy(yp->w, z);
-        }
-    }
+    return goal_c;
 }
 
+/*---------------------------------------------------------------------------*/
+
 static void game_draw_balls(const struct s_file *fp,
                             const float *bill_M, float t)
 {
-    float  c[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
+    float c[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
 
     float ball_M[16];
     float pend_M[16];
 
-    int yi;
-
-    for (yi = 0; yi < fp->yc; yi++)
-    {
-        float ball_M[16];
-        float pend_M[16];
-
-        m_basis(ball_M, fp->yv[yi].e[0], fp->yv[yi].e[1], fp->yv[yi].e[2]);
-        m_basis(pend_M, fp->yv[yi].E[0], fp->yv[yi].E[1], fp->yv[yi].E[2]);
-
-        glPushMatrix();
-        {
-            glTranslatef(fp->yv[yi].p[0],
-                         fp->yv[yi].p[1] + BALL_FUDGE,
-                         fp->yv[yi].p[2]);
-            glScalef(fp->yv[yi].r,
-                     fp->yv[yi].r,
-                     fp->yv[yi].r);
-
-            glColor4fv(c);
-            ball_draw(ball_M, pend_M, bill_M, t);
-        }
-        glPopMatrix();
-    }
-
     m_basis(ball_M, fp->uv[0].e[0], fp->uv[0].e[1], fp->uv[0].e[2]);
     m_basis(pend_M, fp->uv[0].E[0], fp->uv[0].E[1], fp->uv[0].E[2]);
 
@@ -544,7 +488,7 @@ static void game_draw_items(const struct s_file *fp, float t)
 
 static void game_draw_goals(const struct s_file *fp, const float *M, float t)
 {
-    if (goal_e)
+    if (goal_c == 0)
     {
         int zi;
 
@@ -844,11 +788,7 @@ void game_draw(int pose, float t)
 {
     float fov = view_fov;
 
-    if (jump_b && jump_y)
-        fov /= 1.9f * fabsf(jump_dt - 0.5f);
-
-    else if (jump_b)
-        fov *= 2.0f * fabsf(jump_dt - 0.5f);
+    if (jump_b) fov *= 2.f * fabsf(jump_dt - 0.5);
 
     if (game_state)
     {
@@ -1026,7 +966,7 @@ static void game_update_view(float dt)
 
 static void game_update_time(float dt, int b)
 {
-    if (goal_e && goal_k < 1.0f)
+    if (goal_c == 0 && goal_k < 1.0f)
         goal_k += dt;
 
    /* The ticking clock. */
@@ -1047,73 +987,67 @@ static void game_update_time(float dt, int b)
 static int game_update_state(int bt)
 {
     struct s_file *fp = &file;
+    struct s_goal *zp;
     struct s_item *hp;
 
     float p[3];
     float c[3];
 
-    int i;
-
     /* Test for an item. */
 
     if (bt && (hp = sol_item_test(fp, p, COIN_RADIUS)))
     {
+        const char *sound = AUD_COIN;
+
         item_color(hp, c);
         part_burst(p, c);
 
         grow_init(fp, hp->t);
 
         if (hp->t == ITEM_COIN)
+        {
             coins += hp->n;
 
+            /* Check for goal open. */
+
+            if (goal_c > 0)
+            {
+                goal_c -= hp->n;
+                if (goal_c <= 0)
+                {
+                    sound = AUD_SWITCH;
+                    goal_c = 0;
+                }
+            }
+        }
+        audio_play(sound, 1.f);
+
+        /* Reset item type. */
+
         hp->t = ITEM_NONE;
     }
 
     /* Test for a switch. */
 
-    if (sol_swch_test(fp))
+    if (sol_swch_test(fp, 0))
         audio_play(AUD_SWITCH, 1.f);
 
     /* Test for a jump. */
 
-    if (!jump_y && jump_e == 1 && jump_b == 0 && sol_jump_test(fp, jump_p, 0) == 1)
+    if (jump_e == 1 && jump_b == 0 && sol_jump_test(fp, jump_p, 0) == 1)
     {
         jump_b  = 1;
         jump_e  = 0;
         jump_dt = 0.f;
-        jump_y  = 0;
 
         audio_play(AUD_JUMP, 1.f);
     }
     if (jump_e == 0 && jump_b == 0 && sol_jump_test(fp, jump_p, 0) == 0)
         jump_e = 1;
-    if (!jump_b && !jump_y && sol_jump_test(fp, jump_p, 0) == 0)
-        jump_y = 0;
-
-    for (i = 0; i < fp->yc; i++)
-    {
-        if (!jump_y && 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_y  = i + 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_y && i == jump_y - 1
-                    && sol_jump_test(fp, jump_p, fp->yv + i - fp->uv) == 0)
-            jump_y = 0;
-    }
 
     /* Test for a goal. */
 
-    if (bt && goal_e && (sol_goal_test(fp, p, 0)))
+    if (bt && goal_c == 0 && (zp = sol_goal_test(fp, p, 0)))
     {
         audio_play(AUD_GOAL, 1.0f);
         return GAME_GOAL;
@@ -1164,19 +1098,9 @@ int game_step(const float g[3], float dt, int bt)
 
             if (0.5f < jump_dt)
             {
-                if (jump_y)
-                {
-                    fp->yv[jump_y - 1].p[0] = jump_p[0];
-                    fp->yv[jump_y - 1].p[1] = jump_p[1];
-                    fp->yv[jump_y - 1].p[2] = jump_p[2];
-                }
-
-                else
-                {
-                    fp->uv[0].p[0] = jump_p[0];
-                    fp->uv[0].p[1] = jump_p[1];
-                    fp->uv[0].p[2] = jump_p[2];
-                }
+                fp->uv[0].p[0] = jump_p[0];
+                fp->uv[0].p[1] = jump_p[1];
+                fp->uv[0].p[2] = jump_p[2];
             }
             if (1.0f < jump_dt)
                 jump_b = 0;
@@ -1187,8 +1111,6 @@ int game_step(const float g[3], float dt, int bt)
 
             float b = sol_step(fp, h, dt, 0, NULL);
 
-            game_check_balls(fp);
-
             /* Mix the sound of a ball bounce. */
 
             if (b > 0.5f)
@@ -1216,19 +1138,6 @@ int game_step(const float g[3], float dt, int bt)
 
 /*---------------------------------------------------------------------------*/
 
-void game_set_goal(void) 
-{ 
-    audio_play(AUD_SWITCH, 1.0f); 
-    goal_e = 1; 
-}
-
-void game_clr_goal(void)
-{
-    goal_e = 0;
-}
-
-/*---------------------------------------------------------------------------*/
-
 void game_set_x(int k)
 {
     input_set_x(-ANGLE_BOUND * k / JOY_MAX);
@@ -1367,17 +1276,3 @@ void game_fade(float d)
 }
 
 /*---------------------------------------------------------------------------*/
-
-const char *status_to_str(int s)
-{
-    switch (s)
-    {
-    case GAME_NONE:    return _("Aborted");
-    case GAME_TIME:    return _("Time-out");
-    case GAME_GOAL:    return _("Success");
-    case GAME_FALL:    return _("Fall-out");
-    default:           return _("Unknown");
-    }
-}
-
-/*---------------------------------------------------------------------------*/
index 408bf98..4a4727c 100644 (file)
@@ -3,7 +3,8 @@
 
 #include <stdio.h>
 
-#include "lang.h"
+#include "level.h"
+#include "mode.h"
 
 /*---------------------------------------------------------------------------*/
 
 
 /*---------------------------------------------------------------------------*/
 
-int   game_init(const char *, int, int);
+int   game_init(const struct level *, int, int);
 void  game_free(void);
 
 int   curr_clock(void);
 int   curr_coins(void);
+int   curr_goal(void);
 
 void  game_draw(int, float);
 int   game_step(const float[3], float, int);
 
-void  game_set_goal(void);
-void  game_clr_goal(void);
-
 void  game_set_ang(int, int);
 void  game_set_pos(int, int);
 void  game_set_x  (int);
@@ -71,13 +70,4 @@ int input_get(FILE *);
 
 /*---------------------------------------------------------------------------*/
 
-#define GAME_NONE 0
-#define GAME_TIME 1
-#define GAME_GOAL 2
-#define GAME_FALL 3
-
-const char *status_to_str(int);
-
-/*---------------------------------------------------------------------------*/
-
 #endif
index c339d4a..d218db7 100644 (file)
@@ -20,7 +20,7 @@
 #include "hud.h"
 #include "gui.h"
 #include "game.h"
-#include "progress.h"
+#include "levels.h"
 #include "config.h"
 #include "audio.h"
 
 
 static int Lhud_id;
 static int Rhud_id;
+static int Rhud2_id;
 static int time_id;
 
 static int coin_id;
+static int coin2_id;
 static int ball_id;
 static int scor_id;
 static int goal_id;
@@ -64,6 +66,13 @@ void hud_init(void)
         gui_layout(Rhud_id, +1, -1);
     }
 
+    if ((Rhud2_id = gui_hstack(0)))
+    {
+        gui_label(Rhud2_id, _("Coins"), GUI_SML, 0, gui_wht, gui_wht);
+        coin2_id = gui_count(Rhud2_id, 100,   GUI_SML, GUI_NW);
+        gui_layout(Rhud2_id, +1, -1);
+    }
+
     if ((Lhud_id = gui_hstack(0)))
     {
         if ((id = gui_vstack(Lhud_id)))
@@ -103,10 +112,16 @@ void hud_free(void)
 
 void hud_paint(void)
 {
-    if (curr_mode() == MODE_CHALLENGE)
+    int mode = curr_lg()->mode;
+
+    if (mode == MODE_CHALLENGE)
         gui_paint(Lhud_id);
 
-    gui_paint(Rhud_id);
+    if (mode == MODE_PRACTICE)
+        gui_paint(Rhud2_id);
+    else
+        gui_paint(Rhud_id);
+
     gui_paint(time_id);
 
     if (config_get_d(CONFIG_FPS))
@@ -118,11 +133,14 @@ void hud_paint(void)
 
 void hud_update(int pulse)
 {
+    const struct level_game *lg = curr_lg();
+
     int clock = curr_clock();
     int coins = curr_coins();
     int goal  = curr_goal();
-    int balls = curr_balls();
-    int score = curr_score();
+    int balls = lg->balls;
+    int score = lg->score;
+    int mode  = lg->mode;
 
     int c_id;
     int last;
@@ -142,7 +160,7 @@ void hud_update(int pulse)
     {
         gui_set_clock(time_id, clock);
 
-        if (last > clock && pulse)
+        if (last > clock && pulse && mode != MODE_PRACTICE)
         {
             if (clock <= 1000 && (last / 100) > (clock / 100))
             {
@@ -159,7 +177,7 @@ void hud_update(int pulse)
 
     /* balls and score + select coin widget */
 
-    switch (curr_mode())
+    switch (mode)
     {
     case MODE_CHALLENGE:
         if (gui_value(ball_id) != balls) gui_set_count(ball_id, balls);
@@ -168,9 +186,13 @@ void hud_update(int pulse)
         c_id = coin_id;
         break;
 
-    default:
+    case MODE_NORMAL:
         c_id = coin_id;
         break;
+
+    default:
+        c_id = coin2_id;
+        break;
     }
 
 
index ae724d3..7ecb296 100644 (file)
 #include <string.h>
 #include <math.h>
 #include <errno.h>
-#include <assert.h>
 
-#include "solid.h"
 #include "config.h"
+#include "demo.h"
+#include "text.h"
 #include "level.h"
+#include "mode.h"
 #include "set.h"
+#include "solid.h"
 
 /*---------------------------------------------------------------------------*/
 
@@ -37,8 +39,12 @@ static void scan_dict(struct level *l, const struct s_file *fp)
 
         if (strcmp(k, "message") == 0)
             strncpy(l->message, v, MAXSTR);
+        else if (strcmp(k, "back") == 0)
+            strncpy(l->back, v, PATHMAX);
         else if (strcmp(k, "song") == 0)
             strncpy(l->song, v, PATHMAX);
+        else if (strcmp(k, "grad") == 0)
+            strncpy(l->grad, v, PATHMAX);
         else if (strcmp(k, "shot") == 0)
             strncpy(l->shot, v, PATHMAX);
         else if (strcmp(k, "goal") == 0)
@@ -143,6 +149,8 @@ void level_dump(const struct level *l)
            "goal hs:         %d %d %d\n"
            "coin hs:         %d %d %d\n"
            "message:         %s\n"
+           "background:      %s\n"
+           "gradient:        %s\n"
            "screenshot:      %s\n"
            "song:            %s\n",
            l->file,
@@ -160,125 +168,144 @@ void level_dump(const struct level *l)
            l->score.most_coins.coins[1],
            l->score.most_coins.coins[2],
            l->message,
+           l->back,
+           l->grad,
            l->shot,
            l->song);
 }
 
 /*---------------------------------------------------------------------------*/
 
-int  level_exists(int i)
-{
-    return set_level_exists(curr_set(), i);
-}
+static unsigned int do_level_init = 1;
 
-void level_open(int i)
+int level_replay(const char *filename)
 {
-    if (level_exists(i))
-        get_level(i)->is_locked = 0;
+    return demo_replay_init(filename, curr_lg());
 }
 
-int  level_opened(int i)
+int level_play(const struct level *l, int m)
 {
-    return level_exists(i) && !get_level(i)->is_locked;
-}
+    struct level_game *lg = curr_lg();
 
-void level_complete(int i)
-{
-    if (level_exists(i))
-        get_level(i)->is_completed = 1;
-}
+    if (do_level_init)
+    {
+        memset(lg, 0, sizeof (struct level_game));
 
-int  level_completed(int i)
-{
-    return level_exists(i) && get_level(i)->is_completed;
-}
+        lg->mode  = m;
+        lg->level = l;
+        lg->balls = 3;
+    }
 
-int  level_time (int i)
-{
-    assert(level_exists(i));
-    return get_level(i)->time;
-}
+    lg->goal = (lg->mode == MODE_PRACTICE) ? 0 : lg->level->goal;
+    lg->time = (lg->mode == MODE_PRACTICE) ? 0 : lg->level->time;
 
-int  level_goal (int i)
-{
-    assert(level_exists(i));
-    return get_level(i)->goal;
-}
+    /* Clear other fields. */
 
-int  level_bonus(int i)
-{
-    return level_exists(i) && get_level(i)->is_bonus;
+    lg->status = GAME_NONE;
+    lg->coins = 0;
+    lg->timer = lg->time;
+    lg->coin_rank = lg->goal_rank = lg->time_rank =
+        lg->score_rank = lg->times_rank = 3;
+
+    lg->win = lg->dead = lg->unlock = 0;
+    lg->next_level = NULL;
+    lg->bonus = 0;
+
+    return demo_play_init(USER_REPLAY_FILE, lg->level, lg);
 }
 
-const char *level_shot(int i)
+void level_stat(int status, int clock, int coins)
 {
-    return level_exists(i) ? get_level(i)->shot : NULL;
+    struct level_game *lg = curr_lg();
+
+    int mode = lg->mode;
+    int timer = (mode == MODE_PRACTICE) ? clock : lg->time - clock;
+
+    char player[MAXNAM];
+
+    config_get_s(CONFIG_PLAYER, player, MAXNAM);
+
+    lg->status = status;
+    lg->coins = coins;
+    lg->timer = timer;
+
+    if (mode == MODE_CHALLENGE)
+    {
+        /* sum time */
+        lg->times += timer;
+
+        /* sum coins an earn extra balls */
+        if (status == GAME_GOAL || lg->level->is_bonus)
+        {
+            lg->balls += count_extra_balls(lg->score, coins);
+            lg->score += coins;
+        }
+
+        /* lose ball and game */
+        else
+        {
+            lg->dead = (lg->balls <= 0);
+            lg->balls--;
+        }
+    }
+
+    set_finish_level(lg, player);
+
+    demo_play_stat(lg);
 }
 
-const char *level_file(int i)
+void level_stop(void)
 {
-    return level_exists(i) ? get_level(i)->file : NULL;
+    demo_play_stop();
+    do_level_init = 1;
 }
 
-const char *level_repr(int i)
+int level_next(void)
 {
-    return level_exists(i) ? get_level(i)->repr : NULL;
+    struct level_game *lg = curr_lg();
+
+    level_stop();
+    lg->level = lg->next_level;
+    do_level_init = 0;
+
+    return level_play(lg->level, lg->mode);
 }
 
-const char *level_msg(int i)
+int level_same(void)
 {
-    if (level_exists(i) && strlen(get_level(i)->message) > 0)
-        return _(get_level(i)->message);
-
-    return NULL;
+    level_stop();
+    do_level_init = 0;
+    return level_play(curr_lg()->level, curr_lg()->mode);
 }
 
 /*---------------------------------------------------------------------------*/
 
-int level_score_update(int level,
-                       int timer,
-                       int coins,
-                       int *time_rank,
-                       int *goal_rank,
-                       int *coin_rank)
+int count_extra_balls(int old_score, int coins)
 {
-    struct level *l = get_level(level);
-    char player[MAXSTR] = "";
-
-    config_get_s(CONFIG_PLAYER, player, MAXSTR);
-
-    if (time_rank)
-        *time_rank = score_time_insert(&l->score.best_times,
-                                       player, timer, coins);
+    return ((old_score % 100) + coins) / 100;
+}
 
-    if (goal_rank)
-        *goal_rank = score_time_insert(&l->score.unlock_goal,
-                                       player, timer, coins);
+void level_update_player_name(void)
+{
+    char player[MAXNAM];
 
-    if (coin_rank)
-        *coin_rank = score_coin_insert(&l->score.most_coins,
-                                       player, timer, coins);
+    config_get_s(CONFIG_PLAYER, player, MAXNAM);
 
-    if ((time_rank && *time_rank < 3) ||
-        (goal_rank && *goal_rank < 3) ||
-        (coin_rank && *coin_rank < 3))
-        return 1;
-    else
-        return 0;
+    score_change_name(curr_lg(), player);
 }
 
-void level_rename_player(int level,
-                         int time_rank,
-                         int goal_rank,
-                         int coin_rank,
-                         const char *player)
-{
-    struct level *l = get_level(level);
+/*---------------------------------------------------------------------------*/
 
-    strncpy(l->score.best_times.player [time_rank], player, MAXNAM);
-    strncpy(l->score.unlock_goal.player[goal_rank], player, MAXNAM);
-    strncpy(l->score.most_coins.player [coin_rank], player, MAXNAM);
+const char *status_to_str(int m)
+{
+    switch (m)
+    {
+    case GAME_NONE:    return _("Aborted");
+    case GAME_TIME:    return _("Time-out");
+    case GAME_GOAL:    return _("Success");
+    case GAME_FALL:    return _("Fall-out");
+    default:           return _("Unknown");
+    }
 }
 
 /*---------------------------------------------------------------------------*/
-
index c5d9b5e..92f971a 100644 (file)
@@ -3,15 +3,15 @@
 
 #include "base_config.h"
 #include "score.h"
-#include "progress.h"
+#include "levels.h"
 
 /*---------------------------------------------------------------------------*/
 
 struct level
 {
-    /* TODO: turn into an internal structure. */
-
     char file[PATHMAX];
+    char back[PATHMAX];
+    char grad[PATHMAX];
     char shot[PATHMAX];
     char song[PATHMAX];
 
@@ -48,30 +48,26 @@ struct level
 int  level_load(const char *, struct level *);
 void level_dump(const struct level *);
 
-/*---------------------------------------------------------------------------*/
-
-int  level_exists(int);
+int  level_replay(const char *);
+int  level_play(const struct level *, int);
+void level_stat(int, int, int);
+void level_stop(void);
+int  level_next(void);
+int  level_same(void);
 
-void level_open  (int);
-int  level_opened(int);
-
-void level_complete (int);
-int  level_completed(int);
+/*---------------------------------------------------------------------------*/
 
-int  level_time(int);
-int  level_goal(int);
-int  level_bonus(int);
+int count_extra_balls(int, int);
 
-const char *level_shot(int);
-const char *level_file(int);
-const char *level_repr(int);
-const char *level_msg (int);
+void level_update_player_name(void);
 
 /*---------------------------------------------------------------------------*/
 
-int  level_score_update (int, int, int, int *, int *, int *);
-void level_rename_player(int, int, int, int, const char *);
+#define GAME_NONE 0     /* No event (or aborted) */
+#define GAME_TIME 1     /* Time's up */
+#define GAME_GOAL 2     /* Goal reached */
+#define GAME_FALL 3     /* Fall out */
 
-/*---------------------------------------------------------------------------*/
+const char *status_to_str(int);
 
 #endif
index ab6692d..d28c3b8 100644 (file)
@@ -24,7 +24,7 @@
 #include "image.h"
 #include "audio.h"
 #include "demo.h"
-#include "progress.h"
+#include "levels.h"
 #include "game.h"
 #include "gui.h"
 #include "set.h"
@@ -379,7 +379,7 @@ int main(int argc, char *argv[])
 
     if (display_info)
     {
-        if (!progress_replay(demo_path))
+        if (!level_replay(demo_path))
         {
             fprintf(stderr, L_("Replay file '%s': %s\n"), demo_path,
                     errno ?  strerror(errno) : L_("Not a replay file"));
@@ -435,8 +435,9 @@ int main(int argc, char *argv[])
 
     /* Initialise demo playback. */
 
-    if (replay_demo && progress_replay(demo_path))
+    if (replay_demo)
     {
+        level_replay(demo_path);
         demo_play_goto(1);
         goto_state(&st_demo_play);
     }
index 2897e72..36953e4 100644 (file)
@@ -38,8 +38,8 @@ struct set
 
     char user_scores[PATHMAX]; /* User high-score file       */
 
-    struct score coin_score;   /* Challenge score            */
     struct score time_score;   /* Challenge score            */
+    struct score coin_score;   /* Challenge score            */
 
     /* Level info */
 
@@ -62,10 +62,11 @@ static void put_score(FILE *fp, const struct score *s)
     int j;
 
     for (j = 0; j < NSCORE; j++)
-        fprintf(fp, "%d %d %s\n", s->timer[j], s->coins[j], s->player[j]);
+       fprintf(fp, "%d %d %s\n", s->timer[j], s->coins[j], s->player[j]);
 }
 
-void set_store_hs(void)
+/* Store the score of the set. */
+static void set_store_hs(void)
 {
     const struct set *s = &set_v[set];
     FILE *fout;
@@ -165,8 +166,8 @@ static void set_load_hs(void)
         {
             l = &level_v[i];
             res = get_score(fin, &l->score.best_times) &&
-                get_score(fin, &l->score.unlock_goal) &&
-                get_score(fin, &l->score.most_coins);
+                  get_score(fin, &l->score.unlock_goal) &&
+                  get_score(fin, &l->score.most_coins);
         }
 
         fclose(fin);
@@ -384,38 +385,189 @@ int curr_set(void)
     return set;
 }
 
-struct level *get_level(int i)
+const struct level *get_level(int i)
 {
     return (i >= 0 && i < set_v[set].count) ? &level_v[i] : NULL;
 }
 
 /*---------------------------------------------------------------------------*/
 
-int set_score_update(int timer, int coins, int *score_rank, int *times_rank)
+/* Update the level score rank according to coins and timer. */
+static int level_score_update(struct level_game *lg, const char *player)
+{
+    int timer = lg->timer;
+    int coins = lg->coins;
+    struct level *l = &level_v[lg->level->number];
+
+    lg->time_rank = score_time_insert(&l->score.best_times,
+                                      player, timer, coins);
+
+    if (lg->mode == MODE_CHALLENGE || lg->mode == MODE_NORMAL)
+        lg->goal_rank = score_time_insert(&l->score.unlock_goal,
+                                          player, timer, coins);
+    else
+        lg->goal_rank = 3;
+
+    lg->coin_rank = score_coin_insert(&l->score.most_coins,
+                                      player, timer, coins);
+
+    return (lg->time_rank < 3 || lg->goal_rank < 3 || lg->coin_rank < 3);
+}
+
+/* Update the set score rank according to score and times. */
+static int set_score_update(struct level_game *lg, const char *player)
 {
+    int timer = lg->times;
+    int coins = lg->score;
     struct set *s = &set_v[set];
-    char player[MAXSTR] = "";
 
-    config_get_s(CONFIG_PLAYER, player, MAXSTR);
+    lg->score_rank = score_time_insert(&s->time_score, player, timer, coins);
+    lg->times_rank = score_time_insert(&s->coin_score, player, timer, coins);
+
+    return (lg->score_rank < 3 || lg->times_rank < 3);
+}
 
-    if (score_rank)
-        *score_rank = score_coin_insert(&s->coin_score, player, timer, coins);
+/* Update the player name for set and level high-score. */
+void score_change_name(struct level_game *lg, const char *player)
+{
+    struct set   *s = &set_v[set];
+    struct level *l = &level_v[lg->level->number];
 
-    if (times_rank)
-        *times_rank = score_time_insert(&s->time_score, player, timer, coins);
+    strncpy(l->score.best_times.player [lg->time_rank], player, MAXNAM);
+    strncpy(l->score.unlock_goal.player[lg->goal_rank], player, MAXNAM);
+    strncpy(l->score.most_coins.player [lg->coin_rank], player, MAXNAM);
 
-    if ((score_rank && *score_rank < 3) || (times_rank && *times_rank < 3))
-        return 1;
-    else
-        return 0;
+    strncpy(s->coin_score.player[lg->score_rank], player, MAXNAM);
+    strncpy(s->time_score.player[lg->times_rank], player, MAXNAM);
+
+    set_store_hs();
+}
+
+static struct level *next_level(int i)
+{
+    return set_level_exists(set, i + 1) ? &level_v[i + 1] : NULL;
+}
+
+static struct level *next_normal_level(int i)
+{
+    for (i++; i < set_v[set].count; i++)
+        if (!level_v[i].is_bonus)
+            return &level_v[i];
+
+    return NULL;
 }
 
-void set_rename_player(int score_rank, int times_rank, const char *player)
+/*---------------------------------------------------------------------------*/
+
+void set_finish_level(struct level_game *lg, const char *player)
 {
     struct set *s = &set_v[set];
+    int ln = lg->level->number;      /* Current level number       */
+    struct level *cl = &level_v[ln]; /* Current level              */
+    struct level *nl = NULL;         /* Next level                 */
+    int dirty = 0;                   /* Should the score be saved? */
+
+    assert(s == cl->set);
+
+    /* if no set, no next level */
+    if (s == NULL)
+    {
+        /* if no set, return */
+        lg->next_level = NULL;
+        return;
+    }
+
+    /* On level completed */
+    if (lg->status == GAME_GOAL)
+    {
+        /* Update level scores */
+        dirty = level_score_update(lg, player);
+
+        /* Complete the level */
+        if (lg->mode == MODE_CHALLENGE || lg->mode == MODE_NORMAL)
+        {
+            /* Complete the level */
+            if (!cl->is_completed)
+            {
+                cl->is_completed = 1;
+                dirty = 1;
+            }
+        }
+    }
+
+    /* On goal reached */
+    if (lg->status == GAME_GOAL)
+    {
+        /* Identify the following level */
+
+        nl = next_level(ln);
+
+        if (nl != NULL)
+        {
+            /* Skip bonuses if unlocked in any mode */
+
+            if (nl->is_bonus)
+            {
+                if (lg->mode == MODE_CHALLENGE && nl->is_locked)
+                {
+                    nl->is_locked = 0;
+
+                    lg->bonus = 1;
+                    lg->bonus_repr = nl->repr;
+                }
+
+                nl = next_normal_level(nl->number);
+
+                if (nl == NULL && lg->mode == MODE_CHALLENGE)
+                {
+                    lg->win = 1;
+                }
+            }
+        }
+        else if (lg->mode == MODE_CHALLENGE)
+            lg->win = 1;
+    }
+    else if (cl->is_bonus || lg->mode != MODE_CHALLENGE)
+    {
+        /* On fail, identify the next level (only in bonus for challenge) */
+        nl = next_normal_level(ln);
+        /* Next level may be unavailable */
+        if (!cl->is_bonus && nl != NULL && nl->is_locked)
+            nl = NULL;
+        /* Fail a bonus level but win the set! */
+        else if (nl == NULL && lg->mode == MODE_CHALLENGE)
+            lg->win = 1;
+    }
+
+    /* Win ! */
+    if (lg->win)
+    {
+        /* update set score */
+        set_score_update(lg, player);
+        /* unlock all levels */
+        set_cheat();
+        dirty = 1;
+    }
+
+    /* unlock the next level if needed */
+    if (nl != NULL && nl->is_locked)
+    {
+        if (lg->mode == MODE_CHALLENGE || lg->mode == MODE_NORMAL)
+        {
+            lg->unlock = 1;
+            nl->is_locked = 0;
+            dirty = 1;
+        }
+        else
+            nl = NULL;
+    }
+
+    /* got the next level */
+    lg->next_level = nl;
 
-    strncpy(s->coin_score.player[score_rank], player, MAXNAM);
-    strncpy(s->time_score.player[times_rank], player, MAXNAM);
+    /* Update file */
+    if (dirty)
+        set_store_hs();
 }
 
 /*---------------------------------------------------------------------------*/
@@ -436,7 +588,7 @@ void level_snap(int i)
 
     /* Initialize the game for a snapshot. */
 
-    if (game_init(level_v[i].file, 0, 1))
+    if (game_init(&level_v[i], 0, 0))
     {
         /* Render the level and grab the screen. */
 
index e813780..d06676a 100644 (file)
@@ -27,15 +27,14 @@ const char         *set_shot(int);
 const struct score *set_time_score(int);
 const struct score *set_coin_score(int);
 
-int  set_score_update (int, int, int *, int *);
-void set_rename_player(int, int, const char *);
-
-void set_store_hs(void);
 
 /*---------------------------------------------------------------------------*/
 
 int set_level_exists(int, int);
-struct level *get_level(int);
+const struct level *get_level(int);
+
+void set_finish_level(struct level_game *, const char *);
+void score_change_name(struct level_game *, const char *);
 
 void level_snap(int);
 void set_cheat(void);
index 7f60069..b615c2a 100644 (file)
@@ -19,7 +19,7 @@
 #include "set.h"
 #include "game.h"
 #include "demo.h"
-#include "progress.h"
+#include "levels.h"
 #include "audio.h"
 #include "solid.h"
 #include "config.h"
@@ -66,13 +66,12 @@ static int demo_action(int i)
         break;
 
     default:
-        if (progress_replay(demo_get(i)->filename))
+        if (level_replay(demo_get(i)->filename))
         {
             last_viewed = i;
             demo_play_goto(0);
             return goto_state(&st_demo_play);
         }
-        break;
     }
     return 1;
 }
@@ -376,8 +375,6 @@ static void demo_play_timer(int id, float dt)
         demo_paused = 0;
         goto_state(&st_demo_end);
     }
-    else
-        progress_step();
 }
 
 static int demo_play_keybd(int c, int d)
@@ -436,7 +433,7 @@ static int demo_end_action(int i)
         return 0;
     case DEMO_REPLAY:
         demo_replay_stop(0);
-        progress_replay(curr_demo_replay()->filename);
+        level_replay(curr_demo_replay()->filename);
         return goto_state(&st_demo_play);
     case DEMO_CONTINUE:
         return goto_state(&st_demo_play);
index 1ed09af..fc5f945 100644 (file)
@@ -19,7 +19,7 @@
 #include "game.h"
 #include "util.h"
 #include "demo.h"
-#include "progress.h"
+#include "levels.h"
 #include "audio.h"
 #include "config.h"
 #include "st_shared.h"
@@ -36,7 +36,6 @@
 /* Bread crumbs. */
 
 static int new_name;
-static int resume;
 
 static int done_action(int i)
 {
@@ -50,13 +49,6 @@ static int done_action(int i)
     case DONE_NAME:
         new_name = 1;
         return goto_name(&st_done, &st_done, 0);
-
-    case GUI_MOST_COINS:
-    case GUI_BEST_TIMES:
-    case GUI_UNLOCK_GOAL:
-        set_score_type(i);
-        resume = 1;
-        return goto_state(&st_done);
     }
     return 1;
 }
@@ -68,11 +60,11 @@ static int done_enter(void)
 
     int id, jd;
 
-    int high = progress_set_high();
+    int high = (curr_lg()->times_rank < 3) || (curr_lg()->score_rank < 3);
 
     if (new_name)
     {
-        progress_rename();
+        level_update_player_name();
         new_name = 0;
     }
 
@@ -87,31 +79,30 @@ static int done_enter(void)
 
         gui_space(id);
 
-        if ((jd = gui_hstack(id)))
-            gui_score_board(jd, 1);
+        if ((jd = gui_harray(id)))
+        {
+            gui_most_coins(jd, 1);
+            gui_best_times(jd, 1);
+        }
 
         gui_space(id);
 
         if ((jd = gui_harray(id)))
         {
-            gui_start(jd, _("Select Level"), GUI_SML, DONE_OK, 0);
+            /* FIXME, I'm ugly. */
 
             if (high)
-                gui_state(jd, _("Change Name"), GUI_SML, DONE_NAME, 0);
-        }
+               gui_state(jd, _("Change Player Name"), GUI_SML, DONE_NAME, 0);
 
-        if (!resume)
-            gui_pulse(gid, 1.2f);
+            gui_start(jd, _("OK"), GUI_SML, DONE_OK, 0);
+        }
 
         gui_layout(id, 0, 0);
+        gui_pulse(gid, 1.2f);
     }
 
-    set_score_board(set_coin_score(curr_set()), progress_score_rank(),
-                    set_time_score(curr_set()), progress_times_rank(),
-                    set_time_score(curr_set()), progress_times_rank());
-
-    /* Reset hack. */
-    resume = 0;
+    set_best_times(set_time_score(curr_set()), curr_lg()->times_rank, 0);
+    set_most_coins(set_coin_score(curr_set()), curr_lg()->score_rank);
 
     return id;
 }
index d715261..1c55b78 100644 (file)
@@ -15,7 +15,7 @@
 #include "gui.h"
 #include "game.h"
 #include "util.h"
-#include "progress.h"
+#include "levels.h"
 #include "audio.h"
 #include "config.h"
 #include "demo.h"
@@ -35,7 +35,7 @@
 #define FALL_OUT_BACK 4
 #define FALL_OUT_OVER 5
 
-static int resume;
+static int be_back_soon;
 
 static int fall_out_action(int i)
 {
@@ -47,24 +47,22 @@ static int fall_out_action(int i)
         /* Fall through. */
 
     case FALL_OUT_OVER:
-        progress_stop();
+        level_stop();
         return goto_state(&st_over);
 
     case FALL_OUT_SAVE:
-        resume = 1;
+        be_back_soon = 1;
 
-        progress_stop();
+        level_stop();
         return goto_save(&st_fall_out, &st_fall_out);
 
     case FALL_OUT_NEXT:
-        if (progress_next())
-            return goto_state(&st_level);
-        break;
+        level_next();
+        return goto_state(&st_level);
 
     case FALL_OUT_SAME:
-        if (progress_same())
-            return goto_state(&st_level);
-        break;
+        level_same();
+        return goto_state(&st_level);
     }
 
     return 1;
@@ -74,8 +72,10 @@ static int fall_out_enter(void)
 {
     int id, jd, kd;
 
+    const struct level_game *lg = curr_lg();
+
     /* Reset hack. */
-    resume = 0;
+    be_back_soon = 0;
 
     if ((id = gui_vstack(0)))
     {
@@ -85,17 +85,29 @@ static int fall_out_enter(void)
 
         if ((jd = gui_harray(id)))
         {
-            if (progress_dead())
-                gui_start(jd, _("Exit"), GUI_SML, FALL_OUT_OVER, 0);
+            int next_id = 0, retry_id = 0;
+
+            next_id = gui_maybe(jd, _("Next Level"), FALL_OUT_NEXT,
+                                lg->next_level != NULL);
+
+            if (lg->dead)
+            {
+                gui_start(jd, _("Game Over"), GUI_SML, FALL_OUT_OVER, 0);
+            }
+            else
+            {
+                retry_id = gui_state(jd, _("Retry Level"), GUI_SML,
+                                     FALL_OUT_SAME, 0);
+            }
 
-            if (progress_next_avail())
-                gui_start(jd, _("Next Level"),  GUI_SML, FALL_OUT_NEXT, 0);
+            gui_maybe(jd, _("Save Replay"), FALL_OUT_SAVE, demo_saved());
 
-            if (progress_same_avail())
-                gui_start(jd, _("Retry Level"), GUI_SML, FALL_OUT_SAME, 0);
+            /* Default is next if the next level is newly unlocked. */
 
-            if (demo_saved())
-                gui_state(jd, _("Save Replay"), GUI_SML, FALL_OUT_SAVE, 0);
+            if (next_id && lg->unlock)
+                gui_focus(next_id);
+            else if (retry_id)
+                gui_focus(retry_id);
         }
 
         gui_space(id);
@@ -129,7 +141,7 @@ static int fall_out_keybd(int c, int d)
 {
     if (d)
     {
-        if (config_tst_d(CONFIG_KEY_RESTART, c) && progress_same_avail())
+        if (config_tst_d(CONFIG_KEY_RESTART, c) && !curr_lg()->dead)
             return fall_out_action(FALL_OUT_SAME);
     }
     return 1;
@@ -150,7 +162,7 @@ static int fall_out_buttn(int b, int d)
 static void fall_out_leave(int id)
 {
     /* HACK:  don't run animation if only "visiting" a state. */
-    st_fall_out.timer = resume ? shared_timer : fall_out_timer;
+    st_fall_out.timer = be_back_soon ? shared_timer : fall_out_timer;
 
     gui_delete(id);
 }
index a73f140..96f5f98 100644 (file)
@@ -17,7 +17,7 @@
 #include "gui.h"
 #include "game.h"
 #include "util.h"
-#include "progress.h"
+#include "levels.h"
 #include "audio.h"
 #include "config.h"
 #include "demo.h"
@@ -48,7 +48,7 @@ static int score_id;
 /* Bread crumbs. */
 
 static int new_name;
-static int resume;
+static int be_back_soon;
 
 static int goal_action(int i)
 {
@@ -60,42 +60,33 @@ static int goal_action(int i)
         /* Fall through. */
 
     case GOAL_OVER:
-        progress_stop();
+        level_stop();
         return goto_state(&st_over);
 
     case GOAL_SAVE:
-        resume = 1;
+        be_back_soon = 1;
 
-        progress_stop();
+        level_stop();
         return goto_save(&st_goal, &st_goal);
 
     case GOAL_NAME:
         new_name = 1;
-        resume = 1;
+        be_back_soon = 1;
 
-        progress_stop();
+        level_stop();
         return goto_name(&st_goal, &st_goal, 0);
 
     case GOAL_DONE:
-        progress_stop();
+        level_stop();
         return goto_state(&st_done);
 
-    case GUI_MOST_COINS:
-    case GUI_BEST_TIMES:
-    case GUI_UNLOCK_GOAL:
-        set_score_type(i);
-        resume = 1;
-        return goto_state(&st_goal);
-
     case GOAL_NEXT:
-        if (progress_next())
-            return goto_state(&st_level);
-        break;
+        level_next();
+        return goto_state(&st_level);
 
     case GOAL_SAME:
-        if (progress_same())
-            return goto_state(&st_level);
-        break;
+        level_same();
+        return goto_state(&st_level);
     }
 
     return 1;
@@ -105,16 +96,23 @@ static int goal_enter(void)
 {
     const char *s1 = _("New Record");
     const char *s2 = _("GOAL");
+    const char *s3 = _("Congratulations!");
 
     int id, jd, kd;
 
-    const struct level *l = get_level(curr_level());
+    struct level_game *lg = curr_lg();
+    const struct level *l = lg->level;
+
+    int high;
 
-    int high = progress_lvl_high();
+    high = (lg->time_rank < 3) || (lg->goal_rank < 3) || (lg->coin_rank < 3);
+
+    /* Reset hack. */
+    be_back_soon = 0;
 
     if (new_name)
     {
-        progress_rename();
+        level_update_player_name();
         new_name = 0;
     }
 
@@ -122,6 +120,20 @@ static int goal_enter(void)
     {
         int gid;
 
+        if (lg->mode == MODE_CHALLENGE && lg->bonus)
+        {
+            char buf[MAXSTR];
+
+            sprintf(buf, _("You have unlocked bonus level %s!"),
+                    lg->bonus_repr);
+
+            gid = gui_label(id, s3,  GUI_MED, GUI_ALL, gui_grn, gui_red);
+            gid = gui_label(id, buf, GUI_SML, GUI_ALL, gui_blu, gui_grn);
+
+            lg->bonus = 0;
+            lg->bonus_repr = NULL;
+        }
+
         if (high)
             gid = gui_label(id, s1, GUI_MED, GUI_ALL, gui_grn, gui_grn);
         else
@@ -129,110 +141,99 @@ static int goal_enter(void)
 
         gui_space(id);
 
-        if (curr_mode() == MODE_CHALLENGE)
+        if (lg->mode == MODE_CHALLENGE)
         {
-            int coins, score, balls;
-            char msg[MAXSTR] = "";
-            int i;
-
-            /* Reverse-engineer initial score and balls. */
-
-            if (resume)
-            {
-                coins = 0;
-                score = curr_score();
-                balls = curr_balls();
-            }
-            else
-            {
-                coins = curr_coins();
-                score = curr_score() - coins;
-                balls = curr_balls();
-
-                for (i = curr_score(); i > score; i--)
-                    if (progress_reward_ball(i))
-                        balls--;
-            }
-
-            sprintf(msg, ngettext("%d new bonus level",
-                                  "%d new bonus levels",
-                                  curr_bonus()), curr_bonus());
+            int coins = lg->coins;
+            int score = lg->score - coins;
+            int balls = lg->balls - count_extra_balls(score, coins);
 
             if ((jd = gui_hstack(id)))
             {
-
                 if ((kd = gui_harray(jd)))
                 {
-                    balls_id = gui_count(kd, 100, GUI_MED, GUI_NE);
-                    gui_label(kd, _("Balls"), GUI_SML, 0, gui_wht, gui_wht);
+                    balls_id = gui_count(kd, 100, GUI_MED, GUI_RGT);
+                    gui_label(kd, _("Balls"), GUI_SML, GUI_LFT, gui_wht, gui_wht);
                 }
                 if ((kd = gui_harray(jd)))
                 {
-                    score_id = gui_count(kd, 1000, GUI_MED, 0);
-                    gui_label(kd, _("Score"), GUI_SML, 0, gui_wht, gui_wht);
+                    score_id = gui_count(kd, 1000, GUI_MED, GUI_RGT);
+                    gui_label(kd, _("Score"), GUI_SML, GUI_LFT, gui_wht, gui_wht);
                 }
                 if ((kd = gui_harray(jd)))
                 {
-                    coins_id = gui_count(kd, 100, GUI_MED, 0);
-                    gui_label(kd, _("Coins"), GUI_SML, GUI_NW, gui_wht, gui_wht);
+                    coins_id = gui_count(kd, 100, GUI_MED, GUI_RGT);
+                    gui_label(kd, _("Coins"), GUI_SML, GUI_LFT, gui_wht, gui_wht);
                 }
 
                 gui_set_count(balls_id, balls);
                 gui_set_count(score_id, score);
                 gui_set_count(coins_id, coins);
-
             }
-
-            gui_label(id, msg, GUI_SML, GUI_BOT, 0, 0);
-
-            gui_space(id);
         }
         else
         {
             balls_id = score_id = coins_id = 0;
         }
 
-        if ((jd = gui_hstack(id)))
-            gui_score_board(jd, 1);
+        gui_space(id);
+
+        if ((jd = gui_harray(id)))
+        {
+            gui_most_coins(jd, 1);
+            gui_best_times(jd, 1);
+        }
 
         gui_space(id);
 
         if ((jd = gui_harray(id)))
         {
-            if (progress_done())
+            int next_id = 0, retry_id = 0;
+
+            if (lg->win)
                 gui_start(jd, _("Finish"), GUI_SML, GOAL_DONE, 0);
+            else
+                next_id = gui_maybe(jd, _("Next Level"),  GOAL_NEXT,
+                                    lg->next_level != NULL);
 
-            if (progress_next_avail())
-                gui_start(jd, _("Next Level"),  GUI_SML, GOAL_NEXT, 0);
+            if (lg->dead)
+                gui_start(jd, _("Game Over"), GUI_SML, GOAL_OVER, 0);
+            else
+            {
+                retry_id = gui_maybe(jd, _("Retry Level"), GOAL_SAME,
+                                     lg->mode != MODE_CHALLENGE);
+            }
 
-            if (progress_same_avail())
-                gui_start(jd, _("Retry Level"), GUI_SML, GOAL_SAME, 0);
+            gui_maybe(jd, _("Save Replay"), GOAL_SAVE, demo_saved());
 
-            if (demo_saved())
-                gui_state(jd, _("Save Replay"), GUI_SML, GOAL_SAVE, 0);
+            /* Default is next if the next level is newly unlocked. */
 
-            if (high)
-                gui_state(id, _("Change Name"),  GUI_SML, GOAL_NAME, 0);
+            if (next_id && lg->unlock)
+                gui_focus(next_id);
+            else if (lg->mode != MODE_CHALLENGE)
+                gui_focus(retry_id);
         }
 
-        if (!resume)
-            gui_pulse(gid, 1.2f);
+        /* FIXME, I'm ugly. */
 
+        if (high)
+            gui_state(id, _("Change Player Name"),  GUI_SML, GOAL_NAME, 0);
+
+        gui_pulse(gid, 1.2f);
         gui_layout(id, 0, 0);
 
     }
 
-    set_score_board(&l->score.most_coins,  progress_coin_rank(),
-                    &l->score.best_times,  progress_time_rank(),
-                    &l->score.unlock_goal, progress_goal_rank());
+    set_most_coins(&l->score.most_coins, lg->coin_rank);
+
+    if (lg->mode == MODE_CHALLENGE || lg->mode == MODE_NORMAL)
+        set_best_times(&l->score.unlock_goal, lg->goal_rank, 1);
+    else
+        set_best_times(&l->score.best_times, lg->time_rank, 0);
 
     audio_music_fade_out(2.0f);
 
     config_clr_grab();
 
-    /* Reset hack. */
-    resume = 0;
-
     return id;
 }
 
@@ -264,7 +265,7 @@ static void goal_timer(int id, float dt)
             gui_set_count(score_id, score + 1);
             gui_pulse(score_id, 1.1f);
 
-            if (progress_reward_ball(score + 1))
+            if ((score + 1) % 100 == 0)
             {
                 gui_set_count(balls_id, balls + 1);
                 gui_pulse(balls_id, 2.0f);
@@ -292,7 +293,7 @@ static int goal_buttn(int b, int d)
 static void goal_leave(int id)
 {
     /* HACK:  don't run animation if only "visiting" a state. */
-    st_goal.timer = resume ? shared_timer : goal_timer;
+    st_goal.timer = be_back_soon ? shared_timer : goal_timer;
 
     gui_delete(id);
 }
index e623429..a158e79 100644 (file)
@@ -48,14 +48,12 @@ static int help_action(int t)
         break;
 
     case HELP_DEMO_1:
-        if (demo_replay_init(config_data("gui/demo1.nbr"),
-                             NULL, NULL, NULL, NULL, NULL))
+        if (demo_replay_init(config_data("gui/demo1.nbr"), NULL))
             return goto_state(&st_help_demo);
         break;
 
     case HELP_DEMO_2:
-        if (demo_replay_init(config_data("gui/demo2.nbr"),
-                             NULL, NULL, NULL, NULL, NULL))
+        if (demo_replay_init(config_data("gui/demo2.nbr"), NULL))
             return goto_state(&st_help_demo);
         break;
 
@@ -242,6 +240,14 @@ static int help_modes(int id)
 
             gui_space(kd);
 
+            gui_label(kd, _("Practice Mode"), GUI_SML, GUI_TOP, 0, 0);
+            gui_multi(kd,
+                      _("Play without time limit or coin constraint.\\"
+                        "Levels cannot be unlocked in this mode."),
+                      GUI_SML, GUI_BOT, gui_wht, gui_wht);
+
+            gui_space(kd);
+
             gui_label(kd, _("Challenge Mode"), GUI_SML, GUI_TOP, 0, 0);
             gui_multi(kd,
                       _("Start playing from the first level of the set.\\"
index 8e70c78..f408dbd 100644 (file)
@@ -17,7 +17,7 @@
 #include "gui.h"
 #include "game.h"
 #include "set.h"
-#include "progress.h"
+#include "levels.h"
 #include "audio.h"
 #include "config.h"
 #include "st_shared.h"
@@ -33,6 +33,7 @@ static int level_enter(void)
 {
     int id, jd, kd, ld;
     const char *ln;
+    const struct level_game *lg = curr_lg();
     int b;
     const float *textcol1, *textcol2;
 
@@ -40,9 +41,8 @@ static int level_enter(void)
     {
         if ((jd = gui_hstack(id)))
         {
-            ln = level_repr (curr_level());
-            b  = level_bonus(curr_level());
-
+            ln = lg->level->repr;
+            b = lg->level->is_bonus;
             textcol1 = b ? gui_wht : 0;
             textcol2 = b ? gui_grn : 0;
 
@@ -73,7 +73,7 @@ static int level_enter(void)
                     }
                 }
 
-                gui_label(kd, mode_to_str(curr_mode(), 1), GUI_SML, GUI_BOT,
+                gui_label(kd, mode_to_str(lg->mode, 1), GUI_SML, GUI_BOT,
                           gui_wht, gui_wht);
 
             }
@@ -81,9 +81,9 @@ static int level_enter(void)
         }
         gui_space(id);
 
-        gui_multi(id, level_msg(curr_level()),
-                  GUI_SML, GUI_ALL,
-                  gui_wht, gui_wht);
+        if (strlen(lg->level->message) != 0)
+            gui_multi(id, _(lg->level->message), GUI_SML, GUI_ALL, gui_wht,
+                      gui_wht);
 
         gui_layout(id, 0, 0);
     }
@@ -120,7 +120,8 @@ static int level_buttn(int b, int d)
         }
         if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
         {
-            progress_stop();
+            level_stat(GAME_NONE, curr_clock(), curr_coins());
+            level_stop();
             return goto_state(&st_over);
         }
     }
index 4a141b4..c455042 100644 (file)
@@ -15,7 +15,7 @@
 #include "gui.h"
 #include "set.h"
 #include "game.h"
-#include "progress.h"
+#include "levels.h"
 #include "audio.h"
 #include "config.h"
 #include "demo.h"
@@ -30,7 +30,7 @@ static int over_enter(void)
 {
     int id;
 
-    if (curr_mode() != MODE_CHALLENGE)
+    if (curr_lg()->mode != MODE_CHALLENGE)
         return 0;
 
     if ((id = gui_label(0, _("GAME OVER"), GUI_LRG, GUI_ALL, gui_gry, gui_red)))
@@ -49,7 +49,7 @@ static int over_enter(void)
 
 static void over_timer(int id, float dt)
 {
-    if (curr_mode() != MODE_CHALLENGE || time_state() > 3.f)
+    if (curr_lg()->mode != MODE_CHALLENGE || time_state() > 3.f)
         goto_state(&st_start);
 
     gui_timer(id, dt);
index 8c6b5a1..51b5b2a 100644 (file)
@@ -15,7 +15,7 @@
 #include "gui.h"
 #include "config.h"
 #include "game.h"
-#include "progress.h"
+#include "levels.h"
 #include "level.h"
 #include "audio.h"
 #include "hud.h"
@@ -65,17 +65,15 @@ static int pause_action(int i)
         return goto_state(st_continue);
 
     case PAUSE_RESTART:
-        if (progress_same())
-        {
-            clear_pause();
-            SDL_PauseAudio(0);
-            config_set_grab(1);
-            return goto_state(&st_play_ready);
-        }
-        break;
+        level_same();
+        clear_pause();
+        SDL_PauseAudio(0);
+        config_set_grab(1);
+        return goto_state(&st_play_ready);
 
     case PAUSE_EXIT:
-        progress_exit(GAME_NONE);
+        level_stat(GAME_NONE, curr_clock(), curr_coins());
+        level_stop();
         clear_pause();
         SDL_PauseAudio(0);
         audio_music_stop();
@@ -106,8 +104,13 @@ static int pause_enter(void)
         {
             gui_state(jd, _("Quit"), GUI_SML, PAUSE_EXIT, 0);
 
-            if (progress_same_avail())
+            if (curr_lg()->mode != MODE_CHALLENGE)
                 gui_state(jd, _("Restart"), GUI_SML, PAUSE_RESTART, 0);
+            else
+            {
+                int ld = gui_state(jd, _("Restart"), GUI_SML, 0, 0);
+                gui_set_color(ld, gui_gry, gui_gry);
+            }
 
             gui_start(jd, _("Continue"), GUI_SML, PAUSE_CONTINUE, 1);
         }
@@ -140,8 +143,8 @@ static int pause_keybd(int c, int d)
         if (config_tst_d(CONFIG_KEY_PAUSE, c))
             return pause_action(PAUSE_CONTINUE);
 
-        if (config_tst_d(CONFIG_KEY_RESTART, c) &&
-            curr_mode() != MODE_CHALLENGE)
+        if (config_tst_d(CONFIG_KEY_RESTART, c)
+            && curr_lg()->mode != MODE_CHALLENGE)
             return pause_action(PAUSE_RESTART);
     }
     return 1;
index e3d8feb..5eb59ce 100644 (file)
@@ -16,7 +16,7 @@
 #include "hud.h"
 #include "game.h"
 #include "demo.h"
-#include "progress.h"
+#include "levels.h"
 #include "audio.h"
 #include "config.h"
 #include "st_shared.h"
@@ -36,7 +36,8 @@ static int pause_or_exit(void)
 {
     if (SDL_GetModState() & KMOD_SHIFT)
     {
-        progress_exit(GAME_NONE);
+        level_stat(GAME_NONE, curr_clock(), curr_coins());
+        level_stop();
         config_clr_grab();
 
         return goto_state(&st_over);
@@ -227,25 +228,24 @@ static void play_loop_timer(int id, float dt)
     switch (game_step(g, dt, 1))
     {
     case GAME_GOAL:
-        progress_stat(GAME_GOAL);
+        level_stat(GAME_GOAL, curr_clock(), curr_coins());
         gui_stuck();
         goto_state(&st_goal);
         break;
 
     case GAME_FALL:
-        progress_stat(GAME_FALL);
+        level_stat(GAME_FALL, curr_clock(), curr_coins());
         gui_stuck();
         goto_state(&st_fall_out);
         break;
 
     case GAME_TIME:
-        progress_stat(GAME_TIME);
+        level_stat(GAME_TIME, curr_clock(), curr_coins());
         gui_stuck();
         goto_state(&st_time_out);
         break;
 
     default:
-        progress_step();
         break;
     }
 }
@@ -294,10 +294,10 @@ static int play_loop_keybd(int c, int d)
             hud_view_pulse(2);
         }
         if (config_tst_d(CONFIG_KEY_RESTART, c) &&
-            progress_same_avail())
+            curr_lg()->mode != MODE_CHALLENGE)
         {
-            if (progress_same())
-                goto_state(&st_play_ready);
+            level_same();
+            goto_state(&st_play_ready);
         }
         if (config_tst_d(CONFIG_KEY_PAUSE, c))
             goto_pause();
@@ -318,7 +318,7 @@ static int play_loop_keybd(int c, int d)
 
     if (d && c == SDLK_c && config_cheat())
     {
-        progress_stat(GAME_GOAL);
+        level_stat(GAME_GOAL, curr_clock(), curr_coins());
         return goto_state(&st_goal);
     }
     return 1;
index 39813d7..ea4abe3 100644 (file)
@@ -21,7 +21,7 @@
 #include "audio.h"
 #include "config.h"
 #include "demo.h"
-#include "progress.h"
+#include "levels.h"
 #include "text.h"
 
 #include "st_shared.h"
index b2fb56a..d3bdc68 100644 (file)
@@ -14,7 +14,7 @@
 
 #include "gui.h"
 #include "set.h"
-#include "progress.h"
+#include "levels.h"
 #include "game.h"
 #include "audio.h"
 #include "config.h"
index 01a83b0..ec5b582 100644 (file)
@@ -16,7 +16,7 @@
 #include "set.h"
 #include "util.h"
 #include "game.h"
-#include "progress.h"
+#include "levels.h"
 #include "audio.h"
 #include "config.h"
 #include "st_shared.h"
 
 /*---------------------------------------------------------------------------*/
 
-#define START_BACK        -1
-#define START_CHALLENGE   -2
-#define START_OPEN_GOALS  -3
-#define START_LOCK_GOALS  -4
+#define START_BACK      -1
+#define START_PRACTICE  -2
+#define START_NORMAL    -3
+#define START_CHALLENGE -4
 
 static int shot_id;
+static int status_id;
 
 /*---------------------------------------------------------------------------*/
 
@@ -42,58 +43,101 @@ static int shot_id;
 
 static void gui_level(int id, int i)
 {
-    const GLfloat *fore = 0, *back = 0;
+    const GLfloat *fore, *back;
+    const struct level *l;
 
     int jd;
 
-    if (!level_exists(i))
+    if (!set_level_exists(curr_set(), i))
     {
-        gui_label(id, " ", GUI_SML, GUI_ALL, gui_blk, gui_blk);
+        gui_space(id);
         return;
     }
 
-    if (level_opened(i))
+    l = get_level(i);
+
+    if (!l->is_locked)
     {
-        fore = level_bonus(i)     ? gui_grn : gui_wht;
-        back = level_completed(i) ? fore    : gui_yel;
+        fore = l->is_bonus     ? gui_grn : gui_wht;
+        back = l->is_completed ? fore    : gui_yel;
     }
+    else
+        fore = back = gui_gry;
 
-    jd = gui_label(id, level_repr(i), GUI_SML, GUI_ALL, back, fore);
+    jd = gui_label(id, l->repr, GUI_SML, GUI_ALL, back, fore);
 
-    if (level_opened(i) || config_cheat())
-        gui_active(jd, i, 0);
+    gui_active(jd, i, 0);
 }
 
 static void start_over_level(int i)
 {
-    if (level_opened(i) || config_cheat())
+    const struct level *l = get_level(i);
+    if (!l->is_locked || config_cheat())
     {
-        gui_set_image(shot_id, level_shot(i));
+        gui_set_image(shot_id, l->shot);
 
-        set_score_board(&get_level(i)->score.most_coins,  -1,
-                        &get_level(i)->score.best_times,  -1,
-                        &get_level(i)->score.unlock_goal, -1);
+        set_most_coins(&l->score.most_coins, -1);
+
+        if (curr_mode() == MODE_PRACTICE)
+        {
+            set_best_times(&l->score.best_times, -1, 0);
+            if (l->is_bonus)
+                gui_set_label(status_id,
+                              _("Play this bonus level in practice mode"));
+            else
+                gui_set_label(status_id,
+                              _("Play this level in practice mode"));
+        }
+        else
+        {
+            set_best_times(&l->score.unlock_goal, -1, 1);
+            if (l->is_bonus)
+                gui_set_label(status_id,
+                              _("Play this bonus level in normal mode"));
+            else
+                gui_set_label(status_id, _("Play this level in normal mode"));
+        }
+        if (config_cheat())
+        {
+            gui_set_label(status_id, l->file);
+        }
+        return;
     }
+    else if (l->is_bonus)
+        gui_set_label(status_id,
+                      _("Play in challenge mode to unlock extra bonus levels"));
+    else
+        gui_set_label(status_id,
+                      _("Finish previous levels to unlock this level"));
 }
 
 static void start_over(int id)
 {
     int i;
 
+    gui_pulse(id, 1.2f);
     if (id == 0)
         return;
 
-    gui_pulse(id, 1.2f);
-
     i = gui_token(id);
 
-    if (i == START_CHALLENGE || i == START_BACK)
+
+    switch (i)
     {
+    case START_CHALLENGE:
         gui_set_image(shot_id, set_shot(curr_set()));
+        set_most_coins(set_coin_score(curr_set()), -1);
+        set_best_times(set_time_score(curr_set()), -1, 0);
+        gui_set_label(status_id, _("Challenge all levels from the first one"));
+        break;
+
+    case START_NORMAL:
+        gui_set_label(status_id, _("Collect coins and unlock next level"));
+        break;
 
-        set_score_board(set_coin_score(curr_set()), -1,
-                        set_time_score(curr_set()), -1,
-                        set_time_score(curr_set()), -1);
+    case START_PRACTICE:
+        gui_set_label(status_id, _("Train yourself without time nor coin"));
+        break;
     }
 
     if (i >= 0)
@@ -104,37 +148,51 @@ static void start_over(int id)
 
 static int start_action(int i)
 {
+    int mode = curr_mode();
+
     audio_play(AUD_MENU, 1.0f);
 
     switch (i)
     {
     case START_BACK:
         return goto_state(&st_set);
-
-    case START_CHALLENGE:
-        progress_init(MODE_CHALLENGE);
-        return config_cheat() ? 1 : start_action(0);
-
-    case GUI_MOST_COINS:
-    case GUI_BEST_TIMES:
-    case GUI_UNLOCK_GOAL:
-        set_score_type(i);
+    case START_NORMAL:
+        mode_set(MODE_NORMAL);
         return goto_state(&st_start);
-
-    case START_OPEN_GOALS:
-        config_set_d(CONFIG_LOCK_GOALS, 0);
-        return goto_state(&st_start);
-
-    case START_LOCK_GOALS:
-        config_set_d(CONFIG_LOCK_GOALS, 1);
+    case START_PRACTICE:
+        mode_set(MODE_PRACTICE);
         return goto_state(&st_start);
+    }
 
-    default:
-        if (progress_play(i))
-            return goto_state(&st_level);
-        break;
+    if (i == START_CHALLENGE)
+    {
+        /* On cheat, start challenge mode where you want */
+        if (config_cheat())
+        {
+            mode_set(MODE_CHALLENGE);
+            return goto_state(&st_start);
+        }
+        i = 0;
+        mode = MODE_CHALLENGE;
     }
 
+    if (i >= 0)
+    {
+        const struct level *l = get_level(i);
+
+        if (!l->is_locked || config_cheat())
+        {
+            if (level_play(l, mode))
+            {
+                return goto_state(&st_level);
+            }
+            else
+            {
+                level_stop();
+                return 1;
+            }
+        }
+    }
     return 1;
 }
 
@@ -142,11 +200,18 @@ static int start_enter(void)
 {
     int w = config_get_d(CONFIG_WIDTH);
     int h = config_get_d(CONFIG_HEIGHT);
+    int m = curr_mode();
     int i, j;
 
     int id, jd, kd, ld;
 
-    progress_init(MODE_NORMAL);
+    /* Deactivate cheat */
+
+    if (m == MODE_CHALLENGE && !config_cheat())
+    {
+        mode_set(MODE_NORMAL);
+        m = MODE_NORMAL;
+    }
 
     if ((id = gui_vstack(0)))
     {
@@ -159,57 +224,45 @@ static int start_enter(void)
             gui_start(jd, _("Back"),  GUI_SML, START_BACK, 0);
         }
 
+
         if ((jd = gui_harray(id)))
         {
             shot_id = gui_image(jd, set_shot(curr_set()), 7 * w / 16, 7 * h / 16);
 
             if ((kd = gui_varray(jd)))
             {
+                if ((ld = gui_harray(kd)))
+                {
+                    gui_state(ld, _("Practice"), GUI_SML, START_PRACTICE,
+                              m == MODE_PRACTICE);
+                    gui_state(ld, _("Normal"),   GUI_SML, START_NORMAL,
+                              m == MODE_NORMAL);
+                }
                 for (i = 0; i < 5; i++)
                     if ((ld = gui_harray(kd)))
                         for (j = 4; j >= 0; j--)
                             gui_level(ld, i * 5 + j);
 
                 gui_state(kd, _("Challenge"), GUI_SML, START_CHALLENGE,
-                          curr_mode() == MODE_CHALLENGE);
+                          m == MODE_CHALLENGE);
             }
         }
         gui_space(id);
 
-        if ((jd = gui_hstack(id)))
-            gui_score_board(jd, 0);
-
-        gui_space(id);
-
-        if ((jd = gui_hstack(id)))
+        if ((jd = gui_harray(id)))
         {
-            gui_filler(jd);
-
-            if ((kd = gui_harray(jd)))
-            {
-                /* TODO, replace the whitespace hack with something sane. */
-
-                gui_state(kd,
-                          /* TRANSLATORS: adjust the amount of whitespace here
-                           * as necessary for the buttons to look good. */
-                          _("   No   "), GUI_SML, START_OPEN_GOALS,
-                          config_get_d(CONFIG_LOCK_GOALS) == 0);
-
-                gui_state(kd, _("Yes"), GUI_SML, START_LOCK_GOALS,
-                          config_get_d(CONFIG_LOCK_GOALS) == 1);
-            }
-
-            gui_space(jd);
-
-            gui_label(jd, _("Lock Goals of Completed Levels?"),
-                      GUI_SML, GUI_ALL, 0, 0);
-
-            gui_filler(jd);
+            gui_most_coins(jd, 0);
+            gui_best_times(jd, 0);
         }
+        gui_space(id);
+
+        status_id = gui_label(id, _("Choose a level to play"), GUI_SML, GUI_ALL,
+                              gui_yel, gui_wht);
 
         gui_layout(id, 0, 0);
 
-        set_score_board(NULL, -1, NULL, -1, NULL, -1);
+        set_most_coins(NULL, -1);
+        set_best_times(NULL, -1, m != MODE_PRACTICE);
     }
 
     audio_music_fade_to(0.5f, "bgm/inter.ogg");
@@ -245,7 +298,7 @@ static int start_keybd(int c, int d)
         /* Iterate over all levels, taking a screenshot of each. */
 
         for (i = 0; i < MAXLVL; i++)
-            if (level_exists(i))
+            if (set_level_exists(curr_set(), i))
                 level_snap(i);
     }
 
index 7c22ec9..bce3713 100644 (file)
@@ -14,7 +14,7 @@
 
 #include "game.h"
 #include "util.h"
-#include "progress.h"
+#include "levels.h"
 #include "demo.h"
 #include "audio.h"
 #include "gui.h"
@@ -45,22 +45,20 @@ static int time_out_action(int i)
         /* Fall through. */
 
     case TIME_OUT_OVER:
-        progress_stop();
+        level_stop();
         return goto_state(&st_over);
 
     case TIME_OUT_SAVE:
-        progress_stop();
+        level_stop();
         return goto_save(&st_time_out, &st_time_out);
 
     case TIME_OUT_NEXT:
-        if (progress_next())
-            return goto_state(&st_level);
-        break;
+        level_next();
+        return goto_state(&st_level);
 
     case TIME_OUT_SAME:
-        if (progress_same())
-            return goto_state(&st_level);
-        break;
+        level_same();
+        return goto_state(&st_level);
     }
 
     return 1;
@@ -70,6 +68,8 @@ static int time_out_enter(void)
 {
     int id, jd, kd;
 
+    const struct level_game *lg = curr_lg();
+
     if ((id = gui_vstack(0)))
     {
         kd = gui_label(id, _("Time's Up!"), GUI_LRG, GUI_ALL, gui_gry, gui_red);
@@ -78,17 +78,27 @@ static int time_out_enter(void)
 
         if ((jd = gui_harray(id)))
         {
-            if (progress_dead())
-                gui_start(jd, _("Exit"), GUI_SML, TIME_OUT_OVER, 0);
+            int next_id = 0, retry_id = 0;
+
+            next_id = gui_maybe(jd, _("Next Level"),  TIME_OUT_NEXT,
+                                lg->next_level != NULL);
+
+            if (lg->dead)
+                gui_start(jd, _("Game Over"), GUI_SML, TIME_OUT_OVER, 0);
+            else
+            {
+                retry_id = gui_state(jd, _("Retry Level"), GUI_SML,
+                                     TIME_OUT_SAME, 0);
+            }
 
-            if (progress_next_avail())
-                gui_start(jd, _("Next Level"), GUI_SML, TIME_OUT_NEXT, 0);
+            gui_maybe(jd, _("Save Replay"), TIME_OUT_SAVE, demo_saved());
 
-            if (progress_same_avail())
-                gui_start(jd, _("Retry Level"), GUI_SML, TIME_OUT_SAME, 0);
+            /* Default is next if the next level is newly unlocked. */
 
-            if (demo_saved())
-                gui_state(jd, _("Save Replay"), GUI_SML, TIME_OUT_SAVE, 0);
+            if (next_id && lg->unlock)
+                gui_focus(next_id);
+            else if (retry_id)
+                gui_focus(retry_id);
         }
         gui_space(id);
 
@@ -108,7 +118,7 @@ static int time_out_keybd(int c, int d)
 {
     if (d)
     {
-        if (config_tst_d(CONFIG_KEY_RESTART, c) && progress_same_avail())
+        if (config_tst_d(CONFIG_KEY_RESTART, c) && !curr_lg()->dead)
             return time_out_action(TIME_OUT_SAME);
     }
     return 1;
index cb581b2..6e624ae 100644 (file)
@@ -110,6 +110,8 @@ static int title_action(int i)
     return 1;
 }
 
+static struct level title_level;
+
 static int title_enter(void)
 {
     int id, jd, kd;
@@ -151,8 +153,8 @@ static int title_enter(void)
     audio_music_fade_to(0.5f, "bgm/title.ogg");
 
     /* Initialize the title level for display. */
-
-    game_init("map-medium/title.sol", 0, 1);
+    level_load("map-medium/title.sol", &title_level);
+    game_init(&title_level, 0, 0);
 
     real_time = 0.0f;
     mode = 0;
@@ -195,7 +197,7 @@ static void title_timer(int id, float dt)
         {
             if ((demo = demo_pick()))
             {
-                demo_replay_init(demo, NULL, NULL, NULL, NULL, NULL);
+                demo_replay_init(demo, NULL);
                 game_set_fly(0.0f);
                 real_time = 0.0f;
                 mode = 2;
@@ -224,8 +226,7 @@ static void title_timer(int id, float dt)
 
         if (real_time > 1.0f)
         {
-            game_init("map-medium/title.sol", 0, 1);
-
+            game_init(&title_level, 0, 0);
             real_time = 0.0f;
             mode = 0;
         }
index 0710794..d439438 100644 (file)
@@ -38,7 +38,7 @@ static int coin_extra_row;
 
 /* Build a Most Coins top three list with default values. */
 
-static void gui_most_coins(int id, int e)
+void gui_most_coins(int id, int e)
 {
     const char *s = "1234567";
 
@@ -105,7 +105,7 @@ static void gui_most_coins(int id, int e)
 
 /* Set the Most Coins top three list values for level i. */
 
-static void set_most_coins(const struct score *s, int hilight)
+void set_most_coins(const struct score *s, int hilight)
 {
     int j, spe;
     const char *name;
@@ -154,7 +154,7 @@ static int time_extra_row;
 
 /* Build a Best Times top three list with default values. */
 
-static void gui_best_times(int id, int e)
+void gui_best_times(int id, int e)
 {
     const char *s = "1234567";
 
@@ -219,9 +219,9 @@ static void gui_best_times(int id, int e)
     }
 }
 
-/* Set the Best Times top three list values. */
+/* Set the Best Times top three list values for level i. */
 
-static void set_best_times(const struct score *s, int hilight, int goal)
+void set_best_times(const struct score *s, int hilight, int goal)
 {
     int j, spe;
     const char *name;
@@ -248,7 +248,7 @@ static void set_best_times(const struct score *s, int hilight, int goal)
                 gui_set_color(time_name[j], 0, 0);
             else if (j != hilight)
                 gui_set_color(time_name[j], gui_yel, gui_wht);
-            else if (j >= NSCORE)
+            else if (j>= NSCORE)
                 gui_set_color(time_name[j], gui_red, gui_red);
             else
                 gui_set_color(time_name[j], gui_grn, gui_grn);
@@ -262,82 +262,6 @@ static void set_best_times(const struct score *s, int hilight, int goal)
 
 /*---------------------------------------------------------------------------*/
 
-static int score_type = GUI_MOST_COINS;
-
-void gui_score_board(int id, int e)
-{
-    int jd, kd;
-
-    gui_filler(id);
-
-    if ((jd = gui_hstack(id)))
-    {
-        gui_filler(jd);
-
-        if ((kd = gui_vstack(jd)))
-        {
-            gui_filler(kd);
-
-            gui_state(kd, _("Most Coins"),  GUI_SML, GUI_MOST_COINS,
-                      score_type == GUI_MOST_COINS);
-            gui_state(kd, _("Best Times"),  GUI_SML, GUI_BEST_TIMES,
-                      score_type == GUI_BEST_TIMES);
-            gui_state(kd, _("Unlock Goal"), GUI_SML, GUI_UNLOCK_GOAL,
-                      score_type == GUI_UNLOCK_GOAL);
-
-            gui_filler(kd);
-        }
-
-        gui_filler(jd);
-    }
-
-    gui_filler(id);
-
-    switch (score_type)
-    {
-    case GUI_MOST_COINS:
-        gui_most_coins(id, e);
-        break;
-
-    case GUI_BEST_TIMES:
-        gui_best_times(id, e);
-        break;
-
-    case GUI_UNLOCK_GOAL:
-        gui_best_times(id, e);
-        break;
-    }
-
-    gui_filler(id);
-}
-
-void set_score_board(const struct score *smc, int hmc,
-                     const struct score *sbt, int hbt,
-                     const struct score *sug, int hug)
-{
-    switch (score_type)
-    {
-    case GUI_MOST_COINS:
-        set_most_coins(smc, hmc);
-        break;
-
-    case GUI_BEST_TIMES:
-        set_best_times(sbt, hbt, 0);
-        break;
-
-    case GUI_UNLOCK_GOAL:
-        set_best_times(sug, hug, 1);
-        break;
-    }
-}
-
-void set_score_type(int t)
-{
-    score_type = t;
-}
-
-/*---------------------------------------------------------------------------*/
-
 static int lock = 1;
 static int keyd[127];
 
index f10c147..aa1529e 100644 (file)
 #define GUI_BS   -104
 #define GUI_CL   -105
 
-#define GUI_MOST_COINS  -106
-#define GUI_BEST_TIMES  -107
-#define GUI_UNLOCK_GOAL -108
-
-void set_score_type(int);
-void gui_score_board(int, int);
-void set_score_board(const struct score *, int,
-                     const struct score *, int,
-                     const struct score *, int);
+void gui_most_coins(int, int);
+void set_most_coins(const struct score *, int);
+void gui_best_times(int, int);
+void set_best_times(const struct score *, int, int);
 
 void gui_keyboard(int);
 void gui_keyboard_lock(void);
index 8657fb5..630f77a 100644 (file)
@@ -17,7 +17,6 @@
     Mehdi Yousfi-Monod  (mym)
     Michael Middleton   (slippifishi)
     Florian Priester
-    Byron James Johnson (Krabby Krap)
 
 * TRANSLATORS
 
@@ -61,7 +60,6 @@
       - Feature ideas and testing
     Byron James Johnson
       - Platform acceleration toggle
-      - Neverputt ball vs. ball collision
     Laurent Moussault (Lorant)
       - Menu navigation improvements
       - Layout improvements in several screens
@@ -81,8 +79,6 @@
       - Map compiler speed-ups for debugging large maps
     Uoti Urpala
       - Bounces with moving objects
-    Georg Wachter
-      - Generic sphere-vs-sphere collision
     Mehdi Yousfi-Monod
       - Neverball Hall of Fame management
       - Windows packaging
index b87d57d..99e18d9 100644 (file)
@@ -222,20 +222,6 @@ values follow.
 
         Joystick exit button
 
-    gamma 0.78
-
-        gamma  gives the Coefficient of restitution of a sphere-sphere
-        collision.   Its square  gives the fraction  of kinetic energy
-        (in the center-of-mass system)  that will  be conserved in the
-        collision,  so  possible   values range  from  0   (completely
-        inelastic) to 1 (completely elastic) collision. Values greater
-        than 1  mean that in each collision, extra energy is generated.
-
-    putt_collisions 0
-
-        This  key  allows  balls  to  collide   with  other  balls  in
-        Neverputt.
-
 
 
 Contact: <robert.kooima@gmail.com>
index 960439b..a7f88c1 100644 (file)
@@ -46,7 +46,6 @@ 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                  */
 
@@ -83,7 +82,6 @@ void game_init(const char *s)
 {
     jump_e = 1;
     jump_b = 0;
-    jump_u = 0;
 
     view_init();
     sol_load_gl(&file, config_data(s), config_get_d(CONFIG_TEXTURES),
@@ -97,121 +95,6 @@ void game_free(void)
 
 /*---------------------------------------------------------------------------*/
 
-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);
-        }
-
-        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 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;
-                }
-            }
-        }
-
-       /*
-        * 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++)
-    {
-        struct s_ball *yp = fp->yv + i;
-
-        if (yp->p[1] < -20.0f && yp->n)
-        {
-            v_cpy(yp->p, yp->O);
-            v_cpy(yp->v, z);
-            v_cpy(yp->w, z);
-        }
-
-        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);
-                }
-            }
-        }
-    }
-
-    return 0;
-}
-
 static void game_draw_vect_prim(const struct s_file *fp, GLenum mode)
 {
     float p[3];
@@ -275,62 +158,37 @@ static void game_draw_vect(const struct s_file *fp)
 static void game_draw_balls(const struct s_file *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]);
-
-        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();
-    }
+    int ui;
 
     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);
+                ball_draw(ball_M, pend_M, bill_M, t);
             }
             glPopMatrix();
         }
@@ -427,13 +285,7 @@ void game_draw(int pose, float t)
 
     float fov = FOV;
 
-    int i = 0;
-
-    if (config_get_d(CONFIG_BALL_COLLISIONS) && jump_b && jump_u != ball * 2)
-        fov /= 1.9f * fabsf(jump_dt - 0.5f);
-
-    else if (jump_b)
-        fov *= 2.0f * fabsf(jump_dt - 0.5f);
+    if (jump_b) fov *= 2.0f * fabsf(jump_dt - 0.5f);
 
     config_push_persp(fov, 0.1f, FAR_DIST);
     glPushAttrib(GL_LIGHTING_BIT);
@@ -471,23 +323,6 @@ void game_draw(int pose, float t)
 
         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();
@@ -605,126 +440,49 @@ static int game_update_state(float dt)
     struct s_file *fp = &file;
     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))
         audio_play(AUD_SWITCH, 1.f);
 
     /* Test for a jump. */
 
-    if (config_get_d(CONFIG_BALL_COLLISIONS))
-    {
-        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;
-
-                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;
-        }
-    }
-    else
+    if (jump_e == 1 && jump_b == 0 && sol_jump_test(fp, jump_p, ball) == 1)
     {
-        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;
+        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;
+        audio_play(AUD_JUMP, 1.f);
     }
+    if (jump_e == 0 && jump_b == 0 &&  sol_jump_test(fp, jump_p, ball) == 0)
+        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)
     {
-        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;
-            }
-        }
+        t = 0.f;
 
+        if (sol_goal_test(fp, p, ball))
+            return GAME_GOAL;
         else
-        {
-            if (sol_goal_test(fp, p, ball))
-                return GAME_GOAL;
-            else
-                return GAME_STOP;
-        }
+            return GAME_STOP;
     }
 
     return GAME_NONE;
 }
 
-void game_set_played(int b)
-{
-    if (ball)
-        file.uv[ball].P = b;
-    if (!b)
-    {
-        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;
-    }
-}
-
 /*
  * On  most  hardware, rendering  requires  much  more  computing power  than
  * physics.  Since  physics takes less time  than graphics, it  make sense to
@@ -757,49 +515,18 @@ int game_step(const float g[3], float dt)
 
     if (jump_b)
     {
-        if (config_get_d(CONFIG_BALL_COLLISIONS))
-        {
-            jump_dt += dt;
+        jump_dt += dt;
 
-            /* Handle a jump. */
+        /* Handle a jump. */
 
-            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;
-            }
-        }
-
-        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 +540,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 +566,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.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;
 
     view_m = 0.f;
 }
index 27f3160..47bc793 100644 (file)
@@ -43,8 +43,6 @@ int   game_step(const float[3], float);
 
 void  game_update_view(float);
 
-void  game_set_played(int);
-
 void  game_set_rot(int);
 void  game_clr_mag(void);
 void  game_set_mag(int);
index eb9de27..6ed2da0 100644 (file)
@@ -134,7 +134,7 @@ char *hole_tot(int p)
 
     if (p <= party)
     {
-        for (h = 1; h <= hole && h <= 18; h++)
+        for (h = 1; h <= hole && h < count; h++)
             T += score_v[h][p];
 
         sprintf(str, "%d", T);
@@ -152,7 +152,7 @@ char *hole_out(int p)
 
     if (p <= party)
     {
-        for (h = 1; h <= hole && h <= 9; h++)
+        for (h = 1; h <= hole && h <= count / 2; h++)
             T += score_v[h][p];
 
         sprintf(str, "%d", T);
@@ -167,10 +167,11 @@ char *hole_in(int p)
     static char str[MAXSTR];
 
     int h, T = 0;
+    int out = count / 2;
 
-    if (hole > 9 && p <= party)
+    if (hole > out && p <= party)
     {
-        for (h = 10; h <= hole && h <= 18; h++)
+        for (h = out + 1; h <= hole && h < count; h++)
             T += score_v[h][p];
 
         sprintf(str, "%d", T);
@@ -266,63 +267,31 @@ int hole_move(void)
     return 0;
 }
 
-void hole_goal(int playerid)
+void hole_goal(void)
 {
-    if (playerid)
-    {
-        /* HACK: If the player has already beaten the hole, return */
-        if (stat_v[playerid] == 1)
-            return;
-
-        if (score_v[hole][playerid] == 1)
-            audio_play(AUD_ONE, 1.0f);
-
-        else if (score_v[hole][playerid] == score_v[hole][0] - 2)
-            audio_play(AUD_EAGLE, 1.0f);
-        else if (score_v[hole][playerid] == score_v[hole][0] - 1)
-            audio_play(AUD_BIRDIE, 1.0f);
-        else if (score_v[hole][playerid] == score_v[hole][0])
-            audio_play(AUD_PAR, 1.0f);
-        else if (score_v[hole][playerid] == score_v[hole][0] + 1)
-            audio_play(AUD_BOGEY, 1.0f);
-        else if (score_v[hole][playerid] == score_v[hole][0] + 2)
-            audio_play(AUD_DOUBLE, 1.0f);
-        else
-            audio_play(AUD_SUCCESS, 1.0f);
-
-        stat_v[playerid] = 1;
-        done++;
-
-        if (done == party)
-            audio_music_fade_out(2.0f);
-    }
+    score_v[hole][player]++;
 
+    if (score_v[hole][player] == 1)
+        audio_play(AUD_ONE, 1.0f);
+
+    else if (score_v[hole][player] == score_v[hole][0] - 2)
+        audio_play(AUD_EAGLE, 1.0f);
+    else if (score_v[hole][player] == score_v[hole][0] - 1)
+        audio_play(AUD_BIRDIE, 1.0f);
+    else if (score_v[hole][player] == score_v[hole][0])
+        audio_play(AUD_PAR, 1.0f);
+    else if (score_v[hole][player] == score_v[hole][0] + 1)
+        audio_play(AUD_BOGEY, 1.0f);
+    else if (score_v[hole][player] == score_v[hole][0] + 2)
+        audio_play(AUD_DOUBLE, 1.0f);
     else
-    {
-        score_v[hole][player]++;
-
-        if (score_v[hole][player] == 1)
-            audio_play(AUD_ONE, 1.0f);
-
-        else if (score_v[hole][player] == score_v[hole][0] - 2)
-            audio_play(AUD_EAGLE, 1.0f);
-        else if (score_v[hole][player] == score_v[hole][0] - 1)
-            audio_play(AUD_BIRDIE, 1.0f);
-        else if (score_v[hole][player] == score_v[hole][0])
-            audio_play(AUD_PAR, 1.0f);
-        else if (score_v[hole][player] == score_v[hole][0] + 1)
-            audio_play(AUD_BOGEY, 1.0f);
-        else if (score_v[hole][player] == score_v[hole][0] + 2)
-            audio_play(AUD_DOUBLE, 1.0f);
-        else
-            audio_play(AUD_SUCCESS, 1.0f);
+        audio_play(AUD_SUCCESS, 1.0f);
 
-        stat_v[player] = 1;
-        done++;
+    stat_v[player] = 1;
+    done++;
 
-        if (done == party)
-            audio_music_fade_out(2.0f);
-    }
+    if (done == party)
+        audio_music_fade_out(2.0f);
 }
 
 void hole_stop(void)
index e1b1cfb..2063d53 100644 (file)
@@ -28,7 +28,7 @@ const char *curr_par(void);
 void hole_goto(int, int);
 int  hole_next(void);
 int  hole_move(void);
-void hole_goal(int);
+void hole_goal(void);
 void hole_stop(void);
 void hole_fall(void);
 
index 508085b..6898d56 100644 (file)
@@ -239,7 +239,7 @@ static void title_paint(int id, float t)
 
 static void title_timer(int id, float dt)
 {
-    float g[3] = { 0.0f, -9.8f, 0.0f };
+    float g[3] = { 0.f, 0.f, 0.f };
 
     game_step(g, dt);
     game_set_fly(fcosf(time_state() / 10.f));
@@ -873,8 +873,6 @@ static int stroke_enter(void)
     if (paused)
         paused = 0;
 
-    game_set_played(1);
-
     return 0;
 }
 
@@ -893,7 +891,7 @@ static void stroke_paint(int id, float t)
 
 static void stroke_timer(int id, float dt)
 {
-    float g[3] = { 0.0f, -9.8f, 0.0f };
+    float g[3] = { 0.f, 0.f, 0.f };
 
     float k;
 
@@ -1004,7 +1002,7 @@ static int goal_enter(void)
     if (paused)
         paused = 0;
     else
-        hole_goal(0);
+        hole_goal();
 
     hud_init();
 
@@ -1091,7 +1089,7 @@ static void stop_paint(int id, float t)
 
 static void stop_timer(int id, float dt)
 {
-    float g[3] = { 0.0f, -9.8f, 0.0f };
+    float g[3] = { 0.f, 0.f, 0.f };
 
     game_update_view(dt);
     game_step(g, dt);
@@ -1218,8 +1216,6 @@ static int score_enter(void)
     if (paused)
         paused = 0;
 
-    game_set_played(0);
-
     return score_card(_("Scores"), gui_yel, gui_red);
 }
 
diff --git a/putt/st_balt.c b/putt/st_balt.c
deleted file mode 100755 (executable)
index 78838e5..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2003 Robert Kooima - 2008 Byron Johnson
- * Part of the Neverball Project http://icculus.org/neverball/
- *
- * NEVERBALL is  free software; you can redistribute  it and/or modify
- * it under the  terms of the GNU General  Public License as published
- * by the Free  Software Foundation; either version 2  of the License,
- * or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
- * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
- * General Public License for more details.
- */
-
-
-#include "gui.h"
-#include "back.h"
-#include "part.h"
-#include "game.h"
-#include "audio.h"
-#include "config.h"
-
-#include "st_balt.h"
-
-extern struct state st_conf;
-extern struct state st_null;
-
-/*---------------------------------------------------------------------------*/
-
-enum {
-    BALT_BACK = 1,
-    BALT_GOLF,
-    BALT_BILL,
-    BALT_CRAZ
-};
-
-static int balt_action(int i)
-{
-    int r = 1;
-
-    audio_play(AUD_MENU, 1.0f);
-
-    switch (i)
-    {
-    case BALT_BACK:
-        goto_state(&st_conf);
-        break;
-
-    case BALT_GOLF:
-        goto_state(&st_null);
-        config_set_s(CONFIG_BALL_GAMMA, "0.78");
-        goto_state(&st_balt);
-        break;
-
-    case BALT_BILL:
-        goto_state(&st_null);
-        config_set_s(CONFIG_BALL_GAMMA, "1.00");
-        goto_state(&st_balt);
-        break;
-
-    case BALT_CRAZ:
-        goto_state(&st_null);
-        config_set_s(CONFIG_BALL_GAMMA, "1.50");
-        goto_state(&st_balt);
-        break;
-
-    default:
-        break;
-    }
-
-    return r;
-}
-
-static int balt_enter(void)
-{
-    int id, jd;
-
-    char gamma[MAXNAM];
-
-    config_get_s(CONFIG_BALL_GAMMA, gamma, MAXNAM);
-
-    back_init("back/gui.png", config_get_d(CONFIG_GEOMETRY));
-
-    if ((id = gui_vstack(0)))
-    {
-        if ((jd = gui_harray(id)))
-        {
-            gui_space(jd);
-            gui_space(jd);
-            gui_start(jd, _("Back"),                     GUI_SML, BALT_BACK, 0);
-        }
-
-        gui_space(id);
-        gui_space(id);
-
-        if ((jd = gui_harray(id)))
-        {
-            gui_state(jd, _("Billiards"),                GUI_SML, BALT_BILL,
-                          strcmp(gamma, "1.00")  == 0 ||
-                          strcmp(gamma, "1.0")   == 0);
-            gui_state(jd, _("Golf Balls"),               GUI_SML, BALT_GOLF,
-                          strcmp(gamma, "0.78")  == 0);
-        }
-
-        if ((jd = gui_harray(id)))
-        {
-            gui_state(jd, _("Crazy Balls"),              GUI_SML, BALT_CRAZ,
-                          strcmp(gamma, "1.50") == 0 ||
-                          strcmp(gamma, "1.5")  == 0);
-        }
-
-        gui_layout(id, 0, 0);
-    }
-
-    audio_music_fade_to(0.5f, "bgm/inter.ogg");
-
-    return id;
-}
-
-static void balt_leave(int id)
-{
-    back_free();
-    gui_delete(id);
-}
-
-static void balt_paint(int id, float st)
-{
-    config_push_persp((float) config_get_d(CONFIG_VIEW_FOV), 0.1f, FAR_DIST);
-    {
-        back_draw(0);
-    }
-    config_pop_matrix();
-    gui_paint(id);
-}
-
-static void balt_timer(int id, float dt)
-{
-    gui_timer(id, dt);
-}
-
-static void balt_point(int id, int x, int y, int dx, int dy)
-{
-    gui_pulse(gui_point(id, x, y), 1.2f);
-}
-
-static void balt_stick(int id, int a, int v)
-{
-    if (config_tst_d(CONFIG_JOYSTICK_AXIS_X, a))
-        gui_pulse(gui_stick(id, v, 0), 1.2f);
-    if (config_tst_d(CONFIG_JOYSTICK_AXIS_Y, a))
-        gui_pulse(gui_stick(id, 0, v), 1.2f);
-}
-
-static int balt_click(int b, int d)
-{
-    if (b < 0 && d == 1)
-        return balt_action(gui_token(gui_click()));
-    return 1;
-}
-
-static int balt_keybd(int c, int d)
-{
-    return (d && c == SDLK_ESCAPE) ? goto_state(&st_conf) : 1;
-}
-
-static int balt_buttn(int b, int d)
-{
-    if (d)
-    {
-        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_A, b))
-            return balt_action(gui_token(gui_click()));
-        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_B, b))
-            return goto_state(&st_conf);
-        if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
-            return goto_state(&st_conf);
-    }
-    return 1;
-}
-
-/*---------------------------------------------------------------------------*/
-
-
-struct state st_balt = {
-    balt_enter,
-    balt_leave,
-    balt_paint,
-    balt_timer,
-    balt_point,
-    balt_stick,
-    NULL,
-    balt_click,
-    balt_keybd,
-    balt_buttn,
-    1, 0
-};
-
diff --git a/putt/st_balt.h b/putt/st_balt.h
deleted file mode 100755 (executable)
index 62ab748..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef ST_BALT_H
-#define ST_BALT_H
-
-#include "state.h"
-
-extern struct state st_balt;
-
-#endif
index 877191d..fe8b6a0 100644 (file)
@@ -25,7 +25,6 @@
 #include "st_conf.h"
 #include "st_all.h"
 #include "st_resol.h"
-#include "st_balt.h"
 
 /*---------------------------------------------------------------------------*/
 
@@ -39,10 +38,7 @@ enum {
     CONF_SHDON,
     CONF_SHDOF,
     CONF_BACK,
-    CONF_RESOL,
-    CONF_BALT,
-    CONF_BCLON,
-    CONF_BCLOF
+    CONF_RESOL
 };
 
 static int music_id[11];
@@ -116,22 +112,6 @@ static int conf_action(int i)
         goto_state(&st_resol);
         break;
 
-    case CONF_BALT:
-        goto_state(&st_balt);
-        break;
-
-    case CONF_BCLON:
-        goto_state(&st_null);
-        config_set_d(CONFIG_BALL_COLLISIONS, 1);
-        goto_state(&st_conf);
-        break;
-
-    case CONF_BCLOF:
-        goto_state(&st_null);
-        config_set_d(CONFIG_BALL_COLLISIONS, 0);
-        goto_state(&st_conf);
-        break;
-
     default:
         if (100 <= i && i <= 110)
         {
@@ -171,39 +151,18 @@ static int conf_enter(void)
     if ((id = gui_vstack(0)))
     {
         int f = config_get_d(CONFIG_FULLSCREEN);
-        int c = config_get_d(CONFIG_BALL_COLLISIONS);
         int t = config_get_d(CONFIG_TEXTURES);
         int g = config_get_d(CONFIG_GEOMETRY);
         int h = config_get_d(CONFIG_SHADOW);
         int s = config_get_d(CONFIG_SOUND_VOLUME);
         int m = config_get_d(CONFIG_MUSIC_VOLUME);
 
-        char gamma[MAXNAM];
-
         char resolution[20];
 
-        char balt[22];
-
-        config_get_s(CONFIG_BALL_GAMMA, gamma, MAXNAM);
-
         sprintf(resolution, "%d x %d",
                 config_get_d(CONFIG_WIDTH),
                 config_get_d(CONFIG_HEIGHT));
 
-        if (strcmp(gamma, "0.78") == 0)
-                     strcpy(balt, "Golf Balls");
-
-        else if (strcmp(gamma, "1.00") == 0 ||
-                     strcmp(gamma, "1.0") == 0)
-            strcpy(balt, "Billiards");
-
-        else if (strcmp(gamma, "1.50") == 0 ||
-                     strcmp(gamma, "1.5") == 0)
-            strcpy(balt, "Crazy Balls");
-
-        else
-            sprintf(balt, "Custom");
-
         if ((jd = gui_harray(id)))
         {
             gui_label(jd, _("Options"), GUI_SML, GUI_ALL, 0, 0);
@@ -225,7 +184,7 @@ static int conf_enter(void)
         if ((jd = gui_harray(id)) &&
             (kd = gui_harray(jd)))
         {
-            gui_state(kd, resolution,      GUI_SML, CONF_RESOL, 0);
+            gui_state(kd, resolution, GUI_SML, CONF_RESOL, 0);
 
             gui_label(jd, _("Resolution"), GUI_SML, GUI_ALL, 0, 0);
         }
@@ -235,55 +194,28 @@ static int conf_enter(void)
         if ((jd = gui_harray(id)) &&
             (kd = gui_harray(jd)))
         {
-            gui_state(kd, _("Off"),        GUI_SML, CONF_BCLOF, (c == 0));
-            gui_state(kd, _("On"),         GUI_SML, CONF_BCLON, (c == 1));
-
-            gui_label(jd, _("Ball Collisions"), GUI_SML, GUI_ALL, 0, 0);
-        }
-
-        if ((jd = gui_harray(id)) &&
-            (kd = gui_harray(jd)))
-        {
-            if (c == 1)
-            {
-                gui_state(kd, balt,            GUI_SML, CONF_BALT, 0);
-                gui_space(jd);
-            }
-            else
-            {
-                gui_space(kd);
-                gui_space(jd);
-                gui_space(id);
-            }
-        }
-
-        gui_space(id);
-
-        if ((jd = gui_harray(id)) &&
-            (kd = gui_harray(jd)))
-        {
-            gui_state(kd, _("Low"),        GUI_SML, CONF_TEXLO, (t == 2));
-            gui_state(kd, _("High"),       GUI_SML, CONF_TEXHI, (t == 1));
+            gui_state(kd, _("Low"),  GUI_SML, CONF_TEXLO, (t == 2));
+            gui_state(kd, _("High"), GUI_SML, CONF_TEXHI, (t == 1));
 
-            gui_label(jd, _("Textures"),   GUI_SML, GUI_ALL, 0, 0);
+            gui_label(jd, _("Textures"), GUI_SML, GUI_ALL, 0, 0);
         }
 
         if ((jd = gui_harray(id)) &&
             (kd = gui_harray(jd)))
         {
-            gui_state(kd, _("Low"),        GUI_SML, CONF_GEOLO, (g == 0));
-            gui_state(kd, _("High"),       GUI_SML, CONF_GEOHI, (g == 1));
+            gui_state(kd, _("Low"),  GUI_SML, CONF_GEOLO, (g == 0));
+            gui_state(kd, _("High"), GUI_SML, CONF_GEOHI, (g == 1));
 
-            gui_label(jd, _("Geometry"),   GUI_SML, GUI_ALL, 0, 0);
+            gui_label(jd, _("Geometry"), GUI_SML, GUI_ALL, 0, 0);
         }
 
         if ((jd = gui_harray(id)) &&
             (kd = gui_harray(jd)))
         {
-            gui_state(kd, _("Off"),        GUI_SML, CONF_SHDOF, (h == 0));
-            gui_state(kd, _("On"),         GUI_SML, CONF_SHDON, (h == 1));
+            gui_state(kd, _("Off"),  GUI_SML, CONF_SHDOF, (h == 0));
+            gui_state(kd, _("On"),   GUI_SML, CONF_SHDON, (h == 1));
 
-            gui_label(jd, _("Shadow"),     GUI_SML, GUI_ALL, 0, 0);
+            gui_label(jd, _("Shadow"), GUI_SML, GUI_ALL, 0, 0);
         }
 
         gui_space(id);
@@ -404,7 +336,6 @@ static int null_enter(void)
     jump_free();
     flag_free();
     mark_free();
-    oldball_free();
     ball_free();
     shad_free();
 
@@ -417,7 +348,6 @@ static void null_leave(int id)
 
     shad_init();
     ball_init();
-    oldball_init(g);
     mark_init(g);
     flag_init(g);
     jump_init(g);
index 1835d5d..5010500 100644 (file)
 #include "glext.h"
 #include "config.h"
 #include "solid_gl.h"
-#include "image.h"
 
 /*---------------------------------------------------------------------------*/
 
-#define IMG_DEFAULT "ball/default.png"
-#define IMG_ARBBALL "ball/arbball.png"
-
 static int has_solid = 0;
 static int has_inner = 0;
 static int has_outer = 0;
@@ -48,308 +44,6 @@ static float solid_alpha;
 static float inner_alpha;
 static float outer_alpha;
 
-static GLuint oldball_list;
-static GLuint oldball_text;
-static GLuint arbball_list;
-static GLuint arbball_text;
-
-/*---------------------------------------------------------------------------*/
-
-/* These are the faces of an octahedron in positive longitude/latitude. */
-
-static float oldball_octahedron[8][3][2] = {
-    {{   0.0f,  90.0f }, {   0.0f, 0.0f }, {  90.0f, 0.0f }},
-    {{  90.0f,  90.0f }, {  90.0f, 0.0f }, { 180.0f, 0.0f }},
-    {{ 180.0f,  90.0f }, { 180.0f, 0.0f }, { 270.0f, 0.0f }},
-    {{ 270.0f,  90.0f }, { 270.0f, 0.0f }, { 360.0f, 0.0f }},
-    {{   0.0f, -90.0f }, {  90.0f, 0.0f }, {   0.0f, 0.0f }},
-    {{  90.0f, -90.0f }, { 180.0f, 0.0f }, {  90.0f, 0.0f }},
-    {{ 180.0f, -90.0f }, { 270.0f, 0.0f }, { 180.0f, 0.0f }},
-    {{ 270.0f, -90.0f }, { 360.0f, 0.0f }, { 270.0f, 0.0f }},
-};
-
-static void oldball_midpoint(float *P, const float *A, const float *B)
-{
-    float D[2];
-
-    /* The haversine midpoint method. */
-
-    D[0] = fcosf(B[1]) * fcosf(B[0] - A[0]);
-    D[1] = fcosf(B[1]) * fsinf(B[0] - A[0]);
-
-    P[0] = A[0] + fatan2f(D[1], fcosf(A[1]) + D[0]);
-
-    P[1] = fatan2f(fsinf(A[1]) +
-                   fsinf(B[1]),
-                   fsqrtf((fcosf(A[1]) + D[0]) *
-                          (fcosf(A[1]) + D[0]) + D[1] * D[1])); 
-}
-
-static void oldball_vertex(const float *p)
-{
-    /* Draw a vertex with normal and texture coordinate at the given lon/lat. */
-
-    const float x = fsinf(p[0]) * fcosf(p[1]);
-    const float y =               fsinf(p[1]);
-    const float z = fcosf(p[0]) * fcosf(p[1]);
-
-    glTexCoord2f((+p[0]               ) / V_RAD(360.0f),
-                 (-p[1] + V_RAD(90.0f)) / V_RAD(180.0f));
-
-    glNormal3f(x, y, z);
-    glVertex3f(x, y, z);
-}
-
-static void oldball_subdiv(const float *a,
-                        const float *b,
-                        const float *c, int D)
-{
-    if (D > 0)
-    {
-        /* Recursively subdivide the given triangle. */
-
-        float d[2];
-        float e[2];
-        float f[2];
-
-        oldball_midpoint(d, a, b);
-        oldball_midpoint(e, b, c);
-        oldball_midpoint(f, c, a);
-
-        oldball_subdiv(a, d, f, D - 1);
-        oldball_subdiv(d, b, e, D - 1);
-        oldball_subdiv(f, e, c, D - 1);
-        oldball_subdiv(d, e, f, D - 1);
-    }
-    else
-    {
-        /* Draw the given triangle. */
-
-        oldball_vertex(a);
-        oldball_vertex(b);
-        oldball_vertex(c);
-    }
-}
-
-void oldball_init(int b)
-{
-    char name[MAXSTR];
-
-    strncpy(name, IMG_DEFAULT, MAXSTR - 12);
-
-    if ((oldball_text = make_image_from_file(name)))
-    {
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-    }
-
-    oldball_list = glGenLists(1);
-
-    glNewList(oldball_list, GL_COMPILE);
-    {
-#if 1
-        int i, d = b ? 4 : 3;
-
-        glBegin(GL_TRIANGLES);
-        {
-            for (i = 0; i < 8; ++i)
-            {
-                float a[2];
-                float b[2];
-                float c[2];
-
-                a[0] = V_RAD(oldball_octahedron[i][0][0]);
-                a[1] = V_RAD(oldball_octahedron[i][0][1]);
-
-                b[0] = V_RAD(oldball_octahedron[i][1][0]);
-                b[1] = V_RAD(oldball_octahedron[i][1][1]);
-
-                c[0] = V_RAD(oldball_octahedron[i][2][0]);
-                c[1] = V_RAD(oldball_octahedron[i][2][1]);
-
-                oldball_subdiv(a, b, c, d);
-            }
-        }
-        glEnd();
-#else
-        int i, slices = b ? 32 : 16;
-        int j, stacks = b ? 16 :  8;
-
-        for (i = 0; i < stacks; i++)
-        {
-            float k0 = (float)  i      / stacks;
-            float k1 = (float) (i + 1) / stacks;
-
-            float s0 = fsinf(V_PI * (k0 - 0.5));
-            float c0 = fcosf(V_PI * (k0 - 0.5));
-            float s1 = fsinf(V_PI * (k1 - 0.5));
-            float c1 = fcosf(V_PI * (k1 - 0.5));
-
-            glBegin(GL_QUAD_STRIP);
-            {
-                for (j = 0; j <= slices; j++)
-                {
-                    float k = (float) j / slices;
-                    float s = fsinf(V_PI * k * 2.0);
-                    float c = fcosf(V_PI * k * 2.0);
-
-                    glTexCoord2f(k, k0);
-                    glNormal3f(s * c0, c * c0, s0);
-                    glVertex3f(s * c0, c * c0, s0);
-
-                    glTexCoord2f(k, k1);
-                    glNormal3f(s * c1, c * c1, s1);
-                    glVertex3f(s * c1, c * c1, s1);
-                }
-            }
-            glEnd();
-        }
-#endif
-    }
-    glEndList();
-
-    strncpy(name, IMG_ARBBALL, MAXSTR - 12);
-
-    if ((arbball_text = make_image_from_file(name)))
-    {
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-    }
-
-    arbball_list = glGenLists(1);
-
-    glNewList(arbball_list, GL_COMPILE);
-    {
-#if 1
-        int i, d = b ? 4 : 3;
-
-        glBegin(GL_TRIANGLES);
-        {
-            for (i = 0; i < 8; ++i)
-            {
-                float a[2];
-                float b[2];
-                float c[2];
-
-                a[0] = V_RAD(oldball_octahedron[i][0][0]);
-                a[1] = V_RAD(oldball_octahedron[i][0][1]);
-
-                b[0] = V_RAD(oldball_octahedron[i][1][0]);
-                b[1] = V_RAD(oldball_octahedron[i][1][1]);
-
-                c[0] = V_RAD(oldball_octahedron[i][2][0]);
-                c[1] = V_RAD(oldball_octahedron[i][2][1]);
-
-                oldball_subdiv(a, b, c, d);
-            }
-        }
-        glEnd();
-#else
-        int i, slices = b ? 32 : 16;
-        int j, stacks = b ? 16 :  8;
-
-        for (i = 0; i < stacks; i++)
-        {
-            float k0 = (float)  i      / stacks;
-            float k1 = (float) (i + 1) / stacks;
-
-            float s0 = fsinf(V_PI * (k0 - 0.5));
-            float c0 = fcosf(V_PI * (k0 - 0.5));
-            float s1 = fsinf(V_PI * (k1 - 0.5));
-            float c1 = fcosf(V_PI * (k1 - 0.5));
-
-            glBegin(GL_QUAD_STRIP);
-            {
-                for (j = 0; j <= slices; j++)
-                {
-                    float k = (float) j / slices;
-                    float s = fsinf(V_PI * k * 2.0);
-                    float c = fcosf(V_PI * k * 2.0);
-
-                    glTexCoord2f(k, k0);
-                    glNormal3f(s * c0, c * c0, s0);
-                    glVertex3f(s * c0, c * c0, s0);
-
-                    glTexCoord2f(k, k1);
-                    glNormal3f(s * c1, c * c1, s1);
-                    glVertex3f(s * c1, c * c1, s1);
-                }
-            }
-            glEnd();
-        }
-#endif
-    }
-    glEndList();
-}
-
-void oldball_free(void)
-{
-    if (glIsList(oldball_list))
-        glDeleteLists(oldball_list, 1);
-
-    if (glIsTexture(oldball_text))
-        glDeleteTextures(1, &oldball_text);
-
-    if (glIsList(arbball_list))
-        glDeleteLists(arbball_list, 1);
-
-    if (glIsTexture(arbball_text))
-        glDeleteTextures(1, &arbball_text);
-
-    oldball_list = 0;
-    oldball_text = 0;
-
-    arbball_list = 0;
-    arbball_text = 0;
-}
-
-void oldball_draw(int arb)
-{
-    static const float a[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
-    static const float s[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
-    static const float e[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
-    static const float h[1] = { 20.0f };
-
-    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);
-
-    glEnable(GL_COLOR_MATERIAL);
-    {
-        glBindTexture(GL_TEXTURE_2D, (arb) ? (arbball_text) : (oldball_text));
-
-        /* Render the ball back to front in case it is translucent. */
-
-        glDepthMask(GL_FALSE);
-        {
-            glCullFace(GL_FRONT);
-            glCallList((arb) ? (arbball_list) : (oldball_list));
-            glCullFace(GL_BACK);
-            glCallList(oldball_list);
-        }
-        glDepthMask(GL_TRUE);
-
-        /* Render the ball into the depth buffer. */
-
-        glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
-        {
-            glCallList((arb) ? (arbball_list) : (oldball_list));
-        }
-        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-
-        /* Ensure the ball is visible even when obscured by geometry. */
-
-        glDisable(GL_DEPTH_TEST);
-        {
-            glColor4f(1.0f, 1.0f, 1.0f, 0.1f);
-            glCallList((arb) ? (arbball_list) : (oldball_list));
-        }
-        glEnable(GL_DEPTH_TEST);
-    }
-    glDisable(GL_COLOR_MATERIAL);
-}
-
 /*---------------------------------------------------------------------------*/
 
 #define SET(B, v, b) ((v) ? ((B) | (b)) : ((B) & ~(b)))
@@ -385,28 +79,13 @@ void ball_init(void)
 {
     int T = config_get_d(CONFIG_TEXTURES);
 
-    char ball_file[PATHMAX];
     char solid_file[PATHMAX];
     char inner_file[PATHMAX];
     char outer_file[PATHMAX];
 
-    config_get_s(CONFIG_BALL, ball_file, PATHMAX / 2 - 12);
-
-    strncpy(solid_file, "ball/", PATHMAX);
-    strncpy(inner_file, "ball/", PATHMAX);
-    strncpy(outer_file, "ball/", PATHMAX);
-
-    strcat(solid_file, ball_file);
-    strcat(inner_file, ball_file);
-    strcat(outer_file, ball_file);
-
-    strcat(solid_file, "/");
-    strcat(inner_file, "/");
-    strcat(outer_file, "/");
-
-    strcat(solid_file, ball_file);
-    strcat(inner_file, ball_file);
-    strcat(outer_file, ball_file);
+    config_get_s(CONFIG_BALL, solid_file, PATHMAX - 12);
+    config_get_s(CONFIG_BALL, inner_file, PATHMAX - 12);
+    config_get_s(CONFIG_BALL, outer_file, PATHMAX - 12);
 
     strcat(solid_file, "-solid.sol");
     strcat(inner_file, "-inner.sol");
index 2c4b69e..d3a51cc 100644 (file)
 
 void ball_init(void);
 void ball_free(void);
-void oldball_init(int);
-void oldball_free(void);
 void ball_draw(const float *,
                const float *,
                const float *, float);
-void oldball_draw(int);
 
 /*---------------------------------------------------------------------------*/
 
index 675fcc4..b37a9f0 100644 (file)
@@ -118,9 +118,6 @@ void config_init(void)
     config_set_d(CONFIG_CHEAT,                DEFAULT_CHEAT);
     config_set_d(CONFIG_STATS,                DEFAULT_STATS);
     config_set_d(CONFIG_UNIFORM,              DEFAULT_UNIFORM);
-    config_set_d(CONFIG_LOCK_GOALS,           DEFAULT_LOCK_GOALS);
-    config_set_d(CONFIG_BALL_COLLISIONS,      DEFAULT_BALL_COLLISIONS);
-    config_set_s(CONFIG_BALL_GAMMA,           DEFAULT_BALL_GAMMA);
     config_set_d(CONFIG_KEY_FORWARD,          DEFAULT_KEY_FORWARD);
     config_set_d(CONFIG_KEY_BACKWARD,         DEFAULT_KEY_BACKWARD);
     config_set_d(CONFIG_KEY_LEFT,             DEFAULT_KEY_LEFT);
@@ -253,20 +250,12 @@ void config_load(void)
                 else if (strcmp(key, "wiimote_addr") == 0)
                     config_set_s(CONFIG_WIIMOTE_ADDR, val);
 
-                else if (strcmp(key, "cheat")      == 0)
-                    config_set_d(CONFIG_CHEAT,   atoi(val));
-                else if (strcmp(key, "stats")      == 0)
-                    config_set_d(CONFIG_STATS,   atoi(val));
-                else if (strcmp(key, "uniform")    == 0)
+                else if (strcmp(key, "cheat")   == 0)
+                    config_set_d(CONFIG_CHEAT, atoi(val));
+                else if (strcmp(key, "stats")   == 0)
+                    config_set_d(CONFIG_STATS, atoi(val));
+                else if (strcmp(key, "uniform") == 0)
                     config_set_d(CONFIG_UNIFORM, atoi(val));
-
-                else if (strcmp(key, "lock_goals") == 0)
-                    config_set_d(CONFIG_LOCK_GOALS, atoi(val));
-
-                else if (strcmp(key, "ball_collisions") == 0)
-                    config_set_d(CONFIG_BALL_COLLISIONS, atoi(val));
-                else if (strcmp(key, "gamma") == 0)
-                    config_set_s(CONFIG_BALL_GAMMA, val);
             }
 
         fclose(fp);
@@ -386,19 +375,18 @@ void config_save(void)
                 SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_RESTART]));
 
         if (strlen(option_s[CONFIG_PLAYER]) > 0)
-            fprintf(fp, "player               %s\n", option_s[CONFIG_PLAYER]);
+            fprintf(fp, "player       %s\n", option_s[CONFIG_PLAYER]);
         if (strlen(option_s[CONFIG_BALL]) > 0)
-            fprintf(fp, "ball_file            %s\n", option_s[CONFIG_BALL]);
+            fprintf(fp, "ball_file    %s\n", option_s[CONFIG_BALL]);
         if (strlen(option_s[CONFIG_WIIMOTE_ADDR]) > 0)
-            fprintf(fp, "wiimote_addr         %s\n", option_s[CONFIG_WIIMOTE_ADDR]);
-
-        fprintf(fp, "stats                %d\n", option_d[CONFIG_STATS]);
-        fprintf(fp, "uniform              %d\n", option_d[CONFIG_UNIFORM]);
-        fprintf(fp, "lock_goals           %d\n", option_d[CONFIG_LOCK_GOALS]);
-        fprintf(fp, "ball_collisions      %d\n", option_d[CONFIG_BALL_COLLISIONS]);
-
-        if (strlen(option_s[CONFIG_BALL_GAMMA]) > 0)
-            fprintf(fp, "gamma                %s\n", option_s[CONFIG_BALL_GAMMA]);
+            fprintf(fp, "wiimote_addr %s\n", option_s[CONFIG_WIIMOTE_ADDR]);
+
+        fprintf(fp, "stats                %d\n",
+                option_d[CONFIG_STATS]);
+        fprintf(fp, "uniform              %d\n",
+                option_d[CONFIG_UNIFORM]);
+        if (config_cheat())
+            fprintf(fp, "cheat                %d\n", option_d[CONFIG_CHEAT]);
 
         fclose(fp);
     }
index c4e7df4..7d7ac8e 100644 (file)
@@ -88,8 +88,6 @@ enum {
     CONFIG_CHEAT,
     CONFIG_STATS,
     CONFIG_UNIFORM,
-    CONFIG_LOCK_GOALS,
-    CONFIG_BALL_COLLISIONS,
 
     CONFIG_OPTION_D_COUNT
 };
@@ -98,7 +96,6 @@ enum {
     CONFIG_PLAYER,
     CONFIG_BALL,
     CONFIG_WIIMOTE_ADDR,
-    CONFIG_BALL_GAMMA,
 
     CONFIG_OPTION_S_COUNT
 };
@@ -155,7 +152,7 @@ enum {
 #define DEFAULT_ROTATE_SLOW          100
 #define DEFAULT_ROTATE_FAST          200
 #define DEFAULT_PLAYER               ""
-#define DEFAULT_BALL                 "basic-ball"
+#define DEFAULT_BALL                 "ball/basic-ball/basic-ball"
 #define DEFAULT_CHEAT                0
 #define DEFAULT_KEY_FORWARD          SDLK_UP
 #define DEFAULT_KEY_BACKWARD         SDLK_DOWN
@@ -165,9 +162,6 @@ enum {
 #define DEFAULT_KEY_RESTART          SDLK_r
 #define DEFAULT_STATS                0
 #define DEFAULT_UNIFORM              0
-#define DEFAULT_LOCK_GOALS           0 
-#define DEFAULT_BALL_COLLISIONS      0
-#define DEFAULT_BALL_GAMMA           "0.78"
 
 /*---------------------------------------------------------------------------*/
 
index 4559838..680911b 100644 (file)
@@ -61,7 +61,6 @@ static int debug_output = 0;
 #define MAXX    1024
 #define MAXR    2048
 #define MAXU    1024
-#define MAXY    1024
 #define MAXW    1024
 #define MAXD    1024
 #define MAXA    16384
@@ -154,11 +153,6 @@ static int incu(struct s_file *fp)
     return (fp->uc < MAXU) ? fp->uc++ : overflow("ball");
 }
 
-static int incy(struct s_file *fp)
-{
-    return (fp->yc < MAXY) ? fp->yc++ : overflow("ball");
-}
-
 static int incw(struct s_file *fp)
 {
     return (fp->wc < MAXW) ? fp->wc++ : overflow("view");
@@ -192,7 +186,6 @@ static void init_file(struct s_file *fp)
     fp->xc = 0;
     fp->rc = 0;
     fp->uc = 0;
-    fp->yc = 0;
     fp->wc = 0;
     fp->dc = 0;
     fp->ac = 0;
@@ -214,7 +207,6 @@ static void init_file(struct s_file *fp)
     fp->xv = (struct s_swch *) calloc(MAXX, sizeof (struct s_swch));
     fp->rv = (struct s_bill *) calloc(MAXR, sizeof (struct s_bill));
     fp->uv = (struct s_ball *) calloc(MAXU, sizeof (struct s_ball));
-    fp->yv = (struct s_ball *) calloc(MAXY, sizeof (struct s_ball));
     fp->wv = (struct s_view *) calloc(MAXW, sizeof (struct s_view));
     fp->dv = (struct s_dict *) calloc(MAXD, sizeof (struct s_dict));
     fp->av = (char          *) calloc(MAXA, sizeof (char));
@@ -1212,9 +1204,6 @@ static void make_ball(struct s_file *fp,
     up->p[1] = 0.0f;
     up->p[2] = 0.0f;
     up->r    = 0.25f;
-    up->m    = 1;
-    up->n    = 0;
-    up->c    = 0;
 
     for (i = 0; i < c; i++)
     {
@@ -1231,65 +1220,11 @@ static void make_ball(struct s_file *fp,
             up->p[1] = +(float) (z - 24) / SCALE;
             up->p[2] = -(float) (y)      / SCALE;
         }
-
-        if (strcmp(k[i], "mobile") == 0)
-            sscanf(v[i], "%d", &up->m);
-
-        if (strcmp(k[i], "return") == 0)
-            sscanf(v[i], "%d", &up->n);
-
-        if (strcmp(k[i], "collisions") == 0)
-            sscanf(v[i], "%d", &up->c);
     }
 
     up->p[1] += up->r + SMALL;
 }
 
-static void make_abal(struct s_file *fp,
-                      char k[][MAXSTR],
-                      char v[][MAXSTR], int c)
-{
-    int i, yi = incy(fp);
-
-    struct s_ball *yp = fp->yv + yi;
-
-    yp->p[0] = 0.0f;
-    yp->p[1] = 0.0f;
-    yp->p[2] = 0.0f;
-    yp->r    = 0.25f;
-    yp->m    = 1;
-    yp->n    = 0;
-    yp->c    = 0;
-
-    for (i = 0; i < c; i++)
-    {
-        if (strcmp(k[i], "radius") == 0)
-            sscanf(v[i], "%f", &yp->r);
-
-        if (strcmp(k[i], "origin") == 0)
-        {
-            int x = 0, y = 0, z = 0;
-
-            sscanf(v[i], "%d %d %d", &x, &y, &z);
-
-            yp->p[0] = +(float) (x)      / SCALE;
-            yp->p[1] = +(float) (z - 24) / SCALE;
-            yp->p[2] = -(float) (y)      / SCALE;
-        }
-
-        if (strcmp(k[i], "mobile") == 0)
-            sscanf(v[i], "%d", &yp->m);
-
-        if (strcmp(k[i], "return") == 0)
-            sscanf(v[i], "%d", &yp->n);
-
-        if (strcmp(k[i], "collisions") == 0)
-            sscanf(v[i], "%d", &yp->c);
-    }
-
-    yp->p[1] += yp->r + SMALL;
-}
-
 /*---------------------------------------------------------------------------*/
 
 static void read_ent(struct s_file *fp, FILE *fin)
@@ -1319,7 +1254,6 @@ static void read_ent(struct s_file *fp, FILE *fin)
     if (!strcmp(v[i], "info_null"))                make_bill(fp, k, v, c);
     if (!strcmp(v[i], "path_corner"))              make_path(fp, k, v, c);
     if (!strcmp(v[i], "info_player_start"))        make_ball(fp, k, v, c);
-    if (!strcmp(v[i], "info_notnull"))             make_abal(fp, k, v, c);
     if (!strcmp(v[i], "info_player_intermission")) make_view(fp, k, v, c);
     if (!strcmp(v[i], "info_player_deathmatch"))   make_goal(fp, k, v, c);
     if (!strcmp(v[i], "target_teleporter"))        make_jump(fp, k, v, c);
@@ -2379,10 +2313,10 @@ static void dump_file(struct s_file *p, const char *name)
            name, n, m, c,
 #endif
            name, n, c,
-           p->mc, p->vc,         p->ec, p->sc, p->tc,
-           p->gc, p->lc,         p->pc, p->nc, p->bc,
-           p->hc, p->zc,         p->wc, p->jc, p->xc,
-           p->rc, p->uc + p->yc, p->ac, p->dc, p->ic);
+           p->mc, p->vc, p->ec, p->sc, p->tc,
+           p->gc, p->lc, p->pc, p->nc, p->bc,
+           p->hc, p->zc, p->wc, p->jc, p->xc,
+           p->rc, p->uc, p->ac, p->dc, p->ic);
 }
 
 int main(int argc, char *argv[])
index 18f9a2a..b7de4b1 100644 (file)
 #include "solid.h"
 #include "base_config.h"
 #include "binary.h"
-#include "config.h"
 
 #define MAGIC       0x4c4f53af
-#define SOL_VERSION 7
+#define SOL_VERSION 6
 
 #define LARGE 1.0e+5f
 #define SMALL 1.0e-3f
 
-static int ball_collision_flag = 0;
-
 /*---------------------------------------------------------------------------*/
 
 static float erp(float t)
@@ -239,11 +236,6 @@ static void sol_load_ball(FILE *fin, struct s_ball *bp)
 {
     get_array(fin,  bp->p, 3);
     get_float(fin, &bp->r);
-    get_index(fin, &bp->m);
-    get_index(fin, &bp->n);
-    get_index(fin, &bp->c);
-
-    v_cpy(bp->O, bp->p);
 
     bp->e[0][0] = bp->E[0][0] = 1.0f;
     bp->e[0][1] = bp->E[0][1] = 0.0f;
@@ -300,7 +292,6 @@ static int sol_load_file(FILE *fin, struct s_file *fp)
     get_index(fin, &fp->xc);
     get_index(fin, &fp->rc);
     get_index(fin, &fp->uc);
-    get_index(fin, &fp->yc);
     get_index(fin, &fp->wc);
     get_index(fin, &fp->ic);
 
@@ -338,8 +329,6 @@ static int sol_load_file(FILE *fin, struct s_file *fp)
         fp->rv = (struct s_bill *) calloc(fp->rc, sizeof (struct s_bill));
     if (fp->uc)
         fp->uv = (struct s_ball *) calloc(fp->uc, sizeof (struct s_ball));
-    if (fp->yc)
-        fp->yv = (struct s_ball *) calloc(fp->yc, sizeof (struct s_ball));
     if (fp->wc)
         fp->wv = (struct s_view *) calloc(fp->wc, sizeof (struct s_view));
     if (fp->dc)
@@ -367,7 +356,6 @@ static int sol_load_file(FILE *fin, struct s_file *fp)
     for (i = 0; i < fp->xc; i++) sol_load_swch(fin, fp->xv + i);
     for (i = 0; i < fp->rc; i++) sol_load_bill(fin, fp->rv + i);
     for (i = 0; i < fp->uc; i++) sol_load_ball(fin, fp->uv + i);
-    for (i = 0; i < fp->yc; i++) sol_load_ball(fin, fp->yv + i);
     for (i = 0; i < fp->wc; i++) sol_load_view(fin, fp->wv + i);
     for (i = 0; i < fp->ic; i++) get_index(fin, fp->iv + i);
 
@@ -405,11 +393,10 @@ static int sol_load_head(FILE *fin, struct s_file *fp)
     get_index(fin, &fp->xc);
     get_index(fin, &fp->rc);
     get_index(fin, &fp->uc);
-    get_index(fin, &fp->yc);
     get_index(fin, &fp->wc);
     get_index(fin, &fp->ic);
 #endif
-    fseek(fin, 19 * 4, SEEK_CUR);
+    fseek(fin, 18 * 4, SEEK_CUR);
 
     if (fp->ac)
     {
@@ -597,9 +584,6 @@ static void sol_stor_ball(FILE *fout, struct s_ball *bp)
 {
     put_array(fout,  bp->p, 3);
     put_float(fout, &bp->r);
-    put_index(fout, &bp->m);
-    put_index(fout, &bp->n);
-    put_index(fout, &bp->c);
 }
 
 static void sol_stor_view(FILE *fout, struct s_view *wp)
@@ -641,7 +625,6 @@ static void sol_stor_file(FILE *fin, struct s_file *fp)
     put_index(fin, &fp->xc);
     put_index(fin, &fp->rc);
     put_index(fin, &fp->uc);
-    put_index(fin, &fp->yc);
     put_index(fin, &fp->wc);
     put_index(fin, &fp->ic);
 
@@ -664,7 +647,6 @@ static void sol_stor_file(FILE *fin, struct s_file *fp)
     for (i = 0; i < fp->xc; i++) sol_stor_swch(fin, fp->xv + i);
     for (i = 0; i < fp->rc; i++) sol_stor_bill(fin, fp->rv + i);
     for (i = 0; i < fp->uc; i++) sol_stor_ball(fin, fp->uv + i);
-    for (i = 0; i < fp->yc; i++) sol_stor_ball(fin, fp->yv + i);
     for (i = 0; i < fp->wc; i++) sol_stor_view(fin, fp->wv + i);
     for (i = 0; i < fp->ic; i++) put_index(fin, fp->iv + i);
 }
@@ -704,7 +686,6 @@ void sol_free(struct s_file *fp)
     if (fp->xv) free(fp->xv);
     if (fp->rv) free(fp->rv);
     if (fp->uv) free(fp->uv);
-    if (fp->yv) free(fp->yv);
     if (fp->wv) free(fp->wv);
     if (fp->dv) free(fp->dv);
     if (fp->iv) free(fp->iv);
@@ -773,32 +754,6 @@ static float v_vert(float Q[3],
     return t;
 }
 
-static float v_ball(float Q[3],
-                    const float o[3],
-                    const float q[3],
-                    const float w[3],
-                    const float p[3],
-                    const float v[3], float r, float r2)
-{
-    float O[3], P[3], V[3];
-    float t = LARGE;
-
-    v_add(O, o, q);
-    v_sub(P, p, O);
-    v_sub(V, v, w);
-
-    if (v_dot(P, V) < 0.0f)
-    {
-        t = v_sol(P, V, r + r2);
-
-        if (t < LARGE)
-            v_mad(Q, O, w, t);
-    }
-
-    return t;
-
-}
-
 /*
  * Compute the  earliest time  and position of  the intersection  of a
  * sphere and an edge.
@@ -959,130 +914,8 @@ static float sol_bounce(struct s_ball *up,
     v_mad(p, q, n, up->r);
 
     /* Return the "energy" of the impact, to determine the sound amplitude. */
-    return fabsf(v_dot(n, d));
-}
-
-/*
- * Compute the new  linear velocities of two colliding balls.
- * t gives the time after which they collide.
- */
-static float sol_bounce_sphere(const struct s_file *fp,
-                                      struct s_ball *up,
-                                      struct s_ball *u2p,
-                                      const float t)
-{
-    float r_rel[3], v_rel[3], v1_par[3], v1_perp[3], v2_par[3], v2_perp[3],
-          u[3];
-    float v11[3], v12[3], v21[3], v22[3];
-    float *p1 = up->p, *v1 = up->v, *p2 = u2p->p, *v2 = u2p->v;
-    float inertia, factor, gamma;
-    const int u1 = up->m;
-    const int u2 = u2p->m;
-
-    {
-        char gamma_str[MAXNAM];
-        config_get_s(CONFIG_BALL_GAMMA, gamma_str, MAXNAM);
-        gamma = atof(gamma_str);
-    }
-
-   /* Correct positions up to the collision */
-    v_mad(p1, p1, v1, t);
-    v_mad(p2, p2, v2, t);
-
-   /* Floating point precision */
-    if (!(p1[1] - p2[1] > 0.001f ) && !(p2[1] - p1[1] > 0.001f))
-    {
-        if (p1[1] > p2[1])
-            p2[1] = p1[1];
-        else
-            p1[1] = p2[1];
-    }
-
-   /* Hack: prevent losing balls */
-    v_sub(v_rel, v2, v1);
-    if (v_len(v_rel) < 0.001f)
-    {
-        return 0.0f;
-    }
-
-   /* r_rel is the unit vector from p1 to p2 */
-    v_sub(r_rel, p2, p1);
-    v_nrm(r_rel, r_rel);
-
-   /*
-    * project velocities upon r_rel to get components parallel
-    * to r_rel - only these will be changed in the collision
-    */
-    factor = v_dot(v1, r_rel);
-    v_scl(v1_par, r_rel, factor);
-    v_sub(v1_perp, v1, v1_par);
-
-    factor = v_dot(v2, r_rel);
-    v_scl(v2_par, r_rel, factor);
-    v_sub(v2_perp, v2, v2_par);
-
-   /* u is used to calculate the "energy" of the impact */
-    v_sub(u, v2_par, v1_par);
-
-   /* Ensure immobile balls don't travel inside of each other */
-    if (!up->m || !u2p->m)
-        gamma = 0.78f;
-
-   /*
-    * New parallel velocities follow from momentum conservation,
-    * coefficient of restitution GAMMA, mass ratio inertia
-    */
-    inertia = pow(up->r / u2p->r, 3);
-
-    if (!u2p->m)
-    {
-        v_scl(v11, v1_par, -gamma);
-        v_scl(v12, v2_par, gamma + 1.0f);
-        v_add(v1_par, v11, v12); 
-    }
-
-    else if (!up->m)
-    {
-        v_scl(v21, v1_par, gamma + 1.0f);
-        v_scl(v22, v2_par, -gamma);
-        v_add(v2_par, v21, v22); 
-    }
-
-    else
-    {
-        v_scl(v11, v1_par, (inertia - gamma) / (inertia + 1.0f));
-        v_scl(v12, v1_par, (gamma + 1.0f) * inertia / (inertia + 1.0f));
-        v_scl(v21, v2_par, (gamma + 1.0f) / (inertia + 1.0f));
-        v_scl(v22, v2_par, (1.0f - gamma * inertia) / (inertia + 1.0f));
-        v_add(v1_par, v11, v21);
-        v_add(v2_par, v12, v22);
-    }
-
-    if (up->m)
-        v_add(v1, v1_par, v1_perp);
-    if (u2p->m)
-        v_add(v2, v2_par, v2_perp);
-
-   /* Hack: prevent accidental spinning while the ball is stationary */
-    if (v_len(v1) < 0.01f && u1)
-    {
-        up->w[0] = 0.0f;
-        up->w[1] = 0.0f;
-        up->w[2] = 0.0f;
-    }
-
-    if (v_len(v2) < 0.01f && u2)
-    {
-        u2p->w[0] = 0.0f;
-        u2p->w[1] = 0.0f;
-        u2p->w[2] = 0.0f;
-    }
 
-   /*
-    * Return the length of the relative velocity parallel
-    * to the line of impact
-    */
-    return fabsf(v_len(u));
+    return fabsf(v_dot(n, d));
 }
 
 /*
@@ -1202,47 +1035,17 @@ static void sol_body_step(struct s_file *fp, float dt)
 /*
  * Compute the positions of all balls after DT seconds have passed.
  */
-static void sol_ball_step(struct s_file *fp, int arb, float dt)
+static void sol_ball_step(struct s_file *fp, float dt)
 {
     int i;
 
-    if (arb)
+    for (i = 0; i < fp->uc; i++)
     {
-        for (i = 0; i < fp->yc; i++)
-        {
-            struct s_ball *yp = fp->yv + i;
+        struct s_ball *up = fp->uv + i;
 
-            if (!yp->m)
-                continue;
+        v_mad(up->p, up->p, up->v, dt);
 
-            v_mad(yp->p, yp->p, yp->v, dt);
-
-            sol_rotate(yp->e, yp->w, dt);
-        }
-    }
-
-    else
-    {
-        for (i = 0; i < fp->yc; i++)
-        {
-            struct s_ball *yp = fp->yv + i;
-
-            if (!yp->m)
-                continue;
-
-            v_mad(yp->p, yp->p, yp->v, dt);
-
-            sol_rotate(yp->e, yp->w, dt);
-        }
-
-        for (i = 0; i < fp->uc; i++)
-        {
-            struct s_ball *up = fp->uv + i;
-
-            v_mad(up->p, up->p, up->v, dt);
-
-            sol_rotate(up->e, up->w, dt);
-        }
+        sol_rotate(up->e, up->w, dt);
     }
 }
 
@@ -1258,18 +1061,6 @@ static float sol_test_vert(float dt,
     return v_vert(T, o, vp->p, w, up->p, up->v, up->r);
 }
 
-/*---------------------------------------------------------------------------*/
-
-static float sol_test_ball(float dt,
-                           float T[3],
-                           const struct s_ball  *up,
-                           const struct s_ball  *u2p,
-                           const float o[3],
-                           const float w[3])
-{
-    return v_ball(T, o, u2p->p, w, up->p, up->v, up->r, u2p->r);
-}
-
 static float sol_test_edge(float dt,
                            float T[3],
                            const struct s_ball *up,
@@ -1386,48 +1177,16 @@ static float sol_test_lump(float dt,
                            const struct s_file *fp,
                            const struct s_lump *lp,
                            const float o[3],
-                           const float w[3],
-                           const int            ui)
+                           const float w[3])
 {
     float U[3] = {0.0f, 0.0f, 0.0f}; /* init value only to avoid gcc warnings */
     float u, t = dt;
-    int   i;
+    int i;
 
     /* Short circuit a non-solid lump. */
 
     if (lp->fl & L_DETAIL) return t;
 
-    /* Test all balls */
-
-    if (up->r > 0.0f)
-    {
-        for (i = 0; i < fp->yc; i++)
-        {
-            struct s_ball *yp = fp->yv + i;
-
-            if ((u = sol_test_ball(t, U, up, yp, o, yp->v)) < t)
-            {
-                ball_collision_flag = i + fp->yv - fp->uv;
-                t = u;
-            }
-        }
-
-        for (i = 1; config_get_d(CONFIG_BALL_COLLISIONS) && i < fp->uc; i++)
-        {
-            struct s_ball *u2p = fp->uv + i;
-
-            if(i == ui)
-                continue;
-
-            if (u2p->P && up->P &&
-               (u = sol_test_ball(t, U, up, u2p, o, u2p->v)) < t)
-            {
-                ball_collision_flag = i;
-                t = u;
-            }
-        }
-    }
-
     /* Test all verts */
 
     if (up->r > 0.0f)
@@ -1477,8 +1236,7 @@ static float sol_test_node(float dt,
                            const struct s_file *fp,
                            const struct s_node *np,
                            const float o[3],
-                           const float w[3],
-                           const int            ui)
+                           const float w[3])
 {
     float U[3], u, t = dt;
     int i;
@@ -1489,7 +1247,7 @@ static float sol_test_node(float dt,
     {
         const struct s_lump *lp = fp->lv + np->l0 + i;
 
-        if ((u = sol_test_lump(t, U, up, fp, lp, o, w, ui)) < t)
+        if ((u = sol_test_lump(t, U, up, fp, lp, o, w)) < t)
         {
             v_cpy(T, U);
             t = u;
@@ -1502,7 +1260,7 @@ static float sol_test_node(float dt,
     {
         const struct s_node *nq = fp->nv + np->ni;
 
-        if ((u = sol_test_node(t, U, up, fp, nq, o, w, ui)) < t)
+        if ((u = sol_test_node(t, U, up, fp, nq, o, w)) < t)
         {
             v_cpy(T, U);
             t = u;
@@ -1515,7 +1273,7 @@ static float sol_test_node(float dt,
     {
         const struct s_node *nq = fp->nv + np->nj;
 
-        if ((u = sol_test_node(t, U, up, fp, nq, o, w, ui)) < t)
+        if ((u = sol_test_node(t, U, up, fp, nq, o, w)) < t)
         {
             v_cpy(T, U);
             t = u;
@@ -1529,8 +1287,7 @@ static float sol_test_body(float dt,
                            float T[3], float V[3],
                            const struct s_ball *up,
                            const struct s_file *fp,
-                           const struct s_body *bp,
-                           const int            ui)
+                           const struct s_body *bp)
 {
     float U[3], O[3], W[3], u, t = dt;
 
@@ -1539,7 +1296,7 @@ static float sol_test_body(float dt,
     sol_body_p(O, fp, bp);
     sol_body_v(W, fp, bp);
 
-    if ((u = sol_test_node(t, U, up, fp, np, O, W, ui)) < t)
+    if ((u = sol_test_node(t, U, up, fp, np, O, W)) < t)
     {
         v_cpy(T, U);
         v_cpy(V, W);
@@ -1551,8 +1308,7 @@ static float sol_test_body(float dt,
 static float sol_test_file(float dt,
                            float T[3], float V[3],
                            const struct s_ball *up,
-                           const struct s_file *fp,
-                           const int            ui)
+                           const struct s_file *fp)
 {
     float U[3], W[3], u, t = dt;
     int i;
@@ -1561,7 +1317,7 @@ static float sol_test_file(float dt,
     {
         const struct s_body *bp = fp->bv + i;
 
-        if ((u = sol_test_body(t, U, W, up, fp, bp, ui)) < t)
+        if ((u = sol_test_body(t, U, W, up, fp, bp)) < t)
         {
             v_cpy(T, U);
             v_cpy(V, W);
@@ -1583,190 +1339,80 @@ static float sol_test_file(float dt,
 
 float sol_step(struct s_file *fp, const float *g, float dt, int ui, int *m)
 {
-    float b    = 0.0f;
-    int   i, c = 16;
+    float P[3], V[3], v[3], r[3], a[3], d, e, nt, b = 0.0f, tt = dt;
+    int c = 16;
 
-   /*
-    * The user ball loop
-    */
-    for (i = 0; (config_get_d(CONFIG_BALL_COLLISIONS) && i < fp->uc) ||
-                (!config_get_d(CONFIG_BALL_COLLISIONS) && i < 4 + 1); i++)
+    if (ui < fp->uc)
     {
-        float P[3], V[3], v[3], r[3], a[3], d, e, nt = 0.0f, tt = dt;
+        struct s_ball *up = fp->uv + ui;
 
-        if (i < fp->uc)
-        {
-            struct s_ball *up = fp->uv + i;
+        /* If the ball is in contact with a surface, apply friction. */
 
-            /* If the ball is in contact with a surface, apply friction. */
+        v_cpy(a, up->v);
+        v_cpy(v, up->v);
+        v_cpy(up->v, g);
 
-            v_cpy(a, up->v);
-            v_cpy(v, up->v);
-            v_cpy(up->v, g);
+        if (m && sol_test_file(tt, P, V, up, fp) < 0.0005f)
+        {
+            v_cpy(up->v, v);
+            v_sub(r, P, up->p);
 
-            if (m && sol_test_file(tt, P, V, up, fp, i) < 0.0005f)
+            if ((d = v_dot(r, g) / (v_len(r) * v_len(g))) > 0.999f)
             {
-                v_cpy(up->v, v);
-                v_sub(r, P, up->p);
-
-                if ((d = v_dot(r, g) / (v_len(r) * v_len(g))) > 0.999f)
+                if ((e = (v_len(up->v) - dt)) > 0.0f)
                 {
-                    if ((e = (v_len(up->v) - dt)) > 0.0f)
-                    {
-                        /* Scale the linear velocity. */
+                    /* Scale the linear velocity. */
 
-                        v_nrm(up->v, up->v);
-                        v_scl(up->v, up->v, e);
+                    v_nrm(up->v, up->v);
+                    v_scl(up->v, up->v, e);
 
-                        /* Scale the angular velocity. */
+                    /* Scale the angular velocity. */
 
-                        v_sub(v, V, up->v);
-                        v_crs(up->w, v, r);
-                        v_scl(up->w, up->w, -1.0f / (up->r * up->r));
-                    }
-                    else
-                    {
-                        /* Friction has brought the ball to a stop. */
+                    v_sub(v, V, up->v);
+                    v_crs(up->w, v, r);
+                    v_scl(up->w, up->w, -1.0f / (up->r * up->r));
+                }
+                else
+                {
+                    /* Friction has brought the ball to a stop. */
 
-                        up->v[0] = 0.0f;
-                        up->v[1] = 0.0f;
-                        up->v[2] = 0.0f;
+                    up->v[0] = 0.0f;
+                    up->v[1] = 0.0f;
+                    up->v[2] = 0.0f;
 
-                        if(i == ui)
-                            (*m)++;
-                    }
+                    (*m)++;
                 }
-                else v_mad(up->v, v, g, tt);
             }
             else v_mad(up->v, v, g, tt);
-
-            /* Test for collision. */
-
-            while (c && tt && tt > (nt = sol_test_file(tt, P, V, up, fp, i)))
-            {
-                sol_body_step(fp, nt);
-                sol_swch_step(fp, nt);
-                sol_ball_step(fp, 0, nt);
-
-                tt -= nt;
-
-                if (b < ((ball_collision_flag)
-                        ? (d = sol_bounce_sphere(fp, up,
-                           fp->uv + ball_collision_flag, nt))
-                        : (d = sol_bounce(up, P, V, nt))))
-                    b = d;
-               
-                ball_collision_flag = 0;
-
-                c--;
-            }
-
-            if (i == ui || !c)
-            {
-                if (!c)
-                    nt += tt;
-                sol_body_step(fp, nt);
-                sol_swch_step(fp, nt);
-                sol_ball_step(fp, 0, nt);
-            }
-
-            /* Apply the ball's accelleration to the pendulum. */
-
-            v_sub(a, up->v, a);
-
-            sol_pendulum(up, a, g, dt);
         }
-    }
+        else v_mad(up->v, v, g, tt);
 
-   /*
-    * The arbitrary balls loop
-    */
-    for (i = 0; i < fp->yc && c > 0; i++)
-    {
-        float P[3], V[3], v[3], r[3], a[3], d, e, nt = 0.0f, tt = dt;
+        /* Test for collision. */
 
-        if (i < fp->yc)
+        while (c > 0 && tt > 0 && tt > (nt = sol_test_file(tt, P, V, up, fp)))
         {
-            struct s_ball *yp = fp->yv + i;
-
-            if ((!yp->m) || (!config_get_d(CONFIG_BALL_COLLISIONS) && yp->c))
-                continue;
-
-            /* If the ball is in contact with a surface, apply friction. */
+            sol_body_step(fp, nt);
+            sol_swch_step(fp, nt);
+            sol_ball_step(fp, nt);
 
-            v_cpy(a, yp->v);
-            v_cpy(v, yp->v);
-            v_cpy(yp->v, g);
+            tt -= nt;
 
-            if (m && sol_test_file(tt, P, V, yp, fp, i) < 0.0005f)
-            {
-                v_cpy(yp->v, v);
-                v_sub(r, P, yp->p);
-
-                if ((d = v_dot(r, g) / (v_len(r) * v_len(g))) > 0.999f)
-                {
-                    if ((e = (v_len(yp->v) - dt)) > 0.0f)
-                    {
-                        /* Scale the linear velocity. */
+            if (b < (d = sol_bounce(up, P, V, nt)))
+                b = d;
 
-                        v_nrm(yp->v, yp->v);
-                        v_scl(yp->v, yp->v, e);
-
-                        /* Scale the angular velocity. */
-
-                        v_sub(v, V, yp->v);
-                        v_crs(yp->w, v, r);
-                        v_scl(yp->w, yp->w, -1.0f / (yp->r * yp->r));
-                    }
-                    else
-                    {
-                        /* Friction has brought the ball to a stop. */
-
-                        yp->v[0] = 0.0f;
-                        yp->v[1] = 0.0f;
-                        yp->v[2] = 0.0f;
-                    }
-                }
-                else v_mad(yp->v, v, g, tt);
-            }
-            else v_mad(yp->v, v, g, tt);
-
-            /* Test for collision. */
-
-            while (c && tt && tt > (nt = sol_test_file(tt, P, V, yp, fp, i)))
-            {
-                sol_ball_step(fp, 1, nt);
-
-                tt -= nt;
-
-                if (b < ((ball_collision_flag)
-                        ? (d = sol_bounce_sphere(fp, yp,
-                           fp->uv + ball_collision_flag, nt))
-                        : (d = sol_bounce(yp, P, V, nt))))
-                    b = d;
-
-                ball_collision_flag = 0;
-
-                c--;
-            }
+            c--;
+        }
 
-            if (!c)
-            {
-                if (!c && ui == 0)
-                    nt += tt;
-                sol_body_step(fp, nt);
-                sol_swch_step(fp, nt);
-                sol_ball_step(fp, 1, nt);
-            }
+        sol_body_step(fp, tt);
+        sol_swch_step(fp, tt);
+        sol_ball_step(fp, tt);
 
-            /* Apply the ball's accelleration to the pendulum. */
+        /* Apply the ball's accelleration to the pendulum. */
 
-            v_sub(a, yp->v, a);
+        v_sub(a, up->v, a);
 
-            sol_pendulum(yp, a, g, dt);
-        }
+        sol_pendulum(up, a, g, dt);
     }
-
     return b;
 }
 
@@ -1774,132 +1420,57 @@ float sol_step(struct s_file *fp, const float *g, float dt, int ui, int *m)
 
 struct s_item *sol_item_test(struct s_file *fp, float *p, float item_r)
 {
-    int hi, yi;
+    const float *ball_p = fp->uv->p;
+    const float  ball_r = fp->uv->r;
+
+    int hi;
 
     for (hi = 0; hi < fp->hc; hi++)
     {
-        {
-            const float *ball_p = fp->uv->p;
-            const float  ball_r = fp->uv->r;
-
-            float r[3];
-
-            r[0] = ball_p[0] - fp->hv[hi].p[0];
-            r[1] = ball_p[1] - fp->hv[hi].p[1];
-            r[2] = ball_p[2] - fp->hv[hi].p[2];
-
-            if (fp->hv[hi].t != ITEM_NONE && v_len(r) < ball_r + item_r)
-            {
-                p[0] = fp->hv[hi].p[0];
-                p[1] = fp->hv[hi].p[1];
-                p[2] = fp->hv[hi].p[2];
+        float r[3];
 
-                return &fp->hv[hi];
-            }
-        }
+        r[0] = ball_p[0] - fp->hv[hi].p[0];
+        r[1] = ball_p[1] - fp->hv[hi].p[1];
+        r[2] = ball_p[2] - fp->hv[hi].p[2];
 
-        for (yi = 0; yi < fp->yc; yi++)
+        if (fp->hv[hi].t != ITEM_NONE && v_len(r) < ball_r + item_r)
         {
-            const float *ball_p = fp->yv[yi].p;
-            const float  ball_r = fp->yv[yi].r;
-
-            float r[3];
+            p[0] = fp->hv[hi].p[0];
+            p[1] = fp->hv[hi].p[1];
+            p[2] = fp->hv[hi].p[2];
 
-            r[0] = ball_p[0] - fp->hv[hi].p[0];
-            r[1] = ball_p[1] - fp->hv[hi].p[1];
-            r[2] = ball_p[2] - fp->hv[hi].p[2];
-
-            if (fp->hv[hi].t != ITEM_NONE && v_len(r) < ball_r + item_r)
-            {
-                p[0] = fp->hv[hi].p[0];
-                p[1] = fp->hv[hi].p[1];
-                p[2] = fp->hv[hi].p[2];
-
-                return &fp->hv[hi];
-            }
+            return &fp->hv[hi];
         }
     }
     return NULL;
 }
 
-int sol_goal_test(struct s_file *fp, float *p, int ui)
+struct s_goal *sol_goal_test(struct s_file *fp, float *p, int ui)
 {
-    if (config_get_d(CONFIG_BALL_COLLISIONS) && ui)
-    {
-        const float *ball_p = fp->uv[ui].p;
-        const float  ball_r = fp->uv[ui].r;
-        float z[3] = {0.0f, 0.0f, 0.0f};
-        int zi, i;
-
-        for (i = 1; i < fp->uc; i++)
-        {
-            if(fp->uv[i].p[1] < -199.9f)
-                v_cpy(fp->uv[i].v, z);
-            if (v_len(fp->uv[i].v) > 0.0f)
-                return 0;
-            else
-                v_cpy(fp->uv[i].v, z);
-        }
-
-        for (i = 0; i < fp->yc; i++)
-        {
-            if(fp->yv[i].p[1] < -199.9f)
-                v_cpy(fp->yv[i].v, z);
-            if (v_len(fp->yv[i].v) > 0.0f)
-                return 0;
-            else
-                v_cpy(fp->yv[i].v, z);
-        }
-
-        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)
-            {
-                p[0] = fp->zv[zi].p[0];
-                p[1] = -200.0f;
-                p[2] = fp->zv[zi].p[2];
-
-                return 2;
-            }
-        }
-        return 1;
-    }
+    const float *ball_p = fp->uv[ui].p;
+    const float  ball_r = fp->uv[ui].r;
+    int zi;
 
-    else
+    for (zi = 0; zi < fp->zc; zi++)
     {
-        const float *ball_p = fp->uv[ui].p;
-        const float  ball_r = fp->uv[ui].r;
-        int zi;
-
-        for (zi = 0; zi < fp->zc; zi++)
-        {
-            float r[3];
+        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;
+        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)
-            {
-                p[0] = fp->zv[zi].p[0];
-                p[1] = -200.0f;
-                p[2] = fp->zv[zi].p[2];
+        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)
+        {
+            p[0] = fp->zv[zi].p[0];
+            p[1] = fp->zv[zi].p[1];
+            p[2] = fp->zv[zi].p[2];
 
-                return 1;
-            }
+            return &fp->zv[zi];
         }
-        return 0;
     }
+    return NULL;
 }
 
 /*
@@ -1948,145 +1519,75 @@ int sol_jump_test(struct s_file *fp, float *p, int ui)
  * a visible  switch is  activated, return 0  otherwise (no  switch is
  * activated or only invisible switches).
  */
-int sol_swch_test(struct s_file *fp)
+int sol_swch_test(struct s_file *fp, int ui)
 {
-    int xi, i, res = 0;
+    const float *ball_p = fp->uv[ui].p;
+    const float  ball_r = fp->uv[ui].r;
+    int xi;
+    int res = 0;
 
     for (xi = 0; xi < fp->xc; xi++)
     {
         struct s_swch *xp = fp->xv + xi;
 
-        for (i = 0; i < fp->uc; i++)
+        if (xp->t0 == 0 || xp->f == xp->f0)
         {
-            float l, r[3];
-
-            const float *ball_p  = fp->uv[i].p;
-            const float  ball_r  = fp->uv[i].r;
-
-            if (xp->t0 == 0 || xp->f == xp->f0)
-            {
-                r[0] = ball_p[0] - xp->p[0];
-                r[1] = ball_p[2] - xp->p[2];
-                r[2] = 0;
-
-                l = v_len(r) - xp->r;
-
-                if (l < ball_r &&
-                    ball_p[1] > xp->p[1] &&
-                    ball_p[1] < xp->p[1] + SWCH_HEIGHT / 2)
-                {
-                    if (!xp->e && l < -ball_r)
-                    {
-                        int pi = xp->pi;
-                        int pj = xp->pi;
-
-                        xp->b = i * 2;
-
-                        /* The ball enters. */
-
-                        if (xp->t0 == 0)
-                            xp->e = 1;
-
-                        /* Toggle the state, update the path. */
-
-                        xp->f = xp->f ? 0 : 1;
-
-                        do  /* Tortoise and hare cycle traverser. */
-                        {
-                            fp->pv[pi].f = xp->f;
-                            fp->pv[pj].f = xp->f;
-
-                            pi = fp->pv[pi].pi;
-                            pj = fp->pv[pj].pi;
-                            pj = fp->pv[pj].pi;
-                        }
-                        while (pi != pj);
-
-                        /* It toggled to non-default state, start the timer. */
-
-                        if (xp->f != xp->f0)
-                            xp->t  = xp->t0;
-
-                        /* If visible, set the result. */
-
-                        if (!xp->i)
-                            res = 1;
-                    }
-                }
-
-                /* The ball exits. */
-
-                else if (xp->e && xp->b == i * 2)
-                    xp->e = 0;
-            }
-        }
+            float l;
+            float r[3];
 
-        for (i = 0; i < fp->yc; i++)
-        {
-            float l, r[3];
+            r[0] = ball_p[0] - xp->p[0];
+            r[1] = ball_p[2] - xp->p[2];
+            r[2] = 0;
 
-            const float *ball_p  = fp->yv[i].p;
-            const float  ball_r  = fp->yv[i].r;
+            l = v_len(r) - xp->r;
 
-            if (xp->t0 == 0 || xp->f == xp->f0)
+            if (l < ball_r &&
+                ball_p[1] > xp->p[1] &&
+                ball_p[1] < xp->p[1] + SWCH_HEIGHT / 2)
             {
-                r[0] = ball_p[0] - xp->p[0];
-                r[1] = ball_p[2] - xp->p[2];
-                r[2] = 0;
-
-                l = v_len(r) - xp->r;
-
-                if (l < ball_r &&
-                    ball_p[1] > xp->p[1] &&
-                    ball_p[1] < xp->p[1] + SWCH_HEIGHT / 2)
+                if (!xp->e && l < - ball_r)
                 {
-                    if (!xp->e && l < -ball_r)
-                    {
-                        int pi = xp->pi;
-                        int pj = xp->pi;
-
-                        xp->b = i * 2 + 1;
+                    int pi = xp->pi;
+                    int pj = xp->pi;
 
-                        /* The ball enters. */
+                    /* The ball enters. */
 
-                        if (xp->t0 == 0)
-                            xp->e = 1;
+                    if (xp->t0 == 0)
+                        xp->e = 1;
 
-                        /* Toggle the state, update the path. */
+                    /* Toggle the state, update the path. */
 
-                        xp->f = xp->f ? 0 : 1;
+                    xp->f = xp->f ? 0 : 1;
 
-                        do  /* Tortoise and hare cycle traverser. */
-                        {
-                            fp->pv[pi].f = xp->f;
-                            fp->pv[pj].f = xp->f;
+                    do  /* Tortoise and hare cycle traverser. */
+                    {
+                        fp->pv[pi].f = xp->f;
+                        fp->pv[pj].f = xp->f;
 
-                            pi = fp->pv[pi].pi;
-                            pj = fp->pv[pj].pi;
-                            pj = fp->pv[pj].pi;
-                        }
-                        while (pi != pj);
+                        pi = fp->pv[pi].pi;
+                        pj = fp->pv[pj].pi;
+                        pj = fp->pv[pj].pi;
+                    }
+                    while (pi != pj);
 
-                        /* It toggled to non-default state, start the timer. */
+                    /* It toggled to non-default state, start the timer. */
 
-                        if (xp->f != xp->f0)
-                            xp->t  = xp->t0;
+                    if (xp->f != xp->f0)
+                        xp->t  = xp->t0;
 
-                        /* If visible, set the result. */
+                    /* If visible, set the result. */
 
-                        if (!xp->i)
-                            res = 1;
-                    }
+                    if (!xp->i)
+                        res = 1;
                 }
+            }
 
-                /* The ball exits. */
+            /* The ball exits. */
 
-                else if (xp->e && xp->b == i * 2 + 1)
-                    xp->e = 0;
-            }
+            else if (xp->e)
+                xp->e = 0;
         }
     }
-
     return res;
 }
 
index f8eb3a4..6038b83 100644 (file)
  *
  * The Xs are as documented by struct s_file:
  *
- *     f  File           (struct s_file)
- *     m  Material       (struct s_mtrl)
- *     v  Vertex         (struct s_vert)
- *     e  Edge           (struct s_edge)
- *     s  Side           (struct s_side)
- *     t  Texture coord  (struct s_texc)
- *     g  Geometry       (struct s_geom)
- *     l  Lump           (struct s_lump)
- *     n  Node           (struct s_node)
- *     p  Path           (struct s_path)
- *     b  Body           (struct s_body)
- *     h  Item           (struct s_item)
- *     z  Goal           (struct s_goal)
- *     j  Jump           (struct s_jump)
- *     x  Switch         (struct s_swch)
- *     r  Billboard      (struct s_bill)
- *     u  User           (struct s_ball)
- *     y  Arbitrary ball (struct s_ball)
- *     w  Viewpoint      (struct s_view)
- *     d  Dictionary     (struct s_dict)
- *     i  Index          (int)
- *     a  Text           (char)
-
+ *     f  File          (struct s_file)
+ *     m  Material      (struct s_mtrl)
+ *     v  Vertex        (struct s_vert)
+ *     e  Edge          (struct s_edge)
+ *     s  Side          (struct s_side)
+ *     t  Texture coord (struct s_texc)
+ *     g  Geometry      (struct s_geom)
+ *     l  Lump          (struct s_lump)
+ *     n  Node          (struct s_node)
+ *     p  Path          (struct s_path)
+ *     b  Body          (struct s_body)
+ *     h  Item          (struct s_item)
+ *     z  Goal          (struct s_goal)
+ *     j  Jump          (struct s_jump)
+ *     x  Switch        (struct s_swch)
+ *     r  Billboard     (struct s_bill)
+ *     u  User          (struct s_ball)
+ *     w  Viewpoint     (struct s_view)
+ *     d  Dictionary    (struct s_dict)
+ *     i  Index         (int)
+ *     a  Text          (char)
  *
  * The Ys are as follows:
  *
@@ -74,7 +72,7 @@
  * Those members that do not conform to this convention are explicitly
  * documented with a comment.
  *
- * These prefixes are still available: c k o q.
+ * These prefixes are still available: c k o q y.
  */
 
 /*---------------------------------------------------------------------------*/
@@ -225,7 +223,6 @@ struct s_swch
     int   f;                                   /* current state              */
     int   i;                                   /* is invisible?              */
     int   e;                                   /* is a ball inside it?       */
-    int   b;                                   /* which ball?                */
 };
 
 struct s_bill
@@ -254,20 +251,13 @@ struct s_jump
 
 struct s_ball
 {
-    float e[3][3];                             /* basis of orientation         */
-    float p[3];                                /* position vector              */
-    float v[3];                                /* velocity vector              */
-    float w[3];                                /* angular velocity vector      */
-    float E[3][3];                             /* basis of pendulum            */
-    float W[3];                                /* angular pendulum velocity    */
-    float r;                                   /* radius                       */
-    int   P;                                   /* ball in play state           */
-    int   m;                                   /* is ball mobile?              */
-    int   n;                                   /* return the ball on fall-out? */
-    int   c;                                   /* is ball only existant with   *
-                                                * ball_collisions?             */
-    float O[3];                                /* original ball                *
-                                                * location (arbitrary balls)   */
+    float e[3][3];                             /* basis of orientation       */
+    float p[3];                                /* position vector            */
+    float v[3];                                /* velocity vector            */
+    float w[3];                                /* angular velocity vector    */
+    float E[3][3];                             /* basis of pendulum          */
+    float W[3];                                /* angular pendulum velocity  */
+    float r;                                   /* radius                     */
 };
 
 struct s_view
@@ -284,27 +274,26 @@ struct s_dict
 
 struct s_file
 {
-    int   ac;
-    int   mc;
-    int   vc;
-    int   ec;
-    int   sc;
-    int   tc;
-    int   gc;
-    int   lc;
-    int   nc;
-    int   pc;
-    int   bc;
-    int   hc;
-    int   zc;
-    int   jc;
-    int   xc;
-    int   rc;
-    int   uc;
-    int   wc;
-    int   dc;
-    int   ic;
-    int   yc;
+    int ac;
+    int mc;
+    int vc;
+    int ec;
+    int sc;
+    int tc;
+    int gc;
+    int lc;
+    int nc;
+    int pc;
+    int bc;
+    int hc;
+    int zc;
+    int jc;
+    int xc;
+    int rc;
+    int uc;
+    int wc;
+    int dc;
+    int ic;
 
     char          *av;
     struct s_mtrl *mv;
@@ -323,7 +312,6 @@ struct s_file
     struct s_swch *xv;
     struct s_bill *rv;
     struct s_ball *uv;
-    struct s_ball *yv;
     struct s_view *wv;
     struct s_dict *dv;
     int           *iv;
@@ -343,9 +331,9 @@ void  sol_free(struct s_file *);
 float sol_step(struct s_file *, const float *, float, int, int *);
 
 int   sol_jump_test(struct s_file *, float *, int);
-int   sol_swch_test(struct s_file *);
-int   sol_goal_test(struct s_file *, float *, int);
+int   sol_swch_test(struct s_file *, int);
 
+struct s_goal *sol_goal_test(struct s_file *, float *, int);
 struct s_item *sol_item_test(struct s_file *, float *, float);
 
 /*---------------------------------------------------------------------------*/