share/solid.o \
share/binary.o \
share/base_config.o \
- share/config.o \
- share/sync.o \
share/mapc.o
BALL_OBJS := \
share/lang.o \
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 \
putt/hole.o \
putt/course.o \
putt/st_all.o \
- putt/st_balt.o \
putt/st_conf.o \
putt/main.o
$(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.
#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
"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)
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);
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);
/*---------------------------------------------------------------------------*/
-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;
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;
}
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)
{
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);
}
/*---------------------------------------------------------------------------*/
+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*/
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);
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;
}
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) */
};
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
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);
/*---------------------------------------------------------------------------*/
-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);
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 */
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;
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);
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... */
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]);
static void game_draw_goals(const struct s_file *fp, const float *M, float t)
{
- if (goal_e)
+ if (goal_c == 0)
{
int zi;
{
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)
{
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. */
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;
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;
float b = sol_step(fp, h, dt, 0, NULL);
- game_check_balls(fp);
-
/* Mix the sound of a ball bounce. */
if (b > 0.5f)
/*---------------------------------------------------------------------------*/
-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);
}
/*---------------------------------------------------------------------------*/
-
-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");
- }
-}
-
-/*---------------------------------------------------------------------------*/
#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);
/*---------------------------------------------------------------------------*/
-#define GAME_NONE 0
-#define GAME_TIME 1
-#define GAME_GOAL 2
-#define GAME_FALL 3
-
-const char *status_to_str(int);
-
-/*---------------------------------------------------------------------------*/
-
#endif
#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;
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)))
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))
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;
{
gui_set_clock(time_id, clock);
- if (last > clock && pulse)
+ if (last > clock && pulse && mode != MODE_PRACTICE)
{
if (clock <= 1000 && (last / 100) > (clock / 100))
{
/* 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);
c_id = coin_id;
break;
- default:
+ case MODE_NORMAL:
c_id = coin_id;
break;
+
+ default:
+ c_id = coin2_id;
+ break;
}
#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"
/*---------------------------------------------------------------------------*/
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)
"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,
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");
+ }
}
/*---------------------------------------------------------------------------*/
-
#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];
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
#include "image.h"
#include "audio.h"
#include "demo.h"
-#include "progress.h"
+#include "levels.h"
#include "game.h"
#include "gui.h"
#include "set.h"
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"));
/* 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);
}
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 */
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;
{
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);
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();
}
/*---------------------------------------------------------------------------*/
/* 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. */
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);
#include "set.h"
#include "game.h"
#include "demo.h"
-#include "progress.h"
+#include "levels.h"
#include "audio.h"
#include "solid.h"
#include "config.h"
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;
}
demo_paused = 0;
goto_state(&st_demo_end);
}
- else
- progress_step();
}
static int demo_play_keybd(int c, int d)
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);
#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"
/* Bread crumbs. */
static int new_name;
-static int resume;
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;
}
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;
}
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;
}
#include "gui.h"
#include "game.h"
#include "util.h"
-#include "progress.h"
+#include "levels.h"
#include "audio.h"
#include "config.h"
#include "demo.h"
#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)
{
/* 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;
{
int id, jd, kd;
+ const struct level_game *lg = curr_lg();
+
/* Reset hack. */
- resume = 0;
+ be_back_soon = 0;
if ((id = gui_vstack(0)))
{
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);
{
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;
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);
}
#include "gui.h"
#include "game.h"
#include "util.h"
-#include "progress.h"
+#include "levels.h"
#include "audio.h"
#include "config.h"
#include "demo.h"
/* Bread crumbs. */
static int new_name;
-static int resume;
+static int be_back_soon;
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;
{
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;
}
{
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
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;
}
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);
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);
}
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;
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.\\"
#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"
{
int id, jd, kd, ld;
const char *ln;
+ const struct level_game *lg = curr_lg();
int b;
const float *textcol1, *textcol2;
{
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;
}
}
- 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);
}
}
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);
}
}
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);
}
}
#include "gui.h"
#include "set.h"
#include "game.h"
-#include "progress.h"
+#include "levels.h"
#include "audio.h"
#include "config.h"
#include "demo.h"
{
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)))
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);
#include "gui.h"
#include "config.h"
#include "game.h"
-#include "progress.h"
+#include "levels.h"
#include "level.h"
#include "audio.h"
#include "hud.h"
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();
{
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);
}
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;
#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"
{
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);
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;
}
}
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();
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;
#include "audio.h"
#include "config.h"
#include "demo.h"
-#include "progress.h"
+#include "levels.h"
#include "text.h"
#include "st_shared.h"
#include "gui.h"
#include "set.h"
-#include "progress.h"
+#include "levels.h"
#include "game.h"
#include "audio.h"
#include "config.h"
#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;
/*---------------------------------------------------------------------------*/
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)
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;
}
{
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)))
{
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");
/* 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);
}
#include "game.h"
#include "util.h"
-#include "progress.h"
+#include "levels.h"
#include "demo.h"
#include "audio.h"
#include "gui.h"
/* 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;
{
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);
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);
{
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;
return 1;
}
+static struct level title_level;
+
static int title_enter(void)
{
int id, jd, kd;
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;
{
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;
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;
}
/* 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";
/* 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;
/* 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";
}
}
-/* 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;
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);
/*---------------------------------------------------------------------------*/
-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];
#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);
Mehdi Yousfi-Monod (mym)
Michael Middleton (slippifishi)
Florian Priester
- Byron James Johnson (Krabby Krap)
* TRANSLATORS
- 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
- 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
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>
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 */
{
jump_e = 1;
jump_b = 0;
- jump_u = 0;
view_init();
sol_load_gl(&file, config_data(s), config_get_d(CONFIG_TEXTURES),
/*---------------------------------------------------------------------------*/
-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];
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();
}
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);
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();
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
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
{
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)
* 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;
}
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);
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);
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);
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);
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)
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);
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));
if (paused)
paused = 0;
- game_set_played(1);
-
return 0;
}
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;
if (paused)
paused = 0;
else
- hole_goal(0);
+ hole_goal();
hud_init();
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);
if (paused)
paused = 0;
- game_set_played(0);
-
return score_card(_("Scores"), gui_yel, gui_red);
}
+++ /dev/null
-/*
- * 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
-};
-
+++ /dev/null
-#ifndef ST_BALT_H
-#define ST_BALT_H
-
-#include "state.h"
-
-extern struct state st_balt;
-
-#endif
#include "st_conf.h"
#include "st_all.h"
#include "st_resol.h"
-#include "st_balt.h"
/*---------------------------------------------------------------------------*/
CONF_SHDON,
CONF_SHDOF,
CONF_BACK,
- CONF_RESOL,
- CONF_BALT,
- CONF_BCLON,
- CONF_BCLOF
+ CONF_RESOL
};
static int music_id[11];
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)
{
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);
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);
}
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);
jump_free();
flag_free();
mark_free();
- oldball_free();
ball_free();
shad_free();
shad_init();
ball_init();
- oldball_init(g);
mark_init(g);
flag_init(g);
jump_init(g);
#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;
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)))
{
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");
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);
/*---------------------------------------------------------------------------*/
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);
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);
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);
}
CONFIG_CHEAT,
CONFIG_STATS,
CONFIG_UNIFORM,
- CONFIG_LOCK_GOALS,
- CONFIG_BALL_COLLISIONS,
CONFIG_OPTION_D_COUNT
};
CONFIG_PLAYER,
CONFIG_BALL,
CONFIG_WIIMOTE_ADDR,
- CONFIG_BALL_GAMMA,
CONFIG_OPTION_S_COUNT
};
#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
#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"
/*---------------------------------------------------------------------------*/
#define MAXX 1024
#define MAXR 2048
#define MAXU 1024
-#define MAXY 1024
#define MAXW 1024
#define MAXD 1024
#define MAXA 16384
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");
fp->xc = 0;
fp->rc = 0;
fp->uc = 0;
- fp->yc = 0;
fp->wc = 0;
fp->dc = 0;
fp->ac = 0;
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));
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++)
{
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)
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);
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[])
#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)
{
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;
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);
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)
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);
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)
{
{
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)
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);
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);
}
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);
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.
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));
}
/*
/*
* 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);
}
}
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,
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)
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;
{
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;
{
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;
{
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;
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;
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);
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;
{
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);
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;
}
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;
}
/*
* 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;
}
*
* 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:
*
* 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.
*/
/*---------------------------------------------------------------------------*/
int f; /* current state */
int i; /* is invisible? */
int e; /* is a ball inside it? */
- int b; /* which ball? */
};
struct s_bill
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
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;
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;
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);
/*---------------------------------------------------------------------------*/