diff --git a/assets/misc/CHARSEL.TIM b/assets/misc/CHARSEL.TIM new file mode 100644 index 0000000..ec50044 Binary files /dev/null and b/assets/misc/CHARSEL.TIM differ diff --git a/assets/misc/charsel.png b/assets/misc/charsel.png new file mode 100644 index 0000000..c109dcc Binary files /dev/null and b/assets/misc/charsel.png differ diff --git a/include/screen.h b/include/screen.h index fa99422..d6a3a69 100644 --- a/include/screen.h +++ b/include/screen.h @@ -12,6 +12,7 @@ typedef enum { SCREEN_SLIDE, SCREEN_CREDITS, SCREEN_SPRITETEST, + SCREEN_CHARSELECT, } ScreenIndex; void scene_change(ScreenIndex scr); diff --git a/include/screens/charselect.h b/include/screens/charselect.h new file mode 100644 index 0000000..851fca0 --- /dev/null +++ b/include/screens/charselect.h @@ -0,0 +1,9 @@ +#ifndef SCREENS_CHARSELECT_H +#define SCREENS_CHARSELECT_H + +void screen_charselect_load(); +void screen_charselect_unload(void *); +void screen_charselect_update(void *); +void screen_charselect_draw(void *); + +#endif diff --git a/iso.xml b/iso.xml index f981d90..7c6f99a 100644 --- a/iso.xml +++ b/iso.xml @@ -309,6 +309,9 @@ + diff --git a/src/screen.c b/src/screen.c index 3c21aaf..dd61f41 100644 --- a/src/screen.c +++ b/src/screen.c @@ -17,6 +17,7 @@ #include "screens/slide.h" #include "screens/credits.h" #include "screens/sprite_test.h" +#include "screens/charselect.h" // Start with 64k until we make the actual level scene // an object as well @@ -80,6 +81,7 @@ scene_load() case SCREEN_SLIDE: screen_slide_load(); break; case SCREEN_CREDITS: screen_credits_load(); break; case SCREEN_SPRITETEST: screen_sprite_test_load(); break; + case SCREEN_CHARSELECT: screen_charselect_load(); break; default: break; // Unknown scene??? } } @@ -96,6 +98,7 @@ scene_unload() case SCREEN_SLIDE: screen_slide_unload(scene_data); break; case SCREEN_CREDITS: screen_credits_unload(scene_data); break; case SCREEN_SPRITETEST: screen_sprite_test_unload(scene_data); break; + case SCREEN_CHARSELECT: screen_charselect_unload(scene_data); break; default: break; // Unknown scene??? } } @@ -112,6 +115,7 @@ scene_update() case SCREEN_SLIDE: screen_slide_update(scene_data); break; case SCREEN_CREDITS: screen_credits_update(scene_data); break; case SCREEN_SPRITETEST: screen_sprite_test_update(scene_data); break; + case SCREEN_CHARSELECT: screen_charselect_update(scene_data); break; default: break; // Unknown scene??? } } @@ -129,6 +133,7 @@ scene_draw() case SCREEN_SLIDE: screen_slide_draw(scene_data); break; case SCREEN_CREDITS: screen_credits_draw(scene_data); break; case SCREEN_SPRITETEST: screen_sprite_test_draw(scene_data); break; + case SCREEN_CHARSELECT: screen_charselect_draw(scene_data); break; default: break; // Unknown scene??? } } diff --git a/src/screen_charselect.c b/src/screen_charselect.c new file mode 100644 index 0000000..036e714 --- /dev/null +++ b/src/screen_charselect.c @@ -0,0 +1,183 @@ +#include +#include "screen.h" +#include "screens/charselect.h" +#include "player.h" +#include "render.h" +#include "util.h" +#include "input.h" +#include "basic_font.h" +#include "sound.h" + +#include "screens/level.h" + +#define BG_PAUSE 90 +#define BG_FPS 4 +#define BG_FRAMES 4 + +#define CHARSEL_PADDING (SCREEN_XRES >> 2) + +typedef struct { + int8_t character; + int32_t bg_prect_x; + int32_t bg_prect_y; + uint8_t bg_mode; + uint8_t bg_frame; + uint8_t bg_state; + uint16_t bg_timer; + uint8_t charsel_mode; +} screen_charselect_data; + +// TIM 15bpp -- TPAGE: 384x0 +// Sonic: 0x0+22+40 +// Tails: 22x0+40+40 +// Knuckles: 62x0+40+40 + + +void +screen_charselect_load() +{ + screen_charselect_data *data = screen_alloc(sizeof(screen_charselect_data)); + data->character = screen_level_getcharacter(); + + uint32_t length; + TIM_IMAGE tim; + uint8_t *img = file_read("\\MISC\\LVLSEL.TIM;1", &length); + load_texture(img, &tim); + data->bg_mode = tim.mode; + data->bg_prect_x = tim.prect->x; + data->bg_prect_y = tim.prect->y; + free(img); + + img = file_read("\\MISC\\CHARSEL.TIM;1", &length); + load_texture(img, &tim); + data->charsel_mode = tim.mode; + free(img); + + data->bg_frame = 0; + data->bg_state = 0; + data->bg_timer = BG_PAUSE; + + sound_bgm_play(BGM_TITLESCREEN); +} + +void +screen_charselect_unload(void *) +{ + sound_stop_xa(); + screen_free(); +} + +void +screen_charselect_update(void *d) +{ + screen_charselect_data *data = (screen_charselect_data *)d; + + if((data->bg_state == 0) || (data->bg_state == 2)) { + data->bg_timer--; + if(data->bg_timer == 0) { + data->bg_state++; + data->bg_timer = BG_FPS; + } + } else if(data->bg_state == 1) { + data->bg_timer--; + if(data->bg_timer == 0) { + data->bg_frame++; + data->bg_timer = BG_FPS; + if(data->bg_frame == BG_FRAMES - 1) { + data->bg_state++; + data->bg_timer = BG_PAUSE; + } + } + } else if(data->bg_state == 3) { + data->bg_timer--; + if(data->bg_timer == 0) { + data->bg_frame--; + data->bg_timer = BG_FPS; + if(data->bg_frame == 0) { + data->bg_state = 0; + data->bg_timer = BG_PAUSE; + } + } + } + + if(pad_pressed(PAD_RIGHT)) data->character++; + if(pad_pressed(PAD_LEFT)) data->character--; + data->character = + (data->character < 0) + ? 0 + : ((data->character > CHARA_MAX) + ? CHARA_MAX + : data->character); + + if(pad_pressed(PAD_CROSS) || pad_pressed(PAD_START)) { + screen_level_setcharacter(data->character); + screen_level_setlevel(6); + screen_level_setmode(LEVEL_MODE_NORMAL); + scene_change(SCREEN_LEVEL); + } +} + +const char * +_get_char_name(int8_t character) +{ + switch(character) { + case CHARA_SONIC: return "SONIC"; + case CHARA_MILES: return "TAILS"; + case CHARA_KNUCKLES: return "KNUCKLES"; + } + return "UNKNOWN"; +} + +void +screen_charselect_draw(void *d) +{ + screen_charselect_data *data = (screen_charselect_data *)d; + + static const char *title = "CHARACTER SELECT"; + + font_set_color(128, 128, 128); + uint16_t text_hsize = font_measurew_big(title) >> 1; + uint16_t text_xpos = CENTERX - text_hsize; + font_draw_big(title, text_xpos, SCREEN_YRES >> 3); + + // Draw characters + for(uint16_t i = 0; i < 3; i++) { + int16_t xpos = (CHARSEL_PADDING + (i * CHARSEL_PADDING)); + int16_t ypos = (SCREEN_YRES >> 1); + uint8_t is_current_char = (data->character == i); + uint8_t dim = is_current_char ? 128 : 64; + POLY_FT4 *poly = (POLY_FT4 *)get_next_prim(); + increment_prim(sizeof(POLY_FT4)); + setPolyFT4(poly); + setRGB0(poly, dim, dim, dim); + setTPage(poly, data->charsel_mode & 0x3, 0, 384, 0); + poly->clut = 0; + setXYWH(poly, xpos - 20, ypos - 20, 40, 40); + setUVWH(poly, 40 * i, 0, 40, 40); + sort_prim(poly, OTZ_LAYER_PLAYER); + + if(is_current_char) { + const char *charname = _get_char_name(data->character); + text_hsize = font_measurew_sm(charname) >> 1; + font_draw_sm(charname, xpos - text_hsize, ypos + 30); + } + } + + // Draw background + for(uint16_t y = 0; y < SCREEN_YRES; y += 32) { + for(uint16_t x = 0; x < SCREEN_XRES; x += 48) { + POLY_FT4 *poly = (POLY_FT4 *)get_next_prim(); + increment_prim(sizeof(POLY_FT4)); + setPolyFT4(poly); + setRGB0(poly, 96, 96, 96); + poly->tpage = getTPage(data->bg_mode & 0x3, + 0, + data->bg_prect_x, + data->bg_prect_y); + poly->clut = 0; + setXYWH(poly, x, y, 48, 32); + setUVWH(poly, 0, 32 * data->bg_frame, 48, 32); + sort_prim(poly, OTZ_LAYER_LEVEL_BG); + } + } +} diff --git a/src/screen_title.c b/src/screen_title.c index d680610..fd01a6e 100644 --- a/src/screen_title.c +++ b/src/screen_title.c @@ -207,9 +207,7 @@ screen_title_update(void *d) case 2: // New Game // Use Surely Wood Zone 1 as first level screen_title_reset_demo(); - screen_level_setlevel(6); - screen_level_setmode(LEVEL_MODE_NORMAL); - data->next_scene = SCREEN_LEVEL; + data->next_scene = SCREEN_CHARSELECT; level_score_count = 0; break; case 3: // Level Select