Free Hero Mesh

Check-in [52e4d33fdc]
Login
This is a mirror of the main repository for Free Hero Mesh. New tickets and changes will not be accepted at this mirror.
Overview
Comment:Implement PICEDIT.CFG lump
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 52e4d33fdc3c42c99b40bce146f554cdbac6b75c
User & Date: user on 2021-04-30 03:22:46
Other Links: manifest | tags
Context
2021-04-30
03:25
Explain what a Hamster archive is in the documentation. check-in: be6023c165 user: user tags: trunk
03:22
Implement PICEDIT.CFG lump check-in: 52e4d33fdc user: user tags: trunk
2021-04-29
21:49
Add internals.doc to document some of the internals of Free Hero Mesh. check-in: 865ced7aa0 user: user tags: trunk
Changes

Modified TODO from [513c4e1c2f] to [88ed99e2b7].

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  * Edit attributes of existing objects
* Table of contents for levels
  * Can define your own columns
  * User can write SQL queries on them
* Deal better with allowing to skip past corrupted levels
* Picture editor/loading
  * Allowing more altimages
  * Configuration lump for default picture sizes for new pictures
* Puzzle set catalog format (using with internet; a separate program)
* Inventory/replay hybrid view
* Bookmarks
* Message trace menu to enable/disable
* Bugs
  * Figure out why the $SeekerCloser class doesn't seem to work properly
  * Level 232 of SUPERHRO puzzle set (the Lava shouldn't expand? why?)







<







19
20
21
22
23
24
25

26
27
28
29
30
31
32
  * Edit attributes of existing objects
* Table of contents for levels
  * Can define your own columns
  * User can write SQL queries on them
* Deal better with allowing to skip past corrupted levels
* Picture editor/loading
  * Allowing more altimages

* Puzzle set catalog format (using with internet; a separate program)
* Inventory/replay hybrid view
* Bookmarks
* Message trace menu to enable/disable
* Bugs
  * Figure out why the $SeekerCloser class doesn't seem to work properly
  * Level 232 of SUPERHRO puzzle set (the Lava shouldn't expand? why?)

Modified picedit.c from [9a5c536613] to [1befa9e779].

54
55
56
57
58
59
60

61
62
63
64
65
66
67
typedef struct {
  char basename[64];
  Filter filters[64];
  Uint8 nfilters;
} DependentPicture;

static Uint8 cur_type;


static void fn_valid_name(sqlite3_context*cxt,int argc,sqlite3_value**argv) {
  const char*s=sqlite3_value_text(*argv);
  if(!s || !*s || s[strspn(s,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-0123456789")]) {
    sqlite3_result_error(cxt,"Invalid name",-1);
    return;
  }







>







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
typedef struct {
  char basename[64];
  Filter filters[64];
  Uint8 nfilters;
} DependentPicture;

static Uint8 cur_type;
static Uint8 gsizes[16];

static void fn_valid_name(sqlite3_context*cxt,int argc,sqlite3_value**argv) {
  const char*s=sqlite3_value_text(*argv);
  if(!s || !*s || s[strspn(s,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-0123456789")]) {
    sqlite3_result_error(cxt,"Invalid name",-1);
    return;
  }
107
108
109
110
111
112
113

114
115
116




117
118
119
120
121
122
123
    sqlite3_bind_int(st,2,j=(i>4 && !memcmp(".IMG",nam+i-4,4)?1:!memcmp(".DEP",nam+i-4,4)?2:0));
    r+=j;
    i=fgetc(fp)<<16;
    i|=fgetc(fp)<<24;
    i|=fgetc(fp)<<0;
    i|=fgetc(fp)<<8;
    if(!i) continue;

    buf=realloc(buf,i);
    if(!buf) fatal("Allocation failed\n");
    fread(buf,1,i,fp);




    sqlite3_bind_blob(st,3,buf,i,SQLITE_TRANSIENT);
    while((i=sqlite3_step(st))==SQLITE_ROW);
    if(i!=SQLITE_DONE) fatal("SQL error (%d): %s\n",i,sqlite3_errmsg(userdb));
  }
done:
  if(st) sqlite3_finalize(st);
  if(fp) fclose(fp);







>



>
>
>
>







108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
    sqlite3_bind_int(st,2,j=(i>4 && !memcmp(".IMG",nam+i-4,4)?1:!memcmp(".DEP",nam+i-4,4)?2:0));
    r+=j;
    i=fgetc(fp)<<16;
    i|=fgetc(fp)<<24;
    i|=fgetc(fp)<<0;
    i|=fgetc(fp)<<8;
    if(!i) continue;
    if(i<0) fatal("Bad or too big lump in .xclass file\n");
    buf=realloc(buf,i);
    if(!buf) fatal("Allocation failed\n");
    fread(buf,1,i,fp);
    if(!sqlite3_stricmp(nam,"PICEDIT.CFG")) {
      memcpy(gsizes,buf,i<15?i:15);
      if(!*gsizes) *gsizes=picture_size;
    }
    sqlite3_bind_blob(st,3,buf,i,SQLITE_TRANSIENT);
    while((i=sqlite3_step(st))==SQLITE_ROW);
    if(i!=SQLITE_DONE) fatal("SQL error (%d): %s\n",i,sqlite3_errmsg(userdb));
  }
done:
  if(st) sqlite3_finalize(st);
  if(fp) fclose(fp);
1286
1287
1288
1289
1290
1291
1292
1293

1294
1295
1296
1297

1298
1299
1300
1301
1302
1303
1304
  i=sqlite3_column_int(st,2);
  name=strdup(sqlite3_column_text(st,0)?:(const unsigned char*)"???");
  if(!name) fatal("Allocation failed\n");
  if(i==1) {
    load_picture_lump(data,n,pict);
    sqlite3_finalize(st);
    if(!*pict) {
      i=picture_size;

      *pict=malloc(sizeof(Picture)+(i+1)*i);
      if(!*pict) fatal("Allocation failed\n");
      pict[0]->size=i;
      memset(pict[0]->data,0,(i+1)*i);

    }
    edit_picture_1(pict,name);
    fp=open_memstream((char**)&buf,&size);
    if(!fp) fatal("Cannot open memory stream\n");
    for(i=n=0;i<16;i++) if(pict[i]) n++;
    fputc(n,fp);
    for(i=0;i<n;i++) fputc(pict[i]->size,fp);







|
>
|
|
|
|
>







1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
  i=sqlite3_column_int(st,2);
  name=strdup(sqlite3_column_text(st,0)?:(const unsigned char*)"???");
  if(!name) fatal("Allocation failed\n");
  if(i==1) {
    load_picture_lump(data,n,pict);
    sqlite3_finalize(st);
    if(!*pict) {
      if(!*gsizes) *gsizes=picture_size;
      for(i=0;gsizes[i];i++) {
        pict[i]=malloc(sizeof(Picture)+(gsizes[i]+1)*gsizes[i]);
        if(!pict[i]) fatal("Allocation failed\n");
        pict[i]->size=gsizes[i];
        memset(pict[i]->data,0,(gsizes[i]+1)*gsizes[i]);
      }
    }
    edit_picture_1(pict,name);
    fp=open_memstream((char**)&buf,&size);
    if(!fp) fatal("Cannot open memory stream\n");
    for(i=n=0;i<16;i++) if(pict[i]) n++;
    fputc(n,fp);
    for(i=0;i<n;i++) fputc(pict[i]->size,fp);
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
    return;
  }
  sqlite3_bind_text(st,2,s,-1,SQLITE_TRANSIENT);
  i=sqlite3_step(st);
  sqlite3_finalize(st);
  if(i!=SQLITE_DONE) screen_message(sqlite3_errmsg(userdb));
}

























static void set_caption(void) {
  char buf[256];
  snprintf(buf,255,"Free Hero Mesh - %s - Picture",basefilename);
  SDL_WM_SetCaption(buf,buf);
}

void run_picture_editor(void) {
  sqlite3_int64*ids;
  SDL_Event ev;
  SDL_Rect r;
  sqlite3_stmt*st;
  int sc=0;
  int max=load_picture_file();
  int i,n;
  sqlite3_create_function(userdb,"VALID_NAME",1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_valid_name,0,0);
  init_palette();
  optionquery[1]=Q_imageSize;
  picture_size=strtol(xrm_get_resource(resourcedb,optionquery,optionquery,2)?:"16",0,10);
  set_cursor(XC_arrow);
  set_caption();
  i=sqlite3_prepare_v3(userdb,"SELECT `ID`,SUBSTR(`NAME`,1,LENGTH(`NAME`)-4),`TYPE` FROM `PICEDIT` WHERE `TYPE` ORDER BY `NAME` LIMIT ?1 OFFSET ?2;",-1,SQLITE_PREPARE_PERSISTENT,&st,0);
  if(i) fatal("SQL error (%d): %s\n",i,sqlite3_errmsg(userdb));
  ids=calloc(screen->h/8,sizeof(sqlite3_int64));
  if(!ids) fatal("Allocation failed\n");
  redraw:
  sqlite3_reset(st);
  if(sc>max-screen->h/8+1) sc=max-screen->h/8+1;
  if(sc<0) sc=0;
  sqlite3_bind_int(st,1,screen->h/8-1);
  sqlite3_bind_int(st,2,sc);
  SDL_LockSurface(screen);
  r.x=r.y=0; r.w=screen->w; r.h=screen->h;
  SDL_FillRect(screen,&r,0xF0);
  draw_text(0,0,"<ESC> Save/Quit  <F1> Add  <F2> Delete  <F3> Edit  <F4> Rename  <F5> AddDependent",0xF0,0xFB);
  n=0;
  while((i=sqlite3_step(st))==SQLITE_ROW) {
    ids[n++]=sqlite3_column_int64(st,0);
    draw_text(16,8*n,sqlite3_column_text(st,1),0xF0,sqlite3_column_int(st,2)==1?0xF7:0xF2);
    if(8*n+8>screen->h-8) break;
  }
  SDL_UnlockSurface(screen);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


















|















|







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
    return;
  }
  sqlite3_bind_text(st,2,s,-1,SQLITE_TRANSIENT);
  i=sqlite3_step(st);
  sqlite3_finalize(st);
  if(i!=SQLITE_DONE) screen_message(sqlite3_errmsg(userdb));
}

static void do_config(void) {
  sqlite3_stmt*st;
  const char*s;
  char buf[16];
  int i,n;
  for(n=0;n<15;n++) {
    snprintf(buf,15,"%d%c%c variant:",n+1,"snrt"[n>3?3:n],"tddh"[n>3?3:n]);
    s=screen_prompt(buf);
    if(!s || !*s) break;
    gsizes[n]=strtol(s,0,10);
  }
  if(!n) return;
  gsizes[n]=0;
  i=sqlite3_exec(userdb,
    "INSERT INTO `PICEDIT`(`NAME`,`TYPE`,`DATA`) SELECT 'PICEDIT.CFG',0,'' EXCEPT SELECT `NAME`,0,'' FROM `PICEDIT`;"
  ,0,0,0);
  if(i) fatal("SQL error (%d): %s\n",i,sqlite3_errmsg(userdb));
  i=sqlite3_prepare_v2(userdb,"UPDATE `PICEDIT` SET `DATA`=?1 WHERE `NAME`='PICEDIT.CFG';",-1,&st,0);
  if(i) fatal("SQL error (%d): %s\n",i,sqlite3_errmsg(userdb));
  sqlite3_bind_blob(st,1,gsizes,n,0);
  if(sqlite3_step(st)!=SQLITE_DONE) fatal("SQL error: %s\n",sqlite3_errmsg(userdb));
  sqlite3_finalize(st);
}

static void set_caption(void) {
  char buf[256];
  snprintf(buf,255,"Free Hero Mesh - %s - Picture",basefilename);
  SDL_WM_SetCaption(buf,buf);
}

void run_picture_editor(void) {
  sqlite3_int64*ids;
  SDL_Event ev;
  SDL_Rect r;
  sqlite3_stmt*st;
  int sc=0;
  int max=load_picture_file();
  int i,n;
  sqlite3_create_function(userdb,"VALID_NAME",1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_valid_name,0,0);
  init_palette();
  optionquery[1]=Q_imageSize;
  *gsizes=picture_size=strtol(xrm_get_resource(resourcedb,optionquery,optionquery,2)?:"16",0,10);
  set_cursor(XC_arrow);
  set_caption();
  i=sqlite3_prepare_v3(userdb,"SELECT `ID`,SUBSTR(`NAME`,1,LENGTH(`NAME`)-4),`TYPE` FROM `PICEDIT` WHERE `TYPE` ORDER BY `NAME` LIMIT ?1 OFFSET ?2;",-1,SQLITE_PREPARE_PERSISTENT,&st,0);
  if(i) fatal("SQL error (%d): %s\n",i,sqlite3_errmsg(userdb));
  ids=calloc(screen->h/8,sizeof(sqlite3_int64));
  if(!ids) fatal("Allocation failed\n");
  redraw:
  sqlite3_reset(st);
  if(sc>max-screen->h/8+1) sc=max-screen->h/8+1;
  if(sc<0) sc=0;
  sqlite3_bind_int(st,1,screen->h/8-1);
  sqlite3_bind_int(st,2,sc);
  SDL_LockSurface(screen);
  r.x=r.y=0; r.w=screen->w; r.h=screen->h;
  SDL_FillRect(screen,&r,0xF0);
  draw_text(0,0,"<ESC> Save/Quit  <F1> Add  <F2> Delete  <F3> Edit  <F4> Rename  <F5> AddDependent  <F6> Config",0xF0,0xFB);
  n=0;
  while((i=sqlite3_step(st))==SQLITE_ROW) {
    ids[n++]=sqlite3_column_int64(st,0);
    draw_text(16,8*n,sqlite3_column_text(st,1),0xF0,sqlite3_column_int(st,2)==1?0xF7:0xF2);
    if(8*n+8>screen->h-8) break;
  }
  SDL_UnlockSurface(screen);
1474
1475
1476
1477
1478
1479
1480



1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
          case SDLK_F4:
            rename_picture();
            goto redraw;
          case SDLK_F5:
            if(max<65535) max+=add_picture(2);
            else screen_message("Too many pictures");
            goto redraw;



        }
        break;
      case SDL_MOUSEMOTION:
        set_cursor(XC_arrow);
        break;
      case SDL_VIDEOEXPOSE:
        goto redraw;
    }
  }
}







>
>
>










1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
          case SDLK_F4:
            rename_picture();
            goto redraw;
          case SDLK_F5:
            if(max<65535) max+=add_picture(2);
            else screen_message("Too many pictures");
            goto redraw;
          case SDLK_F6:
            do_config();
            goto redraw;
        }
        break;
      case SDL_MOUSEMOTION:
        set_cursor(XC_arrow);
        break;
      case SDL_VIDEOEXPOSE:
        goto redraw;
    }
  }
}

Modified picedit.doc from [861f280ac9] to [daa21e621e].

26
27
28
29
30
31
32







33
34
35
36
37
38
39

The F3 key allows entering a name of a picture to edit.

The F4 key renames a picture.

The F5 key adds a dependent picture (see the below section).









=== Drawing ===

The following keyboard commands are available:

Esc
  Leave the drawing screen.







>
>
>
>
>
>
>







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

The F3 key allows entering a name of a picture to edit.

The F4 key renames a picture.

The F5 key adds a dependent picture (see the below section).

The F6 key is used to set configuration. Currently, this only sets the
default picture sizes. If you specify zero, then it will use the user
configuration, otherwise it is saved with the puzzle set, and will be
used when adding new pictures. You can specify multiple sizes; it will
create it with variants of all of those sizes. You can also specify the
same numbers multiple times if you want multiple variants of that size.


=== Drawing ===

The following keyboard commands are available:

Esc
  Leave the drawing screen.

Modified puzzleset.doc from [27aef9bea9] to [55b65d3faf].

33
34
35
36
37
38
39



40
41
42
43
44
45
46

The DEP lumps are dependent pictures; each one references one or more IMG
lumps, and specifies how to modify them to produce the new picture (e.g.
by rotating, mirroring, changing colours, etc).

The WAV lumps are sound effects. Each is a RIFF WAVE file; it must be of
a type which can be loaded by SDL. (This is currently not used.)





=== Class definition file ===

This file is a plain text file which defines the classes of objects which
are used in the game. See class.doc for details of its format.








>
>
>







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

The DEP lumps are dependent pictures; each one references one or more IMG
lumps, and specifies how to modify them to produce the new picture (e.g.
by rotating, mirroring, changing colours, etc).

The WAV lumps are sound effects. Each is a RIFF WAVE file; it must be of
a type which can be loaded by SDL. (This is currently not used.)

The PICEDIT.CFG lump stores the configuration for the picture editor. It
can safely be deleted.


=== Class definition file ===

This file is a plain text file which defines the classes of objects which
are used in the game. See class.doc for details of its format.