Free Hero Mesh

Check-in [829b9ff683]
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 the "CLASSES" virtual table and the "CLASS_DATA" SQL function.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 829b9ff683bf46c737539fa5ae3adaa5b626b921
User & Date: user on 2018-07-14 00:19:53
Other Links: manifest | tags
Context
2018-07-14
00:23
Ensure each line of help text ends with a line break check-in: c1a1e6bede user: user tags: trunk
00:19
Implement the "CLASSES" virtual table and the "CLASS_DATA" SQL function. check-in: 829b9ff683 user: user tags: trunk
2018-07-10
05:56
Add a "maxObjects" resource. Also add some missing "extern" from declarations in heromesh.h and add a hidden "heap test" option check-in: 402432f1b2 user: user tags: trunk
Changes

Modified function.c from [aa26680e3f] to [dee2ab208b].

12
13
14
15
16
17
18












19
20
21
22
23
24
25
26



















































27
28
29
30
31
32
33
#include "heromesh.h"

typedef struct {
  struct sqlite3_vtab_cursor;
  sqlite3_int64 rowid;
  char unique,eof;
} Cursor;













static void fn_basename(sqlite3_context*cxt,int argc,sqlite3_value**argv) {
  sqlite3_result_text(cxt,basefilename,-1,SQLITE_STATIC);
}

static void fn_cacheid(sqlite3_context*cxt,int argc,sqlite3_value**argv) {
  sqlite3_result_int64(cxt,*(sqlite3_int64*)sqlite3_user_data(cxt));
}




















































static void fn_modstate(sqlite3_context*cxt,int argc,sqlite3_value**argv) {
  sqlite3_result_int(cxt,SDL_GetModState());
}

static void fn_picture_size(sqlite3_context*cxt,int argc,sqlite3_value**argv) {
  sqlite3_result_int(cxt,picture_size);







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








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







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include "heromesh.h"

typedef struct {
  struct sqlite3_vtab_cursor;
  sqlite3_int64 rowid;
  char unique,eof;
} Cursor;

static void find_first_usable_image(const Class*cl,sqlite3_context*cxt) {
  int i;
  if(cl->cflags&CF_GROUP) return;
  if(!cl->images) return;
  for(i=0;i<cl->nimages;i++) {
    if(cl->images[i]&0x8000) {
      sqlite3_result_int(cxt,i);
      return;
    }
  }
}

static void fn_basename(sqlite3_context*cxt,int argc,sqlite3_value**argv) {
  sqlite3_result_text(cxt,basefilename,-1,SQLITE_STATIC);
}

static void fn_cacheid(sqlite3_context*cxt,int argc,sqlite3_value**argv) {
  sqlite3_result_int64(cxt,*(sqlite3_int64*)sqlite3_user_data(cxt));
}

static void fn_class_data(sqlite3_context*cxt,int argc,sqlite3_value**argv) {
  int id=sqlite3_value_int(argv[0]);
  Class*cl;
  if(id<0 || id>=0x4000 || !classes[id]) return;
  cl=classes[id];
  switch(sqlite3_value_int(argv[1])&255) {
    case 0: sqlite3_result_int(cxt,id); break;
    case 1: sqlite3_result_int64(cxt,cl->temperature); break;
    case 2: sqlite3_result_int(cxt,cl->shape); break;
    case 7: find_first_usable_image(cl,cxt); break;
    case 12: sqlite3_result_int64(cxt,cl->misc4&0xFFFFFFFFULL); break;
    case 13: sqlite3_result_int64(cxt,cl->misc5&0xFFFFFFFFULL); break;
    case 14: sqlite3_result_int64(cxt,cl->misc6&0xFFFFFFFFULL); break;
    case 15: sqlite3_result_int64(cxt,cl->misc7&0xFFFFFFFFULL); break;
    case 18: sqlite3_result_int64(cxt,cl->arrivals); break;
    case 19: sqlite3_result_int64(cxt,cl->departures); break;
    case 32: sqlite3_result_int(cxt,cl->oflags&OF_BUSY?1:0); break;
    case 33: sqlite3_result_int(cxt,cl->oflags&OF_INVISIBLE?1:0); break;
    case 34: sqlite3_result_int(cxt,cl->oflags&OF_USERSIGNAL?1:0); break;
    case 35: sqlite3_result_int(cxt,cl->oflags&OF_USERSTATE?1:0); break;
    case 36: sqlite3_result_int(cxt,cl->oflags&OF_KEYCLEARED?1:0); break;
    case 37: sqlite3_result_int(cxt,cl->cflags&CF_PLAYER?1:0); break;
    case 38: sqlite3_result_int(cxt,cl->oflags&OF_DESTROYED?1:0); break;
    case 39: sqlite3_result_int(cxt,cl->oflags&OF_STEALTHY?1:0); break;
    case 40: sqlite3_result_int(cxt,cl->oflags&OF_VISUALONLY?1:0); break;
    case 64: sqlite3_result_int64(cxt,cl->density); break;
    case 65: sqlite3_result_int64(cxt,cl->volume); break;
    case 66: sqlite3_result_int64(cxt,cl->strength); break;
    case 67: sqlite3_result_int64(cxt,cl->weight); break;
    case 69: sqlite3_result_int64(cxt,cl->height); break;
    case 70: sqlite3_result_int64(cxt,cl->climb); break;
    case 72: sqlite3_result_int(cxt,cl->hard[0]); break;
    case 73: sqlite3_result_int(cxt,cl->hard[1]); break;
    case 74: sqlite3_result_int(cxt,cl->hard[2]); break;
    case 75: sqlite3_result_int(cxt,cl->hard[3]); break;
    case 76: sqlite3_result_int(cxt,cl->sharp[0]); break;
    case 77: sqlite3_result_int(cxt,cl->sharp[1]); break;
    case 78: sqlite3_result_int(cxt,cl->sharp[2]); break;
    case 79: sqlite3_result_int(cxt,cl->sharp[3]); break;
    case 80: sqlite3_result_int(cxt,(cl->shape>>0)&3); break;
    case 81: sqlite3_result_int(cxt,(cl->shape>>2)&3); break;
    case 82: sqlite3_result_int(cxt,(cl->shape>>4)&3); break;
    case 83: sqlite3_result_int(cxt,(cl->shape>>6)&3); break;
    case 84: sqlite3_result_int(cxt,cl->shovable); break;
    case 128: sqlite3_result_double(cxt,cl->volume/(double)max_volume); break;
    case 129: sqlite3_result_int(cxt,cl->uservars); break;
    case 130: sqlite3_result_int(cxt,cl->collisionLayers); break;
    case 132: sqlite3_result_int(cxt,cl->cflags&CF_COMPATIBLE?1:0); break;
  }
}

static void fn_modstate(sqlite3_context*cxt,int argc,sqlite3_value**argv) {
  sqlite3_result_int(cxt,SDL_GetModState());
}

static void fn_picture_size(sqlite3_context*cxt,int argc,sqlite3_value**argv) {
  sqlite3_result_int(cxt,picture_size);
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
static int vt0_eof(sqlite3_vtab_cursor*pcur) {
  Cursor*cur=(void*)pcur;
  return cur->eof;
}

static int vt0_index(sqlite3_vtab*vt,sqlite3_index_info*info) {
  int i;
  if(info->nOrderBy==1 && info->aOrderBy->iColumn==-1 && !info->aOrderBy->desc) info->orderByConsumed=1;
  for(i=0;i<info->nConstraint;i++) {
    if(info->aConstraint[i].iColumn==-1 && info->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ && info->aConstraint[i].usable) {
      info->aConstraintUsage[i].argvIndex=1;
      info->aConstraintUsage[i].omit=1;
      info->idxFlags=SQLITE_INDEX_SCAN_UNIQUE;
      break;
    }
  }
  return SQLITE_OK;







|

|







151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
static int vt0_eof(sqlite3_vtab_cursor*pcur) {
  Cursor*cur=(void*)pcur;
  return cur->eof;
}

static int vt0_index(sqlite3_vtab*vt,sqlite3_index_info*info) {
  int i;
  if(info->nOrderBy==1 && (info->aOrderBy->iColumn==-1 || !info->aOrderBy->iColumn) && !info->aOrderBy->desc) info->orderByConsumed=1;
  for(i=0;i<info->nConstraint;i++) {
    if((info->aConstraint[i].iColumn==-1 || !info->aConstraint[i].iColumn) && info->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ && info->aConstraint[i].usable) {
      info->aConstraintUsage[i].argvIndex=1;
      info->aConstraintUsage[i].omit=1;
      info->idxFlags=SQLITE_INDEX_SCAN_UNIQUE;
      break;
    }
  }
  return SQLITE_OK;
197
198
199
200
201
202
203
204







































































































205
206

207
208
209
210
211
212
213


214
215

Module(vt_messages,
  .xColumn=vt1_messages_column,
  .xFilter=vt1_messages_filter,
  .xNext=vt1_messages_next,
  .xUpdate=vt1_messages_update,
);








































































































void init_sql_functions(sqlite3_int64*ptr0,sqlite3_int64*ptr1) {
  sqlite3_create_function(userdb,"BASENAME",0,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_basename,0,0);

  sqlite3_create_function(userdb,"LEVEL_CACHEID",0,SQLITE_UTF8|SQLITE_DETERMINISTIC,ptr0,fn_cacheid,0,0);
  sqlite3_create_function(userdb,"MODSTATE",0,SQLITE_UTF8,0,fn_modstate,0,0);
  sqlite3_create_function(userdb,"PICTURE_SIZE",0,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_picture_size,0,0);
  sqlite3_create_function(userdb,"READ_LUMP_AT",2,SQLITE_UTF8,0,fn_read_lump_at,0,0);
  sqlite3_create_function(userdb,"RESOURCE",-1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_resource,0,0);
  sqlite3_create_function(userdb,"SIGN_EXTEND",1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_sign_extend,0,0);
  sqlite3_create_function(userdb,"SOLUTION_CACHEID",0,SQLITE_UTF8|SQLITE_DETERMINISTIC,ptr1,fn_cacheid,0,0);


  sqlite3_create_module(userdb,"MESSAGES",&vt_messages,"CREATE TABLE `MESSAGES`(`ID` INTEGER PRIMARY KEY, `NAME` TEXT, `TRACE` INT);");
}








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


>







>
>


260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
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
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384

Module(vt_messages,
  .xColumn=vt1_messages_column,
  .xFilter=vt1_messages_filter,
  .xNext=vt1_messages_next,
  .xUpdate=vt1_messages_update,
);

static int vt1_classes_column(sqlite3_vtab_cursor*pcur,sqlite3_context*cxt,int n) {
  Cursor*cur=(void*)pcur;
  switch(n) {
    case 0: // ID
      sqlite3_result_int64(cxt,cur->rowid);
      break;
    case 1: // NAME
      if(sqlite3_vtab_nochange(cxt)) return SQLITE_OK;
      sqlite3_result_text(cxt,classes[cur->rowid]->name,-1,0);
      break;
    case 2: // EDITORHELP
      if(sqlite3_vtab_nochange(cxt)) return SQLITE_OK;
      sqlite3_result_text(cxt,classes[cur->rowid]->edithelp,-1,0);
      break;
    case 3: // HELP
      if(sqlite3_vtab_nochange(cxt)) return SQLITE_OK;
      sqlite3_result_text(cxt,classes[cur->rowid]->gamehelp,-1,0);
      break;
    case 4: // INPUT
      sqlite3_result_int(cxt,classes[cur->rowid]->cflags&CF_INPUT?1:0);
      break;
    case 5: // QUIZ
      sqlite3_result_int(cxt,classes[cur->rowid]->cflags&CF_QUIZ?1:0);
      break;
    case 6: // TRACEIN
      sqlite3_result_int(cxt,classes[cur->rowid]->oflags&OF_TRACEIN?1:0);
      break;
    case 7: // TRACEOUT
      sqlite3_result_int(cxt,classes[cur->rowid]->oflags&OF_TRACEOUT?1:0);
      break;
    case 8: // GROUP
      if(sqlite3_vtab_nochange(cxt)) return SQLITE_OK;
      if(classes[cur->rowid]->cflags&CF_GROUP) {
        char*s=sqlite3_mprintf(" ");
        if(!s) return SQLITE_NOMEM;
        for(n=0;classes[cur->rowid]->codes[n];n++) {
          s=sqlite3_mprintf("%z%s ",s,classes[classes[cur->rowid]->codes[n]]->name);
          if(!s) return SQLITE_NOMEM;
        }
        sqlite3_result_text(cxt,s,-1,sqlite3_free);
      } else {
        sqlite3_result_null(cxt);
      }
      break;
    case 9: // PLAYER
      sqlite3_result_int(cxt,classes[cur->rowid]->cflags&CF_PLAYER?1:0);
      break;
  }
  return SQLITE_OK;
}

static int vt1_classes_filter(sqlite3_vtab_cursor*pcur,int idxNum,const char*idxStr,int argc,sqlite3_value**argv) {
  Cursor*cur=(void*)pcur;
  cur->eof=0;
  if(argc) {
    cur->rowid=sqlite3_value_int64(*argv);
    cur->unique=1;
    if(cur->rowid<=0 || cur->rowid>=0x4000 || !classes[cur->rowid] || classes[cur->rowid]->cflags&CF_NOCLASS2) cur->eof=1;
  } else {
    cur->unique=0;
    cur->rowid=1;
    while(cur->rowid<0x4000 && (!classes[cur->rowid] || classes[cur->rowid]->cflags&CF_NOCLASS2)) ++cur->rowid;
    if(cur->rowid>=0x4000) cur->eof=1;
  }
  return SQLITE_OK;
}

static int vt1_classes_next(sqlite3_vtab_cursor*pcur) {
  Cursor*cur=(void*)pcur;
  if(cur->unique) {
    cur->eof=1;
  } else {
    ++cur->rowid;
    while(cur->rowid<0x4000 && (!classes[cur->rowid] || classes[cur->rowid]->cflags&CF_NOCLASS2)) ++cur->rowid;
    if(cur->rowid>=0x4000) cur->eof=1;
  }
  return SQLITE_OK;
}

static int vt1_classes_update(sqlite3_vtab*vt,int argc,sqlite3_value**argv,sqlite3_int64*rowid) {
  sqlite3_int64 id;
  int v[3];
  if(argc!=5 || sqlite3_value_type(*argv)!=SQLITE_INTEGER) return SQLITE_CONSTRAINT_VTAB;
  id=sqlite3_value_int64(*argv);
  if(id!=sqlite3_value_int64(argv[1])) return SQLITE_CONSTRAINT_VTAB;
  if(id<=0 || id>=0x4000 || !classes[id]) return SQLITE_INTERNAL;
  v[0]=sqlite3_value_int(argv[5]);
  v[1]=sqlite3_value_int(argv[6]);
  v[2]=sqlite3_value_int(argv[7]);
  if((v[0]|v[1]|v[2])&~1) return SQLITE_CONSTRAINT_CHECK;
  if(v[0]) classes[id]->cflags|=CF_QUIZ; else classes[id]->cflags&=~CF_QUIZ;
  classes[id]->oflags&=~(OF_TRACEIN|OF_TRACEOUT);
  classes[id]->oflags|=(v[1]?OF_TRACEIN:0)|(v[2]?OF_TRACEOUT:0);
  return SQLITE_OK;
}

Module(vt_classes,
  .xColumn=vt1_classes_column,
  .xFilter=vt1_classes_filter,
  .xNext=vt1_classes_next,
  .xUpdate=vt1_classes_update,
);

void init_sql_functions(sqlite3_int64*ptr0,sqlite3_int64*ptr1) {
  sqlite3_create_function(userdb,"BASENAME",0,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_basename,0,0);
  sqlite3_create_function(userdb,"CLASS_DATA",2,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_class_data,0,0);
  sqlite3_create_function(userdb,"LEVEL_CACHEID",0,SQLITE_UTF8|SQLITE_DETERMINISTIC,ptr0,fn_cacheid,0,0);
  sqlite3_create_function(userdb,"MODSTATE",0,SQLITE_UTF8,0,fn_modstate,0,0);
  sqlite3_create_function(userdb,"PICTURE_SIZE",0,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_picture_size,0,0);
  sqlite3_create_function(userdb,"READ_LUMP_AT",2,SQLITE_UTF8,0,fn_read_lump_at,0,0);
  sqlite3_create_function(userdb,"RESOURCE",-1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_resource,0,0);
  sqlite3_create_function(userdb,"SIGN_EXTEND",1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_sign_extend,0,0);
  sqlite3_create_function(userdb,"SOLUTION_CACHEID",0,SQLITE_UTF8|SQLITE_DETERMINISTIC,ptr1,fn_cacheid,0,0);
  sqlite3_create_module(userdb,"CLASSES",&vt_classes,"CREATE TABLE `CLASSES`(`ID` INTEGER PRIMARY KEY, `NAME` TEXT, `EDITORHELP` TEXT, `HELP` TEXT,"
   "`INPUT` INT, `QUIZ` INT, `TRACEIN` INT, `TRACEOUT` INT, `GROUP` TEXT, `PLAYER` INT);");
  sqlite3_create_module(userdb,"MESSAGES",&vt_messages,"CREATE TABLE `MESSAGES`(`ID` INTEGER PRIMARY KEY, `NAME` TEXT, `TRACE` INT);");
}

Modified heromesh.h from [2b83b24f84] to [c2593fd5ae].

98
99
100
101
102
103
104


105
106
107
108
109
110
111
#define OF_BUSY 0x0008
#define OF_USERSTATE 0x0010
#define OF_USERSIGNAL 0x0020
#define OF_MOVED 0x0040
#define OF_DONE 0x0080
#define OF_KEYCLEARED 0x0100
#define OF_DESTROYED 0x0200



typedef struct {
  const char*name;
  const char*edithelp; // not present if CF_GROUP
  const char*gamehelp; // not present if CF_GROUP
  Uint16*codes; // if this is CF_GROUP, then instead a zero-terminated list of classes
  Uint16*messages; // use 0xFFFF if no such message block; not present if CF_GROUP







>
>







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#define OF_BUSY 0x0008
#define OF_USERSTATE 0x0010
#define OF_USERSIGNAL 0x0020
#define OF_MOVED 0x0040
#define OF_DONE 0x0080
#define OF_KEYCLEARED 0x0100
#define OF_DESTROYED 0x0200
#define OF_TRACEIN 0x4000 // These more properly belong in CF_ but there is room here for them
#define OF_TRACEOUT 0x8000 // see above

typedef struct {
  const char*name;
  const char*edithelp; // not present if CF_GROUP
  const char*gamehelp; // not present if CF_GROUP
  Uint16*codes; // if this is CF_GROUP, then instead a zero-terminated list of classes
  Uint16*messages; // use 0xFFFF if no such message block; not present if CF_GROUP