Free Hero Mesh

Check-in [66cf1d39ad]
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:Some corrections of custom level table, including initializing the schema properly; start a few more parts of its implementation too.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 66cf1d39adf231ef5edb8595344f2bab22057ca4
User & Date: user on 2021-12-25 06:33:53
Other Links: manifest | tags
Context
2021-12-27
20:33
More corrections, and more work on implementation, of custom level table definitions. check-in: 702847e470 user: user tags: trunk
2021-12-25
06:33
Some corrections of custom level table, including initializing the schema properly; start a few more parts of its implementation too. check-in: 66cf1d39ad user: user tags: trunk
00:11
Start to implement (LevelTable) definition (untested so far, and currently only the definition and not the implementation). check-in: 3b02288a18 user: user tags: trunk
Changes

Modified class.c from [da031da59b] to [64b3d009e0].

2212
2213
2214
2215
2216
2217
2218




2219
2220
2221
2222
2223
2224
2225
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229







+
+
+
+







  for(;;) {
    if(ptr>=0xFFFA) ParseError("Out of memory\n");
    nxttok();
    if(Tokenf(TF_MACRO)) ParseError("Unexpected macro\n");
    if(tokent==TF_CLOSE) {
      ll_code[ptr++]=OP_RET;
      return ptr;
    } else if(Tokenf(TF_INT)) {
      if(!(tokenv&~0xFFL)) ll_code[ptr++]=tokenv;
      else if(!(tokenv&~0xFFFFL)) ll_code[ptr++]=OP_INT16,ll_code[ptr++]=tokenv;
      else ll_code[ptr++]=OP_INT32,ll_code[ptr++]=OP_INT32,ll_code[ptr++]=tokenv>>16,ll_code[ptr++]=tokenv;
    } else if(Tokenf(TF_NAME)) {
      switch(tokenv) {
        case OP_IF:
          if(flowdepth==64) ParseError("Too much flow control nesting\n");
          ll_code[ptr++]=OP_IF;
          flowptr[flowdepth++]=ptr++;
          break;
2282
2283
2284
2285
2286
2287
2288
2289

2290
2291
2292
2293
2294
2295
2296
2286
2287
2288
2289
2290
2291
2292

2293
2294
2295
2296
2297
2298
2299
2300







-
+







    if(!Tokenf(TF_NAME)) ParseError("Unexpected token in (LevelTable) block\n");
    switch(tokenv) {
      case OP_LABEL:
        i=look_hash(hash,LOCAL_HASH_SIZE,0x100,0x13F,ll_ndata+0x100,"data columns")?:(ll_ndata++)+0x100;
        i-=0x100;
        if(datac[i].name) ParseError("Duplicate definition\n");
        datac[i].name=strdup(tokenstr);
        if(datac[i].name) fatal("Allocation failed\n");
        if(!datac[i].name) fatal("Allocation failed\n");
        datac[i].ptr=ptr;
        ptr=level_table_code(ptr,hash);
        break;
      case OP_STRING:
        if(last) ParseError("Extra columns after fill column\n");
        for(i=0;tokenstr[i];i++) if(!(tokenstr[i]&~31)) ParseError("Improper column heading\n");
        strcpy(buf,tokenstr);

Modified class.doc from [73da3ea9bc] to [9f8228ce84].

2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603












2604
2605
2606
2607
2608
2609
2610
2587
2588
2589
2590
2591
2592
2593










2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612







-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+







(<label> <code...>)
  Define a data column. The SQL name of the data column will be that of
  the label name, preceded by a underscore, and some characters will be
  stripped out.

(<string> <label> <width> <format> <color>)
  Defines a display column. The <label> is the name of the data column.
  The <width> is a number 1 to 255 or it can be * for fill width. The
  <format> is a string of one or two characters; see the below list of
  possible formats. The <color> is the text colour, and is optional; it
  can be a number from 1 to 255, or it can be a sequence of parenthesized
  pairs of a number (-127 to +127) and colour, to mean use those colour if
  the value of this column is in range. It uses the colour for all values
  up to and including the specified number, so the numbers should be listed
  in ascending order, in order to work. The <string> is the heading; it is
  not allowed to include control characters, nor can it include graphic
  characters with code number less than 32.
  The <width> is a number 1 to 255 or it can be * for fill width; only
  the last column is allowed to be fill width (although it is also OK if
  no colums are fill width). The <format> is a string of exactly one or
  two characters; see the below list of possible formats. The <color> is
  the text colour, and is optional; it can be a number from 1 to 255, or
  it can be a sequence of parenthesized pairs of a number (-127 to +127)
  and colour, to mean use those colour if the value of this column is
  in range. It uses the colour for all values up to and including the
  specified number, so the numbers should be listed in ascending order,
  in order to work. The <string> is the heading; it is not allowed to
  include control characters, nor can it include graphic characters with
  code number less than 32.

(<local> <type> <code...>)
  Defines a aggregate calculation. The <local> is the name of the aggregate
  to be referred by other blocks. The <type> is the type of aggregate,
  which can be one of: + for the sum, min for the least value (unsigned),
  max for the greatest value (unsigned), ,min for the least value (signed),
  and ,max for the greatest value (signed).

Modified function.c from [29a1dbc515] to [3ae0a5eecb].

1180
1181
1182
1183
1184
1185
1186


1187
1188
1189
1190












1191
1192
1193

1194
1195
1196
1197














1198
1199

1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216

1217






1218

1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230

1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242

1243
1244
1245
1246
1247
1248
1249
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189



1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203

1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223

1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242

1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283







+
+

-
-
-
+
+
+
+
+
+
+
+
+
+
+
+


-
+




+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+

















+
-
+
+
+
+
+
+

+












+












+







  .xBestIndex=vt1_playfield_index,
  .xColumn=vt1_playfield_column,
  .xFilter=vt1_playfield_filter,
  .xNext=vt1_playfield_next,
);

static int vt1_levels_connect(sqlite3*db,void*aux,int argc,const char*const*argv,sqlite3_vtab**vt,char**err) {
  sqlite3_str*str;
  int c,i,j;
  if(levels_schema) goto declare;
  //TODO: Add columns specific to a puzzle set.
  levels_schema=sqlite3_mprintf("CREATE TEMPORARY TABLE `LEVELS`"
   "(`ID` INTEGER PRIMARY KEY, `ORD` INT, `CODE` INT, `WIDTH` INT, `HEIGHT` INT, `TITLE` BLOB, `SOLVED` INT, `SOLVABLE` INT);");
  str=sqlite3_str_new(db);
  sqlite3_str_appendall(str,"CREATE TEMPORARY TABLE `LEVELS`"
   "(`ID` INTEGER PRIMARY KEY, `ORD` INT, `CODE` INT, `WIDTH` INT, `HEIGHT` INT, `TITLE` BLOB, `SOLVED` INT, `SOLVABLE` INT");
  for(i=0;i<ll_ndata;i++) {
    sqlite3_str_append(str,",\"_",3);
    for(j=0;c=ll_data[i].name[j];j++) if(c>32 && c<127 && c!='"' && c!='[' && c!=']' && c!=';' && c!='`') sqlite3_str_appendchar(str,1,c);
    free(ll_data[i].name);
    ll_data[i].name=0;
    sqlite3_str_appendchar(str,1,'"');
  }
  sqlite3_str_appendall(str,");");
  levels_schema=sqlite3_str_finish(str);
  if(!levels_schema) fatal("Allocation failed\n");
  declare:
  sqlite3_declare_vtab(db,levels_schema);
  if(i=sqlite3_declare_vtab(db,levels_schema)) return i;
  *vt=sqlite3_malloc(sizeof(sqlite3_vtab));
  return *vt?SQLITE_OK:SQLITE_NOMEM;
}

typedef struct {
  Value misc1,misc2,misc3;
  Uint8 x,y,dir,bizarro;
  Uint16 class;
} ObjInfo;

static void calculate_level_column(sqlite3_stmt*st,const unsigned char*lvl,long sz) {
  ObjInfo ob;
  ObjInfo mru[2];
  mru[0].class=mru[1].class=0;
  ob.x=ob.y=ob.bizarro=0;
  
}

static int vt1_levels_open(sqlite3_vtab*vt,sqlite3_vtab_cursor**cur) {
  //TODO: Add columns specific to a puzzle set.
  sqlite3_str*str;
  sqlite3_stmt*st1;
  sqlite3_stmt*st2;
  const unsigned char*d;
  unsigned char*p;
  int i,j;
  long n;
  int txn=sqlite3_get_autocommit(userdb)?sqlite3_exec(userdb,"BEGIN;",0,0,0):1;
  if(!levels_schema) return SQLITE_CORRUPT_VTAB;
  if(screen) set_cursor(XC_coffee_mug);
  fprintf(stderr,"Loading level table...\n");
  if(sqlite3_exec(userdb,levels_schema,0,0,0)) {
    err: fatal("SQL error while loading LEVELS table: %s\n",sqlite3_errmsg(userdb));
  }
  if(sqlite3_prepare_v2(userdb,"SELECT `LEVEL`, IFNULL(`DATA`,READ_LUMP_AT(`OFFSET`,?1)), `USERSTATE` FROM `USERCACHEDATA`"
   " WHERE `FILE` = LEVEL_CACHEID() AND `LEVEL` NOT NULL AND `LEVEL` >= 0 ORDER BY `LEVEL`;",-1,&st1,0))
   goto err;
  // ?1=ID, ?2=CODE, ?3=WIDTH, ?4=HEIGHT, ?5=TITLE, ?6=SOLVED, ?7=SOLVABLE
  str=sqlite3_str_new(userdb);
  if(sqlite3_prepare_v3(userdb,"INSERT INTO `LEVELS` VALUES(?1,NULL,?2,?3,?4,?5,?6,?7);",-1,SQLITE_PREPARE_NO_VTAB,&st2,0))
  sqlite3_str_appendall(str,"INSERT INTO `LEVELS` VALUES(?1,NULL,?2,?3,?4,?5,?6,?7");
  for(i=0;i<ll_ndata;i++) sqlite3_str_appendf(str,",?%d",i+8);
  sqlite3_str_appendall(str,");");
  p=sqlite3_str_finish(str);
  if(!p) fatal("Allocation failed\n");
  if(sqlite3_prepare_v3(userdb,p,-1,SQLITE_PREPARE_NO_VTAB,&st2,0))
   goto err;
  sqlite3_free(p);
  sqlite3_bind_pointer(st1,1,levelfp,"http://zzo38computer.org/fossil/heromesh.ui#FILE_ptr",0);
  while((i=sqlite3_step(st1))==SQLITE_ROW) {
    sqlite3_reset(st2);
    sqlite3_bind_int(st2,1,sqlite3_column_int(st1,0));
    d=sqlite3_column_blob(st1,1); n=sqlite3_column_bytes(st1,1);
    if(n<7 || !d) continue;
    sqlite3_bind_int(st2,2,d[2]|(d[3]<<8));
    sqlite3_bind_int(st2,3,(d[4]&63)+1);
    sqlite3_bind_int(st2,4,(d[5]&63)+1);
    for(i=6;i<n && d[i];i++);
    j=d[0]|(d[1]<<8);
    sqlite3_bind_blob(st2,5,d+6,i-6,0);
    calculate_level_column(st2,d,n);
    p=read_lump(FIL_SOLUTION,sqlite3_column_int(st1,0),&n);
    if(p) {
      sqlite3_bind_int(st2,7,(n>2 && d[0]==p[0] && d[1]==p[1]));
      free(p);
    } else {
      sqlite3_bind_int(st2,7,0);
    }
    d=sqlite3_column_blob(st1,2); n=sqlite3_column_bytes(st1,2);
    sqlite3_bind_int(st2,6,(d && n>5 && n-(d[n-2]<<8)-d[n-1]>3 && (d[n-4]<<8)+d[n-3]==j));
    while((i=sqlite3_step(st2))==SQLITE_ROW);
    if(i!=SQLITE_DONE) goto err;
    sqlite3_bind_null(st2,5);
    for(i=0;i<ll_ndata;i++) sqlite3_bind_null(st2,i+8);
  }
  if(i!=SQLITE_DONE) goto err;
  sqlite3_finalize(st1);
  sqlite3_finalize(st2);
  if(sqlite3_prepare_v3(userdb,"UPDATE `LEVELS` SET `ORD` = ?1 WHERE `ID` = ?2;",-1,SQLITE_PREPARE_NO_VTAB,&st2,0))
   goto err;
  for(j=0;j<level_nindex;j++) {

Modified game.c from [de971fc52d] to [d6b8ec0435].

741
742
743
744
745
746
747

748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769


770
771
772
773
774
775
776
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768


769
770
771
772
773
774
775
776
777







+




















-
-
+
+







    i=strtol(v,0,10);
    j=(screen->w-16)/070;
    if(i<1) i=j;
    if(i>j) i=j;
    if(i>255) i=255;
    columns=i;
  }
  if(!ll_head) ll_head="\xB3W \xB3H \xB3 TITLE";
  // ID, ORD, CODE, WIDTH, HEIGHT, TITLE, SOLVED, SOLVABLE, ...
  if(sqlite3_prepare_v2(userdb,"SELECT * FROM `LEVELS` WHERE `ORD` NOT NULL AND `ORD` >= ?1 ORDER BY `ORD`;",-1,&st,0)) {
    screen_message(sqlite3_errmsg(userdb));
    return 0;
  }
  set_cursor(XC_arrow);
  redraw:
  if(sel<0) sel=0;
  if(sel>=level_nindex) sel=level_nindex-1;
  SDL_FillRect(screen,0,0x02);
  r.x=r.y=0;
  r.w=screen->w;
  r.h=24;
  SDL_FillRect(screen,&r,0xF7);
  SDL_LockSurface(screen);
  draw_text(0,0,"<LMB/\x18\x19\x1A\x1B> Select  <MMB/SP> Title  <RMB/RET> Play  <0-9> Find  <ESC> Cancel",0xF7,0xF0);
  draw_text(0,8,"<F1> Wide/Tall  <F2> ID/Ord",0xF7,0xF0);
  sqlite3_reset(st);
  if(mo&1) {
    scrmax=level_nindex;
    draw_text(16,16,"\xB3 ORD \xB3W \xB3H \xB3 TITLE",0xF7,0xF1);
    if(mo&2) draw_text(24,16," ID ",0xF7,0xF1);
    draw_text(16+060,16,ll_head,0xF7,0xF1);
    draw_text(16,16,mo&2?"\xB3 ID  ":"\xB3 ORD ",0xF7,0xF1);
    if(rescroll) {
      if(sel<scroll) scroll=sel;
      if(sel>=scroll+screen->h/8-3) scroll=sel+4-screen->h/8;
      rescroll=0;
    }
    sqlite3_bind_int(st,1,scroll+1);
    for(y=24;y<screen->h-7;y+=8) {

Modified main.c from [3d54a4ff62] to [f3572b0f94].

1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089

1090
1091
1092
1093
1094
1095
1096
1067
1068
1069
1070
1071
1072
1073

1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096







-















+







  set_stack_protection();
#endif
  if(main_options['c']) {
    load_classes();
    return 0;
  }
  init_sql();
  load_key_bindings();
  init_screen();
  if(main_options['p']) {
    run_picture_editor();
    return 0;
  }
  if(main_options['z']) init_composite();
  load_pictures();
  if(main_options['T']) {
    printf("argv[0] = %s\n",argv[0]);
    test_mode();
    return 0;
  }
  if(!main_options['z']) init_usercache();
  if(main_options['n']) return 0;
  load_classes();
  load_key_bindings();
  load_level_index();
  optionquery[1]=Q_maxObjects;
  max_objects=strtoll(xrm_get_resource(resourcedb,optionquery,optionquery,2)?:"",0,0)?:0xFFFF0000L;
  set_tracing();
  annihilate();
  optionquery[1]=Q_level;
  if(level_ord=strtol(xrm_get_resource(resourcedb,optionquery,optionquery,2)?:"",0,10)) {