Free Hero Mesh

Check-in [c75006b3f9]
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 batch import mode.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c75006b3f928a71697c8fe84ac720be67be6ecfc
User & Date: user on 2021-11-18 00:56:27
Other Links: manifest | tags
Context
2021-11-18
18:52
Remove some conversion files from the misc/ directory; now only the Hero Hearts conversion is included and the others are distributed separately from this repository. check-in: c00fd07eb9 user: user tags: trunk
00:56
Implement batch import mode. check-in: c75006b3f9 user: user tags: trunk
2021-11-16
20:02
Some corrections to animate_ext and collide_with functions in exec.c. check-in: c76e659783 user: user tags: trunk
Changes

Modified TODO from [991048a78f] to [7cb165c03f].

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
* 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?)
  * Animation stopping unexpectedly (until a key is pushed)
* Display solution comments/timestamp
* VCR mode
* Command-line switch for batch import/export levels
* SQL
  * Implement the GROUP column in the CLASSES table
  * Allow multiple SQL statements in one binding
* Fonts/text
  * More code pages
  * Large fonts (possibly: width 8 or 16, height 8-32)
  * Multibyte encodings (e.g. EUC-JP)







|







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
* 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?)
  * Animation stopping unexpectedly (until a key is pushed)
* Display solution comments/timestamp
* VCR mode
* Command-line switch for batch export levels
* SQL
  * Implement the GROUP column in the CLASSES table
  * Allow multiple SQL statements in one binding
* Fonts/text
  * More code pages
  * Large fonts (possibly: width 8 or 16, height 8-32)
  * Multibyte encodings (e.g. EUC-JP)

Modified commandline.doc from [aab3fc8cb6] to [53fc4d0825].

40
41
42
43
44
45
46





47
48
49
50
51
52
53
-f
  Only flush the user cache and then terminate.

-h
  Disable portable mode; always use the HOME environment variable to find
  the configuration and database files.






-n
  Create a new puzzle set. The .xclass and .class files should already
  exist; the .level and .solution files should not already exist, and will
  be created with minimal data.

-p
  Start the picture editor.







>
>
>
>
>







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
-f
  Only flush the user cache and then terminate.

-h
  Disable portable mode; always use the HOME environment variable to find
  the configuration and database files.

-i
  Batch import levels. Accepts the level import format (see export.doc)
  from stdin. It will not overwrite existing levels unless the existing
  level is blank, in which case it will overwrite it.

-n
  Create a new puzzle set. The .xclass and .class files should already
  exist; the .level and .solution files should not already exist, and will
  be created with minimal data.

-p
  Start the picture editor.

Modified edit.c from [cca5f42c2a] to [6224a071ca].

990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012

1013
1014
1015
1016
1017
1018
1019
1020

1021
1022
1023
1024
1025
1026
1027
  FILE*fp;
  size_t size=0;
  char*buf=0;
  char*p;
  sqlite3_str*sol=0;
  Value v;
  if(!cmd || !*cmd) return;
  fp=popen(cmd,"r");
  if(!fp) {
    screen_message("Cannot open pipe");
    return;
  }
  discard_solution();
  level_changed=1;
  while(getline(&buf,&size,fp)>0) {
    p=buf;
    p[strcspn(p,"\r\n\f")]=0;
    p+=strspn(p,"\t ");
    switch(*p) {
      case '0' ... '9':
        if(!d) {
          missd:
          screen_message("Missing D line");

          goto done;
        }
        p=import_numbers(p,&x,&y);
        if(!p) goto bad;
        if(x<1 || x>pfwidth || y<1 || y>pfheight) {
          range:
          fprintf(stderr,"Imported level coordinates out of range: %d %d\n",x,y);
          screen_message("Coordinates out of range");

          goto done;
        }
        p=import_value(p,&v);
        if(!p || v.t!=TY_CLASS) goto bad;
        v.u=objalloc(v.u);
        if(v.u==VOIDLINK) goto bad;
        o=objects[v.u];







|















>








>







990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
  FILE*fp;
  size_t size=0;
  char*buf=0;
  char*p;
  sqlite3_str*sol=0;
  Value v;
  if(!cmd || !*cmd) return;
  fp=main_options['i']?stdin:popen(cmd,"r");
  if(!fp) {
    screen_message("Cannot open pipe");
    return;
  }
  discard_solution();
  level_changed=1;
  while(getline(&buf,&size,fp)>0) {
    p=buf;
    p[strcspn(p,"\r\n\f")]=0;
    p+=strspn(p,"\t ");
    switch(*p) {
      case '0' ... '9':
        if(!d) {
          missd:
          screen_message("Missing D line");
          if(main_options['i']) exit(1);
          goto done;
        }
        p=import_numbers(p,&x,&y);
        if(!p) goto bad;
        if(x<1 || x>pfwidth || y<1 || y>pfheight) {
          range:
          fprintf(stderr,"Imported level coordinates out of range: %d %d\n",x,y);
          screen_message("Coordinates out of range");
          if(main_options['i']) exit(1);
          goto done;
        }
        p=import_value(p,&v);
        if(!p || v.t!=TY_CLASS) goto bad;
        v.u=objalloc(v.u);
        if(v.u==VOIDLINK) goto bad;
        o=objects[v.u];
1098
1099
1100
1101
1102
1103
1104



1105
1106
1107
1108

1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
          if(heromesh_key_names[x] && !strcmp(buf+1,heromesh_key_names[x])) {
            sqlite3_str_appendchar(sol,y,x);
            break;
          }
        }
        if(x==256) goto bad;
        break;



      default:
        if(*p && *p!=';') {
          bad:
          fprintf(stderr,"Invalid record in imported data:  %s\n",buf);

          screen_message("Invalid record");
          goto done;
        }
    }
  }
  done:
  free(buf);
  pclose(fp);
  generation_number_inc=0;
  if(sol) {
    solution_length=sqlite3_str_length(sol);
    solution_data=sqlite3_str_finish(sol);
    if(!solution_data) fatal("Allocation failed");
  }
}







>
>
>




>







|







1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
          if(heromesh_key_names[x] && !strcmp(buf+1,heromesh_key_names[x])) {
            sqlite3_str_appendchar(sol,y,x);
            break;
          }
        }
        if(x==256) goto bad;
        break;
      case '=':
        if(main_options['i']) goto done;
        // fall through
      default:
        if(*p && *p!=';') {
          bad:
          fprintf(stderr,"Invalid record in imported data:  %s\n",buf);
          if(main_options['i']) exit(1);
          screen_message("Invalid record");
          goto done;
        }
    }
  }
  done:
  free(buf);
  if(!main_options['i']) pclose(fp);
  generation_number_inc=0;
  if(sol) {
    solution_length=sqlite3_str_length(sol);
    solution_data=sqlite3_str_finish(sol);
    if(!solution_data) fatal("Allocation failed");
  }
}
1706
1707
1708
1709
1710
1711
1712













    "Blank\0" // title
    "\xFF" // objects
  ;
  fwrite(d,1,sizeof(d)-1,fp);
  fflush(fp);
  rewind(fp);
}




















>
>
>
>
>
>
>
>
>
>
>
>
>
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
    "Blank\0" // title
    "\xFF" // objects
  ;
  fwrite(d,1,sizeof(d)-1,fp);
  fflush(fp);
  rewind(fp);
}

void batch_import(void) {
  load_level(level_id);
  if(nobjects) new_level();
  while(!feof(stdin)) {
    if(main_options['v']) fprintf(stderr,"Level %d\n",level_ord);
    import_level("#");
    if(nobjects) {
      save_level();
      if(!feof(stdin)) new_level();
    }
  }
}

Modified export.doc from [78c7466e91] to [d7f4429fb6].

63
64
65
66
67
68
69



70
71
72
73
74
75
76
  class.doc), and optionally the repeat count. This enters it into the
  solution; if at least one command like this is present then it will
  overwrite the existing solution when this level is saved. (Note: This
  does not automatically verify the solution; it only records it.)
  (Currently, this line is implemented only for import, and not for
  export. Later an option might be added to do this on export, too.)





=== Misc values ===

A number is written in decimal, and must be 0 to 65535.

A class name has $ at first.








>
>
>







63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
  class.doc), and optionally the repeat count. This enters it into the
  solution; if at least one command like this is present then it will
  overwrite the existing solution when this level is saved. (Note: This
  does not automatically verify the solution; it only records it.)
  (Currently, this line is implemented only for import, and not for
  export. Later an option might be added to do this on export, too.)

=
  Delimiter between levels; only allowed in batch import mode.


=== Misc values ===

A number is written in decimal, and must be 0 to 65535.

A class name has $ at first.

Modified heromesh.h from [ed576c77f1] to [c5f496bb05].

301
302
303
304
305
306
307

308
309
310
311
312
  Uint8 x0,y0,x1,y1;
} EditorRect;

extern EditorRect editrect;

void run_editor(void);
void write_empty_level_set(FILE*);


// == picedit ==

void run_picture_editor(void);








>





301
302
303
304
305
306
307
308
309
310
311
312
313
  Uint8 x0,y0,x1,y1;
} EditorRect;

extern EditorRect editrect;

void run_editor(void);
void write_empty_level_set(FILE*);
void batch_import(void);

// == picedit ==

void run_picture_editor(void);

Modified main.c from [2701a43599] to [d4c1330f51].

784
785
786
787
788
789
790
791
792
793
794
795
796
797
798

static void test_mode(void) {
  Uint32 n=0;
  SDLKey k;
  SDL_Event ev;
  char buf[32];
  const UserCommand*uc;
  int i;
  set_cursor(XC_tcross);
  SDL_LockSurface(screen);
  draw_text(0,0,"Hello, World!",0xF0,0xFF);
  buf[16]=0;
  for(i=0;i<16;i++) {
    for(n=0;n<16;n++) buf[n]=(i<<4)+n?:255;
    draw_text(4,(i<<3)+12,buf,0xF0,0xF7);







|







784
785
786
787
788
789
790
791
792
793
794
795
796
797
798

static void test_mode(void) {
  Uint32 n=0;
  SDLKey k;
  SDL_Event ev;
  char buf[32];
  const UserCommand*uc;
  int i,j;
  set_cursor(XC_tcross);
  SDL_LockSurface(screen);
  draw_text(0,0,"Hello, World!",0xF0,0xFF);
  buf[16]=0;
  for(i=0;i<16;i++) {
    for(n=0;n<16;n++) buf[n]=(i<<4)+n?:255;
    draw_text(4,(i<<3)+12,buf,0xF0,0xF7);
823
824
825
826
827
828
829









830
831
832
833
834
835
836
          break;
        case SDLK_e:
          n=1;
          goto keytest;
        case SDLK_g:
          n=0;
          goto keytest;









        case SDLK_p:
          sqlite3_exec(userdb,"SELECT * FROM `PICTURES`;",test_sql_callback,0,0);
          break;
        case SDLK_q:
          exit(0);
          break;
        case SDLK_s:







>
>
>
>
>
>
>
>
>







823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
          break;
        case SDLK_e:
          n=1;
          goto keytest;
        case SDLK_g:
          n=0;
          goto keytest;
        case SDLK_i:
          SDL_FillRect(screen,0,5);
          for(i=j=0;;i++) {
            if(picture_size*(i+1)>screen->w) i=0,j++;
            if(picture_size*(j+1)>screen->h) break;
            draw_picture(picture_size*i,picture_size*j,n++);
          }
          SDL_Flip(screen);
          break;
        case SDLK_p:
          sqlite3_exec(userdb,"SELECT * FROM `PICTURES`;",test_sql_callback,0,0);
          break;
        case SDLK_q:
          exit(0);
          break;
        case SDLK_s:
1035
1036
1037
1038
1039
1040
1041

1042
1043
1044
1045
1046
1047
1048
1049
1050
    globalclassname=strrchr(basefilename,'/');
    globalclassname=globalclassname?globalclassname+1:basefilename;
  }
  if(main_options['z']) {
    if(main_options['p'] || main_options['f'] || main_options['e']) fatal("Switches are conflicting with -z\n");
    main_options['r']=1;
  }

  if(main_options['n']) {
    if(main_options['r']) fatal("Switches -r and -n are conflicting\n");
    main_options['x']=1;
  }
  if(main_options['a']) main_options['r']=main_options['x']=1;
  if(main_options['p']) main_options['r']=1;
  if(main_options['f']) main_options['x']=1;
  if(!main_options['c']) {
    set_path(argv[0]);







>
|
|







1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
    globalclassname=strrchr(basefilename,'/');
    globalclassname=globalclassname?globalclassname+1:basefilename;
  }
  if(main_options['z']) {
    if(main_options['p'] || main_options['f'] || main_options['e']) fatal("Switches are conflicting with -z\n");
    main_options['r']=1;
  }
  if(main_options['n'] && main_options['i']) fatal("Switches -n and -i are conflicting\n");
  if(main_options['n'] || main_options['i']) {
    if(main_options['r']) fatal("Switches -r and -%c are conflicting\n",main_options['i']?'i':'n');
    main_options['x']=1;
  }
  if(main_options['a']) main_options['r']=main_options['x']=1;
  if(main_options['p']) main_options['r']=1;
  if(main_options['f']) main_options['x']=1;
  if(!main_options['c']) {
    set_path(argv[0]);
1087
1088
1089
1090
1091
1092
1093


1094


1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
    if(level_ord>level_nindex) level_ord=level_nindex;
    log_if_error(load_level(-level_ord));
  }
  optionquery[1]=Q_maxTrigger;
  max_trigger=strtol(xrm_get_resource(resourcedb,optionquery,optionquery,2)?:"",0,10);
  if(main_options['a']) run_auto_test();
  if(main_options['x']) {


    if(main_options['f']) {


      if(main_options['r']) fatal("Cannot flush user cache; puzzle set is read-only\n");
      flush_usercache();
      return 0;
    }
    fprintf(stderr,"Ready for executing SQL statements.\n");
    no_dead_anim=1;
    do_sql_mode();
    return 0;
  }
  set_autosave();
  for(;;) { if(main_options['e']) run_editor(); else run_game(); }
}







>
>
|
>
>












1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
    if(level_ord>level_nindex) level_ord=level_nindex;
    log_if_error(load_level(-level_ord));
  }
  optionquery[1]=Q_maxTrigger;
  max_trigger=strtol(xrm_get_resource(resourcedb,optionquery,optionquery,2)?:"",0,10);
  if(main_options['a']) run_auto_test();
  if(main_options['x']) {
    if(main_options['i']) {
      batch_import();
      if(main_options['f']) flush_usercache();
      return 0;
    } else if(main_options['f']) {
      if(main_options['r']) fatal("Cannot flush user cache; puzzle set is read-only\n");
      flush_usercache();
      return 0;
    }
    fprintf(stderr,"Ready for executing SQL statements.\n");
    no_dead_anim=1;
    do_sql_mode();
    return 0;
  }
  set_autosave();
  for(;;) { if(main_options['e']) run_editor(); else run_game(); }
}

Modified man6/heromesh.6 from [40aa1aa469] to [be6820057b].

30
31
32
33
34
35
36



37
38
39
40
41
42
43
.IP -e
Start the level editor.
.IP -f
Only flush the user cache and then terminate.
.IP -h
Disable portable mode;
always use the HOME environment variable to find the files.



.IP -n
Create a new puzzle set.
The class definition file and image set must already exist.
.IP -p
Start the picture editor.
.IP -r
Open in read-only mode.







>
>
>







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
.IP -e
Start the level editor.
.IP -f
Only flush the user cache and then terminate.
.IP -h
Disable portable mode;
always use the HOME environment variable to find the files.
.IP -i
Batch import levels.
Accepts the level data (in the export format) from stdin.
.IP -n
Create a new puzzle set.
The class definition file and image set must already exist.
.IP -p
Start the picture editor.
.IP -r
Open in read-only mode.