When KOBO_BENCH=1 is set in the environment, the game becomes a
hands-off benchmark:
* Skips the intro/menu sequence and pushes st_game directly with
scene=0, skill=CLASSIC, invulnerable ship, always_fire = constant
auto-fire, countdown = 0 so "GET READY" auto-pops in 700ms.
* Seeds pubrand and gamerand from KOBO_BENCH_SEED (default 12345)
so the map, stress spawn pattern, and enemy AI are identical
run-to-run.
* Defaults KOBO_STRESS=1500 unless overridden, so the move pass has
a steady workload, and KOBO_PROF=1 so the profiler is on.
* Counts frames in run_game; after KOBO_BENCH_FRAMES (default 1800)
it dumps prof to stderr and exits cleanly.
Usage from repo root (the cwd matters — relative GFX paths only
resolve from here):
KOBO_BENCH=1 ./build/kobodl 2>bench-logs/phaseN.log
A single command produces a comparable profiler dump at every phase
of the DOD refactor — no menus to navigate, no keyboard input,
identical workload.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
796 lines
15 KiB
C++
796 lines
15 KiB
C++
/*(GPL)
|
|
------------------------------------------------------------
|
|
Kobo Deluxe - An enhanced SDL port of XKobo
|
|
------------------------------------------------------------
|
|
* Copyright (C) 1995, 1996 Akira Higuchi
|
|
* Copyright (C) 2002 Jeremy Sheeley
|
|
* Copyright (C) 2001-2003, 2007 David Olofson
|
|
*
|
|
* This program 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
// Define to get time and ships lost printed out per finished stage
|
|
// NOTE: Also disables bonus ships!
|
|
#undef PLAYSTATS
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <math.h>
|
|
#ifndef M_PI
|
|
# define M_PI 3.14159265358979323846 /* pi */
|
|
#endif
|
|
|
|
#include "kobo.h"
|
|
#include "screen.h"
|
|
#include "manage.h"
|
|
#include "options.h"
|
|
#include "scenes.h"
|
|
#include "score.h"
|
|
#include "enemies.h"
|
|
#include "myship.h"
|
|
#include "radar.h"
|
|
#include "gamectl.h"
|
|
#include "states.h"
|
|
#include "audio.h"
|
|
#include "random.h"
|
|
#include "prof.h"
|
|
#include "bench.h"
|
|
|
|
#define GIGA 1000000000
|
|
|
|
// Stress-test spawner: keeps the enemy pool topped up with rocks so frame
|
|
// timing is stable. Enabled by KOBO_STRESS=N (target population, 0 = off).
|
|
static int kobo_stress_target = -1;
|
|
static int kobo_stress_init(void)
|
|
{
|
|
if (kobo_stress_target >= 0) return kobo_stress_target;
|
|
const char *e = getenv("KOBO_STRESS");
|
|
kobo_stress_target = (e && *e) ? atoi(e) : 0;
|
|
if (kobo_stress_target > 0)
|
|
fprintf(stderr, "[stress] target population=%d\n", kobo_stress_target);
|
|
return kobo_stress_target;
|
|
}
|
|
static void kobo_stress_step(void);
|
|
|
|
int _manage::blank = 0;
|
|
int _manage::next_state_out;
|
|
int _manage::next_state_next;
|
|
int _manage::game_seed;
|
|
int _manage::scene_num;
|
|
int _manage::ships;
|
|
int _manage::score;
|
|
float _manage::disp_health;
|
|
float _manage::disp_temp;
|
|
int _manage::score_changed = 1;
|
|
int _manage::ships_changed = 1;
|
|
int _manage::bonus_next;
|
|
int _manage::flush_score_count = 0;
|
|
int _manage::flush_ships_count = 0;
|
|
int _manage::scroll_jump = 0;
|
|
int _manage::delay_count;
|
|
int _manage::rest_cores;
|
|
int _manage::introtime = 0;
|
|
int _manage::exit_manage = 0;
|
|
int _manage::playing = 0;
|
|
int _manage::_get_ready = 0;
|
|
int _manage::_game_over = 0;
|
|
s_hiscore_t _manage::hi;
|
|
int _manage::noise_duration = 0;
|
|
int _manage::noise_timer = 0;
|
|
int _manage::noise_flash = 500;
|
|
float _manage::noise_level = 0.0f;
|
|
int _manage::intro_x = CHIP_SIZEX * (64-18);
|
|
int _manage::intro_y = CHIP_SIZEY * (64-7);
|
|
int _manage::show_bars = 0;
|
|
|
|
#ifdef PLAYSTATS
|
|
static Uint32 start_time = 0;
|
|
static int start_ships = 0;
|
|
#endif
|
|
|
|
|
|
void _manage::set_bars()
|
|
{
|
|
whealth->enable(show_bars);
|
|
wtemp->enable(show_bars);
|
|
wttemp->enable(show_bars);
|
|
}
|
|
|
|
|
|
// NOTE:
|
|
// After a noise out has faded out the sound effects, it's the
|
|
// noise/interfecence effect when the playfield is reinitialized
|
|
// that "accidentally" restores volume!
|
|
//
|
|
void _manage::run_noise()
|
|
{
|
|
if(noise_flash == -2)
|
|
{
|
|
// Damage flash
|
|
noise_timer -= game.speed;
|
|
if(noise_timer <= 0)
|
|
noise_timer = 0;
|
|
screen.noise(noise_timer);
|
|
float t = (float)noise_timer / noise_duration;
|
|
wmain->background(wmain->map_rgb(wmain->fadergb(0xff0000,
|
|
(int)(t * noise_level * 64))));
|
|
screen.set_noise(B_HITNOISE, t * noise_level,
|
|
t * noise_level, 0.0f);
|
|
return;
|
|
}
|
|
else if(noise_flash == -1)
|
|
{
|
|
// Noise-out
|
|
noise_timer -= game.speed;
|
|
if(noise_timer <= 0)
|
|
noise_timer = 0;
|
|
float t = (float)noise_timer / noise_duration;
|
|
float a = t * 2.0f * M_PI;
|
|
wmain->background(wmain->map_rgb(wmain->fadergb(0x00ff99,
|
|
(int)(sin(a * 0.5f) * 0.3f * 64))));
|
|
screen.set_noise(B_NOISE, 1.0f - t,
|
|
sin(a * 0.5f) * 0.3f,
|
|
0.3f + t * 0.5f);
|
|
sound.sfx_volume(t);
|
|
return;
|
|
}
|
|
|
|
wmain->background(wmain->map_rgb(0x00000));
|
|
|
|
// Noise/interference
|
|
int noise;
|
|
if(noise_timer > noise_flash)
|
|
{
|
|
noise_timer -= game.speed;
|
|
noise = 1;
|
|
}
|
|
else if(noise_timer > 0)
|
|
{
|
|
unsigned prob = noise_flash - noise_timer;
|
|
prob <<= 8;
|
|
prob /= noise_flash;
|
|
noise_timer -= game.speed;
|
|
noise = pubrand.get(8) > prob;
|
|
}
|
|
else
|
|
{
|
|
noise_timer = 0;
|
|
noise = 0;
|
|
}
|
|
|
|
noise_level += (noise - noise_level) * 0.3f;
|
|
screen.set_noise(B_NOISE, noise_level, 0.0f, noise_level);
|
|
screen.noise(noise_level > 0.1f);
|
|
|
|
sound.ui_noise(noise);
|
|
}
|
|
|
|
|
|
void _manage::noise(int duration, int flash)
|
|
{
|
|
noise_flash = flash;
|
|
noise_duration = noise_timer = duration;
|
|
sound.ui_noise(-1);
|
|
screen.set_noise(B_NOISE, 1.0f, 0.0f, 1.0f);
|
|
noise_level = 1.0f;
|
|
}
|
|
|
|
|
|
void _manage::noise_out(int duration)
|
|
{
|
|
noise_flash = -1;
|
|
noise_duration = noise_timer = duration;
|
|
screen.noise(1);
|
|
}
|
|
|
|
|
|
void _manage::noise_damage(float amt)
|
|
{
|
|
noise_flash = -2;
|
|
noise_duration = noise_timer = (int)(300.0f + 1500.0f * amt);
|
|
noise_level = 0.3f + 0.3f * amt;
|
|
}
|
|
|
|
|
|
void _manage::game_start()
|
|
{
|
|
_game_over = 0;
|
|
hi.clear();
|
|
|
|
game.set(GAME_SINGLE, (skill_levels_t)scorefile.profile()->skill);
|
|
|
|
#ifdef PLAYSTATS
|
|
ships = 100;
|
|
#else
|
|
ships = game.lives;
|
|
#endif
|
|
disp_health = 0;
|
|
disp_temp = 0;
|
|
score = 0;
|
|
flush_score_count = 0;
|
|
bonus_next = game.bonus_first;
|
|
gengine->period(game.speed);
|
|
sound.period(game.speed);
|
|
screen.init_scene(scene_num);
|
|
init_resources_to_play(1);
|
|
|
|
gamecontrol.clear();
|
|
gamecontrol.repeat(0, 0);
|
|
|
|
playing = 1;
|
|
_get_ready = 1;
|
|
|
|
hi.skill = game.skill;
|
|
hi.playtime = 0;
|
|
hi.gametype = game.type;
|
|
#if 1
|
|
// The new skill levels are under development!
|
|
// We want to mark highscores so they're not mistaken
|
|
// for official scores from a future finalized version.
|
|
if(game.skill != SKILL_CLASSIC)
|
|
hi.gametype |= GAME_EXPERIMENTAL;
|
|
#endif
|
|
hi.saves = 0;
|
|
hi.loads = 0;
|
|
hi.start_scene = scene_num;
|
|
hi.end_lives = ships;
|
|
sound.g_music(SOUND_BGM);
|
|
|
|
#ifdef PLAYSTATS
|
|
start_time = SDL_GetTicks();
|
|
start_ships = ships;
|
|
#endif
|
|
}
|
|
|
|
|
|
void _manage::game_stop()
|
|
{
|
|
if(!prefs->cmd_cheat && !prefs->cmd_pushmove)
|
|
{
|
|
hi.score = score;
|
|
hi.end_scene = scene_num;
|
|
hi.end_health = myship.health();
|
|
|
|
scorefile.record(&hi);
|
|
}
|
|
ships = 0;
|
|
ships_changed = 1;
|
|
audio_channel_stop(0, -1);
|
|
playing = 0;
|
|
}
|
|
|
|
void _manage::next_scene()
|
|
{
|
|
#ifdef PLAYSTATS
|
|
printf("stage %d:\n", scene_num);
|
|
Uint32 nst = SDL_GetTicks();
|
|
printf(" time: %d s\n", (nst - start_time) / 1000);
|
|
printf(" deaths: %d\n", start_ships - ships);
|
|
start_time = nst;
|
|
start_ships = ships;
|
|
#endif
|
|
scene_num++;
|
|
if(scene_num >= GIGA - 1)
|
|
scene_num = GIGA - 2;
|
|
screen.init_scene(scene_num);
|
|
scroll_jump = 1;
|
|
_get_ready = 1;
|
|
}
|
|
|
|
|
|
void _manage::retry()
|
|
{
|
|
if(!prefs->cmd_cheat)
|
|
{
|
|
ships--;
|
|
ships_changed = 1;
|
|
}
|
|
if(ships <= 0)
|
|
{
|
|
if(!_game_over)
|
|
{
|
|
game_stop();
|
|
_game_over = 1;
|
|
}
|
|
}
|
|
else
|
|
_get_ready = 1;
|
|
gamecontrol.clear();
|
|
}
|
|
|
|
|
|
void _manage::init_resources_title()
|
|
{
|
|
noise(1000, 800);
|
|
screen.init_scene(INTRO_SCENE);
|
|
gengine->period(30);
|
|
sound.period(30);
|
|
gamerand.init();
|
|
enemies.init();
|
|
myship.init();
|
|
myship.off();
|
|
screen.prepare();
|
|
screen.generate_fixed_enemies();
|
|
put_info();
|
|
put_score();
|
|
put_ships();
|
|
put_health(1);
|
|
put_temp(1);
|
|
run_intro();
|
|
gengine->force_scroll();
|
|
gamecontrol.repeat(KOBO_KEY_DELAY, KOBO_KEY_REPEAT);
|
|
show_bars = 0;
|
|
set_bars();
|
|
}
|
|
|
|
|
|
void _manage::init_resources_to_play(int newship)
|
|
{
|
|
noise(400, 300);
|
|
delay_count = 0;
|
|
flush_score_count = (flush_score_count) ? -1 : 0;
|
|
flush_ships_count = 0;
|
|
score_changed = 0;
|
|
next_state_out = 0;
|
|
next_state_next = 0;
|
|
|
|
if(kobo_bench_enabled)
|
|
gamerand.init(kobo_bench_seed); // deterministic map + spawn pattern
|
|
else
|
|
gamerand.init();
|
|
game_seed = gamerand.get_seed();
|
|
enemies.init();
|
|
myship.init();
|
|
if(newship)
|
|
myship.health(game.health);
|
|
rest_cores = screen.prepare();
|
|
scroll_jump = 1;
|
|
screen.generate_fixed_enemies();
|
|
put_info();
|
|
put_score();
|
|
put_ships();
|
|
switch(game.skill)
|
|
{
|
|
case SKILL_CLASSIC:
|
|
show_bars = 0;
|
|
break;
|
|
case SKILL_NEWBIE:
|
|
case SKILL_GAMER:
|
|
case SKILL_ELITE:
|
|
case SKILL_GOD:
|
|
default:
|
|
show_bars = 1;
|
|
break;
|
|
}
|
|
set_bars();
|
|
put_health(1);
|
|
put_temp(1);
|
|
myship.put();
|
|
gengine->scroll(PIXEL2CS(myship.get_virtx()),
|
|
PIXEL2CS(myship.get_virty()));
|
|
gengine->force_scroll();
|
|
}
|
|
|
|
|
|
void _manage::put_health(int force)
|
|
{
|
|
int h = myship.health();
|
|
if(h > disp_health)
|
|
{
|
|
disp_health += (float)game.health * .05;
|
|
if(disp_health > h)
|
|
disp_health = h;
|
|
// whealth->background(whealth->map_rgb(0, 100, 0));
|
|
}
|
|
else if(h < disp_health)
|
|
{
|
|
disp_health -= (float)game.health * .1;
|
|
if(disp_health < h)
|
|
disp_health = h;
|
|
// whealth->background(whealth->map_rgb(128, 0, 0));
|
|
}
|
|
// else
|
|
// whealth->background(whealth->map_rgb(0, 0, 0));
|
|
whealth->value((float)disp_health / game.health);
|
|
if(force)
|
|
whealth->invalidate();
|
|
}
|
|
|
|
|
|
void _manage::put_temp(int force)
|
|
{
|
|
wtemp->value(myship.get_nose_temp() / 256.0f);
|
|
wttemp->value(myship.get_tail_temp() / 256.0f);
|
|
if(force)
|
|
{
|
|
wtemp->invalidate();
|
|
wttemp->invalidate();
|
|
}
|
|
}
|
|
|
|
|
|
void _manage::put_info()
|
|
{
|
|
static char s[16];
|
|
|
|
snprintf(s, 16, "%010d", scorefile.highscore());
|
|
dhigh->text(s);
|
|
dhigh->on();
|
|
|
|
snprintf(s, 16, "%03d", scene_num + 1);
|
|
dstage->text(s);
|
|
dstage->on();
|
|
|
|
score_changed = 1;
|
|
ships_changed = 1;
|
|
}
|
|
|
|
|
|
void _manage::put_score()
|
|
{
|
|
if(score_changed)
|
|
{
|
|
static char s[32];
|
|
snprintf(s, 16, "%010d", score);
|
|
dscore->text(s);
|
|
dscore->on();
|
|
if(score > scorefile.highscore())
|
|
{
|
|
dhigh->text(s);
|
|
dhigh->on();
|
|
}
|
|
score_changed = 0;
|
|
}
|
|
if(flush_score_count > 0)
|
|
flush_score();
|
|
}
|
|
|
|
|
|
void _manage::put_ships()
|
|
{
|
|
if(ships_changed)
|
|
{
|
|
static char s[32];
|
|
if(!prefs->cmd_cheat)
|
|
snprintf(s, 16, "%03d", ships);
|
|
else
|
|
snprintf(s, 16, "999");
|
|
dships->text(s);
|
|
dships->on();
|
|
ships_changed = 0;
|
|
}
|
|
if(flush_ships_count > 0)
|
|
flush_ships();
|
|
}
|
|
|
|
|
|
void _manage::flush_score()
|
|
{
|
|
flush_score_count--;
|
|
if(flush_score_count & 1)
|
|
return;
|
|
|
|
if(flush_score_count & 2)
|
|
dscore->off();
|
|
else
|
|
dscore->on();
|
|
if(flush_score_count == 0)
|
|
flush_score_count = -1;
|
|
}
|
|
|
|
|
|
void _manage::flush_ships()
|
|
{
|
|
flush_ships_count--;
|
|
if(flush_ships_count & 1)
|
|
return;
|
|
|
|
if(flush_ships_count & 2)
|
|
dships->off();
|
|
else
|
|
dships->on();
|
|
if(flush_ships_count == 0)
|
|
flush_ships_count = -1;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
void _manage::init()
|
|
{
|
|
scorefile.init();
|
|
ships = 0;
|
|
exit_manage = 0;
|
|
scene_num = -1;
|
|
flush_ships_count = 0;
|
|
flush_score_count = 0;
|
|
delay_count = 0;
|
|
screen.init();
|
|
init_resources_title();
|
|
}
|
|
|
|
|
|
void _manage::run_intro()
|
|
{
|
|
double t = SDL_GetTicks() * 0.001f;
|
|
gengine->scroll(PIXEL2CS(intro_x), PIXEL2CS(intro_y));
|
|
intro_y -= 3;
|
|
intro_x &= MAP_SIZEX*CHIP_SIZEX-1;
|
|
intro_y &= MAP_SIZEY*CHIP_SIZEY-1;
|
|
sound.g_position(intro_x + (WSIZE >> 1), intro_y + (WSIZE >> 1));
|
|
myship.set_position(intro_x + (WSIZE >> 1) + (int)(WSIZE * 0.3f * sin(t)),
|
|
intro_y + (WSIZE >> 1) + (int)(WSIZE * 0.3f * sin(t * 1.73)));
|
|
enemies.move_intro();
|
|
enemies.put();
|
|
|
|
put_health();
|
|
put_temp();
|
|
put_score();
|
|
put_ships();
|
|
|
|
run_noise();
|
|
}
|
|
|
|
|
|
void _manage::update()
|
|
{
|
|
myship.put();
|
|
enemies.put();
|
|
put_score();
|
|
put_ships();
|
|
gengine->scroll(PIXEL2CS(myship.get_virtx()),
|
|
PIXEL2CS(myship.get_virty()));
|
|
if(scroll_jump)
|
|
{
|
|
gengine->force_scroll();
|
|
scroll_jump = 0;
|
|
}
|
|
run_noise();
|
|
}
|
|
|
|
|
|
void _manage::run_pause()
|
|
{
|
|
put_health();
|
|
put_temp();
|
|
update();
|
|
}
|
|
|
|
|
|
void _manage::run_game()
|
|
{
|
|
PROF_ZONE("run_game");
|
|
put_health();
|
|
put_temp();
|
|
|
|
if(delay_count)
|
|
delay_count--;
|
|
|
|
if(delay_count == 1)
|
|
{
|
|
if(enemies.exist_pipe())
|
|
delay_count = 2;
|
|
else
|
|
{
|
|
int newship = next_state_out;
|
|
put_info();
|
|
if(next_state_out)
|
|
{
|
|
retry();
|
|
if(ships <= 0)
|
|
return;
|
|
}
|
|
if(next_state_next)
|
|
next_scene();
|
|
init_resources_to_play(newship);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(kobo_stress_init() > 0)
|
|
kobo_stress_step();
|
|
|
|
{ PROF_ZONE("myship.move"); myship.move(); }
|
|
{ PROF_ZONE("enemies.move"); enemies.move(); }
|
|
{ PROF_ZONE("hit_structure"); myship.hit_structure(); }
|
|
update();
|
|
++hi.playtime;
|
|
prof_frame_tick();
|
|
|
|
// Bench harness: stop the program after a fixed number of frames so a
|
|
// single command produces a comparable profiler dump across phases.
|
|
// Push SDL_EVENT_QUIT instead of calling exit() — exit() runs the
|
|
// atexit handler which tries to shut down SDL audio synchronously and
|
|
// hangs on macOS. Going through the engine's own quit path tears down
|
|
// in the right order.
|
|
if(kobo_bench_enabled && (int)hi.playtime >= kobo_bench_frames)
|
|
{
|
|
static int triggered = 0;
|
|
if(!triggered)
|
|
{
|
|
triggered = 1;
|
|
fprintf(stderr,
|
|
"[bench] reached %d frames; dumping profile and quitting\n",
|
|
kobo_bench_frames);
|
|
prof_dump(stderr);
|
|
SDL_Event ev;
|
|
SDL_zero(ev);
|
|
ev.type = SDL_EVENT_QUIT;
|
|
SDL_PushEvent(&ev);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Top up the enemy pool with rocks until we hit the target population.
|
|
// Rocks are inert enough to give a stable per-frame integration cost.
|
|
static void kobo_stress_step(void)
|
|
{
|
|
extern const enemy_kind rock;
|
|
int target = kobo_stress_target;
|
|
if (target <= 0) return;
|
|
// Spawn at most a few per frame to avoid burst allocation spikes.
|
|
for (int i = 0; i < 8; ++i) {
|
|
int px = (pubrand.get() & (WORLD_SIZEX - 1));
|
|
int py = (pubrand.get() & (WORLD_SIZEY - 1));
|
|
int h = (int)(pubrand.get() & 0x7f) - 64;
|
|
int v = (int)(pubrand.get() & 0x7f) - 64;
|
|
// enemies.make returns 0 on success, non-zero when pool is full.
|
|
if (enemies.make(&rock, px, py, h, v) != 0) break;
|
|
}
|
|
}
|
|
|
|
|
|
void _manage::lost_myship()
|
|
{
|
|
if(delay_count == 0)
|
|
delay_count = 100;
|
|
next_state_out = 1;
|
|
}
|
|
|
|
|
|
void _manage::destroyed_a_core()
|
|
{
|
|
// Award 10% health bonus for destroyed core!
|
|
myship.health_bonus(10);
|
|
rest_cores--;
|
|
if(rest_cores == 0)
|
|
{
|
|
next_state_next = 1;
|
|
delay_count = 50;
|
|
// Award another 25% health bonus for stage cleared!
|
|
myship.health_bonus(25);
|
|
}
|
|
screen.generate_fixed_enemies();
|
|
}
|
|
|
|
|
|
void _manage::add_score(int sc)
|
|
{
|
|
score += sc;
|
|
if(score >= GIGA) //This *could* happen... Or maybe not. :-)
|
|
score = GIGA - 1;
|
|
else if(!prefs->cmd_cheat)
|
|
{
|
|
#ifndef PLAYSTATS
|
|
if(score >= bonus_next)
|
|
{
|
|
bonus_next += game.bonus_every;
|
|
ships++;
|
|
ships_changed = 1;
|
|
flush_ships_count = 50;
|
|
sound.ui_oneup();
|
|
}
|
|
#endif
|
|
if(score >= scorefile.highscore())
|
|
{
|
|
if(flush_score_count == 0)
|
|
flush_score_count = 50;
|
|
}
|
|
}
|
|
score_changed = 1;
|
|
}
|
|
|
|
|
|
void _manage::select_next(int redraw_map)
|
|
{
|
|
if((scene_num < scorefile.last_scene()) || prefs->cmd_cheat)
|
|
{
|
|
sound.ui_tick();
|
|
scene_num++;
|
|
}
|
|
else
|
|
sound.ui_error();
|
|
select_scene(scene_num);
|
|
}
|
|
|
|
|
|
void _manage::select_prev(int redraw_map)
|
|
{
|
|
scene_num--;
|
|
if(scene_num < 0)
|
|
{
|
|
sound.ui_error();
|
|
scene_num = 0;
|
|
}
|
|
else
|
|
sound.ui_tick();
|
|
select_scene(scene_num);
|
|
}
|
|
|
|
|
|
void _manage::regenerate()
|
|
{
|
|
sound.ui_tick();
|
|
select_scene(scene_num, 1);
|
|
}
|
|
|
|
|
|
void _manage::select_scene(int scene, int redraw_map)
|
|
{
|
|
scene_num = scene;
|
|
put_info();
|
|
if(redraw_map)
|
|
screen.init_scene(-scene_num - 1);
|
|
noise(150, 0);
|
|
}
|
|
|
|
|
|
void _manage::abort()
|
|
{
|
|
if(!exit_manage)
|
|
{
|
|
game_stop();
|
|
exit_manage = 1;
|
|
}
|
|
}
|
|
|
|
|
|
void _manage::freeze_abort()
|
|
{
|
|
exit_manage = 1;
|
|
}
|
|
|
|
|
|
void _manage::reenter()
|
|
{
|
|
exit_manage = 0;
|
|
put_health(1);
|
|
put_temp(1);
|
|
put_info();
|
|
put_score();
|
|
put_ships();
|
|
}
|
|
|
|
|
|
int _manage::get_ready()
|
|
{
|
|
if(_get_ready)
|
|
{
|
|
_get_ready = 0;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int _manage::game_over()
|
|
{
|
|
return _game_over;
|
|
}
|