Free Hero Mesh

Check-in [a731b53535]
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 loading the level divisions table; currently it does not do anything with this table, which will be implemented later.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: a731b53535327017a4f8c66d18a376455dcab6ab
User & Date: user on 2022-01-02 21:04:59
Other Links: manifest | tags
Context
2022-01-04
02:21
Implement level index editor, including divisions. (Currently, the divisions is not used outside of the level index editor; later, this should be fixed) check-in: 8117ec3cff user: user tags: trunk
2022-01-02
21:04
Implement loading the level divisions table; currently it does not do anything with this table, which will be implemented later. check-in: a731b53535 user: user tags: trunk
2022-01-01
01:20
Move frequently questions to the separate file, and mention custom columns of LEVELS table in SQL documentation. check-in: c7613ace1d user: user tags: trunk
Changes

Modified main.c from [f3572b0f94] to [9e06dc1a0b].

36
37
38
39
40
41
42

43
44
45
46
47
48
49
  "PRAGMA RECURSIVE_TRIGGERS(1);"
  "CREATE TABLE IF NOT EXISTS `USERCACHEINDEX`(`ID` INTEGER PRIMARY KEY, `NAME` TEXT, `TIME` INT);"
  "CREATE TABLE IF NOT EXISTS `USERCACHEDATA`(`ID` INTEGER PRIMARY KEY, `FILE` INT, `LEVEL` INT, `NAME` TEXT COLLATE NOCASE, `OFFSET` INT, `DATA` BLOB, `USERSTATE` BLOB);"
  "CREATE UNIQUE INDEX IF NOT EXISTS `USERCACHEDATA_I1` ON `USERCACHEDATA`(`FILE`, `LEVEL`);"
  "CREATE TRIGGER IF NOT EXISTS `USERCACHEINDEX_DELETION` AFTER DELETE ON `USERCACHEINDEX` BEGIN DELETE FROM `USERCACHEDATA` WHERE `FILE` = OLD.`ID`; END;"
  "CREATE TEMPORARY TABLE `PICTURES`(`ID` INTEGER PRIMARY KEY, `NAME` TEXT COLLATE NOCASE, `OFFSET` INT, `DEPENDENT` INT);"
  "CREATE TEMPORARY TABLE `VARIABLES`(`ID` INTEGER PRIMARY KEY, `NAME` TEXT);"

  "COMMIT;"
;

sqlite3*userdb;
xrm_db*resourcedb;
const char*basefilename;
xrm_quark optionquery[16];







>







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
  "PRAGMA RECURSIVE_TRIGGERS(1);"
  "CREATE TABLE IF NOT EXISTS `USERCACHEINDEX`(`ID` INTEGER PRIMARY KEY, `NAME` TEXT, `TIME` INT);"
  "CREATE TABLE IF NOT EXISTS `USERCACHEDATA`(`ID` INTEGER PRIMARY KEY, `FILE` INT, `LEVEL` INT, `NAME` TEXT COLLATE NOCASE, `OFFSET` INT, `DATA` BLOB, `USERSTATE` BLOB);"
  "CREATE UNIQUE INDEX IF NOT EXISTS `USERCACHEDATA_I1` ON `USERCACHEDATA`(`FILE`, `LEVEL`);"
  "CREATE TRIGGER IF NOT EXISTS `USERCACHEINDEX_DELETION` AFTER DELETE ON `USERCACHEINDEX` BEGIN DELETE FROM `USERCACHEDATA` WHERE `FILE` = OLD.`ID`; END;"
  "CREATE TEMPORARY TABLE `PICTURES`(`ID` INTEGER PRIMARY KEY, `NAME` TEXT COLLATE NOCASE, `OFFSET` INT, `DEPENDENT` INT);"
  "CREATE TEMPORARY TABLE `VARIABLES`(`ID` INTEGER PRIMARY KEY, `NAME` TEXT);"
  "CREATE TEMPORARY TABLE `DIVISIONS`(`HEADING` BLOB NOT NULL, `FIRST` INT NOT NULL);"
  "COMMIT;"
;

sqlite3*userdb;
xrm_db*resourcedb;
const char*basefilename;
xrm_quark optionquery[16];
195
196
197
198
199
200
201


202
203
204
205
206
207
208
      for(z=0;z<i-4;z++) if(buf[z]<'0' || buf[z]>'9') goto nomatch;
      if(*buf=='0' && i!=5) goto nomatch;
      sqlite3_bind_int(st,2,strtol(buf,0,10));
    } else if(i==9 && suffix[1]=='L' && !sqlite3_stricmp(buf,"CLASS.DEF")) {
      sqlite3_bind_int(st,2,LUMP_CLASS_DEF);
    } else if(i==9 && suffix[1]=='L' && !sqlite3_stricmp(buf,"LEVEL.IDX")) {
      sqlite3_bind_int(st,2,LUMP_LEVEL_IDX);


    } else {
      nomatch: sqlite3_bind_null(st,2);
    }
    while((z=sqlite3_step(st))==SQLITE_ROW);
    if(z!=SQLITE_DONE) fatal("SQL error (%d): %s\n",z,sqlite3_errmsg(userdb));
    fseek(fp,t,SEEK_CUR);
  }







>
>







196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
      for(z=0;z<i-4;z++) if(buf[z]<'0' || buf[z]>'9') goto nomatch;
      if(*buf=='0' && i!=5) goto nomatch;
      sqlite3_bind_int(st,2,strtol(buf,0,10));
    } else if(i==9 && suffix[1]=='L' && !sqlite3_stricmp(buf,"CLASS.DEF")) {
      sqlite3_bind_int(st,2,LUMP_CLASS_DEF);
    } else if(i==9 && suffix[1]=='L' && !sqlite3_stricmp(buf,"LEVEL.IDX")) {
      sqlite3_bind_int(st,2,LUMP_LEVEL_IDX);
    } else if(i==12 && suffix[1]=='L' && !sqlite3_stricmp(buf,"DIVISION.IDX")) {
      sqlite3_bind_int(st,2,LUMP_DIVISION_IDX);
    } else {
      nomatch: sqlite3_bind_null(st,2);
    }
    while((z=sqlite3_step(st))==SQLITE_ROW);
    if(z!=SQLITE_DONE) fatal("SQL error (%d): %s\n",z,sqlite3_errmsg(userdb));
    fseek(fp,t,SEEK_CUR);
  }
275
276
277
278
279
280
281

282
283

284
285
286
287
288
289




















290
291
292
293
294
295
296
  while((e=sqlite3_step(st))==SQLITE_ROW);
  if(e!=SQLITE_DONE) fatal("SQL error (%d): %s\n",e,sqlite3_errmsg(userdb));
  sqlite3_finalize(st);
}

static void load_level_index(void) {
  long sz;

  int i;
  unsigned char*data=read_lump(FIL_LEVEL,LUMP_LEVEL_IDX,&sz);

  if(!data) return;
  if(sz>65536) fatal("Too many levels\n");
  level_index=malloc((level_nindex=sz>>1)*sizeof(Uint16));
  if(!level_index) fatal("Allocation failed\n");
  for(i=0;i<level_nindex;i++) level_index[i]=data[i+i]|(data[i+i+1]<<8);
  free(data);




















}

const char*load_level(int lvl) {
  // Load level by ID. Returns null pointer if successful, or an error message if it failed.
  long sz=0;
  Uint16 of=0;
  unsigned char*buf=lvl>=0?read_lump(FIL_LEVEL,lvl,&sz):0;







>


>






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







278
279
280
281
282
283
284
285
286
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
  while((e=sqlite3_step(st))==SQLITE_ROW);
  if(e!=SQLITE_DONE) fatal("SQL error (%d): %s\n",e,sqlite3_errmsg(userdb));
  sqlite3_finalize(st);
}

static void load_level_index(void) {
  long sz;
  sqlite3_stmt*st;
  int i;
  unsigned char*data=read_lump(FIL_LEVEL,LUMP_LEVEL_IDX,&sz);
  unsigned char*p;
  if(!data) return;
  if(sz>65536) fatal("Too many levels\n");
  level_index=malloc((level_nindex=sz>>1)*sizeof(Uint16));
  if(!level_index) fatal("Allocation failed\n");
  for(i=0;i<level_nindex;i++) level_index[i]=data[i+i]|(data[i+i+1]<<8);
  free(data);
  // Load divisions
  data=read_lump(FIL_LEVEL,LUMP_DIVISION_IDX,&sz);
  if(!data || sz<3) {
    free(data);
    return;
  }
  if(i=sqlite3_prepare_v2(userdb,"INSERT INTO `DIVISIONS`(`HEADING`,`FIRST`) VALUES(?1,?2);",-1,&st,0))
   fatal("SQL error (%d): %s\n",i,sqlite3_errmsg(userdb));
  p=data;
  while(p<data+sz-3) {
    sqlite3_reset(st);
    sqlite3_bind_int(st,2,p[0]|(p[1]<<8));
    p+=2;
    sqlite3_bind_blob(st,1,p,i=strnlen(p,data+sz-p),0);
    p+=i;
    if(p<data+sz) p++;
    while(sqlite3_step(st)==SQLITE_ROW);
  }
  sqlite3_finalize(st);
  free(data);
}

const char*load_level(int lvl) {
  // Load level by ID. Returns null pointer if successful, or an error message if it failed.
  long sz=0;
  Uint16 of=0;
  unsigned char*buf=lvl>=0?read_lump(FIL_LEVEL,lvl,&sz):0;

Modified sql.doc from [39d3d35105] to [4e8a641099].

173
174
175
176
177
178
179









180
181
182
183
184
185
186
TEXT, "HELP" TEXT, "INPUT" INT, "QUIZ" INT, "TRACEIN" INT, "TRACEOUT" INT,
"GROUP" TEXT, "PLAYER" INT); *
  A list of classes in the current puzzle set; mostly read-only. Only
  QUIZ, TRACEIN, and TRACEOUT are writable. If TRACEIN is true then it
  will trace messages received by this class (if tracing is enabled). If
  TRACEOUT is true then it will trace messages sent by this class (if
  tracing is enabled).










CREATE TABLE "INVENTORY"("ID" INTEGER PRIMARY KEY, "CLASS" INT, "IMAGE"
INT, "VALUE" INT); *
  This table contains the current inventory, and is read-only. It is not
  meaningful in the editor.

CREATE TEMPORARY TABLE "LEVELS"("ID" INTEGER PRIMARY KEY, "ORD" INT,







>
>
>
>
>
>
>
>
>







173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
TEXT, "HELP" TEXT, "INPUT" INT, "QUIZ" INT, "TRACEIN" INT, "TRACEOUT" INT,
"GROUP" TEXT, "PLAYER" INT); *
  A list of classes in the current puzzle set; mostly read-only. Only
  QUIZ, TRACEIN, and TRACEOUT are writable. If TRACEIN is true then it
  will trace messages received by this class (if tracing is enabled). If
  TRACEOUT is true then it will trace messages sent by this class (if
  tracing is enabled).

CREATE TEMPORARY TABLE "DIVISIONS"("HEADING" BLOB NOT NULL, "FIRST" INT
NOT NULL);
  The list of level divisions. The HEADING is the (unformatted) heading
  text, and the FIRST is the order number (not ID number) of the first
  level to which this heading applies. (Note: Writing to this table by
  use of SQL statements will not automatically update the puzzle set.
  However, if you use SQL and then use the level index editor, then that
  will make the changes permanent.)

CREATE TABLE "INVENTORY"("ID" INTEGER PRIMARY KEY, "CLASS" INT, "IMAGE"
INT, "VALUE" INT); *
  This table contains the current inventory, and is read-only. It is not
  meaningful in the editor.

CREATE TEMPORARY TABLE "LEVELS"("ID" INTEGER PRIMARY KEY, "ORD" INT,