Index: exec.c ================================================================== --- exec.c +++ exec.c @@ -3249,11 +3249,11 @@ case OP_WEIGHT_C: StackReq(1,1); Push(GetVariableOrAttributeOf(weight,NVALUE)); break; case OP_WEIGHT_E: NoIgnore(); StackReq(1,0); t1=Pop(); Numeric(t1); o->weight=t1.u; break; case OP_WEIGHT_E16: NoIgnore(); StackReq(1,0); t1=Pop(); Numeric(t1); o->weight=t1.u&0xFFFF; break; case OP_WEIGHT_EC: NoIgnore(); StackReq(2,0); t1=Pop(); Numeric(t1); i=v_object(Pop()); if(i!=VOIDLINK) objects[i]->weight=t1.u; break; case OP_WEIGHT_EC16: NoIgnore(); StackReq(2,0); t1=Pop(); Numeric(t1); i=v_object(Pop()); if(i!=VOIDLINK) objects[i]->weight=t1.u&0xFFFF; break; - case OP_WINLEVEL: key_ignored=0; gameover=1; gameover_score=move_number+1; Throw(0); break; + case OP_WINLEVEL: key_ignored=0; gameover=1; gameover_score=NO_SCORE; Throw(0); break; case OP_WINLEVEL_C: StackReq(1,0); t1=Pop(); Numeric(t1); key_ignored=0; gameover=1; gameover_score=t1.s; Throw(0); break; case OP_XDIR: StackReq(1,1); t1=Pop(); Numeric(t1); Push(NVALUE(o->x+x_delta[resolve_dir(obj,t1.u)])); break; case OP_XDIR_C: StackReq(2,1); t1=Pop(); Numeric(t1); i=v_object(Pop()); if(i==VOIDLINK) Push(NVALUE(0)); else Push(NVALUE(objects[i]->x+x_delta[resolve_dir(i,t1.u)])); break; case OP_XLOC: StackReq(0,1); Push(NVALUE(o->x)); break; case OP_XLOC_C: StackReq(1,1); Push(GetVariableOf(x,NVALUE)); break; Index: function.c ================================================================== --- function.c +++ function.c @@ -327,11 +327,25 @@ static void fn_modstate(sqlite3_context*cxt,int argc,sqlite3_value**argv) { sqlite3_result_int(cxt,SDL_GetModState()); } static void fn_move_list(sqlite3_context*cxt,int argc,sqlite3_value**argv) { - if(replay_count) sqlite3_result_blob(cxt,replay_list,replay_count,SQLITE_TRANSIENT); + char*p=0; + size_t s=0; + FILE*f=open_memstream(&p,&s); + if(!f) { + sqlite3_result_error_nomem(cxt); + return; + } + encode_move_list(f); + fclose(f); + if(s) { + sqlite3_result_blob(cxt,p,s,free); + } else { + sqlite3_result_zeroblob(cxt,0); + free(p); + } } static void fn_movenumber(sqlite3_context*cxt,int argc,sqlite3_value**argv) { sqlite3_result_int(cxt,replay_pos); } Index: game.c ================================================================== --- game.c +++ game.c @@ -17,25 +17,66 @@ #include "heromesh.h" #include "quarks.h" #include "cursorshapes.h" #include "names.h" -Uint8*replay_list; +MoveItem*replay_list; Uint16 replay_size,replay_count,replay_pos,replay_mark; Uint8 solution_replay=255; static volatile Uint8 timerflag; static int exam_scroll; -static Uint8*inputs; +static MoveItem*inputs; static int inputs_size,inputs_count; static Uint8 side_mode=255; static Uint8 should_record_solution; static Uint8 replay_speed; static Uint8 replay_time; static Uint8 solved; static Uint8 inserting,saved_inserting; static sqlite3_stmt*autowin; + +int encode_move(FILE*fp,MoveItem v) { + // Encodes a single move and writes the encoded move to the file. + // Returns the number of bytes of the encoded move. + fputc(v,fp); + return 1; +} + +int encode_move_list(FILE*fp) { + // Encodes the current replay list into the file; returns the number of bytes. + fwrite(replay_list,1,replay_count,fp); + return replay_count; +} + +MoveItem decode_move(FILE*fp) { + // Decodes a single move from the file, and returns the move. + // Returns zero if there is no more moves. + int v=fgetc(fp); + return (v==EOF?0:v); +} + +int decode_move_list(FILE*fp) { + // Decodes a move list from the file, and stores it in replay_list and replay_count. + // Returns the number of moves (replay_count). + MoveItem v; + size_t s=0; + free(replay_list); + replay_list=0; + replay_count=0; + FILE*o=open_memstream((char**)&replay_list,&s); + if(!o) fatal("Allocation failed\n"); + while(replay_count<0xFFFD && (v=decode_move(fp))) { + fwrite(&v,1,sizeof(MoveItem),o); + replay_count++; + } + fclose(o); + if(replay_count && !replay_list) fatal("Allocation failed\n"); + s/=sizeof(MoveItem); + replay_size=(s>0xFFFF?0xFFFF:s); + return replay_count; +} static void record_solution(void); static void setup_game(void) { const char*v; Index: heromesh.h ================================================================== --- heromesh.h +++ heromesh.h @@ -232,10 +232,11 @@ void init_sql_functions(sqlite3_int64*ptr0,sqlite3_int64*ptr1); // == exec == #define VOIDLINK ((Uint32)(-1)) +#define NO_SCORE ((Sint32)(0x80000000)) #define ANI_STOP 0x00 #define ANI_ONCE 0x01 #define ANI_LOOP 0x02 #define ANI_OSC 0x08 @@ -317,13 +318,20 @@ const char*init_level(void); void swap_world(void); // == game == -extern Uint8*replay_list; +typedef Uint8 MoveItem; + +extern MoveItem*replay_list; extern Uint16 replay_size,replay_count,replay_pos,replay_mark; extern Uint8 solution_replay; + +int encode_move(FILE*fp,MoveItem v); +int encode_move_list(FILE*fp); +MoveItem decode_move(FILE*fp); +int decode_move_list(FILE*fp); void run_game(void); void run_auto_test(void); void locate_me(int x,int y);