RogueLife/src/menu.c

171 lines
4.9 KiB
C

#include "map.h"
#include "level.h"
#include "render.h"
#include <gint/timer.h>
#include <gint/cpu.h>
#include <gint/keyboard.h>
#include <gint/defs/util.h>
#include <gint/usb.h>
#include <gint/usb-ff-bulk.h>
#include <stdlib.h>
typedef struct {
/* Same mechanism as in game_t */
level_t const *level;
map_t const *map;
uint16_t *map_anim;
camera_t camera;
} menu_game_t;
static menu_game_t *menu_load_game(level_t const *level)
{
menu_game_t *mg = malloc(sizeof *mg);
mg->level = level;
mg->map = level->map;
mg->map_anim = malloc(mg->map->width * mg->map->height *
sizeof *mg->map_anim);
for(int i = 0; i < mg->map->width * mg->map->height; i++)
mg->map_anim[i] = rand() & 4095;
camera_init(&mg->camera, mg->map);
return mg;
}
static void menu_destroy_game(menu_game_t *mg)
{
free(mg->map_anim);
free(mg);
}
static void menu_render_game(menu_game_t *mg)
{
render_map_layer(mg->map, &mg->camera, 0, 0, HORIZONTAL, mg->map_anim,
DIMAGE_NONE);
render_map_layer(mg->map, &mg->camera, 0, 0, VERTICAL, mg->map_anim,
DIMAGE_NONE);
render_map_layer(mg->map, &mg->camera, 0, 0, CEILING, mg->map_anim,
DIMAGE_NONE);
}
static void menu_update_animations(menu_game_t *mg, fixed_t dt)
{
for(int i = 0; i < mg->map->width * mg->map->height; i++)
mg->map_anim[i] += fround(dt * 1000);
}
int menu_level_select(int start)
{
extern bopti_image_t img_menu_title, img_menu_arrows;
menu_game_t *options[LEVEL_COUNT];
#define OPTION_COUNT LEVEL_COUNT
for(int i = 0; i < LEVEL_COUNT; i++)
options[i] = menu_load_game(level_all[i]);
int selection = (start >= 0 && start < OPTION_COUNT) ? start : 0;
int target_x=0, x=0;
/* Time spent in the transition animation that moves the GUI items away
before starting the level. */
fixed_t transition_time = fix(0.0);
int volatile frame_tick = 1;
int t = timer_configure(TIMER_ANY, 1000000 / FRAME_RATE,
GINT_CALL_SET(&frame_tick));
timer_start(t);
while(1) {
while(!frame_tick)
sleep();
fixed_t dt = fix(1) / FRAME_RATE;
if(x != target_x) {
int dx = (target_x - x) / 6;
if(x < target_x && dx < 6)
dx = min(target_x-x, 6);
if(x > target_x && dx > -6)
dx = max(target_x-x, -6);
x += dx;
}
/* GUI positioning variables, accounting for the final transition */
fixed_t TRANSITION_LEN = fix(0.75);
int LOGO_Y = cubic(9, 9-85, transition_time, TRANSITION_LEN);
int ARROW1_X = cubic(16, 16-50, transition_time, TRANSITION_LEN);
int ARROW2_X = cubic(345, 345+50, transition_time, TRANSITION_LEN);
int NAME_Y = cubic(DHEIGHT-24, DHEIGHT+10, transition_time,
TRANSITION_LEN);
dclear(C_BLACK);
for(int i = 0; i < OPTION_COUNT; i++) {
if(-x <= (i-1)*DWIDTH)
continue;
if(-x >= (i+1)*DWIDTH)
continue;
int local_offset = x + i*DWIDTH;
fixed_t map_center = fix(options[i]->map->width) / 2;
options[i]->camera.x = map_center - fix(local_offset) / TILE_WIDTH;
menu_render_game(options[i]);
dprint_opt(DWIDTH/2 + local_offset, NAME_Y, C_WHITE, C_NONE,
DTEXT_CENTER, DTEXT_MIDDLE, "%s", options[i]->level->name);
}
dimage(148, LOGO_Y, &img_menu_title);
if(selection > 0)
dsubimage(ARROW1_X, 93, &img_menu_arrows, 0, 0, 35, 42,
DIMAGE_NONE);
if(selection < OPTION_COUNT - 1)
dsubimage(ARROW2_X, 93, &img_menu_arrows, 35, 0, 35, 42,
DIMAGE_NONE);
dupdate();
for(int i = 0; i < OPTION_COUNT; i++)
menu_update_animations(options[i], dt);
int key = getkey_opt(GETKEY_MENU, &frame_tick).key;
extern bool rogue_life_video_capture;
if(key == KEY_F6 && keydown(KEY_ALPHA) && !keydown(KEY_VARS)
&& usb_is_open()) {
rogue_life_video_capture = !rogue_life_video_capture;
}
if(rogue_life_video_capture) {
usb_fxlink_videocapture(false);
}
if(transition_time <= fix(0.0)
&& key == KEY_LEFT && selection > 0) {
selection--;
target_x += DWIDTH;
}
if(transition_time <= fix(0.0)
&& key == KEY_RIGHT && selection < OPTION_COUNT - 1) {
selection++;
target_x -= DWIDTH;
}
if(key == KEY_EXE || key == KEY_SHIFT) {
transition_time = dt;
}
else if(transition_time > fix(0.0)) {
transition_time += dt;
if(transition_time >= TRANSITION_LEN)
break;
}
}
timer_stop(t);
for(size_t i = 0; i < OPTION_COUNT; i++)
menu_destroy_game(options[i]);
return selection;
}