Add auto-demos!

This commit is contained in:
Lucas S. Vieira 2024-11-23 01:00:17 -03:00
parent 639ed1605c
commit 8610238161
12 changed files with 555 additions and 34 deletions

30
include/demo.h Normal file
View file

@ -0,0 +1,30 @@
#ifndef DEMO_H
#define DEMO_H
#include "input.h"
// Tools for recording and playing game demos.
typedef struct {
uint16_t state;
uint32_t num_frames;
} DemoPlaybackSample;
typedef struct {
InputState state;
uint32_t timer;
uint32_t sample;
} DemoState;
void demo_init();
// The way we record input is by actually measuring the number of frames
// that the current state has taken a certain value, then we output that
// value in hex along with the number of frames (1-based) that it stayed
// that way.
void demo_record();
void demo_update_playback(int level, InputState *s);
#endif

View file

@ -3,10 +3,21 @@
#include <psxpad.h>
typedef struct {
uint16_t current;
uint16_t old;
} InputState;
void pad_init(void);
void pad_update(void);
void input_get_state(InputState *);
uint16_t input_pressing(InputState *, PadButton);
uint16_t input_pressed(InputState *, PadButton);
uint16_t pad_pressing(PadButton b);
uint16_t pad_pressed(PadButton b);
uint16_t pad_pressed_any();
#endif

View file

@ -5,6 +5,7 @@
#include <psxgte.h>
#include "level.h"
#include "collision.h"
#include "input.h"
// Constants for running the game at a fixed 60 FPS.
// These constants are also in a 12-scale format for fixed point math.
@ -55,6 +56,8 @@ typedef enum {
} PlayerAction;
typedef struct {
InputState input;
Chara chara;
CharaAnim *cur_anim;

View file

@ -3,6 +3,12 @@
#include <stdint.h>
typedef enum {
LEVEL_MODE_NORMAL,
LEVEL_MODE_RECORD,
LEVEL_MODE_DEMO,
} LEVELMODE;
void screen_level_load();
void screen_level_unload(void *);
void screen_level_update(void *);
@ -12,5 +18,6 @@ void screen_level_setlevel(uint8_t menuchoice);
uint8_t screen_level_getlevel(void);
void screen_level_setstate(uint8_t state);
uint8_t screen_level_getstate();
void screen_level_setmode(LEVELMODE mode);
#endif

View file

@ -6,4 +6,7 @@ void screen_title_unload(void *);
void screen_title_update(void *);
void screen_title_draw(void *);
void screen_title_reset_demo();
void screen_title_cycle_demo();
#endif

335
src/demo.c Normal file
View file

@ -0,0 +1,335 @@
#include "demo.h"
#include <stdio.h>
static DemoState _demo;
void
demo_init()
{
_demo = (DemoState){ 0 };
}
void
demo_record()
{
InputState s;
input_get_state(&s);
if(s.current != _demo.state.current) {
printf(" {.state = 0x%04x, .num_frames = %d},\n",
_demo.state.current, _demo.timer + 1);
_demo.state.current = s.current;
_demo.timer = 0;
} else _demo.timer++;
}
DemoPlaybackSample *_get_playback_data(int level);
void
demo_update_playback(int level, InputState *s)
{
s->old = s->current;
DemoPlaybackSample *_data = _get_playback_data(level);
if(_demo.timer == 0) {
_demo.sample++;
DemoPlaybackSample *_sample = &_data[_demo.sample-1];
// End of playback is marked by a sample with 0 frames
if(_sample->num_frames == 0) {
s->current = 0x0000;
_demo.timer = 0;
_demo.sample--;
return;
}
s->current = _sample->state;
_demo.timer = _sample->num_frames - 1;
return;
}
_demo.timer--;
}
static DemoPlaybackSample _dummydemo[] = {
{.state = 0x0000, .num_frames = 0},
};
static DemoPlaybackSample _pz1demo[] = {
{.state = 0x0000, .num_frames = 155},
{.state = 0x0020, .num_frames = 294},
{.state = 0x0060, .num_frames = 3},
{.state = 0x0040, .num_frames = 11},
{.state = 0x0000, .num_frames = 39},
{.state = 0x0080, .num_frames = 8},
{.state = 0x0000, .num_frames = 19},
{.state = 0x0080, .num_frames = 7},
{.state = 0x0000, .num_frames = 30},
{.state = 0x0080, .num_frames = 7},
{.state = 0x0000, .num_frames = 41},
{.state = 0x0080, .num_frames = 126},
{.state = 0x0000, .num_frames = 8},
{.state = 0x0020, .num_frames = 51},
{.state = 0x4020, .num_frames = 37},
{.state = 0x0020, .num_frames = 186},
{.state = 0x0060, .num_frames = 187},
{.state = 0x0020, .num_frames = 3},
{.state = 0x0000, .num_frames = 14},
{.state = 0x0020, .num_frames = 33},
{.state = 0x4020, .num_frames = 1},
{.state = 0x4000, .num_frames = 8},
{.state = 0x0000, .num_frames = 3},
{.state = 0x4000, .num_frames = 37},
{.state = 0x4020, .num_frames = 27},
{.state = 0x0020, .num_frames = 13},
{.state = 0x0060, .num_frames = 24},
{.state = 0x0040, .num_frames = 2},
{.state = 0x0000, .num_frames = 252},
{.state = 0x0080, .num_frames = 22},
{.state = 0x4080, .num_frames = 14},
{.state = 0x0080, .num_frames = 21},
{.state = 0x0000, .num_frames = 20},
{.state = 0x4000, .num_frames = 1},
{.state = 0x4080, .num_frames = 7},
{.state = 0x4000, .num_frames = 1},
{.state = 0x0000, .num_frames = 87},
{.state = 0x0020, .num_frames = 19},
{.state = 0x0000, .num_frames = 15},
{.state = 0x4000, .num_frames = 15},
{.state = 0x0000, .num_frames = 55},
{.state = 0x0080, .num_frames = 3},
{.state = 0x0000, .num_frames = 10},
{.state = 0x0020, .num_frames = 28},
{.state = 0x0000, .num_frames = 16},
{.state = 0x0080, .num_frames = 63},
{.state = 0x0000, .num_frames = 12},
{.state = 0x0080, .num_frames = 9},
{.state = 0x0000, .num_frames = 45},
{.state = 0x4000, .num_frames = 15},
{.state = 0x0000, .num_frames = 20},
{.state = 0x0080, .num_frames = 32},
{.state = 0x4080, .num_frames = 35},
{.state = 0x0080, .num_frames = 192},
{.state = 0x0000, .num_frames = 34},
{.state = 0x0020, .num_frames = 581},
{.state = 0x0000, .num_frames = 0},
};
static DemoPlaybackSample _ghz1demo[] = {
{.state = 0x0000, .num_frames = 165},
{.state = 0x0020, .num_frames = 70},
{.state = 0x4020, .num_frames = 3},
{.state = 0x4000, .num_frames = 4},
{.state = 0x0000, .num_frames = 36},
{.state = 0x0020, .num_frames = 39},
{.state = 0x0000, .num_frames = 12},
{.state = 0x4000, .num_frames = 2},
{.state = 0x4020, .num_frames = 6},
{.state = 0x0000, .num_frames = 38},
{.state = 0x0020, .num_frames = 39},
{.state = 0x0000, .num_frames = 12},
{.state = 0x0020, .num_frames = 1},
{.state = 0x4020, .num_frames = 20},
{.state = 0x0020, .num_frames = 4},
{.state = 0x0000, .num_frames = 20},
{.state = 0x0020, .num_frames = 27},
{.state = 0x4020, .num_frames = 5},
{.state = 0x4000, .num_frames = 3},
{.state = 0x0000, .num_frames = 39},
{.state = 0x0020, .num_frames = 75},
{.state = 0x0000, .num_frames = 10},
{.state = 0x0080, .num_frames = 28},
{.state = 0x4080, .num_frames = 26},
{.state = 0x0080, .num_frames = 20},
{.state = 0x4080, .num_frames = 1},
{.state = 0x4000, .num_frames = 10},
{.state = 0x0000, .num_frames = 12},
{.state = 0x0080, .num_frames = 5},
{.state = 0x0000, .num_frames = 21},
{.state = 0x0020, .num_frames = 40},
{.state = 0x0000, .num_frames = 17},
{.state = 0x0080, .num_frames = 42},
{.state = 0x0000, .num_frames = 8},
{.state = 0x4000, .num_frames = 8},
{.state = 0x4020, .num_frames = 4},
{.state = 0x0020, .num_frames = 3},
{.state = 0x0000, .num_frames = 23},
{.state = 0x0020, .num_frames = 29},
{.state = 0x0000, .num_frames = 12},
{.state = 0x0020, .num_frames = 9},
{.state = 0x0000, .num_frames = 10},
{.state = 0x0020, .num_frames = 10},
{.state = 0x4020, .num_frames = 10},
{.state = 0x0020, .num_frames = 16},
{.state = 0x0000, .num_frames = 19},
{.state = 0x0020, .num_frames = 20},
{.state = 0x4020, .num_frames = 8},
{.state = 0x0020, .num_frames = 4},
{.state = 0x0000, .num_frames = 28},
{.state = 0x0020, .num_frames = 17},
{.state = 0x0000, .num_frames = 179},
{.state = 0x4000, .num_frames = 1},
{.state = 0x4020, .num_frames = 9},
{.state = 0x0020, .num_frames = 1},
{.state = 0x0000, .num_frames = 46},
{.state = 0x0020, .num_frames = 228},
{.state = 0x0000, .num_frames = 24},
{.state = 0x0020, .num_frames = 76},
{.state = 0x0000, .num_frames = 42},
{.state = 0x0020, .num_frames = 46},
{.state = 0x4020, .num_frames = 19},
{.state = 0x0020, .num_frames = 14},
{.state = 0x0000, .num_frames = 13},
{.state = 0x0020, .num_frames = 10},
{.state = 0x0000, .num_frames = 48},
{.state = 0x4000, .num_frames = 1},
{.state = 0x4020, .num_frames = 9},
{.state = 0x0000, .num_frames = 44},
{.state = 0x0020, .num_frames = 26},
{.state = 0x0000, .num_frames = 11},
{.state = 0x0020, .num_frames = 49},
{.state = 0x0000, .num_frames = 76},
{.state = 0x0040, .num_frames = 8},
{.state = 0x4040, .num_frames = 10},
{.state = 0x0040, .num_frames = 30},
{.state = 0x0000, .num_frames = 82},
{.state = 0x0020, .num_frames = 39},
{.state = 0x4020, .num_frames = 33},
{.state = 0x0020, .num_frames = 74},
{.state = 0x0000, .num_frames = 0},
};
static DemoPlaybackSample _swz1demo[] = {
{.state = 0x0000, .num_frames = 207},
{.state = 0x0020, .num_frames = 342},
{.state = 0x0000, .num_frames = 14},
{.state = 0x0020, .num_frames = 47},
{.state = 0x0000, .num_frames = 59},
{.state = 0x0020, .num_frames = 250},
{.state = 0x0000, .num_frames = 24},
{.state = 0x0020, .num_frames = 14},
{.state = 0x4020, .num_frames = 10},
{.state = 0x4000, .num_frames = 3},
{.state = 0x0000, .num_frames = 45},
{.state = 0x4000, .num_frames = 2},
{.state = 0x4020, .num_frames = 12},
{.state = 0x0020, .num_frames = 1},
{.state = 0x0000, .num_frames = 28},
{.state = 0x0020, .num_frames = 5},
{.state = 0x0000, .num_frames = 12},
{.state = 0x4000, .num_frames = 3},
{.state = 0x4020, .num_frames = 9},
{.state = 0x0020, .num_frames = 2},
{.state = 0x0000, .num_frames = 31},
{.state = 0x0080, .num_frames = 8},
{.state = 0x0000, .num_frames = 13},
{.state = 0x4000, .num_frames = 4},
{.state = 0x4020, .num_frames = 7},
{.state = 0x0020, .num_frames = 4},
{.state = 0x0000, .num_frames = 49},
{.state = 0x0020, .num_frames = 1},
{.state = 0x4020, .num_frames = 28},
{.state = 0x4000, .num_frames = 1},
{.state = 0x0000, .num_frames = 26},
{.state = 0x0020, .num_frames = 11},
{.state = 0x4020, .num_frames = 12},
{.state = 0x4000, .num_frames = 3},
{.state = 0x0000, .num_frames = 15},
{.state = 0x0080, .num_frames = 18},
{.state = 0x0000, .num_frames = 29},
{.state = 0x0020, .num_frames = 94},
{.state = 0x4020, .num_frames = 16},
{.state = 0x0020, .num_frames = 107},
{.state = 0x0000, .num_frames = 13},
{.state = 0x0080, .num_frames = 17},
{.state = 0x0000, .num_frames = 11},
{.state = 0x4000, .num_frames = 14},
{.state = 0x4020, .num_frames = 22},
{.state = 0x0020, .num_frames = 31},
{.state = 0x0000, .num_frames = 24},
{.state = 0x0020, .num_frames = 12},
{.state = 0x0000, .num_frames = 13},
{.state = 0x0020, .num_frames = 13},
{.state = 0x0000, .num_frames = 5},
{.state = 0x4000, .num_frames = 6},
{.state = 0x4020, .num_frames = 7},
{.state = 0x4000, .num_frames = 4},
{.state = 0x0000, .num_frames = 16},
{.state = 0x0020, .num_frames = 12},
{.state = 0x0000, .num_frames = 66},
{.state = 0x0020, .num_frames = 36},
{.state = 0x4020, .num_frames = 29},
{.state = 0x0020, .num_frames = 69},
{.state = 0x0000, .num_frames = 35},
{.state = 0x0020, .num_frames = 46},
{.state = 0x4020, .num_frames = 30},
{.state = 0x0020, .num_frames = 26},
{.state = 0x0000, .num_frames = 15},
{.state = 0x0020, .num_frames = 33},
{.state = 0x4020, .num_frames = 16},
{.state = 0x0020, .num_frames = 61},
{.state = 0x0000, .num_frames = 20},
{.state = 0x0020, .num_frames = 18},
{.state = 0x0000, .num_frames = 21},
{.state = 0x0020, .num_frames = 52},
{.state = 0x4020, .num_frames = 2},
{.state = 0x4000, .num_frames = 17},
{.state = 0x0000, .num_frames = 28},
{.state = 0x0080, .num_frames = 17},
{.state = 0x0000, .num_frames = 3},
{.state = 0x4000, .num_frames = 6},
{.state = 0x4020, .num_frames = 12},
{.state = 0x0020, .num_frames = 6},
{.state = 0x0000, .num_frames = 19},
{.state = 0x0020, .num_frames = 6},
{.state = 0x0000, .num_frames = 15},
{.state = 0x4020, .num_frames = 21},
{.state = 0x0020, .num_frames = 132},
{.state = 0x0000, .num_frames = 1},
{.state = 0x0020, .num_frames = 1},
{.state = 0x0000, .num_frames = 0},
};
static DemoPlaybackSample _ez1demo[] = {
{.state = 0x0000, .num_frames = 141},
{.state = 0x0020, .num_frames = 227},
{.state = 0x0060, .num_frames = 64},
{.state = 0x0020, .num_frames = 2},
{.state = 0x0000, .num_frames = 46},
{.state = 0x0020, .num_frames = 32},
{.state = 0x0000, .num_frames = 34},
{.state = 0x0020, .num_frames = 38},
{.state = 0x4020, .num_frames = 15},
{.state = 0x0020, .num_frames = 11},
{.state = 0x0000, .num_frames = 38},
{.state = 0x0020, .num_frames = 254},
{.state = 0x0000, .num_frames = 7},
{.state = 0x0080, .num_frames = 29},
{.state = 0x4080, .num_frames = 26},
{.state = 0x0080, .num_frames = 29},
{.state = 0x0000, .num_frames = 25},
{.state = 0x0080, .num_frames = 7},
{.state = 0x0000, .num_frames = 8},
{.state = 0x0080, .num_frames = 129},
{.state = 0x4080, .num_frames = 11},
{.state = 0x0000, .num_frames = 28},
{.state = 0x0020, .num_frames = 21},
{.state = 0x0000, .num_frames = 3},
{.state = 0x4000, .num_frames = 41},
{.state = 0x0000, .num_frames = 63},
{.state = 0x0080, .num_frames = 13},
{.state = 0x4080, .num_frames = 15},
{.state = 0x0080, .num_frames = 2},
{.state = 0x0000, .num_frames = 0},
};
DemoPlaybackSample *
_get_playback_data(int level)
{
switch(level) {
case 0: return _pz1demo;
case 4: return _ghz1demo;
case 6: return _swz1demo;
case 16: return _ez1demo;
default: return _dummydemo;
}
}

View file

@ -3,8 +3,7 @@
#include <psxpad.h>
static uint8_t _padbuff[2][34];
static uint16_t _cur_state = 0;
static uint16_t _old_state = 0;
static InputState _gstate = { 0 };
void
pad_init(void)
@ -22,19 +21,43 @@ pad_update(void)
((pad->type == PAD_ID_DIGITAL) // Digital
|| (pad->type == PAD_ID_ANALOG_STICK) // DualShock in digital mode
|| (pad->type == PAD_ID_ANALOG))) { // DualShock in analog mode
_old_state = _cur_state;
_cur_state = ~pad->btn;
_gstate.old = _gstate.current;
_gstate.current = ~pad->btn;
}
}
void
input_get_state(InputState *s)
{
*s = _gstate;
}
uint16_t
input_pressing(InputState *s, PadButton b)
{
return s->current & b;
}
uint16_t
input_pressed(InputState *s, PadButton b)
{
return !(s->old & b) && (s->current & b);
}
uint16_t
pad_pressing(PadButton b)
{
return _cur_state & b;
return input_pressing(&_gstate, b);
}
uint16_t
pad_pressed(PadButton b)
{
return !(_old_state & b) && (_cur_state & b);
return input_pressed(&_gstate, b);
}
uint16_t
pad_pressed_any()
{
return _gstate.current != 0x0000;
}

View file

@ -58,6 +58,7 @@ load_player(Player *player,
const char *chara_filename,
TIM_IMAGE *sprites)
{
player->input = (InputState){ 0 };
load_chara(&player->chara, chara_filename, sprites);
player->cur_anim = NULL;
player->pos = (VECTOR){ 0 };
@ -406,10 +407,14 @@ _player_update_collision_tb(Player *player)
void
player_update(Player *player)
{
// NOTE THAT PLAYER INPUT IS NOT UPDATED AUTOMATICALLY!
// One must call input_get_state on player->input so that
// player input is recognized. This is done in screen_level.c.
_player_update_collision_lr(player);
_player_update_collision_tb(player);
// Iframes
// i-frames
if(player->iframes > 0) player->iframes--;
// X movement
@ -430,9 +435,9 @@ player_update(Player *player)
* angle_sin) >> 12;
// Deceleration on input
if(player->vel.vz > 0 && pad_pressing(PAD_LEFT))
if(player->vel.vz > 0 && input_pressing(&player->input, PAD_LEFT))
player->vel.vz -= X_ROLL_DECEL + X_ROLL_FRICTION;
else if(player->vel.vz < 0 && pad_pressing(PAD_RIGHT))
else if(player->vel.vz < 0 && input_pressing(&player->input, PAD_RIGHT))
player->vel.vz += X_ROLL_DECEL + X_ROLL_FRICTION;
else {
// Apply roll friction
@ -444,7 +449,7 @@ player_update(Player *player)
player->action = ACTION_NONE;
} else if(player->action == ACTION_SPINDASH) {
// Release
if(!pad_pressing(PAD_DOWN)) {
if(!input_pressing(&player->input, PAD_DOWN)) {
player->vel.vz +=
(0x8000 + (floor12(player->spinrev) >> 1)) * player->anim_dir;
player->action = ACTION_ROLLING;
@ -455,7 +460,7 @@ player_update(Player *player)
if(player->spinrev > 0) {
player->spinrev -= (div12(player->spinrev, 0x200) << 12) / 0x100000;
}
if(pad_pressed(PAD_CROSS)) {
if(input_pressed(&player->input, PAD_CROSS)) {
player->spinrev += 0x2000;
sound_play_vag(sfx_dash, 0);
}
@ -464,7 +469,8 @@ player_update(Player *player)
// Default physics
player->action = ACTION_NONE;
if(pad_pressing(PAD_RIGHT) && (player->ctrllock == 0)) {
if(input_pressing(&player->input, PAD_RIGHT)
&& (player->ctrllock == 0)) {
if(player->vel.vz < 0) {
player->action = ACTION_SKIDDING;
player->vel.vz += X_DECEL;
@ -473,7 +479,8 @@ player_update(Player *player)
player->vel.vz += X_ACCEL;
player->anim_dir = 1;
}
} else if(pad_pressing(PAD_LEFT) && (player->ctrllock == 0)) {
} else if(input_pressing(&player->input, PAD_LEFT)
&& (player->ctrllock == 0)) {
if(player->vel.vz > 0) {
player->action = ACTION_SKIDDING;
player->vel.vz -= X_DECEL;
@ -502,12 +509,13 @@ player_update(Player *player)
}
/* Action changers */
if(pad_pressing(PAD_DOWN)) {
if(input_pressing(&player->input, PAD_DOWN)) {
if(abs(player->vel.vz) >= X_MIN_ROLL_SPD) { // Rolling
player->action = ACTION_ROLLING;
player_set_animation_direct(player, ANIM_ROLLING);
sound_play_vag(sfx_roll, 0);
} else if(player->vel.vz == 0 && pad_pressed(PAD_CROSS)) { // Spindash
} else if(player->vel.vz == 0
&& input_pressed(&player->input, PAD_CROSS)) { // Spindash
player->action = ACTION_SPINDASH;
player_set_animation_direct(player, ANIM_ROLLING);
player->spinrev = 0;
@ -526,12 +534,14 @@ player_update(Player *player)
player->vel.vy = (player->vel.vz * -rsin(player->angle)) >> 12;
} else {
// Air X movement
if(pad_pressing(PAD_RIGHT) && (player->ctrllock == 0)) {
if(input_pressing(&player->input, PAD_RIGHT)
&& (player->ctrllock == 0)) {
if(player->vel.vx < X_TOP_SPD)
player->vel.vx += X_AIR_ACCEL;
if(!player->airdirlock)
player->anim_dir = 1;
} else if(pad_pressing(PAD_LEFT) && (player->ctrllock == 0)) {
} else if(input_pressing(&player->input, PAD_LEFT)
&& (player->ctrllock == 0)) {
if(player->vel.vx > -X_TOP_SPD)
player->vel.vx -= X_AIR_ACCEL;
if(!player->airdirlock)
@ -557,7 +567,7 @@ player_update(Player *player)
// Y movement
if(!player->grnd) {
if(player->action == ACTION_JUMPING) {
if(!pad_pressing(PAD_CROSS)) {
if(!input_pressing(&player->input, PAD_CROSS)) {
// Short jump
if(player->vel.vy < -Y_MIN_JUMP)
player->vel.vy = -Y_MIN_JUMP;
@ -578,7 +588,7 @@ player_update(Player *player)
? Y_HURT_GRAVITY
: Y_GRAVITY;
} else {
if(pad_pressed(PAD_CROSS) && player->action != ACTION_SPINDASH) {
if(input_pressed(&player->input, PAD_CROSS) && player->action != ACTION_SPINDASH) {
player->vel.vx -= (Y_JUMP_STRENGTH * rsin(player->angle)) >> 12;
player->vel.vy -= (Y_JUMP_STRENGTH * rcos(player->angle)) >> 12;
player->grnd = 0;
@ -597,18 +607,19 @@ player_update(Player *player)
} else if(player->vel.vz == 0) {
if(player->action == ACTION_SPINDASH) {
player_set_animation_direct(player, ANIM_ROLLING);
} else if(pad_pressing(PAD_UP)) {
} else if(input_pressing(&player->input, PAD_UP)) {
player_set_animation_direct(player, ANIM_LOOKUP);
player->idle_timer = ANIM_IDLE_TIMER_MAX;
player->action = ACTION_LOOKUP;
} else if(pad_pressing(PAD_DOWN)) {
} else if(input_pressing(&player->input, PAD_DOWN)) {
player_set_animation_direct(player, ANIM_CROUCHDOWN);
player->idle_timer = ANIM_IDLE_TIMER_MAX;
player->action = ACTION_CROUCHDOWN;
} else if(player->idle_timer == 0) {
player_set_animation_direct(player, ANIM_IDLE);
player->loopback_frame = 2;
} else if (!pad_pressing(PAD_LEFT) && !pad_pressing(PAD_RIGHT)) {
} else if (!input_pressing(&player->input, PAD_LEFT)
&& !input_pressing(&player->input, PAD_RIGHT)) {
player_set_animation_direct(player, ANIM_STOPPED);
if(player->idle_timer > 0) player->idle_timer--;
}

View file

@ -141,7 +141,7 @@ screen_alloc(uint32_t size)
void
screen_free()
{
printf("Scene: Disposing of %d / %d bytes\n",
printf("Scene: Disposing of %u / %u bytes\n",
alloc_arena_bytes_used(&screen_arena),
alloc_arena_bytes_free(&screen_arena));
alloc_arena_free(&screen_arena);

View file

@ -18,6 +18,9 @@
#include "object.h"
#include "parallax.h"
#include "basic_font.h"
#include "demo.h"
#include "screens/fmv.h"
extern int debug_mode;
@ -35,6 +38,7 @@ uint8_t level_fade;
uint8_t level_ring_count;
uint32_t level_score_count;
uint8_t level_finished;
LEVELMODE level_mode;
// Forward function declarations
@ -88,6 +92,8 @@ screen_level_load()
level_ring_count = 0;
level_finished = 0;
demo_init();
}
void
@ -163,12 +169,30 @@ screen_level_update(void *d)
}
}
if(pad_pressed(PAD_START)
&& !level_finished
&& (data->level_transition == 2)) {
paused = !paused;
if(paused) sound_xa_set_volume(0x00);
else sound_xa_set_volume(XA_DEFAULT_VOLUME);
// Toggle pause. But only if not playing a demo!
if(level_mode != LEVEL_MODE_DEMO) {
if(pad_pressed(PAD_START)
&& !level_finished
&& (data->level_transition == 2)) {
paused = !paused;
if(paused) sound_xa_set_volume(0x00);
else sound_xa_set_volume(XA_DEFAULT_VOLUME);
}
} else {
// If in demo mode, absolutely any button press will
// trigger its end!
uint32_t seconds = get_elapsed_frames() / 60;
if((pad_pressed_any() || (seconds >= 30))
&& (screen_level_getstate() == 2)) {
screen_level_setstate(3);
}
if(screen_level_getstate() == 4) {
// Go back to SONICTEAM FMV
screen_fmv_set_next(SCREEN_TITLE);
screen_fmv_enqueue("\\SONICT.STR;1");
scene_change(SCREEN_FMV);
}
}
if(paused) {
@ -228,6 +252,20 @@ screen_level_update(void *d)
}
}
// Record level demo. Uncomment to print.
switch(level_mode) {
case LEVEL_MODE_DEMO:
demo_update_playback(level, &player.input);
break;
case LEVEL_MODE_RECORD:
demo_record();
input_get_state(&player.input);
break;
default:
input_get_state(&player.input);
break;
}
camera_update(&camera, &player);
update_obj_window(&leveldata, &obj_table_common, camera.pos.vx, camera.pos.vy);
object_pool_update(&obj_table_common);
@ -713,3 +751,10 @@ screen_level_getstate()
screen_level_data *data = screen_get_data();
return data->level_transition;
}
void
screen_level_setmode(LEVELMODE mode)
{
level_mode = mode;
}

View file

@ -201,6 +201,13 @@ screen_levelselect_update(void *d)
data->music_selected = data->soundtest_selection;
} else {
screen_level_setlevel(data->menu_choice);
screen_level_setmode(LEVEL_MODE_NORMAL);
// Start auto-demo
if(pad_pressing(PAD_TRIANGLE)) {
screen_level_setmode(LEVEL_MODE_DEMO);
} else if(pad_pressing(PAD_CIRCLE)) {
screen_level_setmode(LEVEL_MODE_RECORD);
}
scene_change(SCREEN_LEVEL);
}
}

View file

@ -14,9 +14,13 @@
#include "screens/level.h"
#define AUTODEMO_WAIT_FRAMES 1500
extern int debug_mode;
extern uint32_t level_score_count;
uint16_t demo_number = 0;
typedef struct {
int32_t prect_x;
int32_t prect_y;
@ -71,6 +75,8 @@ typedef struct {
VECTOR scale;
MATRIX world;
uint32_t autodemo_timer;
/* Model planet; */
} screen_title_data;
@ -112,6 +118,8 @@ screen_title_load()
data->selected = 0;
data->next_scene = 0;
data->autodemo_timer = 0;
bzero(data->prl_pos, PRL_NUM_PIECES * sizeof(int32_t));
data->prl_pos[0] = 32 << 12; // Island center
@ -166,10 +174,19 @@ screen_title_update(void *d)
if(data->rgb_count < 128)
data->rgb_count += 4;
else {
if(data->menu_option == 0 && pad_pressed(PAD_START)) {
// TODO: Check for saved data
data->menu_option = 2; // New Game
//data->menu_option = 1; // Continue
if(data->menu_option == 0) {
// Play AutoDemo if you took too long!
// Wait until music stops playing.
data->autodemo_timer++;
if(data->autodemo_timer > AUTODEMO_WAIT_FRAMES) {
data->selected = 1;
}
if(pad_pressed(PAD_START)) {
// TODO: Check for saved data
data->menu_option = 2; // New Game
//data->menu_option = 1; // Continue
}
} else if(data->menu_option > 0) {
if(pad_pressed(PAD_LEFT) && (data->menu_option > 1))
data->menu_option--;
@ -181,13 +198,17 @@ screen_title_update(void *d)
switch(data->menu_option) {
case 1: // Continue
// For now, this redirects you to Green Hill Zone 1
screen_title_reset_demo();
screen_level_setlevel(4);
screen_level_setmode(LEVEL_MODE_NORMAL);
data->next_scene = SCREEN_LEVEL;
level_score_count = 0;
break;
case 2: // New Game
// Use Playground Zone 1 as first level
screen_title_reset_demo();
screen_level_setlevel(0);
screen_level_setmode(LEVEL_MODE_NORMAL);
data->next_scene = SCREEN_LEVEL;
level_score_count = 0;
break;
@ -204,7 +225,14 @@ screen_title_update(void *d)
if(data->rgb_count > 0) data->rgb_count -= 4;
else {
scene_change(data->next_scene);
if(data->autodemo_timer >= AUTODEMO_WAIT_FRAMES) {
screen_level_setlevel(demo_number);
screen_level_setmode(LEVEL_MODE_DEMO);
level_score_count = 0;
// Cycle to next demo if we ever come back here
screen_title_cycle_demo();
scene_change(SCREEN_LEVEL);
} else scene_change(data->next_scene);
}
}
@ -414,3 +442,21 @@ screen_title_draw(void *d)
x = SCREEN_XRES - (strlen(buffer) * 8) - 8;
font_draw_sm(buffer, x, SCREEN_YRES - 14);
}
void
screen_title_reset_demo()
{
demo_number = 0;
}
void
screen_title_cycle_demo()
{
switch(demo_number) {
case 0: demo_number = 4; break;
case 4: demo_number = 6; break;
case 6: demo_number = 16; break;
case 16: demo_number = 0; break;
default: demo_number = 0; break;
}
}