Introduced playername option, fancied up the replayview menu, etc
This commit is contained in:
parent
d1f4aa03e3
commit
a322371b5f
17 changed files with 311 additions and 67 deletions
|
@ -12,7 +12,8 @@
|
|||
#include "parser.h"
|
||||
|
||||
typedef struct Config {
|
||||
int intval[64];
|
||||
int intval[64];
|
||||
char* strval[64];
|
||||
} Config;
|
||||
|
||||
extern Config tconfig;
|
||||
|
@ -41,6 +42,8 @@ enum {
|
|||
|
||||
VID_WIDTH,
|
||||
VID_HEIGHT,
|
||||
|
||||
PLAYERNAME
|
||||
};
|
||||
|
||||
void parse_config(char *filename);
|
||||
|
|
13
src/config.l
13
src/config.l
|
@ -44,6 +44,8 @@
|
|||
"vid_width" { yylval = VID_WIDTH; return tVID_WIDTH; }
|
||||
"vid_height" { yylval = VID_HEIGHT; return tVID_HEIGHT; }
|
||||
|
||||
"playername" { yylval = PLAYERNAME; return tPLAYERNAME; }
|
||||
|
||||
"shift" { yylval = SDLK_LSHIFT; return SKEY; }
|
||||
"ctrl" { yylval = SDLK_LCTRL; return SKEY; }
|
||||
"return" { yylval = SDLK_RETURN; return SKEY; }
|
||||
|
@ -54,7 +56,6 @@
|
|||
"right" { yylval = SDLK_RIGHT; return SKEY; }
|
||||
"left" { yylval = SDLK_LEFT; return SKEY; }
|
||||
|
||||
|
||||
[0-9]+ { yylval = atoi(yytext); return NUMBER; }
|
||||
[a-zA-Z] { yylval = yytext[0]; return tCHAR; }
|
||||
|
||||
|
@ -65,6 +66,16 @@
|
|||
|
||||
K[0-9]+ { yylval = atoi(yytext + 1); return tCHAR; }
|
||||
|
||||
\"[^\"\n\r]+\" {
|
||||
int l = strlen(yytext) - 1;
|
||||
char *s = malloc(l);
|
||||
strcpy(s, yytext + 1);
|
||||
s[l-1] = 0;
|
||||
|
||||
yylval = (int)s;
|
||||
return tSTRING;
|
||||
}
|
||||
|
||||
\n return LB;
|
||||
[ \t] ;
|
||||
|
||||
|
|
23
src/config.y
23
src/config.y
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include "paths/native.h"
|
||||
#include "taisei_err.h"
|
||||
|
||||
|
||||
Config tconfig;
|
||||
int lineno;
|
||||
|
||||
|
@ -55,10 +55,13 @@
|
|||
%token tVID_WIDTH
|
||||
%token tVID_HEIGHT
|
||||
|
||||
%token tPLAYERNAME
|
||||
|
||||
%token SKEY
|
||||
|
||||
%token NUMBER
|
||||
%token tCHAR
|
||||
%token tSTRING
|
||||
|
||||
%token SEMI
|
||||
%token EQ
|
||||
|
@ -74,6 +77,14 @@ line : key_key EQ key_val {
|
|||
if($1 > sizeof(tconfig.intval)/sizeof(int))
|
||||
errx(-1, "config index out of range"); // should not happen
|
||||
tconfig.intval[$1] = $3;
|
||||
}
|
||||
| key_strkey EQ tSTRING {
|
||||
if($1 > sizeof(tconfig.strval)/sizeof(char*))
|
||||
errx(-1, "config index out of range"); // should not happen
|
||||
|
||||
if(tconfig.strval[$1])
|
||||
free(tconfig.strval[$1]);
|
||||
tconfig.strval[$1] = $3;
|
||||
};
|
||||
|
||||
key_val : SKEY
|
||||
|
@ -98,6 +109,9 @@ key_key : tKEY_UP
|
|||
| tVID_HEIGHT
|
||||
| tSAVE_RPY;
|
||||
|
||||
key_strkey : tPLAYERNAME;
|
||||
|
||||
|
||||
nl : LB { lineno++; };
|
||||
%%
|
||||
|
||||
|
@ -113,7 +127,6 @@ void parse_config(char *filename) {
|
|||
|
||||
strcat(buf, "/");
|
||||
strcat(buf, filename);
|
||||
|
||||
yyin = fopen(buf, "r");
|
||||
|
||||
printf("parse_config():\n");
|
||||
|
@ -129,6 +142,8 @@ void parse_config(char *filename) {
|
|||
}
|
||||
|
||||
void config_preset() {
|
||||
memset(tconfig.strval, 0, sizeof(tconfig.strval));
|
||||
|
||||
tconfig.intval[KEY_UP] = SDLK_UP;
|
||||
tconfig.intval[KEY_DOWN] = SDLK_DOWN;
|
||||
tconfig.intval[KEY_LEFT] = SDLK_LEFT;
|
||||
|
@ -153,6 +168,10 @@ void config_preset() {
|
|||
|
||||
tconfig.intval[VID_WIDTH] = RESX;
|
||||
tconfig.intval[VID_HEIGHT] = RESY;
|
||||
|
||||
char *name = "Player";
|
||||
tconfig.strval[PLAYERNAME] = malloc(strlen(name)+1);
|
||||
strcpy(tconfig.strval[PLAYERNAME], name);
|
||||
}
|
||||
|
||||
int config_sym2key(int sym) {
|
||||
|
|
31
src/global.c
31
src/global.c
|
@ -176,3 +176,34 @@ void global_processevent(SDL_Event *event)
|
|||
video_toggle_fullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
int strendswith(char *s, char *e) {
|
||||
int ls = strlen(s);
|
||||
int le = strlen(e);
|
||||
|
||||
if(le > ls)
|
||||
return False;
|
||||
|
||||
int i; for(i = ls - 1; i < le; ++i)
|
||||
if(s[i] != e[i])
|
||||
return False;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
char* difficulty_name(Difficulty diff) {
|
||||
switch(diff) {
|
||||
case D_Easy: return "Easy"; break;
|
||||
case D_Normal: return "Nromal"; break;
|
||||
case D_Hard: return "Hard"; break;
|
||||
case D_Lunatic: return "Lunatic"; break;
|
||||
default: return "Unknown"; break;
|
||||
}
|
||||
}
|
||||
|
||||
void stralloc(char **dest, char *src) {
|
||||
if(*dest)
|
||||
free(*dest);
|
||||
*dest = malloc(strlen(src)+1);
|
||||
strcpy(*dest, src);
|
||||
}
|
||||
|
|
|
@ -139,6 +139,9 @@ void global_processevent(SDL_Event*);
|
|||
void take_screenshot();
|
||||
|
||||
double approach(double v, double t, double d);
|
||||
int strendswith(char *s, char *e);
|
||||
char* difficulty_name(Difficulty diff);
|
||||
void stralloc(char **dest, char *src);
|
||||
|
||||
// this is used by both player and replay code
|
||||
enum {
|
||||
|
|
|
@ -49,7 +49,7 @@ void taisei_shutdown() {
|
|||
int main(int argc, char** argv) {
|
||||
if(tsrand_test())
|
||||
return 0;
|
||||
|
||||
|
||||
MKDIR(get_config_path());
|
||||
MKDIR(get_screenshots_path());
|
||||
MKDIR(get_replays_path());
|
||||
|
@ -106,10 +106,12 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
#endif
|
||||
|
||||
printf("playename = %s\n", tconfig.strval[PLAYERNAME]);
|
||||
|
||||
MenuData menu;
|
||||
create_main_menu(&menu);
|
||||
printf("-- menu\n");
|
||||
main_menu_loop(&menu);
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -10,12 +10,13 @@
|
|||
|
||||
void add_menu_entry(MenuData *menu, char *name, void (*action)(void *), void *arg) {
|
||||
menu->entries = realloc(menu->entries, (++menu->ecount)*sizeof(MenuEntry));
|
||||
menu->entries[menu->ecount-1].name = malloc(strlen(name)+1);
|
||||
strcpy(menu->entries[menu->ecount-1].name, name);
|
||||
menu->entries[menu->ecount-1].action = action;
|
||||
menu->entries[menu->ecount-1].freearg = False;
|
||||
menu->entries[menu->ecount-1].arg = arg;
|
||||
menu->entries[menu->ecount-1].drawdata = 0;
|
||||
MenuEntry *e = &(menu->entries[menu->ecount-1]);
|
||||
memset(e, 0, sizeof(MenuEntry));
|
||||
|
||||
e->name = malloc(strlen(name)+1);
|
||||
strcpy(e->name, name);
|
||||
e->action = action;
|
||||
e->arg = arg;
|
||||
}
|
||||
|
||||
void add_menu_separator(MenuData *menu) {
|
||||
|
@ -34,7 +35,7 @@ void destroy_menu(MenuData *menu) {
|
|||
|
||||
free(e->name);
|
||||
if(e->freearg)
|
||||
free(e->arg);
|
||||
e->freearg(e->arg);
|
||||
}
|
||||
|
||||
free(menu->entries);
|
||||
|
|
|
@ -14,10 +14,11 @@
|
|||
|
||||
typedef struct {
|
||||
char *name;
|
||||
void (*action)(void* arg);
|
||||
void (*action)(void *arg);
|
||||
void *arg;
|
||||
float drawdata;
|
||||
int freearg;
|
||||
void (*freearg)(void *arg);
|
||||
void (*draw)(void *e, int i, int cnt);
|
||||
} MenuEntry;
|
||||
|
||||
typedef enum MenuType { // whether to close on selection or not.
|
||||
|
|
|
@ -60,8 +60,7 @@ void free_bindings(MenuData *m)
|
|||
|
||||
// Binds the last entry to an integer config option having limited values (BT_IntValue type binding).
|
||||
// Values are defined with bind_addvalue.
|
||||
OptionBinding* bind_option(MenuData *m, char *optname, int cfgentry, BindingGetter getter, BindingSetter setter)
|
||||
{
|
||||
OptionBinding* bind_option(MenuData *m, char *optname, int cfgentry, BindingGetter getter, BindingSetter setter) {
|
||||
OptionBinding *bind;
|
||||
bind = allocate_binding(m);
|
||||
|
||||
|
@ -77,8 +76,7 @@ OptionBinding* bind_option(MenuData *m, char *optname, int cfgentry, BindingGett
|
|||
}
|
||||
|
||||
// Binds the last entry to a keybinding config option (BT_KeyBinding type binding).
|
||||
OptionBinding* bind_keybinding(MenuData *m, char *optname, int cfgentry)
|
||||
{
|
||||
OptionBinding* bind_keybinding(MenuData *m, char *optname, int cfgentry) {
|
||||
OptionBinding *bind;
|
||||
bind = allocate_binding(m);
|
||||
|
||||
|
@ -91,6 +89,25 @@ OptionBinding* bind_keybinding(MenuData *m, char *optname, int cfgentry)
|
|||
return bind;
|
||||
}
|
||||
|
||||
// For string values, with a "textbox" editor
|
||||
OptionBinding* bind_stroption(MenuData *m, char *optname, int cfgentry) {
|
||||
OptionBinding *bind;
|
||||
bind = allocate_binding(m);
|
||||
|
||||
bind->configentry = cfgentry;
|
||||
bind->optname = malloc(strlen(optname) + 1);
|
||||
strcpy(bind->optname, optname);
|
||||
bind->enabled = True;
|
||||
bind->type = BT_StrValue;
|
||||
|
||||
bind->valcount = 1;
|
||||
bind->values = malloc(sizeof(char*));
|
||||
*bind->values = malloc(128);
|
||||
strncpy(*bind->values, tconfig.strval[cfgentry], 128);
|
||||
|
||||
return bind;
|
||||
}
|
||||
|
||||
// Super-special binding type for the resolution setting
|
||||
OptionBinding* bind_resolution(MenuData *m) {
|
||||
OptionBinding *bind;
|
||||
|
@ -340,6 +357,10 @@ void menu_save_config(MenuData *m, char *filename)
|
|||
fprintf(out, "%s = K%i\n", bind->optname, tconfig.intval[bind->configentry]);
|
||||
break;
|
||||
|
||||
case BT_StrValue:
|
||||
fprintf(out, "%s = \"%s\"\n", bind->optname, tconfig.strval[bind->configentry]);
|
||||
break;
|
||||
|
||||
case BT_Resolution:
|
||||
// at this point, the intended resolution is what the user has picked
|
||||
fprintf(out, "vid_width = %i\nvid_height = %i\n", video.intended.width, video.intended.height);
|
||||
|
@ -393,6 +414,12 @@ void create_options_menu(MenuData *m) {
|
|||
|
||||
#define bind_onoff(b) bind_addvalue(b, "on"); bind_addvalue(b, "off")
|
||||
|
||||
add_menu_entry(m, "Player Name", do_nothing, NULL);
|
||||
b = bind_stroption(m, "playername", PLAYERNAME);
|
||||
|
||||
add_menu_separator(m);
|
||||
allocate_binding(m);
|
||||
|
||||
add_menu_entry(m, "Video Mode", do_nothing, NULL);
|
||||
b = bind_resolution(m);
|
||||
|
||||
|
@ -430,7 +457,7 @@ void create_options_menu(MenuData *m) {
|
|||
bind_addvalue(b, "off");
|
||||
bind_addvalue(b, "ask");
|
||||
|
||||
add_menu_entry(m, " ", NULL, NULL);
|
||||
add_menu_separator(m);
|
||||
allocate_binding(m);
|
||||
|
||||
add_menu_entry(m, "Move up", do_nothing, NULL);
|
||||
|
@ -445,7 +472,7 @@ void create_options_menu(MenuData *m) {
|
|||
add_menu_entry(m, "Move right", do_nothing, NULL);
|
||||
bind_keybinding(m, "key_right", KEY_RIGHT);
|
||||
|
||||
add_menu_entry(m, " ", NULL, NULL);
|
||||
add_menu_separator(m);
|
||||
allocate_binding(m);
|
||||
|
||||
add_menu_entry(m, "Fire", do_nothing, NULL);
|
||||
|
@ -457,7 +484,7 @@ void create_options_menu(MenuData *m) {
|
|||
add_menu_entry(m, "Bomb", do_nothing, NULL);
|
||||
bind_keybinding(m, "key_bomb", KEY_BOMB);
|
||||
|
||||
add_menu_entry(m, " ", NULL, NULL);
|
||||
add_menu_separator(m);
|
||||
allocate_binding(m);
|
||||
|
||||
add_menu_entry(m, "Toggle fullscreen", do_nothing, NULL);
|
||||
|
@ -466,7 +493,7 @@ void create_options_menu(MenuData *m) {
|
|||
add_menu_entry(m, "Take a screenshot", do_nothing, NULL);
|
||||
bind_keybinding(m, "key_screenshot", KEY_SCREENSHOT);
|
||||
|
||||
add_menu_entry(m, " ", NULL, NULL);
|
||||
add_menu_separator(m);
|
||||
allocate_binding(m);
|
||||
|
||||
add_menu_entry(m, "Return to the main menu", backtomain, m);
|
||||
|
@ -508,6 +535,9 @@ void draw_options_menu(MenuData *menu) {
|
|||
int i, caption_drawn = 0;
|
||||
|
||||
for(i = 0; i < menu->ecount; i++) {
|
||||
if(!menu->entries[i].name)
|
||||
continue;
|
||||
|
||||
menu->entries[i].drawdata += 0.2 * (10*(i == menu->cursor) - menu->entries[i].drawdata);
|
||||
|
||||
bind = &(binds[i]);
|
||||
|
@ -559,15 +589,22 @@ void draw_options_menu(MenuData *menu) {
|
|||
caption_drawn = 1;
|
||||
}
|
||||
|
||||
if(bind->blockinput)
|
||||
{
|
||||
if(bind->blockinput) {
|
||||
glColor4f(0,1,0,0.7);
|
||||
draw_text(AL_Right, origin, 20*i, "Press a key to assign, ESC to cancel", _fonts.standard);
|
||||
}
|
||||
else
|
||||
} else
|
||||
draw_text(AL_Right, origin, 20*i, SDL_GetKeyName(tconfig.intval[bind->configentry]), _fonts.standard);
|
||||
break;
|
||||
|
||||
case BT_StrValue:
|
||||
if(bind->blockinput) {
|
||||
glColor4f(0,1,0,0.7);
|
||||
if(strlen(*bind->values))
|
||||
draw_text(AL_Right, origin, 20*i, *bind->values, _fonts.standard);
|
||||
} else
|
||||
draw_text(AL_Right, origin, 20*i, tconfig.strval[bind->configentry], _fonts.standard);
|
||||
break;
|
||||
|
||||
case BT_Resolution: {
|
||||
char tmp[16];
|
||||
int w, h;
|
||||
|
@ -600,27 +637,58 @@ void draw_options_menu(MenuData *menu) {
|
|||
|
||||
void bind_input(MenuData *menu, OptionBinding *b)
|
||||
{
|
||||
// yes, no global_input() here.
|
||||
|
||||
SDL_Event event;
|
||||
|
||||
if(b->type != BT_KeyBinding) // shouldn't happen, but just in case.
|
||||
{
|
||||
b->blockinput = False;
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_EnableUNICODE(True);
|
||||
while(SDL_PollEvent(&event)) {
|
||||
int sym = event.key.keysym.sym;
|
||||
int uni = event.key.keysym.unicode;
|
||||
|
||||
if(event.type == SDL_KEYDOWN) {
|
||||
if(sym != SDLK_ESCAPE) // escape means cancel
|
||||
tconfig.intval[b->configentry] = sym;
|
||||
b->blockinput = False;
|
||||
if(sym != SDLK_ESCAPE) {
|
||||
switch(b->type) {
|
||||
case BT_KeyBinding:
|
||||
tconfig.intval[b->configentry] = sym;
|
||||
b->blockinput = False;
|
||||
break;
|
||||
|
||||
case BT_StrValue: {
|
||||
// Very basic editor for string config values
|
||||
// b->values is a pointer to the editor buffer string here (char**)
|
||||
// Normally it's used to store the value names for BT_IntValue binds, though.
|
||||
// TODO: implement a cursor here (so we can use arrow keys for editing)
|
||||
|
||||
char c = (char)(uni & 0x7F);
|
||||
char *dest = *b->values;
|
||||
|
||||
if(sym == SDLK_RETURN) {
|
||||
if(strlen(dest))
|
||||
stralloc(&(tconfig.strval[b->configentry]), dest);
|
||||
else
|
||||
strncpy(dest, tconfig.strval[b->configentry], 128);
|
||||
b->blockinput = False;
|
||||
} else if(sym == SDLK_BACKSPACE) {
|
||||
if(strlen(dest))
|
||||
dest[strlen(dest)-1] = 0;
|
||||
} else if(uni && sym != SDLK_TAB && c != ':') { // we use ':' as a separator for replays (and might use it as such somewhere else), and I don't feel like escaping it.
|
||||
strncat(dest, &c, 128);
|
||||
dest[strlen(dest)-1] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: // should never get there anyway
|
||||
b->blockinput = False;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
b->blockinput = False;
|
||||
|
||||
} else if(event.type == SDL_QUIT) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
SDL_EnableUNICODE(False);
|
||||
}
|
||||
|
||||
static void options_key_action(MenuData *menu, int sym) {
|
||||
|
@ -649,7 +717,11 @@ static void options_key_action(MenuData *menu, int sym) {
|
|||
if(bind->enabled) switch(bind->type)
|
||||
{
|
||||
case BT_IntValue: case BT_Resolution: bind_setnext(bind); break;
|
||||
case BT_KeyBinding: bind->blockinput = True; break;
|
||||
case BT_KeyBinding: bind->blockinput = True; break;
|
||||
case BT_StrValue:
|
||||
bind->selected = strlen(tconfig.strval[bind->configentry]);
|
||||
bind->blockinput = True;
|
||||
break;
|
||||
} else menu->quit = 1;
|
||||
} else if(sym == tconfig.intval[KEY_LEFT] || sym == SDLK_LEFT) {
|
||||
menu->selected = menu->cursor;
|
||||
|
|
|
@ -23,6 +23,7 @@ typedef int (*BindingDependence)();
|
|||
typedef enum BindingType {
|
||||
BT_IntValue,
|
||||
BT_KeyBinding,
|
||||
BT_StrValue,
|
||||
BT_Resolution
|
||||
} BindingType;
|
||||
|
||||
|
|
|
@ -7,17 +7,19 @@
|
|||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <time.h>
|
||||
#include "global.h"
|
||||
#include "menu.h"
|
||||
#include "options.h"
|
||||
#include "mainmenu.h"
|
||||
#include "replayview.h"
|
||||
#include "paths/native.h"
|
||||
#include "plrmodes.h"
|
||||
|
||||
void backtomain(void*);
|
||||
|
||||
void start_replay(void *arg) {
|
||||
replay_load(&global.replay, (char*)arg);
|
||||
replay_copy(&global.replay, (Replay*)arg);
|
||||
StageInfo *s = stage_get(global.replay.stage);
|
||||
|
||||
if(!s) {
|
||||
|
@ -33,18 +35,73 @@ void start_replay(void *arg) {
|
|||
global.game_over = 0;
|
||||
}
|
||||
|
||||
int strendswith(char *s, char *e) {
|
||||
int ls = strlen(s);
|
||||
int le = strlen(e);
|
||||
static void replayview_freearg(void *a) {
|
||||
Replay *r = (Replay*)a;
|
||||
replay_destroy(r);
|
||||
free(r);
|
||||
}
|
||||
|
||||
static void replayview_drawitem(void *n, int item, int cnt) {
|
||||
MenuEntry *e = (MenuEntry*)n;
|
||||
Replay *rpy = (Replay*)e->arg;
|
||||
float sizes[] = {0.7, 1.5, 0.8, 0.9, 1.0};
|
||||
|
||||
if(le > ls)
|
||||
return False;
|
||||
//draw_text(AL_Left, 20 - e->drawdata, 20*i, "lol replay omg", _fonts.standard);
|
||||
|
||||
int i; for(i = ls - 1; i < le; ++i)
|
||||
if(s[i] != e[i])
|
||||
return False;
|
||||
|
||||
return True;
|
||||
int columns = 5, i, j;
|
||||
for(i = 0; i < columns; ++i) {
|
||||
char tmp[128];
|
||||
int csize = sizes[i] * (SCREEN_W - 210)/columns;
|
||||
int o = 0;
|
||||
|
||||
for(j = 0; j < i; ++j)
|
||||
o += sizes[j] * (SCREEN_W - 210)/columns;
|
||||
|
||||
Alignment a = AL_Center;
|
||||
|
||||
// hell yeah, another loop-switch sequence
|
||||
switch(i) {
|
||||
case 0:
|
||||
a = AL_Left;
|
||||
snprintf(tmp, 128, "Stage %i", rpy->stage);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
a = AL_Center;
|
||||
strncpy(tmp, rpy->playername, 128);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
plrmode_repr(tmp, 128, rpy->plr_char, rpy->plr_shot);
|
||||
tmp[0] = tmp[0] - 'a' + 'A';
|
||||
break;
|
||||
|
||||
case 3:
|
||||
snprintf(tmp, 128, difficulty_name(rpy->diff));
|
||||
break;
|
||||
|
||||
case 4:
|
||||
a = AL_Left;
|
||||
|
||||
time_t t = rpy->seed;
|
||||
struct tm* timeinfo = localtime(&t);
|
||||
strftime(tmp, 128, "%H:%M %m/%d/%y", timeinfo);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
switch(a) {
|
||||
case AL_Center: o += csize * 0.5 - stringwidth(tmp, _fonts.standard) * 0.5; break;
|
||||
case AL_Right: o += csize - stringwidth(tmp, _fonts.standard); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
draw_text(AL_Left, o + 10, 20*item, tmp, _fonts.standard);
|
||||
}
|
||||
}
|
||||
|
||||
int replayview_cmp(const void *a, const void *b) {
|
||||
return ((Replay*)(((MenuEntry*)b)->arg))->seed - ((Replay*)(((MenuEntry*)a)->arg))->seed;
|
||||
}
|
||||
|
||||
int fill_replayview_menu(MenuData *m) {
|
||||
|
@ -64,17 +121,25 @@ int fill_replayview_menu(MenuData *m) {
|
|||
if(!strendswith(e->d_name, ext))
|
||||
continue;
|
||||
|
||||
Replay *rpy = malloc(sizeof(Replay));
|
||||
replay_load(rpy, e->d_name);
|
||||
|
||||
/*
|
||||
int size = strlen(e->d_name) - strlen(ext) + 1;
|
||||
char *s = (char*)malloc(size);
|
||||
strncpy(s, e->d_name, size);
|
||||
s[size-1] = 0;
|
||||
*/
|
||||
|
||||
add_menu_entry(m, s, start_replay, s);
|
||||
m->entries[m->ecount-1].freearg = True;
|
||||
add_menu_entry(m, " ", start_replay, rpy);
|
||||
m->entries[m->ecount-1].freearg = replayview_freearg;
|
||||
m->entries[m->ecount-1].draw = replayview_drawitem;
|
||||
++rpys;
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
qsort(m->entries, m->ecount, sizeof(MenuEntry), replayview_cmp);
|
||||
return rpys;
|
||||
}
|
||||
|
||||
|
@ -93,6 +158,8 @@ void create_replayview_menu(MenuData *m) {
|
|||
add_menu_separator(m);
|
||||
add_menu_entry(m, "Back", backtomain, m);
|
||||
}
|
||||
|
||||
printf("create_replayview_menu()\n");
|
||||
}
|
||||
|
||||
void draw_stage_menu(MenuData *m);
|
||||
|
|
|
@ -18,7 +18,8 @@ void save_rpy(void *a) {
|
|||
time_t rawtime;
|
||||
struct tm * timeinfo;
|
||||
|
||||
time(&rawtime);
|
||||
// time when the game was *initiated*
|
||||
rawtime = (time_t)rpy->seed;
|
||||
timeinfo = localtime(&rawtime);
|
||||
strftime(strtime, 128, "%Y%m%d_%H-%M-%S_%Z", timeinfo);
|
||||
|
||||
|
|
|
@ -35,10 +35,7 @@ void create_stage_menu(MenuData *m) {
|
|||
|
||||
void draw_stage_menu(MenuData *m) {
|
||||
draw_options_menu_bg(m);
|
||||
|
||||
int w, h;
|
||||
TTF_SizeText(_fonts.mainmenu, m->title, &w, &h);
|
||||
draw_text(AL_Right, (w + 10) * (1-m->fade), 30, m->title, _fonts.mainmenu);
|
||||
draw_text(AL_Right, (stringwidth(m->title, _fonts.mainmenu) + 10) * (1-m->fade), 30, m->title, _fonts.mainmenu);
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(100, 100 + min(0, SCREEN_H * 0.7 - 100 - m->drawdata[2]), 0);
|
||||
|
@ -64,7 +61,9 @@ void draw_stage_menu(MenuData *m) {
|
|||
else
|
||||
glColor4f(1, 1, 1, 0.7);
|
||||
|
||||
if(e->name)
|
||||
if(e->draw)
|
||||
e->draw(e, i, m->ecount);
|
||||
else if(e->name)
|
||||
draw_text(AL_Left, 20 - e->drawdata, 20*i, e->name, _fonts.standard);
|
||||
}
|
||||
|
||||
|
|
26
src/replay.c
26
src/replay.c
|
@ -41,6 +41,8 @@ void replay_init(Replay *rpy, StageInfo *stage, int seed, Player *plr) {
|
|||
void replay_destroy(Replay *rpy) {
|
||||
if(rpy->events)
|
||||
free(rpy->events);
|
||||
if(rpy->playername)
|
||||
free(rpy->playername);
|
||||
memset(rpy, 0, sizeof(Replay));
|
||||
printf("Replay destroyed.\n");
|
||||
}
|
||||
|
@ -95,7 +97,7 @@ int replay_write(Replay *rpy, FILE *file) {
|
|||
|
||||
// header
|
||||
replay_write_int(file, REPLAY_MAGICNUMBER);
|
||||
replay_write_string(file, "Taisei replay file");
|
||||
replay_write_string(file, tconfig.strval[PLAYERNAME]);
|
||||
replay_write_string(file, "This file is not for your eyes, move on");
|
||||
replay_write_int(file, 1);
|
||||
|
||||
|
@ -163,6 +165,7 @@ int replay_read(Replay *rpy, FILE *file) {
|
|||
int readstate = RPY_H_MAGIC;
|
||||
int bufidx = 0, eidx = 0;
|
||||
char buf[REPLAY_READ_MAXSTRLEN], c;
|
||||
memset(rpy, 0, sizeof(Replay));
|
||||
|
||||
while((c = fgetc(file)) != EOF) {
|
||||
if(c == ':') {
|
||||
|
@ -181,7 +184,8 @@ int replay_read(Replay *rpy, FILE *file) {
|
|||
}
|
||||
|
||||
case RPY_H_META1:
|
||||
printf("replay_read(): %s\n", buf);
|
||||
stralloc(&rpy->playername, buf);
|
||||
printf("replay_read(): replay META1 is: %s\n", buf);
|
||||
break;
|
||||
|
||||
case RPY_H_META2: case RPY_H_REPLAYCOUNT: // skip
|
||||
|
@ -231,14 +235,17 @@ int replay_read(Replay *rpy, FILE *file) {
|
|||
#undef FLOATOF
|
||||
#undef INTOF
|
||||
|
||||
char* replay_getpath(char *name) {
|
||||
char* replay_getpath(char *name, int ext) {
|
||||
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);
|
||||
if(ext)
|
||||
sprintf(p, "%s/%s.%s", get_replays_path(), name, REPLAY_EXTENSION);
|
||||
else
|
||||
sprintf(p, "%s/%s", get_replays_path(), name);
|
||||
return p;
|
||||
}
|
||||
|
||||
int replay_save(Replay *rpy, char *name) {
|
||||
char *p = replay_getpath(name);
|
||||
char *p = replay_getpath(name, !strendswith(name, REPLAY_EXTENSION));
|
||||
printf("replay_save(): saving %s\n", p);
|
||||
|
||||
FILE *fp = fopen(p, "w");
|
||||
|
@ -256,7 +263,7 @@ int replay_save(Replay *rpy, char *name) {
|
|||
}
|
||||
|
||||
int replay_load(Replay *rpy, char *name) {
|
||||
char *p = replay_getpath(name);
|
||||
char *p = replay_getpath(name, !strendswith(name, REPLAY_EXTENSION));
|
||||
printf("replay_load(): loading %s\n", p);
|
||||
|
||||
FILE *fp = fopen(p, "r");
|
||||
|
@ -271,3 +278,10 @@ int replay_load(Replay *rpy, char *name) {
|
|||
fclose(fp);
|
||||
return result;
|
||||
}
|
||||
|
||||
void replay_copy(Replay *dst, Replay *src) {
|
||||
memcpy(dst, src, sizeof(Replay));
|
||||
dst->capacity = dst->ecount;
|
||||
dst->events = (ReplayEvent*)malloc(sizeof(ReplayEvent) * dst->capacity);
|
||||
memcpy(dst->events, src->events, dst->capacity * sizeof(ReplayEvent));
|
||||
}
|
||||
|
|
|
@ -19,9 +19,12 @@ typedef struct ReplayEvent {
|
|||
} ReplayEvent;
|
||||
|
||||
typedef struct Replay {
|
||||
// metadata
|
||||
char *playername;
|
||||
|
||||
// initial game settings
|
||||
int stage;
|
||||
int seed;
|
||||
int seed; // this also happens to be the game initiation time - and we use this property, don't break it please
|
||||
int diff;
|
||||
int points;
|
||||
|
||||
|
@ -33,6 +36,7 @@ typedef struct Replay {
|
|||
int plr_lifes;
|
||||
int plr_bombs;
|
||||
|
||||
// events
|
||||
ReplayEvent *events;
|
||||
int ecount;
|
||||
|
||||
|
@ -54,9 +58,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
|
||||
char* replay_getpath(char *name, int ext); // must be freed
|
||||
int replay_save(Replay *rpy, char *name);
|
||||
int replay_load(Replay *rpy, char *name);
|
||||
void replay_copy(Replay *dst, Replay *src);
|
||||
|
||||
#define REPLAY_ALLOC_INITIAL 100
|
||||
#define REPLAY_ALLOC_ADDITIONAL 100
|
||||
|
|
|
@ -76,3 +76,15 @@ void draw_text(Alignment align, float x, float y, const char *text, TTF_Font *fo
|
|||
free(buf);
|
||||
}
|
||||
|
||||
int stringwidth(char *s, TTF_Font *font) {
|
||||
int w;
|
||||
TTF_SizeText(font, s, &w, NULL);
|
||||
return w;
|
||||
}
|
||||
|
||||
int charwidth(char c, TTF_Font *font) {
|
||||
char s[2];
|
||||
s[0] = c;
|
||||
s[1] = 0;
|
||||
return stringwidth(s, font);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@ typedef enum {
|
|||
Texture *load_text(const char *text, TTF_Font *font);
|
||||
void draw_text(Alignment align, float x, float y, const char *text, TTF_Font *font);
|
||||
void init_fonts();
|
||||
int stringwidth(char *s, TTF_Font *font);
|
||||
int charwidth(char c, TTF_Font *font);
|
||||
|
||||
struct Fonts {
|
||||
TTF_Font *standard;
|
||||
|
@ -29,4 +31,4 @@ struct Fonts {
|
|||
|
||||
extern struct Fonts _fonts;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue