Free Hero Mesh

Check-in [656b937843]
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:Auto-update the LEVELS table when it is appropriate to do so.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 656b937843c03779373754fcd7e51e19cf08b9a7
User & Date: user on 2021-12-15 07:12:25
Other Links: manifest | tags
Context
2021-12-17
03:01
Implement list of levels (currently the tall mode lacks details; this will be added in future). check-in: 2b9a22d541 user: user tags: trunk
2021-12-15
07:12
Auto-update the LEVELS table when it is appropriate to do so. check-in: 656b937843 user: user tags: trunk
2021-12-14
06:54
Start to implement the LEVELS table. check-in: c4208ea179 user: user tags: trunk
Changes

Modified TODO from [6e5666c132] to [be82d4c6e3].

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  * Coordinate input (may be suitable for some kind of games)
  * Possibility to define auto-generation levels mode
* Editor
  * Mouse dragging
  * Level index editor
* Table of contents for levels (partially implemented)
  * Can define your own columns
  * Update SOLVED (and SOLVABLE) column during playing
  * Cache invalidation in editor
  * Can be divisions by sections
* Deal better with allowing to skip past corrupted levels
* Picture editor/loading
  * Allowing more altimages
  * Batch insert multiple dependent image lumps
* Puzzle set catalog format (using with internet; a separate program)
* Inventory/replay hybrid view







<
<







14
15
16
17
18
19
20


21
22
23
24
25
26
27
  * Coordinate input (may be suitable for some kind of games)
  * Possibility to define auto-generation levels mode
* Editor
  * Mouse dragging
  * Level index editor
* Table of contents for levels (partially implemented)
  * Can define your own columns


  * Can be divisions by sections
* Deal better with allowing to skip past corrupted levels
* Picture editor/loading
  * Allowing more altimages
  * Batch insert multiple dependent image lumps
* Puzzle set catalog format (using with internet; a separate program)
* Inventory/replay hybrid view

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

268
269
270
271
272
273
274





275
276
277
278
279
280
281
  }
  // Done
  sz=sqlite3_str_length(str);
  if(i=sqlite3_str_errcode(str)) fatal("SQL string error (%d)\n",i);
  data=sqlite3_str_finish(str);
  if(!data) fatal("Allocation failed\n");
  sqlite3_exec(userdb,"BEGIN;",0,0,0);





  write_lump(FIL_LEVEL,level_id,sz,data);
  sqlite3_free(data);
  if(level_ord==level_nindex+1) update_level_index();
  rewrite_class_def();
  if(solution_data) {
    solution_data[0]=level_version&255;
    solution_data[1]=level_version>>8;







>
>
>
>
>







268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
  }
  // Done
  sz=sqlite3_str_length(str);
  if(i=sqlite3_str_errcode(str)) fatal("SQL string error (%d)\n",i);
  data=sqlite3_str_finish(str);
  if(!data) fatal("Allocation failed\n");
  sqlite3_exec(userdb,"BEGIN;",0,0,0);
  // This next line might fail if the LEVELS table has not been loaded yet.
  // Attempting to drop it before it is loaded is slower than it should be, somehow.
  // (I also suspect there might be a bug in SQLite, although I am unsure.)
  // Therefore, it first tries to truncate it; if it hasn't been loaded, it fails.
  sqlite3_exec(userdb,"DELETE FROM LEVELS; DROP TABLE TEMP.LEVELS;",0,0,0);
  write_lump(FIL_LEVEL,level_id,sz,data);
  sqlite3_free(data);
  if(level_ord==level_nindex+1) update_level_index();
  rewrite_class_def();
  if(solution_data) {
    solution_data[0]=level_version&255;
    solution_data[1]=level_version>>8;

Modified function.c from [77ed877244] to [a630f4aa7d].

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
  .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) {

  //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);");
  if(!levels_schema) fatal("Allocation failed\n");

  sqlite3_declare_vtab(db,levels_schema);
  *vt=sqlite3_malloc(sizeof(sqlite3_vtab));
  return *vt?SQLITE_OK:SQLITE_NOMEM;
}

static int vt1_levels_open(sqlite3_vtab*vt,sqlite3_vtab_cursor**cur) {
  //TODO: Add columns specific to a puzzle set.
  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 index...\n");
  if(sqlite3_exec(userdb,levels_schema,0,0,0)) {
    err: fatal("SQL error while loading LEVELS table: %s\n",sqlite3_errmsg(userdb));
  }
  sqlite3_free(levels_schema);
  levels_schema=0;
  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
  if(sqlite3_prepare_v3(userdb,"INSERT INTO `LEVELS` VALUES(?1,NULL,?2,?3,?4,?5,?6,?7);",-1,SQLITE_PREPARE_NO_VTAB,&st2,0))
   goto err;
  sqlite3_bind_pointer(st1,1,levelfp,"http://zzo38computer.org/fossil/heromesh.ui#FILE_ptr",0);







>




>
















|



<
<







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
  .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) {
  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);");
  if(!levels_schema) fatal("Allocation failed\n");
  declare:
  sqlite3_declare_vtab(db,levels_schema);
  *vt=sqlite3_malloc(sizeof(sqlite3_vtab));
  return *vt?SQLITE_OK:SQLITE_NOMEM;
}

static int vt1_levels_open(sqlite3_vtab*vt,sqlite3_vtab_cursor**cur) {
  //TODO: Add columns specific to a puzzle set.
  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
  if(sqlite3_prepare_v3(userdb,"INSERT INTO `LEVELS` VALUES(?1,NULL,?2,?3,?4,?5,?6,?7);",-1,SQLITE_PREPARE_NO_VTAB,&st2,0))
   goto err;
  sqlite3_bind_pointer(st1,1,levelfp,"http://zzo38computer.org/fossil/heromesh.ui#FILE_ptr",0);

Modified game.c from [641fb75f65] to [5006bb9149].

978
979
980
981
982
983
984

985
986
987
988
989
990
991
    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);

}

void run_game(void) {
  int i;
  SDL_Event ev;
  set_caption();
  replay_count=0;







>







978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
    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();
  replay_count=0;
1047
1048
1049
1050
1051
1052
1053

1054
1055
1056
1057
1058
1059
1060
        if(inputs_count) {
          for(i=0;i<inputs_count && !gameover;i++) if(inputs[i]) input_move(inputs[i]);
          inputs_count=0;
          if(saved_inserting) inserting=1,saved_inserting=0;
          no_dead_anim=0;
          if(gameover==1) {
            if(should_record_solution) record_solution();

            if(autowin) do_autowin();
          }
        }
        redraw_game();
        timerflag=0; // ensure we have not missed a timer event
        break;
    }







>







1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
        if(inputs_count) {
          for(i=0;i<inputs_count && !gameover;i++) if(inputs[i]) input_move(inputs[i]);
          inputs_count=0;
          if(saved_inserting) inserting=1,saved_inserting=0;
          no_dead_anim=0;
          if(gameover==1) {
            if(should_record_solution) record_solution();
            if(!solution_replay && !solved) sqlite3_exec(userdb,"UPDATE `LEVELS` SET `SOLVED` = 1 WHERE `ID` = LEVEL_ID();",0,0,0);
            if(autowin) do_autowin();
          }
        }
        redraw_game();
        timerflag=0; // ensure we have not missed a timer event
        break;
    }