share/tilt.o \
share/common.o \
ball/hud.o \
- ball/mode.o \
ball/game.o \
ball/score.o \
ball/level.o \
- ball/levels.o \
+ ball/progress.o \
ball/set.o \
ball/demo.o \
ball/util.o \
#include "binary.h"
#include "text.h"
#include "common.h"
+#include "level.h"
/*---------------------------------------------------------------------------*/
#define MAGIC 0x52424EAF
-#define DEMO_VERSION 5
+#define DEMO_VERSION 6
#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->back, d->grad, d->song,
- d->time, d->goal, d->score, d->balls, d->times);
+ d->shot, d->file,
+ d->time, d->goal, d->goal_e, 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,
- const struct level_game *lg)
+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)
{
struct demo demo;
strncpy(demo.filename, config_user(name), MAXSTR);
strcat(demo.filename, REPLAY_EXT);
- demo.mode = lg->mode;
+ demo.mode = 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 = lg->time;
- demo.goal = lg->goal;
- demo.score = lg->score;
- demo.balls = lg->balls;
- demo.times = lg->times;
+ demo.time = t;
+ demo.goal = g;
+ demo.goal_e = e;
+ demo.score = s;
+ demo.balls = b;
+ demo.times = tt;
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, lg->time, lg->goal);
+ return game_init(level->file, t, e);
}
return 0;
}
input_put(demo_fp);
}
-void demo_play_stat(const struct level_game *lg)
+void demo_play_stat(int status, int coins, int timer)
{
if (demo_fp)
{
fseek(demo_fp, 8, SEEK_SET);
- put_index(demo_fp, &lg->timer);
- put_index(demo_fp, &lg->coins);
- put_index(demo_fp, &lg->status);
+ put_index(demo_fp, &timer);
+ put_index(demo_fp, &coins);
+ put_index(demo_fp, &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, struct level_game *lg)
+int demo_replay_init(const char *name, int *g, int *m, int *b, int *s, int *tt)
{
demo_status = GAME_NONE;
demo_fp = fopen(name, FMODE_RB);
base_name(text_from_locale(demo_replay.filename), REPLAY_EXT),
PATHMAX);
- if (!demo_load_level(&demo_replay, &demo_level_replay))
+ if (level_load(demo_replay.file, &demo_level_replay))
+ {
+ demo_level_replay.time = demo_replay.time;
+ demo_level_replay.goal = demo_replay.goal;
+ }
+ else
return 0;
- if (lg)
- {
- 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;
+ 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;
- /* A normal replay demo */
+ if (g)
+ {
audio_music_fade_to(0.5f, demo_level_replay.song);
- return game_init(&demo_level_replay, demo_replay.time,
- demo_replay.goal);
+
+ return game_init(demo_level_replay.file,
+ demo_level_replay.time,
+ demo_replay.goal_e);
}
- else /* A title screen demo */
- return game_init(&demo_level_replay, demo_replay.time, 0);
+ else
+ return game_init(demo_level_replay.file,
+ demo_level_replay.time, 1);
}
return 0;
}
struct demo
{
- 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 name[PATHMAX]; /* demo basename */
+ char filename[MAXSTR]; /* demo path */
+
+ char player[MAXNAM];
+ time_t date;
+
+ int timer;
+ int coins;
+ int status;
+ int mode;
+
char shot[PATHMAX]; /* image filename */
char file[PATHMAX]; /* level filename */
- 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 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 */
};
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
int demo_play_init(const char *, const struct level *,
- const struct level_game *);
+ int, int, int, int, int, int, int);
void demo_play_step(void);
-void demo_play_stat(const struct level_game *);
+void demo_play_stat(int, int, int);
void demo_play_stop(void);
int demo_saved (void);
/*---------------------------------------------------------------------------*/
-int demo_replay_init(const char *, struct level_game *);
+int demo_replay_init(const char *, int *, int *, int *, int *, int *);
int demo_replay_step(float);
void demo_replay_stop(int);
void demo_replay_dump_info(void);
#include "solid_gl.h"
#include "config.h"
#include "binary.h"
-#include "level.h"
/*---------------------------------------------------------------------------*/
static float view_k;
static int coins = 0; /* Collected coins */
-static int goal_c = 0; /* Goal coins remaining (0 = open) */
+static int goal_e = 0; /* Goal enabled flag */
static float goal_k = 0; /* Goal animation */
static int jump_e = 1; /* Jumping enabled flag */
static int jump_b = 0; /* Jump-in-progress flag */
view_e[2][2] = 1.f;
}
-int game_init(const struct level *level, int t, int g)
+int game_init(const char *file_name, int t, int e)
{
+ 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(level->file),
+ if (!sol_load_gl(&file, config_data(file_name),
config_get_d(CONFIG_TEXTURES),
config_get_d(CONFIG_SHADOW)))
return (game_state = 0);
jump_e = 1;
jump_b = 0;
- goal_c = g;
- goal_k = (g == 0) ? 1.0f : 0.0f;
+ goal_e = e ? 1 : 0;
+ goal_k = e ? 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(level->grad, config_get_d(CONFIG_GEOMETRY));
+ back_init(grad_name, config_get_d(CONFIG_GEOMETRY));
- sol_load_gl(&back, config_data(level->back),
+ sol_load_gl(&back, config_data(back_name),
config_get_d(CONFIG_TEXTURES), 0);
/* Initialize ball size tracking... */
return coins;
}
-int curr_goal(void)
-{
- return goal_c;
-}
-
/*---------------------------------------------------------------------------*/
static void game_draw_balls(const struct s_file *fp,
static void game_draw_goals(const struct s_file *fp, const float *M, float t)
{
- if (goal_c == 0)
+ if (goal_e)
{
int zi;
static void game_update_time(float dt, int b)
{
- if (goal_c == 0 && goal_k < 1.0f)
+ if (goal_e && goal_k < 1.0f)
goal_k += dt;
/* The ticking clock. */
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);
+ audio_play(AUD_COIN, 1.f);
- /* Reset item type. */
+ /* Discard item. */
hp->t = ITEM_NONE;
}
/* Test for a goal. */
- if (bt && goal_c == 0 && (zp = sol_goal_test(fp, p, 0)))
+ if (bt && goal_e && (zp = sol_goal_test(fp, p, 0)))
{
audio_play(AUD_GOAL, 1.0f);
return GAME_GOAL;
/*---------------------------------------------------------------------------*/
+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 "level.h"
-#include "mode.h"
+#include "lang.h"
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
-int game_init(const struct level *, int, int);
+int game_init(const char *, 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 "levels.h"
+#include "progress.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)
{
- int mode = curr_lg()->mode;
-
- if (mode == MODE_CHALLENGE)
+ if (curr_mode() == MODE_CHALLENGE)
gui_paint(Lhud_id);
- if (mode == MODE_PRACTICE)
- gui_paint(Rhud2_id);
- else
- gui_paint(Rhud_id);
-
+ 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 = lg->balls;
- int score = lg->score;
- int mode = lg->mode;
+ int balls = curr_balls();
+ int score = curr_score();
int c_id;
int last;
{
gui_set_clock(time_id, clock);
- if (last > clock && pulse && mode != MODE_PRACTICE)
+ if (last > clock && pulse)
{
if (clock <= 1000 && (last / 100) > (clock / 100))
{
/* balls and score + select coin widget */
- switch (mode)
+ switch (curr_mode())
{
case MODE_CHALLENGE:
if (gui_value(ball_id) != balls) gui_set_count(ball_id, balls);
c_id = coin_id;
break;
- case MODE_NORMAL:
- c_id = coin_id;
- break;
-
default:
- c_id = coin2_id;
+ c_id = coin_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);
}
/*---------------------------------------------------------------------------*/
-static unsigned int do_level_init = 1;
-
-int level_replay(const char *filename)
+int level_exists(int i)
{
- return demo_replay_init(filename, curr_lg());
+ return set_level_exists(curr_set(), i);
}
-int level_play(const struct level *l, int m)
+void level_open(int i)
{
- struct level_game *lg = curr_lg();
-
- if (do_level_init)
- {
- memset(lg, 0, sizeof (struct level_game));
-
- lg->mode = m;
- lg->level = l;
- lg->balls = 3;
- }
-
- lg->goal = (lg->mode == MODE_PRACTICE) ? 0 : lg->level->goal;
- lg->time = (lg->mode == MODE_PRACTICE) ? 0 : lg->level->time;
-
- /* Clear other fields. */
-
- 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);
+ if (level_exists(i))
+ get_level(i)->is_locked = 0;
}
-void level_stat(int status, int clock, int coins)
+int level_opened(int i)
{
- 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;
+ return level_exists(i) && !get_level(i)->is_locked;
+}
- /* 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;
- }
+void level_complete(int i)
+{
+ if (level_exists(i))
+ get_level(i)->is_completed = 1;
+}
- /* lose ball and game */
- else
- {
- lg->dead = (lg->balls <= 0);
- lg->balls--;
- }
- }
+int level_completed(int i)
+{
+ return level_exists(i) && get_level(i)->is_completed;
+}
- set_finish_level(lg, player);
+int level_time (int i)
+{
+ assert(level_exists(i));
+ return get_level(i)->time;
+}
- demo_play_stat(lg);
+int level_goal (int i)
+{
+ assert(level_exists(i));
+ return get_level(i)->goal;
}
-void level_stop(void)
+int level_bonus(int i)
{
- demo_play_stop();
- do_level_init = 1;
+ return level_exists(i) && get_level(i)->is_bonus;
}
-int level_next(void)
+const char *level_shot(int i)
{
- struct level_game *lg = curr_lg();
+ return level_exists(i) ? get_level(i)->shot : NULL;
+}
- level_stop();
- lg->level = lg->next_level;
- do_level_init = 0;
+const char *level_file(int i)
+{
+ return level_exists(i) ? get_level(i)->file : NULL;
+}
- return level_play(lg->level, lg->mode);
+const char *level_repr(int i)
+{
+ return level_exists(i) ? get_level(i)->repr : NULL;
}
-int level_same(void)
+const char *level_msg(int i)
{
- level_stop();
- do_level_init = 0;
- return level_play(curr_lg()->level, curr_lg()->mode);
+ if (level_exists(i) && strlen(get_level(i)->message) > 0)
+ return _(get_level(i)->message);
+
+ return NULL;
}
/*---------------------------------------------------------------------------*/
-int count_extra_balls(int old_score, int coins)
+int level_score_update(int level,
+ int timer,
+ int coins,
+ int *time_rank,
+ int *goal_rank,
+ int *coin_rank)
{
- return ((old_score % 100) + coins) / 100;
-}
+ struct level *l = get_level(level);
+ char player[MAXSTR] = "";
-void level_update_player_name(void)
-{
- char player[MAXNAM];
+ config_get_s(CONFIG_PLAYER, player, MAXSTR);
- config_get_s(CONFIG_PLAYER, player, MAXNAM);
+ if (time_rank)
+ *time_rank = score_time_insert(&l->score.best_times,
+ player, timer, coins);
- score_change_name(curr_lg(), player);
-}
+ if (goal_rank)
+ *goal_rank = score_time_insert(&l->score.unlock_goal,
+ player, timer, coins);
-/*---------------------------------------------------------------------------*/
+ if (coin_rank)
+ *coin_rank = score_coin_insert(&l->score.most_coins,
+ player, timer, coins);
-const char *status_to_str(int m)
+ if ((time_rank && *time_rank < 3) ||
+ (goal_rank && *goal_rank < 3) ||
+ (coin_rank && *coin_rank < 3))
+ return 1;
+ else
+ return 0;
+}
+
+void level_rename_player(int level,
+ int time_rank,
+ int goal_rank,
+ int coin_rank,
+ const char *player)
{
- 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");
- }
+ 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);
}
/*---------------------------------------------------------------------------*/
+
#include "base_config.h"
#include "score.h"
-#include "levels.h"
+#include "progress.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_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);
-
/*---------------------------------------------------------------------------*/
-int count_extra_balls(int, int);
+int level_exists(int);
+
+void level_open (int);
+int level_opened(int);
-void level_update_player_name(void);
+void level_complete (int);
+int level_completed(int);
+
+int level_time(int);
+int level_goal(int);
+int level_bonus(int);
+
+const char *level_shot(int);
+const char *level_file(int);
+const char *level_repr(int);
+const char *level_msg (int);
/*---------------------------------------------------------------------------*/
-#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 */
+int level_score_update (int, int, int, int *, int *, int *);
+void level_rename_player(int, int, int, int, const char *);
-const char *status_to_str(int);
+/*---------------------------------------------------------------------------*/
#endif
+++ /dev/null
-/*
- * Copyright (C) 2003 Robert Kooima
- *
- * 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 "levels.h"
-
-/*---------------------------------------------------------------------------*/
-
-/* Currently playing level. */
-static struct level_game current_level_game;
-
-struct level_game *curr_lg(void)
-{
- return ¤t_level_game;
-}
-
-/*---------------------------------------------------------------------------*/
+++ /dev/null
-#ifndef LEVELS_H
-#define LEVELS_H
-
-/*---------------------------------------------------------------------------*/
-
-struct level_game
-{
- int mode; /* game mode */
- const struct level *level; /* the level played */
-
- int goal; /* coins needed */
- int time; /* time limit */
-
- /* MODE_CHALLENGE only */
- int score; /* coin total */
- int balls; /* live count */
- int times; /* time total */
-
- int bonus; /* is a bonus level message needed? */
- char *bonus_repr; /* representation of the unlocked bonus level */
-
- /* Once a level is finished */
- int status; /* status ending */
- int coins; /* coins collected */
- int timer; /* time elapsed */
-
- /* rank = 3 => unclassed */
- int coin_rank; /* rank in the level high-scores */
- int goal_rank; /* rank in the level high-scores */
- int time_rank; /* rank in the level high-scores */
- int score_rank; /* rank in the set high-scores */
- int times_rank; /* rank in the set high-scores */
-
- /* What about the game and the set? */
- int dead; /* Is the game over and lost? */
- int win; /* Is the game over and win? */
- int unlock; /* Is the next level newly unlocked */
- const struct level *next_level; /* next level (NULL no next level) */
-};
-
-struct level_game *curr_lg(void);
-
-/*---------------------------------------------------------------------------*/
-
-#endif
#include "image.h"
#include "audio.h"
#include "demo.h"
-#include "levels.h"
+#include "progress.h"
#include "game.h"
#include "gui.h"
#include "set.h"
if (display_info)
{
- if (!level_replay(demo_path))
+ if (!progress_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)
+ if (replay_demo && progress_replay(demo_path))
{
- level_replay(demo_path);
demo_play_goto(1);
goto_state(&st_demo_play);
}
+++ /dev/null
-/*
- * Copyright (C) 2007 Robert Kooima
- *
- * 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 "mode.h"
-#include "lang.h"
-
-/*---------------------------------------------------------------------------*/
-
-static int mode = MODE_NORMAL;
-
-/*---------------------------------------------------------------------------*/
-
-int curr_mode(void)
-{
- return mode;
-}
-
-void mode_set(int new_mode)
-{
- mode = new_mode;
-}
-
-const char *mode_to_str(int m, int l)
-{
- switch (m)
- {
- case MODE_CHALLENGE: return l ? _("Challenge Mode") : _("Challenge");
- case MODE_NORMAL: return l ? _("Normal Mode") : _("Normal");
- case MODE_PRACTICE: return l ? _("Practice Mode") : _("Practice");
- default: return l ? _("Unknown Mode") : _("Unknown");
- }
-}
-
-/*---------------------------------------------------------------------------*/
+++ /dev/null
-#ifndef MODE_H
-#define MODE_H
-
-/*---------------------------------------------------------------------------*/
-
-#define MODE_CHALLENGE 1
-#define MODE_NORMAL 2
-#define MODE_PRACTICE 3
-
-#define MODE_COUNT 3
-
-void mode_set(int);
-int curr_mode(void);
-
-const char *mode_to_str(int, int);
-
-/*---------------------------------------------------------------------------*/
-
-#endif
--- /dev/null
+/*
+ * Copyright (C) 2003 Robert Kooima
+ *
+ * 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 "progress.h"
+#include "config.h"
+#include "game.h"
+#include "demo.h"
+#include "level.h"
+#include "set.h"
+#include "lang.h"
+#include "score.h"
+
+/*---------------------------------------------------------------------------*/
+
+struct progress
+{
+ int balls;
+ int score;
+ int times;
+};
+
+static int mode = MODE_NORMAL;
+
+static int level = 0;
+static int next = -1;
+static int done = 0;
+
+static int bonus = 0;
+
+static struct progress curr;
+static struct progress prev;
+
+/* Set stats. */
+
+static int score_rank = 3;
+static int times_rank = 3;
+
+/* Level stats. */
+
+static int status = GAME_NONE;
+
+static int coins = 0;
+static int timer = 0;
+
+static int goal = 0; /* Current goal value. */
+static int goal_i = 0; /* Initial goal value. */
+
+static int time_rank = 3;
+static int goal_rank = 3;
+static int coin_rank = 3;
+
+/*---------------------------------------------------------------------------*/
+
+void progress_init(int m)
+{
+ mode = m;
+ bonus = 0;
+
+ curr.balls = 2;
+ curr.score = 0;
+ curr.times = 0;
+
+ prev = curr;
+
+ score_rank = times_rank = 3;
+
+ done = 0;
+}
+
+int progress_play(int i)
+{
+ if (level_opened(i) || config_cheat())
+ {
+ level = i;
+
+ next = -1;
+ status = GAME_NONE;
+ coins = 0;
+ timer = 0;
+ goal = goal_i = level_goal(level);
+
+ prev = curr;
+
+ time_rank = goal_rank = coin_rank = 3;
+
+ if (demo_play_init(USER_REPLAY_FILE, get_level(level), mode,
+ level_time(level), level_goal(level),
+ (mode != MODE_CHALLENGE && level_completed(level) &&
+ config_get_d(CONFIG_LOCK_GOALS) == 0) || goal == 0,
+ curr.score, curr.balls, curr.times))
+ {
+ return 1;
+ }
+ else
+ {
+ demo_play_stop();
+ return 0;
+ }
+ }
+ return 0;
+}
+
+void progress_step(void)
+{
+ if (goal > 0)
+ {
+ goal = goal_i - curr_coins();
+
+ if (goal <= 0)
+ {
+ game_set_goal();
+ goal = 0;
+ }
+ }
+}
+
+void progress_stat(int s)
+{
+ int i, dirty = 0;
+
+ status = s;
+
+ coins = curr_coins();
+ timer = level_time(level) - curr_clock();
+
+ switch (status)
+ {
+ case GAME_GOAL:
+
+ for (i = curr.score + 1; i <= curr.score + coins; i++)
+ if (progress_reward_ball(i))
+ curr.balls++;
+
+ curr.score += coins;
+ curr.times += timer;
+
+ dirty = level_score_update(level, timer, coins,
+ &time_rank,
+ goal == 0 ? &goal_rank : NULL,
+ &coin_rank);
+
+ if (!level_completed(level))
+ {
+ level_complete(level);
+ dirty = 1;
+ }
+
+ /* Compute next level. */
+
+ if (mode == MODE_CHALLENGE)
+ {
+ for (next = level + 1; level_bonus(next); next++)
+ if (!level_opened(next))
+ {
+ level_open(next);
+ dirty = 1;
+ bonus++;
+ }
+ }
+ else
+ {
+ for (next = level + 1;
+ level_bonus(next) && !level_opened(next);
+ next++)
+ /* Do nothing. */;
+ }
+
+ /* Complete the set or open next level. */
+
+ if (!level_exists(next))
+ {
+ if (mode == MODE_CHALLENGE)
+ {
+ dirty = set_score_update(curr.times, curr.score,
+ &score_rank, ×_rank);
+ done = 1;
+ }
+ }
+ else
+ {
+ level_open(next);
+ dirty = 1;
+ }
+
+ break;
+
+ case GAME_FALL:
+ /* Fall through. */
+
+ case GAME_TIME:
+ for (next = level + 1;
+ level_exists(next) && !level_opened(next);
+ next++)
+ /* Do nothing. */;
+
+ curr.balls--;
+ break;
+ }
+
+ if (dirty)
+ set_store_hs();
+
+ demo_play_stat(status, coins, timer);
+}
+
+void progress_stop(void)
+{
+ demo_play_stop();
+}
+
+void progress_exit(int s)
+{
+ progress_stat(s);
+ progress_stop();
+}
+
+int progress_replay(const char *filename)
+{
+ if (demo_replay_init(filename, &goal, &mode,
+ &curr.balls,
+ &curr.score,
+ &curr.times))
+ {
+ goal_i = goal;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+int progress_next_avail(void)
+{
+ if (mode == MODE_CHALLENGE)
+ return status == GAME_GOAL && level_exists(next);
+ else
+ return level_opened(next);
+}
+
+int progress_same_avail(void)
+{
+ switch (status)
+ {
+ case GAME_NONE:
+ return mode != MODE_CHALLENGE;
+
+ default:
+ if (mode == MODE_CHALLENGE)
+ return !progress_dead();
+ else
+ return 1;
+ }
+}
+
+int progress_next(void)
+{
+ progress_stop();
+ return progress_play(next);
+}
+
+int progress_same(void)
+{
+ progress_stop();
+ curr = status == GAME_GOAL ? prev : curr;
+ return progress_play(level);
+}
+
+int progress_dead(void)
+{
+ return mode == MODE_CHALLENGE ? curr.balls < 0 : 0;
+}
+
+int progress_done(void)
+{
+ return done;
+}
+
+int progress_lvl_high(void)
+{
+ return time_rank < 3 || goal_rank < 3 || coin_rank < 3;
+}
+
+int progress_set_high(void)
+{
+ return score_rank < 3 || times_rank < 3;
+}
+
+void progress_rename(int set_only)
+{
+ char player[MAXNAM] = "";
+
+ config_get_s(CONFIG_PLAYER, player, sizeof (player));
+
+ if (set_only)
+ {
+ set_rename_player(score_rank, times_rank, player);
+ }
+ else
+ {
+ level_rename_player(level, time_rank, goal_rank, coin_rank, player);
+
+ if (progress_done())
+ set_rename_player(score_rank, times_rank, player);
+ }
+
+ set_store_hs();
+}
+
+int progress_reward_ball(int s)
+{
+ return s > 0 && s % 100 == 0;
+}
+
+/*---------------------------------------------------------------------------*/
+
+int curr_level(void) { return level; }
+int curr_balls(void) { return curr.balls; }
+int curr_score(void) { return curr.score; }
+int curr_mode (void) { return mode; }
+int curr_bonus(void) { return bonus; }
+int curr_goal (void) { return goal; }
+
+int progress_time_rank(void) { return time_rank; }
+int progress_goal_rank(void) { return goal_rank; }
+int progress_coin_rank(void) { return coin_rank; }
+
+int progress_times_rank(void) { return times_rank; }
+int progress_score_rank(void) { return score_rank; }
+
+/*---------------------------------------------------------------------------*/
+
+const char *mode_to_str(int m, int l)
+{
+ switch (m)
+ {
+ case MODE_CHALLENGE: return l ? _("Challenge Mode") : _("Challenge");
+ case MODE_NORMAL: return l ? _("Normal Mode") : _("Normal");
+ default: return l ? _("Unknown Mode") : _("Unknown");
+ }
+}
+
+/*---------------------------------------------------------------------------*/
--- /dev/null
+#ifndef PROGRESS_H
+#define PROGRESS_H
+
+/*---------------------------------------------------------------------------*/
+
+void progress_init(int);
+
+int progress_play(int level);
+void progress_step(void);
+void progress_stat(int status);
+void progress_stop(void);
+void progress_exit(int status);
+
+int progress_next_avail(void);
+int progress_next(void);
+int progress_same_avail(void);
+int progress_same(void);
+
+void progress_rename(int);
+
+int progress_replay(const char *);
+
+int progress_dead(void);
+int progress_done(void);
+
+int progress_lvl_high(void);
+int progress_set_high(void);
+
+int curr_level(void);
+int curr_balls(void);
+int curr_score(void);
+int curr_mode (void);
+int curr_bonus(void);
+int curr_goal (void);
+
+int progress_time_rank(void);
+int progress_goal_rank(void);
+int progress_coin_rank(void);
+
+int progress_times_rank(void);
+int progress_score_rank(void);
+
+int progress_reward_ball(int);
+
+/*---------------------------------------------------------------------------*/
+
+#define MODE_CHALLENGE 1
+#define MODE_NORMAL 2
+
+#define MODE_COUNT 2
+
+const char *mode_to_str(int, int);
+
+/*---------------------------------------------------------------------------*/
+
+#endif
char user_scores[PATHMAX]; /* User high-score file */
- struct score time_score; /* Challenge score */
struct score coin_score; /* Challenge score */
+ struct score time_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]);
}
-/* Store the score of the set. */
-static void set_store_hs(void)
+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;
}
-const struct level *get_level(int i)
+struct level *get_level(int i)
{
return (i >= 0 && i < set_v[set].count) ? &level_v[i] : NULL;
}
/*---------------------------------------------------------------------------*/
-/* 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 set_score_update(int timer, int coins, int *score_rank, int *times_rank)
{
- int timer = lg->times;
- int coins = lg->score;
struct set *s = &set_v[set];
+ char 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);
-}
-
-/* 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];
-
- 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);
-
- strncpy(s->coin_score.player[lg->score_rank], player, MAXNAM);
- strncpy(s->time_score.player[lg->times_rank], player, MAXNAM);
+ config_get_s(CONFIG_PLAYER, player, MAXSTR);
- set_store_hs();
-}
-
-static struct level *next_level(int i)
-{
- return set_level_exists(set, i + 1) ? &level_v[i + 1] : NULL;
-}
+ if (score_rank)
+ *score_rank = score_coin_insert(&s->coin_score, player, timer, coins);
-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];
+ if (times_rank)
+ *times_rank = score_time_insert(&s->time_score, player, timer, coins);
- return NULL;
+ if ((score_rank && *score_rank < 3) || (times_rank && *times_rank < 3))
+ return 1;
+ else
+ return 0;
}
-/*---------------------------------------------------------------------------*/
-
-void set_finish_level(struct level_game *lg, const char *player)
+void set_rename_player(int score_rank, int times_rank, 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;
- /* Update file */
- if (dirty)
- set_store_hs();
+ strncpy(s->coin_score.player[score_rank], player, MAXNAM);
+ strncpy(s->time_score.player[times_rank], player, MAXNAM);
}
/*---------------------------------------------------------------------------*/
/* Initialize the game for a snapshot. */
- if (game_init(&level_v[i], 0, 0))
+ if (game_init(level_v[i].file, 0, 1))
{
/* 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);
-const struct level *get_level(int);
-
-void set_finish_level(struct level_game *, const char *);
-void score_change_name(struct level_game *, const char *);
+struct level *get_level(int);
void level_snap(int);
void set_cheat(void);
#include "set.h"
#include "game.h"
#include "demo.h"
-#include "levels.h"
+#include "progress.h"
#include "audio.h"
#include "solid.h"
#include "config.h"
break;
default:
- if (level_replay(demo_get(i)->filename))
+ if (progress_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);
- level_replay(curr_demo_replay()->filename);
+ progress_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 "levels.h"
+#include "progress.h"
#include "audio.h"
#include "config.h"
#include "st_shared.h"
/*---------------------------------------------------------------------------*/
#define DONE_OK 1
-#define DONE_NAME 2
/* Bread crumbs. */
static int new_name;
+static int resume;
static int done_action(int i)
{
case DONE_OK:
return goto_state(&st_start);
- case DONE_NAME:
+ case GUI_NAME:
new_name = 1;
return goto_name(&st_done, &st_done, 0);
+
+ case GUI_MOST_COINS:
+ case GUI_BEST_TIMES:
+ case GUI_UNLOCK_GOAL:
+ gui_score_set(i);
+ resume = 1;
+ return goto_state(&st_done);
}
return 1;
}
int id, jd;
- int high = (curr_lg()->times_rank < 3) || (curr_lg()->score_rank < 3);
+ int high = progress_set_high();
if (new_name)
{
- level_update_player_name();
+ progress_rename(1);
new_name = 0;
}
gui_space(id);
- if ((jd = gui_harray(id)))
- {
- gui_most_coins(jd, 1);
- gui_best_times(jd, 1);
- }
+ if ((jd = gui_hstack(id)))
+ gui_score_board(jd, 1, high);
gui_space(id);
- if ((jd = gui_harray(id)))
- {
- /* FIXME, I'm ugly. */
-
- if (high)
- gui_state(jd, _("Change Player Name"), GUI_SML, DONE_NAME, 0);
+ gui_start(id, _("Select Level"), GUI_SML, DONE_OK, 0);
- gui_start(jd, _("OK"), GUI_SML, DONE_OK, 0);
- }
+ if (!resume)
+ gui_pulse(gid, 1.2f);
gui_layout(id, 0, 0);
- gui_pulse(gid, 1.2f);
}
- 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);
+ 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;
return id;
}
+static int done_keybd(int c, int d)
+{
+ if (d && config_tst_d(CONFIG_KEY_SCORE_NEXT, c))
+ return done_action(gui_score_next(gui_score_get()));
+
+ return 1;
+}
+
static int done_buttn(int b, int d)
{
if (d)
shared_stick,
shared_angle,
shared_click,
- NULL,
+ done_keybd,
done_buttn,
1, 0
};
#include "gui.h"
#include "game.h"
#include "util.h"
-#include "levels.h"
+#include "progress.h"
#include "audio.h"
#include "config.h"
#include "demo.h"
#define FALL_OUT_BACK 4
#define FALL_OUT_OVER 5
-static int be_back_soon;
+static int resume;
static int fall_out_action(int i)
{
/* Fall through. */
case FALL_OUT_OVER:
- level_stop();
+ progress_stop();
return goto_state(&st_over);
case FALL_OUT_SAVE:
- be_back_soon = 1;
+ resume = 1;
- level_stop();
+ progress_stop();
return goto_save(&st_fall_out, &st_fall_out);
case FALL_OUT_NEXT:
- level_next();
- return goto_state(&st_level);
+ if (progress_next())
+ return goto_state(&st_level);
+ break;
case FALL_OUT_SAME:
- level_same();
- return goto_state(&st_level);
+ if (progress_same())
+ return goto_state(&st_level);
+ break;
}
return 1;
{
int id, jd, kd;
- const struct level_game *lg = curr_lg();
-
/* Reset hack. */
- be_back_soon = 0;
+ resume = 0;
if ((id = gui_vstack(0)))
{
if ((jd = gui_harray(id)))
{
- 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_dead())
+ gui_start(jd, _("Exit"), GUI_SML, FALL_OUT_OVER, 0);
- gui_maybe(jd, _("Save Replay"), FALL_OUT_SAVE, demo_saved());
+ if (progress_next_avail())
+ gui_start(jd, _("Next Level"), GUI_SML, FALL_OUT_NEXT, 0);
- /* Default is next if the next level is newly unlocked. */
+ if (progress_same_avail())
+ gui_start(jd, _("Retry Level"), GUI_SML, FALL_OUT_SAME, 0);
- if (next_id && lg->unlock)
- gui_focus(next_id);
- else if (retry_id)
- gui_focus(retry_id);
+ if (demo_saved())
+ gui_state(jd, _("Save Replay"), GUI_SML, FALL_OUT_SAVE, 0);
}
gui_space(id);
{
if (d)
{
- if (config_tst_d(CONFIG_KEY_RESTART, c) && !curr_lg()->dead)
+ if (config_tst_d(CONFIG_KEY_RESTART, c) && progress_same_avail())
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 = be_back_soon ? shared_timer : fall_out_timer;
+ st_fall_out.timer = resume ? shared_timer : fall_out_timer;
gui_delete(id);
}
#include "gui.h"
#include "game.h"
#include "util.h"
-#include "levels.h"
+#include "progress.h"
#include "audio.h"
#include "config.h"
#include "demo.h"
#define GOAL_SAVE 3
#define GOAL_BACK 4
#define GOAL_DONE 5
-#define GOAL_NAME 6
-#define GOAL_OVER 7
+#define GOAL_OVER 6
static int balls_id;
static int coins_id;
/* Bread crumbs. */
static int new_name;
-static int be_back_soon;
+static int resume;
static int goal_action(int i)
{
/* Fall through. */
case GOAL_OVER:
- level_stop();
+ progress_stop();
return goto_state(&st_over);
case GOAL_SAVE:
- be_back_soon = 1;
+ resume = 1;
- level_stop();
+ progress_stop();
return goto_save(&st_goal, &st_goal);
- case GOAL_NAME:
+ case GUI_NAME:
new_name = 1;
- be_back_soon = 1;
+ resume = 1;
- level_stop();
+ progress_stop();
return goto_name(&st_goal, &st_goal, 0);
case GOAL_DONE:
- level_stop();
+ progress_stop();
return goto_state(&st_done);
+ case GUI_MOST_COINS:
+ case GUI_BEST_TIMES:
+ case GUI_UNLOCK_GOAL:
+ gui_score_set(i);
+ resume = 1;
+ return goto_state(&st_goal);
+
case GOAL_NEXT:
- level_next();
- return goto_state(&st_level);
+ if (progress_next())
+ return goto_state(&st_level);
+ break;
case GOAL_SAME:
- level_same();
- return goto_state(&st_level);
+ if (progress_same())
+ return goto_state(&st_level);
+ break;
}
return 1;
{
const char *s1 = _("New Record");
const char *s2 = _("GOAL");
- const char *s3 = _("Congratulations!");
int id, jd, kd;
- struct level_game *lg = curr_lg();
- const struct level *l = lg->level;
-
- int high;
-
- high = (lg->time_rank < 3) || (lg->goal_rank < 3) || (lg->coin_rank < 3);
+ const struct level *l = get_level(curr_level());
- /* Reset hack. */
- be_back_soon = 0;
+ int high = progress_lvl_high();
if (new_name)
{
- level_update_player_name();
+ progress_rename(0);
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 (lg->mode == MODE_CHALLENGE)
+ if (curr_mode() == MODE_CHALLENGE)
{
- int coins = lg->coins;
- int score = lg->score - coins;
- int balls = lg->balls - count_extra_balls(score, coins);
+ 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());
if ((jd = gui_hstack(id)))
{
+
if ((kd = gui_harray(jd)))
{
- balls_id = gui_count(kd, 100, GUI_MED, GUI_RGT);
- gui_label(kd, _("Balls"), GUI_SML, GUI_LFT, gui_wht, gui_wht);
+ balls_id = gui_count(kd, 100, GUI_MED, GUI_NE);
+ gui_label(kd, _("Balls"), GUI_SML, 0, gui_wht, gui_wht);
}
if ((kd = gui_harray(jd)))
{
- score_id = gui_count(kd, 1000, GUI_MED, GUI_RGT);
- gui_label(kd, _("Score"), GUI_SML, GUI_LFT, gui_wht, gui_wht);
+ score_id = gui_count(kd, 1000, GUI_MED, 0);
+ gui_label(kd, _("Score"), GUI_SML, 0, gui_wht, gui_wht);
}
if ((kd = gui_harray(jd)))
{
- coins_id = gui_count(kd, 100, GUI_MED, GUI_RGT);
- gui_label(kd, _("Coins"), GUI_SML, GUI_LFT, gui_wht, gui_wht);
+ coins_id = gui_count(kd, 100, GUI_MED, 0);
+ gui_label(kd, _("Coins"), GUI_SML, GUI_NW, 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;
}
- gui_space(id);
-
- if ((jd = gui_harray(id)))
- {
- gui_most_coins(jd, 1);
- gui_best_times(jd, 1);
- }
+ if ((jd = gui_hstack(id)))
+ gui_score_board(jd, 1, high);
gui_space(id);
if ((jd = gui_harray(id)))
{
- int next_id = 0, retry_id = 0;
-
- if (lg->win)
+ if (progress_done())
gui_start(jd, _("Finish"), GUI_SML, GOAL_DONE, 0);
- else
- next_id = gui_maybe(jd, _("Next Level"), GOAL_NEXT,
- lg->next_level != NULL);
-
- 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);
- }
- gui_maybe(jd, _("Save Replay"), GOAL_SAVE, demo_saved());
+ if (progress_next_avail())
+ gui_start(jd, _("Next Level"), GUI_SML, GOAL_NEXT, 0);
- /* Default is next if the next level is newly unlocked. */
+ if (progress_same_avail())
+ gui_start(jd, _("Retry Level"), GUI_SML, GOAL_SAME, 0);
- if (next_id && lg->unlock)
- gui_focus(next_id);
- else if (lg->mode != MODE_CHALLENGE)
- gui_focus(retry_id);
+ if (demo_saved())
+ gui_state(jd, _("Save Replay"), GUI_SML, GOAL_SAVE, 0);
}
- /* FIXME, I'm ugly. */
-
- if (high)
- gui_state(id, _("Change Player Name"), GUI_SML, GOAL_NAME, 0);
+ if (!resume)
+ gui_pulse(gid, 1.2f);
- gui_pulse(gid, 1.2f);
gui_layout(id, 0, 0);
}
- 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);
+ set_score_board(&l->score.most_coins, progress_coin_rank(),
+ &l->score.best_times, progress_time_rank(),
+ &l->score.unlock_goal, progress_goal_rank());
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 ((score + 1) % 100 == 0)
+ if (progress_reward_ball(score + 1))
{
gui_set_count(balls_id, balls + 1);
gui_pulse(balls_id, 2.0f);
gui_timer(id, dt);
}
+static int goal_keybd(int c, int d)
+{
+ if (d && config_tst_d(CONFIG_KEY_SCORE_NEXT, c))
+ return goal_action(gui_score_next(gui_score_get()));
+
+ return 1;
+}
+
static int goal_buttn(int b, int d)
{
if (d)
static void goal_leave(int id)
{
/* HACK: don't run animation if only "visiting" a state. */
- st_goal.timer = be_back_soon ? shared_timer : goal_timer;
+ st_goal.timer = resume ? shared_timer : goal_timer;
gui_delete(id);
}
shared_stick,
shared_angle,
shared_click,
- NULL,
+ goal_keybd,
goal_buttn,
1, 0
};
break;
case HELP_DEMO_1:
- if (demo_replay_init(config_data("gui/demo1.nbr"), NULL))
+ if (demo_replay_init(config_data("gui/demo1.nbr"),
+ NULL, NULL, NULL, NULL, NULL))
return goto_state(&st_help_demo);
break;
case HELP_DEMO_2:
- if (demo_replay_init(config_data("gui/demo2.nbr"), NULL))
+ if (demo_replay_init(config_data("gui/demo2.nbr"),
+ NULL, NULL, NULL, NULL, 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 "levels.h"
+#include "progress.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 = lg->level->repr;
- b = lg->level->is_bonus;
+ ln = level_repr (curr_level());
+ b = level_bonus(curr_level());
+
textcol1 = b ? gui_wht : 0;
textcol2 = b ? gui_grn : 0;
}
}
- gui_label(kd, mode_to_str(lg->mode, 1), GUI_SML, GUI_BOT,
+ gui_label(kd, mode_to_str(curr_mode(), 1), GUI_SML, GUI_BOT,
gui_wht, gui_wht);
}
}
gui_space(id);
- if (strlen(lg->level->message) != 0)
- gui_multi(id, _(lg->level->message), GUI_SML, GUI_ALL, gui_wht,
- gui_wht);
+ gui_multi(id, level_msg(curr_level()),
+ GUI_SML, GUI_ALL,
+ gui_wht, gui_wht);
gui_layout(id, 0, 0);
}
}
if (config_tst_d(CONFIG_JOYSTICK_BUTTON_EXIT, b))
{
- level_stat(GAME_NONE, curr_clock(), curr_coins());
- level_stop();
+ progress_stop();
return goto_state(&st_over);
}
}
#include "gui.h"
#include "set.h"
#include "game.h"
-#include "levels.h"
+#include "progress.h"
#include "audio.h"
#include "config.h"
#include "demo.h"
{
int id;
- if (curr_lg()->mode != MODE_CHALLENGE)
+ if (curr_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_lg()->mode != MODE_CHALLENGE || time_state() > 3.f)
+ if (curr_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 "levels.h"
+#include "progress.h"
#include "level.h"
#include "audio.h"
#include "hud.h"
return goto_state(st_continue);
case PAUSE_RESTART:
- level_same();
- clear_pause();
- SDL_PauseAudio(0);
- config_set_grab(1);
- return goto_state(&st_play_ready);
+ if (progress_same())
+ {
+ clear_pause();
+ SDL_PauseAudio(0);
+ config_set_grab(1);
+ return goto_state(&st_play_ready);
+ }
+ break;
case PAUSE_EXIT:
- level_stat(GAME_NONE, curr_clock(), curr_coins());
- level_stop();
+ progress_exit(GAME_NONE);
clear_pause();
SDL_PauseAudio(0);
audio_music_stop();
{
gui_state(jd, _("Quit"), GUI_SML, PAUSE_EXIT, 0);
- if (curr_lg()->mode != MODE_CHALLENGE)
+ if (progress_same_avail())
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_lg()->mode != MODE_CHALLENGE)
+ if (config_tst_d(CONFIG_KEY_RESTART, c) && progress_same_avail())
return pause_action(PAUSE_RESTART);
}
return 1;
#include "hud.h"
#include "game.h"
#include "demo.h"
-#include "levels.h"
+#include "progress.h"
#include "audio.h"
#include "config.h"
#include "st_shared.h"
{
if (SDL_GetModState() & KMOD_SHIFT)
{
- level_stat(GAME_NONE, curr_clock(), curr_coins());
- level_stop();
+ progress_exit(GAME_NONE);
config_clr_grab();
return goto_state(&st_over);
switch (game_step(g, dt, 1))
{
case GAME_GOAL:
- level_stat(GAME_GOAL, curr_clock(), curr_coins());
+ progress_stat(GAME_GOAL);
gui_stuck();
goto_state(&st_goal);
break;
case GAME_FALL:
- level_stat(GAME_FALL, curr_clock(), curr_coins());
+ progress_stat(GAME_FALL);
gui_stuck();
goto_state(&st_fall_out);
break;
case GAME_TIME:
- level_stat(GAME_TIME, curr_clock(), curr_coins());
+ progress_stat(GAME_TIME);
gui_stuck();
goto_state(&st_time_out);
break;
default:
+ progress_step();
break;
}
}
hud_view_pulse(2);
}
if (config_tst_d(CONFIG_KEY_RESTART, c) &&
- curr_lg()->mode != MODE_CHALLENGE)
+ progress_same_avail())
{
- level_same();
- goto_state(&st_play_ready);
+ if (progress_same())
+ goto_state(&st_play_ready);
}
if (config_tst_d(CONFIG_KEY_PAUSE, c))
goto_pause();
if (d && c == SDLK_c && config_cheat())
{
- level_stat(GAME_GOAL, curr_clock(), curr_coins());
+ progress_stat(GAME_GOAL);
return goto_state(&st_goal);
}
return 1;
#include "audio.h"
#include "config.h"
#include "demo.h"
-#include "levels.h"
+#include "progress.h"
#include "text.h"
#include "st_shared.h"
#include "gui.h"
#include "set.h"
-#include "levels.h"
+#include "progress.h"
#include "game.h"
#include "audio.h"
#include "config.h"
#include "set.h"
#include "util.h"
#include "game.h"
-#include "levels.h"
+#include "progress.h"
#include "audio.h"
#include "config.h"
#include "st_shared.h"
/*---------------------------------------------------------------------------*/
-#define START_BACK -1
-#define START_PRACTICE -2
-#define START_NORMAL -3
-#define START_CHALLENGE -4
+#define START_BACK -1
+#define START_CHALLENGE -2
+#define START_OPEN_GOALS -3
+#define START_LOCK_GOALS -4
static int shot_id;
-static int status_id;
/*---------------------------------------------------------------------------*/
static void gui_level(int id, int i)
{
- const GLfloat *fore, *back;
- const struct level *l;
+ const GLfloat *fore = 0, *back = 0;
int jd;
- if (!set_level_exists(curr_set(), i))
+ if (!level_exists(i))
{
- gui_space(id);
+ gui_label(id, " ", GUI_SML, GUI_ALL, gui_blk, gui_blk);
return;
}
- l = get_level(i);
-
- if (!l->is_locked)
+ if (level_opened(i))
{
- fore = l->is_bonus ? gui_grn : gui_wht;
- back = l->is_completed ? fore : gui_yel;
+ fore = level_bonus(i) ? gui_grn : gui_wht;
+ back = level_completed(i) ? fore : gui_yel;
}
- else
- fore = back = gui_gry;
- jd = gui_label(id, l->repr, GUI_SML, GUI_ALL, back, fore);
+ jd = gui_label(id, level_repr(i), GUI_SML, GUI_ALL, back, fore);
- gui_active(jd, i, 0);
+ if (level_opened(i) || config_cheat())
+ gui_active(jd, i, 0);
}
static void start_over_level(int i)
{
- const struct level *l = get_level(i);
- if (!l->is_locked || config_cheat())
+ if (level_opened(i) || config_cheat())
{
- gui_set_image(shot_id, l->shot);
-
- set_most_coins(&l->score.most_coins, -1);
+ gui_set_image(shot_id, level_shot(i));
- 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;
+ set_score_board(&get_level(i)->score.most_coins, -1,
+ &get_level(i)->score.best_times, -1,
+ &get_level(i)->score.unlock_goal, -1);
}
- 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)
+static void start_over(int id, int pulse)
{
int i;
- gui_pulse(id, 1.2f);
if (id == 0)
return;
- i = gui_token(id);
+ if (pulse)
+ gui_pulse(id, 1.2f);
+ i = gui_token(id);
- switch (i)
+ if (i == START_CHALLENGE || i == START_BACK)
{
- 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;
- case START_PRACTICE:
- gui_set_label(status_id, _("Train yourself without time nor coin"));
- break;
+ set_score_board(set_coin_score(curr_set()), -1,
+ set_time_score(curr_set()), -1,
+ set_time_score(curr_set()), -1);
}
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_NORMAL:
- mode_set(MODE_NORMAL);
- return goto_state(&st_start);
- case START_PRACTICE:
- mode_set(MODE_PRACTICE);
+
+ 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:
+ gui_score_set(i);
return goto_state(&st_start);
- }
- 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;
- }
+ case START_OPEN_GOALS:
+ config_set_d(CONFIG_LOCK_GOALS, 0);
+ return goto_state(&st_start);
- if (i >= 0)
- {
- const struct level *l = get_level(i);
+ case START_LOCK_GOALS:
+ config_set_d(CONFIG_LOCK_GOALS, 1);
+ return goto_state(&st_start);
- if (!l->is_locked || config_cheat())
- {
- if (level_play(l, mode))
- {
- return goto_state(&st_level);
- }
- else
- {
- level_stop();
- return 1;
- }
- }
+ default:
+ if (progress_play(i))
+ return goto_state(&st_level);
+ break;
}
+
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;
- /* Deactivate cheat */
-
- if (m == MODE_CHALLENGE && !config_cheat())
- {
- mode_set(MODE_NORMAL);
- m = MODE_NORMAL;
- }
+ progress_init(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,
- m == MODE_CHALLENGE);
+ curr_mode() == MODE_CHALLENGE);
}
}
gui_space(id);
- if ((jd = gui_harray(id)))
- {
- gui_most_coins(jd, 0);
- gui_best_times(jd, 0);
- }
+ if ((jd = gui_hstack(id)))
+ gui_score_board(jd, 0, 0);
+
gui_space(id);
- status_id = gui_label(id, _("Choose a level to play"), GUI_SML, GUI_ALL,
- gui_yel, gui_wht);
+ if ((jd = gui_hstack(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_layout(id, 0, 0);
- set_most_coins(NULL, -1);
- set_best_times(NULL, -1, m != MODE_PRACTICE);
+ set_score_board(NULL, -1, NULL, -1, NULL, -1);
}
audio_music_fade_to(0.5f, "bgm/inter.ogg");
static void start_point(int id, int x, int y, int dx, int dy)
{
- start_over(gui_point(id, x, y));
+ start_over(gui_point(id, x, y), 1);
}
static void start_stick(int id, int a, int v)
int x = (config_tst_d(CONFIG_JOYSTICK_AXIS_X, a)) ? v : 0;
int y = (config_tst_d(CONFIG_JOYSTICK_AXIS_Y, a)) ? v : 0;
- start_over(gui_stick(id, x, y));
+ start_over(gui_stick(id, x, y), 1);
}
static int start_keybd(int c, int d)
{
- if (d && c == SDLK_c && config_cheat())
+ if (d)
{
- set_cheat();
- return goto_state(&st_start);
- }
+ if (c == SDLK_c && config_cheat())
+ {
+ set_cheat();
+ return goto_state(&st_start);
+ }
+ else if (c == SDLK_F12)
+ {
+ int i;
- if (d && c == SDLK_F12)
- {
- int i;
+ /* Iterate over all levels, taking a screenshot of each. */
+
+ for (i = 0; i < MAXLVL; i++)
+ if (level_exists(i))
+ level_snap(i);
+ }
+ else if (config_tst_d(CONFIG_KEY_SCORE_NEXT, c))
+ {
+ int active = gui_click();
- /* Iterate over all levels, taking a screenshot of each. */
+ if (start_action(gui_score_next(gui_score_get())))
+ {
+ /* HACK ALERT
+ *
+ * This assumes that 'active' is a valid widget ID even after
+ * the above start_action has recreated the entire widget
+ * hierarchy. Maybe it is. Maybe it isn't.
+ */
+ gui_focus(active);
+ start_over(active, 0);
- for (i = 0; i < MAXLVL; i++)
- if (set_level_exists(curr_set(), i))
- level_snap(i);
+ return 1;
+ }
+ else
+ return 0;
+ }
}
return 1;
#include "game.h"
#include "util.h"
-#include "levels.h"
+#include "progress.h"
#include "demo.h"
#include "audio.h"
#include "gui.h"
/* Fall through. */
case TIME_OUT_OVER:
- level_stop();
+ progress_stop();
return goto_state(&st_over);
case TIME_OUT_SAVE:
- level_stop();
+ progress_stop();
return goto_save(&st_time_out, &st_time_out);
case TIME_OUT_NEXT:
- level_next();
- return goto_state(&st_level);
+ if (progress_next())
+ return goto_state(&st_level);
+ break;
case TIME_OUT_SAME:
- level_same();
- return goto_state(&st_level);
+ if (progress_same())
+ return goto_state(&st_level);
+ break;
}
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)))
{
- 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_dead())
+ gui_start(jd, _("Exit"), GUI_SML, TIME_OUT_OVER, 0);
- gui_maybe(jd, _("Save Replay"), TIME_OUT_SAVE, demo_saved());
+ if (progress_next_avail())
+ gui_start(jd, _("Next Level"), GUI_SML, TIME_OUT_NEXT, 0);
- /* Default is next if the next level is newly unlocked. */
+ if (progress_same_avail())
+ gui_start(jd, _("Retry Level"), GUI_SML, TIME_OUT_SAME, 0);
- if (next_id && lg->unlock)
- gui_focus(next_id);
- else if (retry_id)
- gui_focus(retry_id);
+ if (demo_saved())
+ gui_state(jd, _("Save Replay"), GUI_SML, TIME_OUT_SAVE, 0);
}
gui_space(id);
{
if (d)
{
- if (config_tst_d(CONFIG_KEY_RESTART, c) && !curr_lg()->dead)
+ if (config_tst_d(CONFIG_KEY_RESTART, c) && progress_same_avail())
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. */
- level_load("map-medium/title.sol", &title_level);
- game_init(&title_level, 0, 0);
+
+ game_init("map-medium/title.sol", 0, 1);
real_time = 0.0f;
mode = 0;
{
if ((demo = demo_pick()))
{
- demo_replay_init(demo, NULL);
+ demo_replay_init(demo, NULL, NULL, NULL, NULL, NULL);
game_set_fly(0.0f);
real_time = 0.0f;
mode = 2;
if (real_time > 1.0f)
{
- game_init(&title_level, 0, 0);
+ game_init("map-medium/title.sol", 0, 1);
+
real_time = 0.0f;
mode = 0;
}
/* Build a Most Coins top three list with default values. */
-void gui_most_coins(int id, int e)
+static void gui_most_coins(int id, int e)
{
const char *s = "1234567";
}
}
-/* Set the Most Coins top three list values for level i. */
+/* Set the Most Coins top three list values. */
-void set_most_coins(const struct score *s, int hilight)
+static void set_most_coins(const struct score *s, int hilight)
{
- int j, spe;
const char *name;
+ int j;
if (s == NULL)
{
for (j = 0; j < NSCORE + coin_extra_row; j++)
{
name = s->player[j];
- spe = is_special_name(name);
- if (spe)
- gui_set_color(coin_name[j], 0, 0);
- else if (j != hilight)
- gui_set_color(coin_name[j], gui_yel, gui_wht);
- else if (j>= NSCORE)
- gui_set_color(coin_name[j], gui_red, gui_red);
+ if (j == hilight)
+ {
+ if (j < NSCORE)
+ gui_set_color(coin_name[j], gui_grn, gui_grn);
+ else
+ gui_set_color(coin_name[j], gui_red, gui_red);
+ }
else
- gui_set_color(coin_name[j], gui_grn, gui_grn);
+ gui_set_color(coin_name[j], gui_yel, gui_wht);
gui_set_count(coin_coin[j], s->coins[j]);
- gui_set_label(coin_name[j], spe ? _(name) : name);
+ gui_set_label(coin_name[j], is_special_name(name) ? _(name) : name);
gui_set_clock(coin_time[j], s->timer[j]);
}
}
/* Build a Best Times top three list with default values. */
-void gui_best_times(int id, int e)
+static void gui_best_times(int id, int e)
{
const char *s = "1234567";
}
}
-/* Set the Best Times top three list values for level i. */
+/* Set the Best Times top three list values. */
-void set_best_times(const struct score *s, int hilight, int goal)
+static void set_best_times(const struct score *s, int hilight, int goal)
{
- int j, spe;
const char *name;
+ int j;
gui_set_label(time_label, goal ? _("Unlock Goal") : _("Best Times"));
for (j = 0; j < NSCORE + time_extra_row; j++)
{
name = s->player[j];
- spe = is_special_name(name);
- if (spe)
- 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)
- gui_set_color(time_name[j], gui_red, gui_red);
+ if (j == hilight)
+ {
+ if (j < NSCORE)
+ gui_set_color(time_name[j], gui_grn, gui_grn);
+ else
+ gui_set_color(time_name[j], gui_red, gui_red);
+ }
else
- gui_set_color(time_name[j], gui_grn, gui_grn);
+ gui_set_color(time_name[j], gui_yel, gui_wht);
gui_set_clock(time_time[j], s->timer[j]);
- gui_set_label(time_name[j], spe ? _(name) : name);
+ gui_set_label(time_name[j], is_special_name(name) ? _(name) : name);
gui_set_count(time_coin[j], s->coins[j]);
}
}
/*---------------------------------------------------------------------------*/
+static int score_type = GUI_MOST_COINS;
+
+void gui_score_board(int id, int e, int h)
+{
+ int jd, kd, ld;
+
+ 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);
+
+ if (h)
+ {
+ gui_space(kd);
+
+ if ((ld = gui_hstack(kd)))
+ {
+ gui_filler(ld);
+ gui_state(ld, _("Change Name"), GUI_SML, GUI_NAME, 0);
+ gui_filler(ld);
+ }
+ }
+
+ 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 gui_score_set(int t)
+{
+ score_type = t;
+}
+
+int gui_score_get(void)
+{
+ return score_type;
+}
+
+int gui_score_next(int t)
+{
+ switch (t)
+ {
+ case GUI_MOST_COINS: return GUI_BEST_TIMES;
+ case GUI_BEST_TIMES: return GUI_UNLOCK_GOAL;
+ case GUI_UNLOCK_GOAL: return GUI_MOST_COINS;
+
+ default:
+ return GUI_MOST_COINS;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+
static int lock = 1;
static int keyd[127];
#define GUI_BS -104
#define GUI_CL -105
-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);
+#define GUI_MOST_COINS -106
+#define GUI_BEST_TIMES -107
+#define GUI_UNLOCK_GOAL -108
+
+#define GUI_NAME -109
+
+void gui_score_set(int);
+int gui_score_get(void);
+int gui_score_next(int);
+
+void gui_score_board(int, int, int);
+void set_score_board(const struct score *, int,
+ const struct score *, int,
+ const struct score *, int);
void gui_keyboard(int);
void gui_keyboard_lock(void);
config_set_d(CONFIG_KEY_RIGHT, DEFAULT_KEY_RIGHT);
config_set_d(CONFIG_KEY_PAUSE, DEFAULT_KEY_PAUSE);
config_set_d(CONFIG_KEY_RESTART, DEFAULT_KEY_RESTART);
+ config_set_d(CONFIG_KEY_SCORE_NEXT, DEFAULT_KEY_SCORE_NEXT);
config_set_d(CONFIG_SCREENSHOT, DEFAULT_SCREENSHOT);
+ config_set_d(CONFIG_LOCK_GOALS, DEFAULT_LOCK_GOALS);
}
void config_load(void)
else if (strcmp(key, "key_restart") == 0)
config_key(val, CONFIG_KEY_RESTART, DEFAULT_KEY_RESTART);
+ else if (strcmp(key, "key_score_next") == 0)
+ config_key(val, CONFIG_KEY_SCORE_NEXT, DEFAULT_KEY_SCORE_NEXT);
+
else if (strcmp(key, "player") == 0)
config_set_s(CONFIG_PLAYER, val);
else if (strcmp(key, "ball_file") == 0)
config_set_d(CONFIG_UNIFORM, atoi(val));
else if (strcmp(key, "screenshot") == 0)
config_set_d(CONFIG_SCREENSHOT, atoi(val));
+ else if (strcmp(key, "lock_goals") == 0)
+ config_set_d(CONFIG_LOCK_GOALS, atoi(val));
}
fclose(fp);
fprintf(fp, "key_restart %s\n",
SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_RESTART]));
+ fprintf(fp, "key_score_next %s\n",
+ SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_SCORE_NEXT]));
+
if (strlen(option_s[CONFIG_PLAYER]) > 0)
fprintf(fp, "player %s\n", option_s[CONFIG_PLAYER]);
if (strlen(option_s[CONFIG_BALL]) > 0)
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, "screenshot %d\n",
- option_d[CONFIG_SCREENSHOT]);
+ fprintf(fp, "stats %d\n", option_d[CONFIG_STATS]);
+ fprintf(fp, "uniform %d\n", option_d[CONFIG_UNIFORM]);
+ fprintf(fp, "screenshot %d\n", option_d[CONFIG_SCREENSHOT]);
+ fprintf(fp, "lock_goals %d\n", option_d[CONFIG_LOCK_GOALS]);
if (config_cheat())
fprintf(fp, "cheat %d\n", option_d[CONFIG_CHEAT]);
CONFIG_KEY_RIGHT,
CONFIG_KEY_PAUSE,
CONFIG_KEY_RESTART,
+ CONFIG_KEY_SCORE_NEXT,
CONFIG_CHEAT,
CONFIG_STATS,
CONFIG_UNIFORM,
CONFIG_SCREENSHOT,
+ CONFIG_LOCK_GOALS,
CONFIG_OPTION_D_COUNT
};
#define DEFAULT_KEY_RIGHT SDLK_RIGHT
#define DEFAULT_KEY_PAUSE SDLK_SPACE
#define DEFAULT_KEY_RESTART SDLK_r
+#define DEFAULT_KEY_SCORE_NEXT SDLK_TAB
#define DEFAULT_STATS 0
#define DEFAULT_UNIFORM 0
#define DEFAULT_SCREENSHOT 0
+#define DEFAULT_LOCK_GOALS 0
/*---------------------------------------------------------------------------*/
#define _(String) (String)
#define L_(String) (String)
+#define ngettext(msgid, msgid_plural, n) ((n) == 1 ? (msgid) : (msgid_plural))
+
#endif /* ENABLE_NLS */
/* No-op, useful for marking up strings for extraction-only. */