mirror of
https://github.com/luksamuk/engine-psx.git
synced 2025-04-28 13:28:02 +03:00
Add a proper credits screen and a heads-up display
This commit is contained in:
parent
09d5493087
commit
48e6d2bded
11 changed files with 378 additions and 14 deletions
|
@ -16,6 +16,9 @@ void font_flush();
|
|||
void font_draw_big(const char *text, int16_t vx, int16_t vy);
|
||||
void font_draw_sm(const char *text, int16_t vx, int16_t vy);
|
||||
|
||||
uint16_t font_measurew_big(const char *text);
|
||||
uint16_t font_measurew_sm(const char *text);
|
||||
|
||||
void font_set_color(uint8_t r0, uint8_t g0, uint8_t b0);
|
||||
void font_reset_color();
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ typedef enum {
|
|||
SCREEN_TITLE,
|
||||
SCREEN_MODELTEST,
|
||||
SCREEN_COMINGSOON,
|
||||
SCREEN_CREDITS,
|
||||
} ScreenIndex;
|
||||
|
||||
void scene_change(ScreenIndex scr);
|
||||
|
|
9
include/screens/credits.h
Normal file
9
include/screens/credits.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef SCREENS_CREDITS_H
|
||||
#define SCREENS_CREDITS_H
|
||||
|
||||
void screen_credits_load();
|
||||
void screen_credits_unload(void *);
|
||||
void screen_credits_update(void *);
|
||||
void screen_credits_draw(void *);
|
||||
|
||||
#endif
|
|
@ -152,6 +152,84 @@ _draw_glyph(
|
|||
sort_prim(sprt, 1); // 1 = HUD and text layer
|
||||
}
|
||||
|
||||
uint16_t
|
||||
_font_measurew_generic(const char *text,
|
||||
const uint8_t ws_w,
|
||||
const uint8_t gap,
|
||||
uint8_t *ginfo)
|
||||
{
|
||||
uint16_t w = 0;
|
||||
uint16_t vx = 0;
|
||||
while(*text != '\0') {
|
||||
switch(*text) {
|
||||
case ' ':
|
||||
vx += ws_w + gap;
|
||||
text++;
|
||||
continue;
|
||||
case '\n':
|
||||
vx = 0;
|
||||
text++;
|
||||
continue;
|
||||
case '\t':
|
||||
vx += (ws_w << 2) + (gap << 2);
|
||||
text++;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t offset = 0xff;
|
||||
|
||||
if((*text >= 'a') && (*text <= 'z'))
|
||||
offset = (uint8_t)((unsigned)(*text) - (unsigned)('a'));
|
||||
else if((*text >= 'A') && (*text <= 'Z'))
|
||||
offset = (uint8_t)((unsigned)(*text) - (unsigned)('A'));
|
||||
else if((*text >= '0') && (*text <= '9')) {
|
||||
offset = 26 + (uint8_t)((unsigned)(*text) - (unsigned)('0'));
|
||||
} else {
|
||||
switch(*text) {
|
||||
case '*': offset = 36; break;
|
||||
case '.': offset = 37; break;
|
||||
case ';': offset = 38; break;
|
||||
case '-': offset = 39; break;
|
||||
case '=': offset = 40; break;
|
||||
case '!': offset = 41; break;
|
||||
case '?': offset = 42; break;
|
||||
default: offset = 0xff; break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t gw = ws_w;
|
||||
if(offset != 0xff) {
|
||||
uint8_t *info = &ginfo[offset * 4];
|
||||
if(info[0] == 0xff) {
|
||||
// Glyph doesn't exist, so don't draw
|
||||
goto jump_ws;
|
||||
}
|
||||
gw = info[2];
|
||||
}
|
||||
|
||||
jump_ws:
|
||||
vx += gw + gap;
|
||||
text++;
|
||||
|
||||
if(vx > w) w = vx;
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
font_measurew_big(const char *text)
|
||||
{
|
||||
return _font_measurew_generic(
|
||||
text, GLYPH_WHITE_WIDTH, GLYPH_GAP, glyph_info_big);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
font_measurew_sm(const char *text)
|
||||
{
|
||||
return _font_measurew_generic(
|
||||
text, GLYPH_SML_WHITE_WIDTH, GLYPH_SML_GAP, glyph_info_sm);
|
||||
}
|
||||
|
||||
void
|
||||
_font_draw_generic(const char *text, int16_t vx, int16_t vy,
|
||||
const uint8_t ws_w, const uint8_t ws_h,
|
||||
|
|
|
@ -25,6 +25,9 @@ extern SoundEffect sfx_sprn;
|
|||
extern SoundEffect sfx_chek;
|
||||
extern int debug_mode;
|
||||
|
||||
extern uint8_t level_ring_count;
|
||||
extern uint8_t level_score_count;
|
||||
|
||||
// Update functions
|
||||
static void _ring_update(ObjectState *state, ObjectTableEntry *typedata, VECTOR *pos);
|
||||
static void _goal_sign_update(ObjectState *state, ObjectTableEntry *typedata, VECTOR *pos);
|
||||
|
@ -112,6 +115,7 @@ _ring_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos)
|
|||
state->anim_state.animation = 1;
|
||||
state->anim_state.frame = 0;
|
||||
state->props ^= OBJ_FLAG_ANIM_LOCK; // Unlock from global timer
|
||||
level_ring_count++;
|
||||
sound_play_vag(sfx_ring, 0);
|
||||
}
|
||||
} else if(state->anim_state.animation == OBJ_ANIMATION_NO_ANIMATION
|
||||
|
@ -183,6 +187,14 @@ _monitor_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos)
|
|||
state->frag_anim_state->animation = OBJ_ANIMATION_NO_ANIMATION;
|
||||
sound_play_vag(sfx_pop, 0);
|
||||
|
||||
switch(((MonitorExtra *)state->extra)->kind) {
|
||||
case MONITOR_KIND_RING:
|
||||
level_ring_count += 10;
|
||||
sound_play_vag(sfx_ring, 0);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if(!player.grnd && player.vel.vy > 0) {
|
||||
player.vel.vy *= -1;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "screens/title.h"
|
||||
#include "screens/modeltest.h"
|
||||
#include "screens/comingsoon.h"
|
||||
#include "screens/credits.h"
|
||||
|
||||
// Start with 64k until we make the actual level scene
|
||||
// an object as well
|
||||
|
@ -57,8 +58,6 @@ void
|
|||
scene_change(ScreenIndex scr)
|
||||
{
|
||||
printf("Change scene: %d -> %d\n", current_scene, scr);
|
||||
//set_clear_color(0, 0, 0);
|
||||
//render_loading_text();
|
||||
render_loading_logo();
|
||||
|
||||
if(current_scene >= 0)
|
||||
|
@ -78,6 +77,7 @@ scene_load()
|
|||
case SCREEN_TITLE: screen_title_load(); break;
|
||||
case SCREEN_MODELTEST: screen_modeltest_load(); break;
|
||||
case SCREEN_COMINGSOON: screen_comingsoon_load(); break;
|
||||
case SCREEN_CREDITS: screen_credits_load(); break;
|
||||
default: break; // Unknown scene???
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +93,7 @@ scene_unload()
|
|||
case SCREEN_TITLE: screen_title_unload(scene_data); break;
|
||||
case SCREEN_MODELTEST: screen_modeltest_unload(scene_data); break;
|
||||
case SCREEN_COMINGSOON: screen_comingsoon_unload(scene_data); break;
|
||||
case SCREEN_CREDITS: screen_credits_unload(scene_data); break;
|
||||
default: break; // Unknown scene???
|
||||
}
|
||||
}
|
||||
|
@ -108,6 +109,7 @@ scene_update()
|
|||
case SCREEN_TITLE: screen_title_update(scene_data); break;
|
||||
case SCREEN_MODELTEST: screen_modeltest_update(scene_data); break;
|
||||
case SCREEN_COMINGSOON: screen_comingsoon_update(scene_data); break;
|
||||
case SCREEN_CREDITS: screen_credits_update(scene_data); break;
|
||||
default: break; // Unknown scene???
|
||||
}
|
||||
}
|
||||
|
@ -124,6 +126,7 @@ scene_draw()
|
|||
case SCREEN_TITLE: screen_title_draw(scene_data); break;
|
||||
case SCREEN_MODELTEST: screen_modeltest_draw(scene_data); break;
|
||||
case SCREEN_COMINGSOON: screen_comingsoon_draw(scene_data); break;
|
||||
case SCREEN_CREDITS: screen_credits_draw(scene_data); break;
|
||||
default: break; // Unknown scene???
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
#include "input.h"
|
||||
#include "sound.h"
|
||||
|
||||
#include "screens/fmv.h"
|
||||
|
||||
typedef struct {
|
||||
int32_t prectx;
|
||||
int32_t precty;
|
||||
|
@ -42,6 +40,7 @@ screen_comingsoon_load()
|
|||
void
|
||||
screen_comingsoon_unload(void *)
|
||||
{
|
||||
sound_stop_xa();
|
||||
screen_free();
|
||||
}
|
||||
|
||||
|
@ -68,11 +67,7 @@ screen_comingsoon_update(void *d)
|
|||
}
|
||||
} else {
|
||||
if(data->fade > 0) data->fade -= 2;
|
||||
else {
|
||||
screen_fmv_set_next(SCREEN_TITLE);
|
||||
screen_fmv_enqueue("\\SONICT.STR;1");
|
||||
scene_change(SCREEN_FMV);
|
||||
}
|
||||
else scene_change(SCREEN_CREDITS);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
237
src/screen_credits.c
Normal file
237
src/screen_credits.c
Normal file
|
@ -0,0 +1,237 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "screen.h"
|
||||
#include "screens/credits.h"
|
||||
#include "render.h"
|
||||
#include "basic_font.h"
|
||||
#include "input.h"
|
||||
|
||||
static const char *creditstxt[] = {
|
||||
"SONIC XA CREDITS",
|
||||
"\r",
|
||||
|
||||
|
||||
/* Programming credits */
|
||||
"Lead Developer",
|
||||
"luksamuk",
|
||||
"\r",
|
||||
|
||||
"Level Design",
|
||||
"luksamuk",
|
||||
"\r",
|
||||
|
||||
|
||||
/* BGM */
|
||||
"background music",
|
||||
"\r",
|
||||
|
||||
"Amen Break Remixed Loop 01 160 BPM",
|
||||
"By u_ul6ysm8501",
|
||||
"\r",
|
||||
|
||||
"Playgrond Zone 1",
|
||||
"Rusty Ruin Act 1",
|
||||
"By Richard Jacques",
|
||||
"\r",
|
||||
|
||||
"Playground Zone 2",
|
||||
"Rusty Ruin Act 2",
|
||||
"By Richard Jacques",
|
||||
"\r",
|
||||
|
||||
"Playground Zone 3",
|
||||
"Let Mom Sleep",
|
||||
"By Hideki Naganuma",
|
||||
"\r",
|
||||
|
||||
"Playground Zone 4",
|
||||
"Let Mom Sleep Remix",
|
||||
"By Hideki Naganuma",
|
||||
"Remixed by Richard Jacques",
|
||||
"\r",
|
||||
|
||||
"Green Hill Zone",
|
||||
"Palmtree Panic P Mix",
|
||||
"By Sonic Team",
|
||||
"\r",
|
||||
|
||||
"Surely Wood Zone",
|
||||
"El Gato Battle 2 Vortex Remake",
|
||||
"By pkVortex",
|
||||
"\r",
|
||||
|
||||
"You Can Do Anything",
|
||||
"By Sonic Team",
|
||||
"\r",
|
||||
|
||||
|
||||
/* Graphics credits */
|
||||
"Character Sprites Ripping",
|
||||
"Triangly",
|
||||
"Paraemon",
|
||||
"\r",
|
||||
|
||||
"Level and Menu Graphics Ripping",
|
||||
"Paraemon",
|
||||
"WarCR",
|
||||
"\r",
|
||||
|
||||
"Original Level Graphics",
|
||||
"NiteShadow",
|
||||
"Techokami",
|
||||
"\r",
|
||||
|
||||
"Fonts Ripping",
|
||||
"Flare",
|
||||
"Storice",
|
||||
"\r",
|
||||
|
||||
"Original Fonts",
|
||||
"Mr. Alien",
|
||||
"\r",
|
||||
|
||||
"Objects Ripping",
|
||||
"Paraemon",
|
||||
"\r",
|
||||
|
||||
"Original Sprites and Tiles",
|
||||
"Sonic Team",
|
||||
"\r",
|
||||
|
||||
|
||||
/* Ending */
|
||||
"sonic the hedgehog owned by",
|
||||
"sonic team",
|
||||
"sega inc",
|
||||
"\r",
|
||||
|
||||
"special thanks",
|
||||
"PSXDEV Network",
|
||||
"The Spriters Resource",
|
||||
"\r",
|
||||
|
||||
|
||||
NULL,
|
||||
};
|
||||
|
||||
#define SLIDE_FRAMES 128
|
||||
#define FADE_FRAMES 64
|
||||
|
||||
typedef struct {
|
||||
uint8_t entry;
|
||||
uint8_t fade;
|
||||
int8_t countdown;
|
||||
uint8_t state;
|
||||
} screen_credits_data;
|
||||
|
||||
void
|
||||
screen_credits_load()
|
||||
{
|
||||
screen_credits_data *data = screen_alloc(sizeof(screen_credits_data));
|
||||
set_clear_color(0, 0, 0);
|
||||
|
||||
data->entry = 0;
|
||||
data->fade = 0;
|
||||
data->countdown = FADE_FRAMES;
|
||||
data->state = 0;
|
||||
}
|
||||
|
||||
void
|
||||
screen_credits_unload(void *)
|
||||
{
|
||||
screen_free();
|
||||
}
|
||||
|
||||
void
|
||||
screen_credits_update(void *d)
|
||||
{
|
||||
screen_credits_data *data = (screen_credits_data *)d;
|
||||
if(creditstxt[data->entry] != NULL
|
||||
&& (!pad_pressed(PAD_START) && !pad_pressed(PAD_CROSS))) {
|
||||
switch(data->state) {
|
||||
case 0: // Pre-fade-in
|
||||
data->countdown = FADE_FRAMES;
|
||||
data->fade = 0;
|
||||
data->state = 1;
|
||||
break;
|
||||
case 1: // Fade-in
|
||||
data->countdown--;
|
||||
data->fade += 2;
|
||||
if(data->countdown == 0) {
|
||||
data->state = 2;
|
||||
data->countdown = SLIDE_FRAMES;
|
||||
}
|
||||
break;
|
||||
case 2: // Displaying
|
||||
data->countdown--;
|
||||
if(data->countdown == 0) {
|
||||
data->countdown = FADE_FRAMES;
|
||||
data->state = 3;
|
||||
}
|
||||
break;
|
||||
case 3: // Fade-out
|
||||
data->countdown--;
|
||||
data->fade -= 2;
|
||||
if(data->countdown == 0) {
|
||||
while(creditstxt[data->entry] != NULL
|
||||
&& creditstxt[data->entry][0] != '\r')
|
||||
data->entry++;
|
||||
if(creditstxt[data->entry] != NULL &&
|
||||
creditstxt[data->entry][0] == '\r') {
|
||||
data->entry++;
|
||||
data->state = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
} else {
|
||||
// Go to title screen
|
||||
scene_change(SCREEN_TITLE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
screen_credits_draw(void *d)
|
||||
{
|
||||
screen_credits_data *data = (screen_credits_data *)d;
|
||||
|
||||
// Get current text
|
||||
const char **window = &creditstxt[data->entry];
|
||||
if(*window != NULL) {
|
||||
// Calculate height and vy
|
||||
const char **cursor = window;
|
||||
uint16_t height = 0;
|
||||
while((*cursor)[0] != '\r') {
|
||||
cursor++;
|
||||
height += GLYPH_WHITE_HEIGHT + GLYPH_GAP;
|
||||
}
|
||||
|
||||
int16_t vy = CENTERY - (height >> 1);
|
||||
|
||||
// Render text line by line
|
||||
cursor = window;
|
||||
uint8_t is_first = 1;
|
||||
while((*cursor)[0] != '\r') {
|
||||
uint16_t width = font_measurew_big(*cursor);
|
||||
int16_t vx = CENTERX - (width >> 1);
|
||||
if(is_first) {
|
||||
font_set_color(
|
||||
LERPC(data->fade, 128),
|
||||
LERPC(data->fade, 128),
|
||||
LERPC(data->fade, 0));
|
||||
} else {
|
||||
font_set_color(
|
||||
LERPC(data->fade, 128),
|
||||
LERPC(data->fade, 128),
|
||||
LERPC(data->fade, 128));
|
||||
}
|
||||
font_draw_big(*cursor, vx, vy);
|
||||
|
||||
if(is_first) is_first = 0;
|
||||
cursor++;
|
||||
vy += GLYPH_WHITE_HEIGHT + GLYPH_GAP;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
#include "model.h"
|
||||
#include "object.h"
|
||||
#include "parallax.h"
|
||||
#include "basic_font.h"
|
||||
|
||||
extern int debug_mode;
|
||||
|
||||
|
@ -32,6 +33,8 @@ LevelData leveldata;
|
|||
Camera camera;
|
||||
ObjectTable obj_table_common;
|
||||
uint8_t level_fade;
|
||||
uint8_t level_ring_count;
|
||||
uint8_t level_score_count;
|
||||
|
||||
#define CHANNELS_PER_BGM 3
|
||||
static uint32_t bgm_loop_sectors[] = {
|
||||
|
@ -110,6 +113,9 @@ screen_level_load()
|
|||
reset_elapsed_frames();
|
||||
|
||||
level_fade = 0;
|
||||
|
||||
level_ring_count = 0;
|
||||
level_score_count = 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -282,6 +288,24 @@ screen_level_draw(void *d)
|
|||
draw_text(x, CENTERY - 12, 0, line1);
|
||||
}
|
||||
|
||||
// Heads-up display
|
||||
font_set_color(
|
||||
LERPC(level_fade, 0x7f),
|
||||
LERPC(level_fade, 0x7f),
|
||||
0);
|
||||
font_draw_big("SCORE", 10, 10);
|
||||
font_draw_big("TIME", 10, 24);
|
||||
font_draw_big("RINGS", 10, 38);
|
||||
font_set_color(
|
||||
LERPC(level_fade, 0x7f),
|
||||
LERPC(level_fade, 0x7f),
|
||||
LERPC(level_fade, 0x7f));
|
||||
font_draw_big("00000000", 60, 10);
|
||||
font_draw_big("0:00", 54, 24);
|
||||
snprintf(buffer, 255, "%3d", level_ring_count);
|
||||
font_draw_big(buffer, 60, 38);
|
||||
font_reset_color();
|
||||
|
||||
if(debug_mode) {
|
||||
// Video debug
|
||||
snprintf(buffer, 255,
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
#define CHOICE_SONICT 9
|
||||
#define CHOICE_INTRO 10
|
||||
#define CHOICE_SOON 11
|
||||
#define MAX_LEVELS (CHOICE_SOON + 1)
|
||||
#define CHOICE_CREDITS 12
|
||||
#define MAX_LEVELS (CHOICE_CREDITS + 1)
|
||||
|
||||
typedef struct {
|
||||
uint8_t menu_choice;
|
||||
|
@ -37,8 +38,8 @@ extern int debug_mode;
|
|||
static const char *menutext[] = {
|
||||
"PLAYGROUND ZONE 1",
|
||||
" ZONE 2",
|
||||
"TESTBED ZONE 1",
|
||||
" ZONE 2",
|
||||
" ZONE 3",
|
||||
" ZONE 4",
|
||||
"GREEN HILL ZONE 1",
|
||||
" ZONE 2",
|
||||
"SURELY WOOD ZONE 1",
|
||||
|
@ -46,13 +47,13 @@ static const char *menutext[] = {
|
|||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
|
||||
"MODELTEST",
|
||||
"TITLESCREEN",
|
||||
"SONICTEAM",
|
||||
"INTRO",
|
||||
"COMINGSOON",
|
||||
"CREDITS",
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
@ -154,6 +155,8 @@ screen_levelselect_update(void *d)
|
|||
scene_change(SCREEN_MODELTEST);
|
||||
} else if(data->menu_choice == CHOICE_SOON) {
|
||||
scene_change(SCREEN_COMINGSOON);
|
||||
} else if(data->menu_choice == CHOICE_CREDITS) {
|
||||
scene_change(SCREEN_CREDITS);
|
||||
} else {
|
||||
screen_level_setlevel(data->menu_choice);
|
||||
scene_change(SCREEN_LEVEL);
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include "input.h"
|
||||
#include "screen.h"
|
||||
#include "sound.h"
|
||||
/* #include "model.h" */
|
||||
#include "timer.h"
|
||||
|
||||
#include "screens/fmv.h"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue