proper replay saving and some minor stuff

This commit is contained in:
Andrew "Akari" Alexeyew 2012-07-16 18:47:06 +03:00
parent 6afad43f83
commit 5308856f1f
23 changed files with 287 additions and 51 deletions

View file

@ -19,7 +19,7 @@ ADD_FLEX_BISON_DEPENDENCY(cfgscanner cfgparser)
set(SRCs
main.c
stage.c
replay.c
replay.c
global.c
player.c
projectile.c
@ -39,7 +39,8 @@ set(SRCs
menu/options.c
menu/stageselect.c
menu/ingamemenu.c
menu/gameovermenu.c
menu/gameovermenu.c
menu/savereplay.c
menu/difficulty.c
menu/charselect.c
stages/stage0.c

View file

@ -35,7 +35,9 @@ enum {
NO_AUDIO,
NO_STAGEBG,
NO_STAGEBG_FPSLIMIT
NO_STAGEBG_FPSLIMIT,
SAVE_RPY
};
void parse_config(char *filename);

View file

@ -39,6 +39,8 @@
"disable_stagebg" { yylval = NO_STAGEBG; return tNO_STAGEBG; }
"disable_stagebg_auto_fpslimit" { yylval = NO_STAGEBG_FPSLIMIT; return tNO_STAGEBG_FPSLIMIT; }
"save_rpy" { yylval = SAVE_RPY; return tSAVE_RPY; }
"shift" { yylval = SDLK_LSHIFT; return SKEY; }
"ctrl" { yylval = SDLK_LCTRL; return SKEY; }
"return" { yylval = SDLK_RETURN; return SKEY; }

View file

@ -49,6 +49,7 @@
%token tNO_AUDIO
%token tNO_STAGEBG
%token tNO_STAGEBG_FPSLIMIT
%token tSAVE_RPY
%token SKEY
@ -88,7 +89,8 @@ key_key : tKEY_UP
| tNO_AUDIO
| tFULLSCREEN
| tNO_STAGEBG
| tNO_STAGEBG_FPSLIMIT;
| tNO_STAGEBG_FPSLIMIT
| tSAVE_RPY;
nl : LB { lineno++; };
%%
@ -140,6 +142,8 @@ void config_preset() {
tconfig.intval[NO_STAGEBG] = 0;
tconfig.intval[NO_STAGEBG_FPSLIMIT] = 40;
tconfig.intval[SAVE_RPY] = 2;
}
int config_sym2key(int sym) {

View file

@ -62,6 +62,8 @@ void set_ortho() {
}
void fade_out(float f) {
if(f == 0) return;
glColor4f(0,0,0,f);
glPushMatrix();

View file

@ -134,4 +134,6 @@ enum {
EV_OVER // replay-only
};
#define REPLAY_ASKSAVE (tconfig.intval[SAVE_RPY] == 2 && global.replay.active)
#endif

View file

@ -39,14 +39,16 @@ void taisei_shutdown() {
printf("-- Good Bye.\n");
}
int main(int argc, char** argv) {
#ifdef __MINGW32__
mkdir(get_config_path());
mkdir(get_screenshots_path());
#define MKDIR(p) mkdir(p)
#else
mkdir(get_config_path(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
mkdir(get_screenshots_path(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
#define MKDIR(p) mkdir(p, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)
#endif
int main(int argc, char** argv) {
MKDIR(get_config_path());
MKDIR(get_screenshots_path());
MKDIR(get_replays_path());
parse_config(CONFIG_FILE);

View file

@ -118,4 +118,3 @@ void normalize(Vector v) {
float length(Vector v) {
return sqrt(pow(v[0],2) + pow(v[1],2) + pow(v[2],2));
}

View file

@ -1,3 +1,10 @@
/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
* Copyright (C) 2011, Alexeyew Andrew <http://akari.thebadasschoobs.org/>
*/
#include "menu.h"
#include "gameovermenu.h"
@ -7,6 +14,9 @@ void continue_game(void *arg)
{
printf("The game is being continued...\n");
if(global.replaymode == REPLAY_RECORD) // actually... I'd be strange if REPLAY_PLAY ever got there
replay_destroy(&global.replay); // 19:39:29 [@ laochailan] no. no fame for continue users >:D
global.plr.lifes = PLR_START_LIVES;
global.plr.continues += 1;
@ -22,15 +32,9 @@ MenuData *create_gameover_menu() {
MenuData *m = malloc(sizeof(MenuData));
create_menu(m);
if(global.plr.continues)
{
char s[64];
snprintf(s, sizeof(s), "Continue (%i)", global.plr.continues);
add_menu_entry(m, s, continue_game, NULL);
}
else
add_menu_entry(m, "Continue", continue_game, NULL);
char s[64];
snprintf(s, sizeof(s), "Continue (%i)", MAX_CONTINUES - global.plr.continues);
add_menu_entry(m, s, continue_game, NULL);
add_menu_entry(m, "Give up", give_up, NULL);
return m;

View file

@ -1,3 +1,10 @@
/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
* Copyright (C) 2011, Alexeyew Andrew <http://akari.thebadasschoobs.org/>
*/
#ifndef GAMEOVERMENU_H
#define GAMEOVERMENU_H

View file

@ -27,6 +27,7 @@ MenuData *create_ingame_menu() {
void ingame_menu_logic(MenuData **menu) {
menu_logic(*menu);
if((*menu)->quit == 2 && (*menu)->selected != 1) { // let the stage clean up when returning to title
destroy_menu(*menu);
free(*menu);
@ -36,8 +37,18 @@ void ingame_menu_logic(MenuData **menu) {
void draw_ingame_menu(MenuData *menu) {
float rad = IMENU_BLUR;
float fade = menu->fade;
if( // horrible hacks because we have no sane transitions between ingame menus
REPLAY_ASKSAVE && (
(menu->selected != 0 && menu->quit == 1 && !menu->context) ||
(!menu->quit && menu->context)
)
) fade = 0;
if(menu->selected != 1) // hardly hardcoded. 1 -> "Return to Title"
rad = IMENU_BLUR * (1.0-menu->fade);
rad = IMENU_BLUR * (1.0-fade);
if(!tconfig.intval[NO_SHADER]) {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
@ -65,7 +76,13 @@ void draw_ingame_menu(MenuData *menu) {
// cirno's perfect math class #2: Euler Sign ~ Differential Fun
menu->drawdata[0] += (menu->cursor*35 - menu->drawdata[0])/7.0;
menu->drawdata[1] += (strlen(menu->entries[menu->cursor].name)*5 - menu->drawdata[1])/10.0;
if(menu->context) {
float s = 0.3 + 0.2 * sin(menu->frames/10.0);
glColor4f(1-s/2, 1-s/2, 1-s, 1.0 - menu->fade);
draw_text(AL_Center, 0, -2 * 35, (char*)menu->context, _fonts.standard);
}
int i;
for(i = 0; i < menu->ecount; i++) {
float s = 0, t = 0.7;
@ -80,4 +97,4 @@ void draw_ingame_menu(MenuData *menu) {
glColor4f(1,1,1,1);
glPopMatrix();
}
}

View file

@ -257,6 +257,22 @@ int bind_stagebg_fpslimit_dependence() {
return tconfig.intval[NO_STAGEBG] == 2;
}
int bind_saverpy_get(void *b)
{
int v = tconfig.intval[((OptionBinding*)b)->configentry];
if(v > 1)
return v;
return !v;
}
int bind_saverpy_set(void *b, int v)
{
if(v > 1)
return tconfig.intval[((OptionBinding*)b)->configentry] = v;
return !(tconfig.intval[((OptionBinding*)b)->configentry] = !v);
}
// --- Config saving --- //
void menu_save_config(MenuData *m, char *filename)
@ -348,7 +364,7 @@ void create_options_menu(MenuData *m) {
add_menu_entry(m, "Stage Background", do_nothing, NULL);
b = bind_option(m, "disable_stagebg", NO_STAGEBG, bind_common_intget,
bind_common_intset);
bind_common_intset);
bind_addvalue(b, "on");
bind_addvalue(b, "off");
bind_addvalue(b, "auto");
@ -358,7 +374,14 @@ void create_options_menu(MenuData *m) {
bind_common_intset);
bind_setvaluerange(b, 20, 60);
bind_setdependence(b, bind_stagebg_fpslimit_dependence);
add_menu_entry(m, "Save Replays", do_nothing, NULL);
b = bind_option(m, "save_rpy", SAVE_RPY, bind_saverpy_get,
bind_saverpy_set);
bind_addvalue(b, "on");
bind_addvalue(b, "off");
bind_addvalue(b, "ask");
add_menu_entry(m, " ", NULL, NULL);
allocate_binding(m);

46
src/menu/savereplay.c Executable file
View file

@ -0,0 +1,46 @@
/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
* Copyright (C) 2012, Alexeyew Andrew <http://akari.thebadasschoobs.org/>
*/
#include <time.h>
#include "savereplay.h"
#include "global.h"
#include "replay.h"
#include "plrmodes.h"
void save_rpy(void *a) {
Replay *rpy = &global.replay;
char strtime[128], name[128];
time_t rawtime;
struct tm * timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
strftime(strtime, 128, "%Y%m%d_%H-%M-%S_%Z", timeinfo);
char prepr[16];
plrmode_repr(prepr, 16, rpy->plr_char, rpy->plr_shot);
snprintf(name, 128, "taisei_stg%d_%s_%s", rpy->stage, prepr, strtime);
replay_save(rpy, name);
}
void dont_save_rpy(void *a) {
//((MenuData*)a)->quit = 2;
((MenuData*)a)->selected = 0;
}
MenuData* create_saverpy_menu() {
MenuData *m = malloc(sizeof(MenuData));
create_menu(m);
m->context = "Save replay?";
add_menu_entry(m, "Yes", save_rpy, m);
add_menu_entry(m, "No", dont_save_rpy, m);
return m;
}

17
src/menu/savereplay.h Executable file
View file

@ -0,0 +1,17 @@
/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
* Copyright (C) 2012, Alexeyew Andrew <http://akari.thebadasschoobs.org/>
*/
#ifndef SAVERPYMENU_H
#define SAVERPYMENU_H
#include "menu.h"
void save_rpy(void*);
MenuData *create_saverpy_menu();
#endif

View file

@ -11,5 +11,6 @@
const char *get_prefix();
const char *get_config_path();
const char *get_screenshots_path();
const char *get_replays_path();
#endif

View file

@ -18,3 +18,7 @@ const char *get_config_path() {
const char *get_screenshots_path() {
return "./screenshots";
}
const char *get_replays_path() {
return "./screenshots";
}

View file

@ -12,9 +12,11 @@
#define CFG_DIR "/.taisei"
#define SCR_DIR "/screenshots"
#define RPY_DIR "/replays"
char *conf_path = NULL;
char *scr_path = NULL;
char *conf_path = NULL;
char *scr_path = NULL;
char *rpy_path = NULL;
const char *get_prefix() {
return FILE_PREFIX;
@ -40,3 +42,12 @@ const char *get_screenshots_path() {
return scr_path;
}
const char *get_replays_path() {
if(rpy_path == NULL) {
rpy_path = malloc(strlen(RPY_DIR) + strlen(get_config_path()) + 1);
strcpy(rpy_path, get_config_path());
strcat(rpy_path, RPY_DIR);
}
return rpy_path;
}

View file

@ -207,8 +207,6 @@ void plr_realdeath(Player *plr) {
if(plr->lifes-- == 0) {
if(plr->continues < MAX_CONTINUES) {
if(global.replaymode == REPLAY_RECORD) // actually... I'd be strange if REPLAY_PLAY ever got there
replay_destroy(&global.replay); // 19:39:29 [@ laochailan] no. no fame for continue users >:D
global.menu = create_gameover_menu();
} else
game_over();

View file

@ -473,4 +473,21 @@ void marisa_power(Player *plr, float npow) {
}
break;
}
}
}
int plrmode_repr(char *out, size_t outsize, Character pchar, ShotMode pshot) {
char *plr, sht;
switch(pchar) {
case Marisa : plr = "marisa" ; break;
case Youmu : plr = "youmu" ; break;
default : plr = "wtf" ; break;
}
switch(pshot) {
case MarisaLaser: sht = 'A' ; break;
case MarisaStar : sht = 'B' ; break;
}
return snprintf(out, outsize, "%s%c", plr, sht);
}

View file

@ -29,4 +29,7 @@ void marisa_shot(Player *plr);
void marisa_bomb(Player *plr);
void marisa_power(Player *plr, float npow);
#endif
/* Misc */
int plrmode_repr(char *out, size_t outsize, Character pchar, ShotMode pshot);
#endif

View file

@ -64,16 +64,8 @@ void replay_event(Replay *rpy, int type, int key) {
printf("The new capacity is %d\n", rpy->capacity);
}
if(type == EV_OVER) {
if(type == EV_OVER)
printf("The replay is OVER\n");
char p[1337];
snprintf(p, 1337, "%s/test.%s", get_config_path(), REPLAY_EXTENSION);
FILE *fp = fopen(p, "w");
replay_write(rpy, fp);
fflush(fp);
fclose(fp);
}
}
void replay_write_separator(FILE *file) {
@ -247,3 +239,44 @@ int replay_read(Replay *rpy, FILE *file) {
#undef FLOATOF
#undef INTOF
char* replay_getpath(char *name) {
char *p = (char*)malloc(strlen(get_replays_path()) + strlen(name) + strlen(REPLAY_EXTENSION) + 3);
sprintf(p, "%s/%s.%s", get_replays_path(), name, REPLAY_EXTENSION);
return p;
}
int replay_save(Replay *rpy, char *name) {
char *p = replay_getpath(name);
printf("replay_save(): saving %s\n", p);
FILE *fp = fopen(p, "w");
if(!fp) {
printf("replay_save(): fopen() failed\n");
return False;
}
free(p);
int result = replay_write(rpy, fp);
fflush(fp);
fclose(fp);
return result;
}
int replay_load(Replay *rpy, char *name) {
char *p = replay_getpath(name);
printf("replay_load(): loading %s\n", p);
FILE *fp = fopen(p, "r");
if(!fp) {
printf("replay_load(): fopen() failed\n");
return False;
}
free(p);
int result = replay_read(rpy, fp);
fclose(fp);
return result;
}

View file

@ -53,6 +53,10 @@ void replay_event(Replay *rpy, int type, int key);
int replay_write(Replay *rpy, FILE *file);
int replay_read(Replay *rpy, FILE *file);
char* replay_getpath(char *name); // must be freed
int replay_save(Replay *rpy, char *name);
int replay_load(Replay *rpy, char *name);
#define REPLAY_ALLOC_INITIAL 100
#define REPLAY_ALLOC_ADDITIONAL 100
#define REPLAY_MAGICNUMBER 1337

View file

@ -14,6 +14,7 @@
#include "config.h"
#include "player.h"
#include "menu/ingamemenu.h"
#include "menu/savereplay.h"
StageInfo stages[] = {
// TODO: Give the stages actual titles/subtitles
@ -41,6 +42,7 @@ void stage_start() {
global.game_over = 0;
global.points = 0;
global.nostagebg = False;
global.fps.show_fps = 0;
global.plr.recovery = 0;
}
@ -181,6 +183,9 @@ void stage_draw(StageRule bgdraw, ShaderRule *shaderrules, int time) {
global.nostagebg = True;
}
if(tconfig.intval[NO_STAGEBG] == 1)
global.nostagebg = True;
if(!global.nostagebg && !global.menu)
bgdraw();
@ -189,10 +194,10 @@ void stage_draw(StageRule bgdraw, ShaderRule *shaderrules, int time) {
set_ortho();
glPushMatrix();
glTranslatef(VIEWPORT_X,VIEWPORT_Y,0);
if(!global.menu) {
glPushMatrix();
glTranslatef(VIEWPORT_X,VIEWPORT_Y,0);
if(!global.menu) {
if(!tconfig.intval[NO_SHADER])
apply_bg_shaders(shaderrules);
@ -244,24 +249,36 @@ void stage_draw(StageRule bgdraw, ShaderRule *shaderrules, int time) {
// glColor4f(1,1,1,1);
glPopMatrix();
}
} else {
draw_ingame_menu(global.menu);
glPopMatrix();
}
glPopMatrix();
if(global.frames < 4*FADE_TIME)
fade_out(1.0 - global.frames/(float)(4*FADE_TIME));
if(global.timer > time - 4*FADE_TIME) {
fade_out((global.timer - time + 4*FADE_TIME)/(float)(4*FADE_TIME));
}
draw_hud();
if(global.menu) {
glPushMatrix();
glTranslatef(VIEWPORT_X,VIEWPORT_Y,0);
draw_ingame_menu(global.menu);
glPopMatrix();
}
if(global.menu && global.menu->selected == 1)
fade_out(global.menu->fade);
draw_hud();
if(global.menu) {
// horrible hacks because we have no sane transitions between ingame menus
if(REPLAY_ASKSAVE) {
if(global.menu->context && global.menu->quit == 1) {
fade_out(global.menu->fade);
}
} else {
fade_out(global.menu->fade);
}
}
}
void apply_bg_shaders(ShaderRule *shaderrules) {
@ -434,8 +451,28 @@ void stage_loop(StageInfo* info, StageRule start, StageRule end, StageRule draw,
frame_rate(&global.lasttime);
}
if(global.replaymode == REPLAY_RECORD)
if(global.replaymode == REPLAY_RECORD) {
replay_event(&global.replay, EV_OVER, 0);
if(REPLAY_ASKSAVE) {
global.menu = create_saverpy_menu();
while(global.menu) {
ingame_menu_logic(&global.menu);
if(!global.menu)
break;
menu_input(global.menu);
stage_draw(draw, shaderrules, endtime);
SDL_GL_SwapBuffers();
frame_rate(&global.lasttime);
}
}
if(global.replay.active && tconfig.intval[SAVE_RPY] == 1)
save_rpy(NULL);
}
end();
stage_end();