Index: function.c ================================================================== --- function.c +++ function.c @@ -14,18 +14,81 @@ 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;inimages;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()); } @@ -90,13 +153,13 @@ 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; + if(info->nOrderBy==1 && (info->aOrderBy->iColumn==-1 || !info->aOrderBy->iColumn) && !info->aOrderBy->desc) info->orderByConsumed=1; for(i=0;inConstraint;i++) { - if(info->aConstraint[i].iColumn==-1 && info->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ && info->aConstraint[i].usable) { + 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; } @@ -199,17 +262,123 @@ .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);"); } Index: heromesh.h ================================================================== --- heromesh.h +++ heromesh.h @@ -100,10 +100,12 @@ #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