41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
// 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;
free(replay_list);
replay_list=0;
replay_size=0;
replay_count=0;
FILE*o=open_memstream((char**)&replay_list,&replay_size);
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");
return replay_count;
}
|
>
>
|
|
|
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
// 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.
// Does not write a null terminator.
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;
FILE*o;
free(replay_list);
replay_list=0;
replay_size=0;
replay_count=0;
o=open_memstream((char**)&replay_list,&replay_size);
if(!o) fatal("Allocation failed\n");
while(replay_count<0xFFFE && (v=decode_move(fp))) {
fwrite(&v,1,sizeof(MoveItem),o);
replay_count++;
}
fclose(o);
if(replay_count && !replay_list) fatal("Allocation failed\n");
return replay_count;
}
|
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
|
SDL_LockSurface(screen);
draw_text(0,40,buf,0xF0,0xF1);
SDL_UnlockSurface(screen);
SDL_Flip(screen);
}
static void save_replay(void) {
long sz=replay_size;
if(solution_replay || !replay_list) return;
if(sz<replay_count+6) {
replay_list=realloc(replay_list,sz=replay_count+6);
if(!replay_list) fatal("Allocation failed\n");
replay_size=sz;
}
if(gameover==1) solved=1;
sz=replay_count+6;
replay_list[sz-6]=replay_mark>>8;
replay_list[sz-5]=replay_mark;
replay_list[sz-4]=(level_version+solved-1)>>8;
replay_list[sz-3]=level_version+solved-1;
replay_list[sz-2]=replay_count>>8;
replay_list[sz-1]=replay_count;
write_userstate(FIL_LEVEL,level_id,sz,replay_list);
}
static void load_replay(void) {
long sz;
int i;
free(replay_list);
if(solution_replay) {
replay_list=read_lump(FIL_SOLUTION,level_id,&sz);
// Solution format: version (16-bits), flag (8-bits), user name (null-terminated), timestamp (64-bits), move list
if(sz>3) {
i=replay_list[0]|(replay_list[1]<<8);
if(i!=level_version) goto notfound;
i=3;
if(replay_list[2]&1) {
while(i<sz && replay_list[i]) i++;
i++;
}
if(replay_list[2]&2) i+=8;
if(i>=sz || sz-i>0xFFFF) goto notfound;
replay_size=sz;
memmove(replay_list,replay_list+i,replay_count=sz-i);
replay_mark=0;
} else {
goto notfound;
}
} else {
replay_list=read_userstate(FIL_LEVEL,level_id,&sz);
if(sz>=2) {
replay_size=sz;
replay_count=(replay_list[sz-2]<<8)|replay_list[sz-1];
if(sz-replay_count>=4) replay_mark=(replay_list[replay_count]<<8)|replay_list[replay_count+1]; else replay_mark=0;
if(sz-replay_count>=6) {
i=(replay_list[replay_count+2]<<8)|replay_list[replay_count+3];
if(i==level_version) solved=1;
}
} else {
notfound:
replay_count=replay_mark=replay_size=0;
free(replay_list);
replay_list=0;
}
}
}
static void begin_level(int id) {
const char*t;
replay_time=0;
if(replay_count) save_replay();
inputs_count=0;
|
>
|
>
|
|
<
>
|
>
>
>
>
>
>
|
>
<
|
>
|
|
<
<
<
<
>
>
>
|
>
>
>
|
>
>
>
|
>
>
|
|
<
>
|
|
|
>
>
>
>
>
|
|
>
|
<
<
<
<
<
<
<
|
<
>
|
>
>
|
<
>
|
|
|
>
>
>
|
>
>
|
|
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
|
|
>
>
>
>
|
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
|
SDL_LockSurface(screen);
draw_text(0,40,buf,0xF0,0xF1);
SDL_UnlockSurface(screen);
SDL_Flip(screen);
}
static void save_replay(void) {
unsigned char*buf=0;
size_t sz=0;
FILE*fp;
if(solution_replay || !replay_list || !replay_count) return;
if(gameover==1) solved=1;
fp=open_memstream((char**)&buf,&sz);
if(!fp) fatal("Allocation failed\n");
fputc(0x00,fp);
fputc(0x01,fp);
encode_move_list(fp);
fputc(0x00,fp);
if(solved) {
fputc(0x41,fp);
fputc(level_version,fp);
fputc(level_version>>8,fp);
}
if(replay_mark) {
fputc(0x42,fp);
fputc(replay_mark,fp);
fputc(replay_mark>>8,fp);
}
fclose(fp);
if(!buf) fatal("Allocation failed\n");
write_userstate(FIL_LEVEL,level_id,sz,buf);
free(buf);
}
static void load_replay(void) {
FILE*fp=0;
unsigned char*buf=0;
long sz;
int i,j;
free(replay_list);
replay_list=0;
replay_count=replay_mark=replay_size=0;
if(solution_replay) {
gameover_score=NO_SCORE;
if(buf=read_lump(FIL_SOLUTION,level_id,&sz)) {
fp=fmemopen(buf,sz,"r");
if(!fp) fatal("Allocation failed\n");
// Solution format: version (16-bits), flag (8-bits), score (32-bits), user name (null-terminated), timestamp (64-bits), move list
if(sz>3) {
i=fgetc(fp); i|=fgetc(fp)<<8;
if(i==level_version) {
j=fgetc(fp);
if(j&128) {
gameover_score=fgetc(fp);
gameover_score|=fgetc(fp)<<8;
gameover_score|=fgetc(fp)<<16;
gameover_score|=fgetc(fp)<<24;
}
if(j&1) while(fgetc(fp)>0);
if(j&2) for(i=0;i<8;i++) fgetc(fp);
decode_move_list(fp);
}
}
}
} else if(buf=read_userstate(FIL_LEVEL,level_id,&sz)) {
fp=fmemopen(buf,sz,"r");
if(!fp) fatal("Allocation failed\n");
if(sz>2 && *buf) {
// Old format
replay_count=(buf[sz-2]<<8)|buf[sz-1];
if(sz-replay_count>=4) replay_mark=(buf[replay_count]<<8)|buf[replay_count+1]; else replay_mark=0;
if(sz-replay_count>=6) {
i=(buf[replay_count+2]<<8)|buf[replay_count+3];
if(i==level_version) solved=1;
}
replay_list=malloc(replay_size=sizeof(MoveItem)*replay_count+1);
if(!replay_list) fatal("Allocation failed\n");
for(i=0;i<replay_size;i++) replay_list[i]=buf[i];
} else {
// New format
fgetc(fp); // skip first null byte
while((i=fgetc(fp))!=EOF) switch(i) {
case 0x01: // Replay list
if(replay_list) goto skip;
decode_move_list(fp);
break;
case 0x41: // Solved version
i=fgetc(fp); i|=fgetc(fp)<<8;
if(i==level_version) solved=1;
break;
case 0x42: // Mark
replay_mark=fgetc(fp);
replay_mark|=fgetc(fp)<<8;
break;
default: skip:
if(i<0x40) {
while(fgetc(fp)>0);
} else if(i<0x80) {
fgetc(fp); fgetc(fp);
} else if(i<0xC0) {
for(i=0;i<4;i++) fgetc(fp);
} else {
for(i=0;i<8;i++) fgetc(fp);
}
}
}
}
if(fp) fclose(fp);
free(buf);
}
static void begin_level(int id) {
const char*t;
replay_time=0;
if(replay_count) save_replay();
inputs_count=0;
|
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
|
}
timerflag=1;
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;
}
if(!key_ignored) {
if(inserting) {
if(replay_pos>=0xFFFE || replay_pos==replay_count) {
inserting=0;
} else {
if(replay_count>=0xFFFE) replay_count=0xFFFD;
if(replay_size<0xFFFF) {
replay_list=realloc(replay_list,replay_size=0xFFFF);
if(!replay_list) fatal("Allocation failed\n");
}
memmove(replay_list+replay_pos+1,replay_list+replay_pos,replay_count-replay_pos);
replay_count++;
}
}
if(replay_pos>=replay_size) {
if(replay_size>0xFDFF) replay_size=0xFDFF;
if(replay_size+0x200<=replay_pos) fatal("Confusion in input_move function\n");
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;
}
}
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);
sqlite3_exec(userdb,"UPDATE `LEVELS` SET `SOLVABLE` = 1 WHERE `ID` = LEVEL_ID();",0,0,0);
}
void run_game(void) {
int i;
SDL_Event ev;
set_caption();
|
|
|
|
<
|
|
|
>
>
|
|
|
>
>
>
>
|
|
|
>
|
|
>
>
>
|
>
>
|
|
|
<
<
>
|
|
<
>
>
>
|
<
<
<
|
<
|
>
>
>
>
|
|
|
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
|
}
timerflag=1;
return n;
}
static inline void input_move(Uint8 k) {
const char*t=execute_turn(k);
if(replay_pos>0xFFFE && !gameover) t="Too many moves played";
if(t) {
screen_message(t);
gameover=-1;
return;
}
if(!key_ignored) {
if(inserting) {
if(replay_pos>=0xFFFE || replay_pos==replay_count) {
inserting=0;
} else {
if(replay_count>0xFFFE) replay_count=0xFFFE;
if(replay_size<0xFFFF) {
replay_list=realloc(replay_list,replay_size=0xFFFF);
if(!replay_list) fatal("Allocation failed\n");
}
memmove(replay_list+replay_pos+1,replay_list+replay_pos,replay_count-replay_pos);
replay_count++;
}
}
if(replay_pos>=replay_size) {
if(replay_size>0xFFFF) replay_size=0xFFFF;
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;
}
}
static void record_solution(void) {
const char*v;
const char*com;
FILE*fp;
Uint8 flag;
long n;
unsigned char*buf=0;
size_t sz=0;
if(solution_replay) return;
if(buf=read_lump(FIL_SOLUTION,level_id,&n)) {
if(n<3 || (buf[0]|(buf[1]<<8))!=level_version || (buf[2]&~0x83)) goto dontkeep;
n-=3;
if((buf[2]&128) && n>4) {
Sint32 sco=buf[3]|(buf[4]<<8)|(buf[5]<<16)|(buf[6]<<24);
if(gameover_score!=NO_SCORE && sco<=gameover_score) goto dontkeep;
} else {
if(buf[2]&1) n-=strnlen(buf+3,n);
if(buf[2]&2) n-=8;
if(n<=0 || n>replay_pos) goto dontkeep;
}
free(buf);
return;
dontkeep:
free(buf);
buf=0;
}
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)?:"";
flag=0;
if(com) flag|=1;
if(boolxrm(v,0)) flag|=2;
if(gameover_score!=NO_SCORE) flag|=128;
fp=open_memstream((char**)&buf,&sz);
if(!fp) fatal("Allocation failed\n");
fputc(level_version,fp);
fputc(level_version>>8,fp);
fputc(flag,fp);
if(flag&128) {
fputc(gameover_score,fp);
fputc(gameover_score>>8,fp);
fputc(gameover_score>>16,fp);
fputc(gameover_score>>24,fp);
}
if(flag&1) fwrite(com,1,strlen(com+1),fp);
n=replay_count;
replay_count=replay_pos;
encode_move_list(fp);
replay_count=n;
fclose(fp);
if(!buf) fatal("Allocation failed\n");
write_lump(FIL_SOLUTION,level_id,sz,buf);
free(buf);
sqlite3_exec(userdb,"UPDATE `LEVELS` SET `SOLVABLE` = 1 WHERE `ID` = LEVEL_ID();",0,0,0);
}
void run_game(void) {
int i;
SDL_Event ev;
set_caption();
|