Index: config.doc ================================================================== --- config.doc +++ config.doc @@ -65,10 +65,15 @@ .progress If positive, how many steps between dots in the progress report for the auto testing most. If negative, number of milliseconds to sleep before each level is executed. +.saveSolutions + If true, then solutions are saved if you solve a level in less moves + than the currently recorded solution (or if no solution is already + recorded). This has no effect in read-only mode. + .screenFlags SDL flags: d = double buffer, f = full screen, h = use hardware surface, n = no window frame, p = hardware palette, r = allow the window to be resized, y = asynchronous blit, z = no parachute. Some flags might not work if the window manager does not support them. @@ -84,10 +89,17 @@ .showInventory True means to show the inventory in the margin by default; false means to show the move list in the margin by default. Either way, it is possible to change the display at run time. +.solutionComment + If defined, record the specified text as the solution comment, whenever + a solution is recorded. + +.solutionTimestamp + If true, record a timestamp with the solution. + .sqlCoveringIndexScan Boolean controlling if SQLite will use covering index scans. .sqlExtensions Names of SQLite extensions with spaces in between. Index: game.c ================================================================== --- game.c +++ game.c @@ -9,10 +9,11 @@ #include "SDL.h" #include #include #include +#include #include "sqlite3.h" #include "smallxrm.h" #include "heromesh.h" #include "quarks.h" #include "cursorshapes.h" @@ -25,16 +26,24 @@ static volatile Uint8 timerflag; static int exam_scroll; static Uint8*inputs; static int inputs_size,inputs_count; static Uint8 side_mode=255; +static Uint8 should_record_solution; static void setup_game(void) { const char*v; optionquery[1]=Q_showInventory; v=xrm_get_resource(resourcedb,optionquery,optionquery,2)?:""; side_mode=boolxrm(v,1); + if(main_options['r']) { + should_record_solution=0; + } else { + optionquery[1]=Q_saveSolutions; + v=xrm_get_resource(resourcedb,optionquery,optionquery,2)?:""; + should_record_solution=boolxrm(v,0); + } solution_replay=0; } static void redraw_game(void) { char buf[32]; @@ -787,10 +796,54 @@ } replay_list[replay_pos++]=k; if(replay_pos>replay_count) replay_count=replay_pos; } } + +static void record_solution(void) { + const char*v; + const char*com; + Uint8*data; + Uint8*p; + long sz; + if(solution_replay) return; + if(data=read_lump(FIL_SOLUTION,level_id,&sz)) { + if(sz<3 || (data[0]|(data[1]<<8))!=level_version || (data[2]&~3)) goto dontkeep; + sz-=3; + if(data[2]&1) sz-=strnlen(data+3,sz); + if(data[2]&2) sz-=8; + if(sz<=0 || sz>replay_pos) goto dontkeep; + free(data); + return; + dontkeep: + free(data); + } + optionquery[1]=Q_solutionComment; + com=xrm_get_resource(resourcedb,optionquery,optionquery,2); + if(com && !*com) com=0; + optionquery[1]=Q_solutionTimestamp; + v=xrm_get_resource(resourcedb,optionquery,optionquery,2)?:""; + data=malloc(sz=replay_pos+(boolxrm(v,0)?8:0)+(com?strlen(com)+1:0)+3); + if(!data) fatal("Allocation failed\n"); + data[0]=level_version&255; + data[1]=level_version>>8; + data[2]=(boolxrm(v,0)?2:0)|(com?1:0); + p=data+3; + if(com) { + strcpy(p,com); + p+=strlen(com)+1; + } + if(data[2]&2) { + time_t t=time(0); + p[0]=t>>000; p[1]=t>>010; p[2]=t>>020; p[3]=t>>030; + p[4]=t>>040; p[5]=t>>050; p[6]=t>>060; p[7]=t>>070; + p+=8; + } + memcpy(p,replay_list,replay_pos); + write_lump(FIL_SOLUTION,level_id,sz,data); + free(data); +} void run_game(void) { int i; SDL_Event ev; set_caption(); @@ -845,10 +898,11 @@ replay: if(inputs_count) { for(i=0;i