#include <SDL.h>
#include <stdio.h>
#include <string.h>
-#include <errno.h>
#include "glext.h"
#include "config.h"
/*---------------------------------------------------------------------------*/
-static void shot(void)
+static int shot_pending;
+
+static void shot_prep(void)
+{
+ shot_pending = 1;
+}
+
+static void shot_take(void)
{
static char filename[MAXSTR];
- sprintf(filename, "Screenshots/screen%05d.png", config_screenshot());
- image_snap(filename);
+ if (shot_pending)
+ {
+ sprintf(filename, "Screenshots/screen%05d.png", config_screenshot());
+ image_snap(filename);
+ shot_pending = 0;
+ }
}
/*---------------------------------------------------------------------------*/
static void toggle_wire(void)
{
+#if !ENABLE_OPENGLES
static int wire = 0;
if (wire)
glDisable(GL_LIGHTING);
wire = 1;
}
+#endif
}
/*---------------------------------------------------------------------------*/
+static int handle_key_dn(SDL_Event *e)
+{
+ int d = 1;
+ int c;
+
+ c = e->key.keysym.sym;
+
+ if (config_tst_d(CONFIG_KEY_FORWARD, c))
+ st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_Y), -1.0f);
+
+ else if (config_tst_d(CONFIG_KEY_BACKWARD, c))
+ st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_Y), +1.0f);
+
+ else if (config_tst_d(CONFIG_KEY_LEFT, c))
+ st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_X), -1.0f);
+
+ else if (config_tst_d(CONFIG_KEY_RIGHT, c))
+ st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_X), +1.0f);
+
+ else switch (c)
+ {
+ case SDLK_F10: shot_prep(); break;
+ case SDLK_F9: config_tgl_d(CONFIG_FPS); break;
+ case SDLK_F8: config_tgl_d(CONFIG_NICE); break;
+
+ case SDLK_F7:
+ if (config_cheat())
+ toggle_wire();
+ break;
+ case SDLK_RETURN:
+ d = st_buttn(config_get_d(CONFIG_JOYSTICK_BUTTON_A), 1);
+ break;
+ case SDLK_ESCAPE:
+ d = st_buttn(config_get_d(CONFIG_JOYSTICK_BUTTON_EXIT), 1);
+ break;
+
+ default:
+ if (SDL_EnableUNICODE(-1))
+ d = st_keybd(e->key.keysym.unicode, 1);
+ else
+ d = st_keybd(e->key.keysym.sym, 1);
+ }
+
+ return d;
+}
+
+static int handle_key_up(SDL_Event *e)
+{
+ int d = 1;
+ int c;
+
+ c = e->key.keysym.sym;
+
+ if (config_tst_d(CONFIG_KEY_FORWARD, c))
+ st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_Y), 0);
+
+ else if (config_tst_d(CONFIG_KEY_BACKWARD, c))
+ st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_Y), 0);
+
+ else if (config_tst_d(CONFIG_KEY_LEFT, c))
+ st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_X), 0);
+
+ else if (config_tst_d(CONFIG_KEY_RIGHT, c))
+ st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_X), 0);
+
+ else switch (c)
+ {
+ case SDLK_RETURN:
+ d = st_buttn(config_get_d(CONFIG_JOYSTICK_BUTTON_A), 0);
+ break;
+ case SDLK_ESCAPE:
+ d = st_buttn(config_get_d(CONFIG_JOYSTICK_BUTTON_EXIT), 0);
+ break;
+
+ default:
+ d = st_keybd(e->key.keysym.sym, 0);
+ }
+
+ return d;
+}
+
static int loop(void)
{
SDL_Event e;
int d = 1;
- int c;
/* Process SDL events. */
break;
case SDL_KEYDOWN:
-
- c = e.key.keysym.sym;
-
- if (config_tst_d(CONFIG_KEY_FORWARD, c))
- st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_Y), -JOY_MAX);
-
- else if (config_tst_d(CONFIG_KEY_BACKWARD, c))
- st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_Y), +JOY_MAX);
-
- else if (config_tst_d(CONFIG_KEY_LEFT, c))
- st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_X), -JOY_MAX);
-
- else if (config_tst_d(CONFIG_KEY_RIGHT, c))
- st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_X), +JOY_MAX);
-
- else switch (c)
- {
- case SDLK_F10: shot(); break;
- case SDLK_F9: config_tgl_d(CONFIG_FPS); break;
- case SDLK_F8: config_tgl_d(CONFIG_NICE); break;
-
- case SDLK_F7:
- if (config_cheat())
- toggle_wire();
- break;
-
- case SDLK_RETURN:
- d = st_buttn(config_get_d(CONFIG_JOYSTICK_BUTTON_A), 1);
- break;
- case SDLK_ESCAPE:
- d = st_buttn(config_get_d(CONFIG_JOYSTICK_BUTTON_EXIT), 1);
- break;
-
- default:
- if (SDL_EnableUNICODE(-1))
- d = st_keybd(e.key.keysym.unicode, 1);
- else
- d = st_keybd(e.key.keysym.sym, 1);
- }
-
+ d = handle_key_dn(&e);
break;
case SDL_KEYUP:
-
- c = e.key.keysym.sym;
-
- if (config_tst_d(CONFIG_KEY_FORWARD, c))
- st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_Y), 1);
-
- else if (config_tst_d(CONFIG_KEY_BACKWARD, c))
- st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_Y), 1);
-
- else if (config_tst_d(CONFIG_KEY_LEFT, c))
- st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_X), 1);
-
- else if (config_tst_d(CONFIG_KEY_RIGHT, c))
- st_stick(config_get_d(CONFIG_JOYSTICK_AXIS_X), 1);
-
- else switch (c)
- {
- case SDLK_RETURN:
- d = st_buttn(config_get_d(CONFIG_JOYSTICK_BUTTON_A), 0);
- break;
- case SDLK_ESCAPE:
- d = st_buttn(config_get_d(CONFIG_JOYSTICK_BUTTON_EXIT), 0);
- break;
-
- default:
- d = st_keybd(e.key.keysym.sym, 0);
- }
+ d = handle_key_up(&e);
+ break;
case SDL_ACTIVEEVENT:
if (e.active.state == SDL_APPINPUTFOCUS)
if (e.active.gain == 0 && video_get_grab())
- goto_pause();
+ goto_state(&st_pause);
break;
case SDL_JOYAXISMOTION:
- st_stick(e.jaxis.axis, e.jaxis.value);
+ st_stick(e.jaxis.axis, JOY_VALUE(e.jaxis.value));
break;
case SDL_JOYBUTTONDOWN:
/* Convert D-pad button events into joystick axis motion. */
- if (pad[0] && !pad[1]) st_stick(X, -JOY_MAX);
- else if (pad[1] && !pad[0]) st_stick(X, +JOY_MAX);
- else st_stick(X, 1);
+ if (pad[0] && !pad[1]) st_stick(X, -1.0f);
+ else if (pad[1] && !pad[0]) st_stick(X, +1.0f);
+ else st_stick(X, 0.0f);
- if (pad[2] && !pad[3]) st_stick(Y, -JOY_MAX);
- else if (pad[3] && !pad[2]) st_stick(Y, +JOY_MAX);
- else st_stick(Y, 1);
+ if (pad[2] && !pad[3]) st_stick(Y, -1.0f);
+ else if (pad[3] && !pad[2]) st_stick(Y, +1.0f);
+ else st_stick(Y, 0.0f);
}
else d = st_buttn(b, s);
}
/*---------------------------------------------------------------------------*/
-static char *data_path = NULL;
-static char *demo_path = NULL;
+static char *opt_data;
+static char *opt_replay;
+static char *opt_level;
-static unsigned int display_info = 0;
-static unsigned int replay_demo = 0;
-
-#define usage \
+#define opt_usage \
L_( \
"Usage: %s [options ...]\n" \
"Options:\n" \
" -v, --version show version.\n" \
" -d, --data <dir> use 'dir' as game data directory.\n" \
" -r, --replay <file> play the replay 'file'.\n" \
- " -i, --info display info about a replay.\n" \
+ " -l, --level <file> load the level 'file'\n" \
)
-#define argument_error(option) { \
- fprintf(stderr, L_("Option '%s' requires an argument.\n"), option); \
-}
+#define opt_error(option) \
+ fprintf(stderr, L_("Option '%s' requires an argument.\n"), option)
-static void parse_args(int argc, char **argv)
+static void opt_parse(int argc, char **argv)
{
int i;
{
if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0)
{
- printf(usage, argv[0]);
+ printf(opt_usage, argv[0]);
exit(EXIT_SUCCESS);
}
{
if (i + 1 == argc)
{
- argument_error(argv[i]);
+ opt_error(argv[i]);
exit(EXIT_FAILURE);
}
- data_path = argv[++i];
+ opt_data = argv[++i];
continue;
}
{
if (i + 1 == argc)
{
- argument_error(argv[i]);
+ opt_error(argv[i]);
exit(EXIT_FAILURE);
}
- demo_path = argv[++i];
+ opt_replay = argv[++i];
continue;
}
- if (strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--info") == 0)
+ if (strcmp(argv[i], "-l") == 0 || strcmp(argv[i], "--level") == 0)
{
- display_info = 1;
+ if (i + 1 == argc)
+ {
+ opt_error(argv[i]);
+ exit(EXIT_FAILURE);
+ }
+ opt_level = argv[++i];
continue;
}
- /* Assume a single unrecognised argument is a replay name. */
+ /* Perform magic on a single unrecognized argument. */
if (argc == 2)
{
- demo_path = argv[i];
- break;
- }
- }
+ size_t len = strlen(argv[i]);
+ int level = 0;
- /* Resolve conflicts. */
+ if (len > 4)
+ {
+ char *ext = argv[i] + len - 4;
- if (demo_path)
- replay_demo = display_info ? 0 : 1;
- else
- if (display_info)
- {
- /* FIXME, I'm a required option. */
- fputs(L_("Option '--info' requires '--replay'.\n"), stderr);
- exit(EXIT_FAILURE);
+ if (strcmp(ext, ".map") == 0)
+ strncpy(ext, ".sol", 4);
+
+ if (strcmp(ext, ".sol") == 0)
+ level = 1;
+ }
+
+ if (level)
+ opt_level = argv[i];
+ else
+ opt_replay = argv[i];
+
+ break;
}
+ }
}
-#undef usage
-#undef argument_error
+#undef opt_usage
+#undef opt_error
/*---------------------------------------------------------------------------*/
static int is_replay(struct dir_item *item)
{
- return strcmp(item->path + strlen(item->path) - 4, ".nbr") == 0;
+ return str_ends_with(item->path, ".nbr");
}
-static int is_score(struct dir_item *item)
+static int is_score_file(struct dir_item *item)
{
- return strncmp(item->path, "neverballhs-", sizeof ("neverballhs-") - 1) == 0;
+ return str_starts_with(item->path, "neverballhs-");
}
static void make_dirs_and_migrate(void)
if (fs_mkdir("Scores"))
{
- if ((items = fs_dir_scan("", is_score)))
+ if ((items = fs_dir_scan("", is_score_file)))
{
for (i = 0; i < array_len(items); i++)
{
fs_mkdir("Screenshots");
}
+/*---------------------------------------------------------------------------*/
+
int main(int argc, char *argv[])
{
SDL_Joystick *joy = NULL;
- int t1, t0, uniform;
+ int t1, t0;
if (!fs_init(argv[0]))
{
- fputs("Failure to initialize virtual file system\n", stderr);
+ fprintf(stderr, "Failure to initialize virtual file system: %s\n",
+ fs_error());
return 1;
}
lang_init("neverball");
- parse_args(argc, argv);
+ opt_parse(argc, argv);
- config_paths(data_path);
+ config_paths(opt_data);
make_dirs_and_migrate();
- /* Initialize SDL system and subsystems */
+ /* Initialize SDL. */
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) == -1)
{
return 1;
}
- /* Intitialize the configuration */
+ /* Intitialize configuration. */
config_init();
config_load();
- /* Dump replay information and exit. */
+ /* Initialize joystick. */
- if (display_info && fs_add_path(dir_name(demo_path)))
- {
- if (!progress_replay(base_name(demo_path, NULL)))
- {
- fprintf(stderr, L_("Replay file '%s': %s\n"), demo_path,
- errno ? strerror(errno) : L_("Not a replay file"));
- return 1;
- }
- demo_replay_dump_info();
- return 0;
- }
-
- /* Initialize the joystick. */
-
- if (SDL_NumJoysticks() > 0)
+ if (config_get_d(CONFIG_JOYSTICK) && SDL_NumJoysticks() > 0)
{
joy = SDL_JoystickOpen(config_get_d(CONFIG_JOYSTICK_DEVICE));
if (joy)
SDL_JoystickEventState(SDL_ENABLE);
}
- /* Initialize the audio. */
+ /* Initialize audio. */
audio_init();
tilt_init();
- /* Initialize the video. */
+ /* Initialize video. */
if (!video_init(TITLE, ICON))
return 1;
init_state(&st_null);
- /* Initialise demo playback. */
+ /* Initialize demo playback or load the level. */
- if (replay_demo && fs_add_path(dir_name(demo_path)) &&
- progress_replay(base_name(demo_path, NULL)))
+ if (opt_replay &&
+ fs_add_path(dir_name(opt_replay)) &&
+ progress_replay(base_name(opt_replay)))
{
demo_play_goto(1);
goto_state(&st_demo_play);
}
+ else if (opt_level)
+ {
+ const char *path = fs_resolve(opt_level);
+ int loaded = 0;
+
+ if (path)
+ {
+ /* HACK: must be around for the duration of the game. */
+ static struct level level;
+
+ if (level_load(path, &level))
+ {
+ progress_init(MODE_STANDALONE);
+
+ if (progress_play(&level))
+ {
+ goto_state(&st_level);
+ loaded = 1;
+ }
+ }
+ }
+ else fprintf(stderr, "%s: file is not in game path\n", opt_level);
+
+ if (!loaded)
+ goto_state(&st_title);
+ }
else
goto_state(&st_title);
/* Run the main game loop. */
- uniform = config_get_d(CONFIG_UNIFORM);
t0 = SDL_GetTicks();
while (loop())
{
- t1 = SDL_GetTicks();
-
- if (uniform)
- {
- /* Step the game uniformly, as configured. */
-
- int u;
-
- for (u = 0; u < abs(uniform); ++u)
- {
- st_timer(DT);
- t0 += (int) (DT * 1000);
- }
- }
- else
+ if ((t1 = SDL_GetTicks()) > t0)
{
- /* Step the game state at least up to the current time. */
+ /* Step the game state. */
- while (t1 > t0)
- {
- st_timer(DT);
- t0 += (int) (DT * 1000);
- }
- }
+ st_timer(0.001f * (t1 - t0));
- /* Render. */
+ t0 = t1;
- st_paint(0.001f * t0);
- video_swap();
+ /* Render. */
- if (uniform < 0)
- shot();
+ st_paint(0.001f * t0);
+ shot_take();
+ video_swap();
- if (config_get_d(CONFIG_NICE))
- SDL_Delay(1);
+ if (config_get_d(CONFIG_NICE))
+ SDL_Delay(1);
+ }
}
- /* Gracefully close the game */
+ config_save();
- if (SDL_JoystickOpened(0))
+ if (joy)
SDL_JoystickClose(joy);
tilt_free();
SDL_Quit();
- config_save();
-
return 0;
}