Index: function.c ================================================================== --- function.c +++ function.c @@ -239,10 +239,14 @@ } static void fn_modstate(sqlite3_context*cxt,int argc,sqlite3_value**argv) { sqlite3_result_int(cxt,SDL_GetModState()); } + +static void fn_movenumber(sqlite3_context*cxt,int argc,sqlite3_value**argv) { + sqlite3_result_int(cxt,replay_pos); +} static void fn_mvalue(sqlite3_context*cxt,int argc,sqlite3_value**argv) { int a; if(sqlite3_value_type(*argv)==SQLITE_NULL) return; a=sqlite3_value_int(*argv)&0xFFFF; @@ -935,10 +939,11 @@ sqlite3_create_function(userdb,"LEVEL_CACHEID",0,SQLITE_UTF8|SQLITE_DETERMINISTIC,ptr0,fn_cacheid,0,0); sqlite3_create_function(userdb,"LEVEL_ID",0,SQLITE_UTF8,&level_id,fn_level,0,0); sqlite3_create_function(userdb,"LEVEL_TITLE",0,SQLITE_UTF8,0,fn_level_title,0,0); sqlite3_create_function(userdb,"LOAD_LEVEL",1,SQLITE_UTF8,0,fn_load_level,0,0); sqlite3_create_function(userdb,"MODSTATE",0,SQLITE_UTF8,0,fn_modstate,0,0); + sqlite3_create_function(userdb,"MOVENUMBER",0,SQLITE_UTF8,0,fn_movenumber,0,0); sqlite3_create_function(userdb,"MVALUE",1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_mvalue,0,0); sqlite3_create_function(userdb,"NVALUE",1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_zero_extend,0,0); sqlite3_create_function(userdb,"OVALUE",1,SQLITE_UTF8,0,fn_ovalue,0,0); sqlite3_create_function(userdb,"PFHEIGHT",0,SQLITE_UTF8,&pfheight,fn_pfsize,0,0); sqlite3_create_function(userdb,"PFWIDTH",0,SQLITE_UTF8,&pfwidth,fn_pfsize,0,0); Index: game.c ================================================================== --- game.c +++ game.c @@ -16,10 +16,13 @@ #include "heromesh.h" #include "quarks.h" #include "cursorshapes.h" #include "names.h" +Uint8*replay_list; +Uint16 replay_size,replay_count,replay_pos,replay_mark; + static volatile Uint8 timerflag; static int exam_scroll; static Uint8*inputs; static int inputs_size,inputs_count; @@ -139,13 +142,12 @@ SDL_Flip(screen); } static void begin_level(int id) { const char*t; - free(inputs); - inputs=0; - inputs_size=inputs_count=0; + inputs_count=0; + replay_pos=0; t=load_level(id)?:init_level(); if(t) { gameover=-1; screen_message(t); } else { @@ -394,11 +396,10 @@ if(n==VOIDLINK) return; while(n!=VOIDLINK && objects[n]->up!=VOIDLINK) n=objects[n]->up; if(!classes[objects[n]->class]->gamehelp) return; s=sqlite3_mprintf("\x0C\x0E%s:%d\\ %s\x0B\x0F%s",classes[objects[n]->class]->name,objects[n]->image,classes[objects[n]->class]->name,classes[objects[n]->class]->gamehelp); if(!s) fatal("Allocation failed\n"); - modal_draw_popup(s); sqlite3_free(s); } static int game_command(int prev,int cmd,int number,int argc,sqlite3_stmt*args,void*aux) { @@ -408,10 +409,33 @@ inputs=realloc(inputs,inputs_size+=32); if(!inputs) fatal("Allocation failed\n"); } inputs[inputs_count++]=number; return 0; + case '+ ': // Replay + if(number>replay_count-replay_pos) number=replay_count-replay_pos; + if(inputs_count+number>=inputs_size) { + inputs=realloc(inputs,inputs_size+=number+1); + if(!inputs) fatal("Allocation failed\n"); + } + memcpy(inputs+inputs_count,replay_list+replay_pos,number); + inputs_count+=number; + return 0; + case '- ': // Rewind + number=replay_pos-number; + if(number<0) number=0; + //fallthru + case '= ': // Restart + begin_level(level_id); + if(!number) return 1; + if(number>replay_count) number=replay_count; + if(number>=inputs_size) { + inputs=realloc(inputs,inputs_size=number+1); + if(!inputs) fatal("Allocation failed\n"); + } + memcpy(inputs,replay_list,inputs_count=number); + return 1; case '^E': // Edit return -2; case '^Q': // Quit return -1; case '^T': // Show title @@ -459,16 +483,24 @@ return n; } static inline void input_move(Uint8 k) { const char*t=execute_turn(k); + if(replay_pos==65534 && !gameover) t="Too many moves played"; if(t) { screen_message(t); gameover=-1; return; } - //TODO: Record this move, if applicable + if(!key_ignored) { + if(replay_pos>=replay_size) { + replay_list=realloc(replay_list,replay_size+=0x200); + if(!replay_list) fatal("Allocation failed\n"); + } + replay_list[replay_pos++]=k; + if(replay_pos>replay_count) replay_count=replay_pos; + } } void run_game(void) { int i; SDL_Event ev; Index: heromesh.h ================================================================== --- heromesh.h +++ heromesh.h @@ -249,13 +249,16 @@ const char*execute_turn(int key); const char*init_level(void); // == game == +extern Uint8*replay_list; +extern Uint16 replay_size,replay_count,replay_pos,replay_mark; + void run_game(void); void locate_me(int x,int y); // == edit == void run_editor(void); void write_empty_level_set(FILE*);