Index: exec.c ================================================================== --- exec.c +++ exec.c @@ -64,10 +64,11 @@ } #define OBJECT_ARRAY_BLOCK 256 Uint32 objalloc(Uint16 c) { // Allocates a new object of the given class; links into the event list but not into the playfield. + // All fields are initialized by the class or to zero. // Does not send any messages or otherwise notify anyone that it has been created. // Returns VOIDLINK if object cannot be created. Uint32 n; Class*cl=classes[c]; Object*o=calloc(1,sizeof(Object)+cl->uservars*sizeof(Value)); @@ -140,20 +141,20 @@ } void annihilate(void) { Uint32 i; + for(i=0;i<64*64;i++) playfield[i]=VOIDLINK; + firstobj=lastobj=VOIDLINK; if(!objects) return; for(i=0;icflags&CF_GROUP) return; @@ -93,10 +93,37 @@ int a; if(sqlite3_value_type(*argv)==SQLITE_NULL) return; a=sqlite3_value_int(*argv)&0xFFFF; sqlite3_result_int64(cxt,a|((sqlite3_int64)TY_CLASS<<32)); } + +static void fn_heromesh_type(sqlite3_context*cxt,int argc,sqlite3_value**argv) { + static const char*const n[16]={ + [TY_NUMBER]="number", + [TY_CLASS]="class", + [TY_MESSAGE]="message", + [TY_LEVELSTRING]="string", + [TY_STRING]="string", + [TY_SOUND]="sound", + [TY_USOUND]="sound", + }; + int i; + if(sqlite3_value_type(*argv)!=SQLITE_INTEGER) return; + i=sqlite3_value_int64(*argv)>>32; + sqlite3_result_text(cxt,i<0||i>TY_MAXTYPE?"object":n[i]?:"???",-1,SQLITE_STATIC); +} + +static void fn_load_level(sqlite3_context*cxt,int argc,sqlite3_value**argv) { + const char*s; + if(!main_options['x']) { + sqlite3_result_error(cxt,"LOAD_LEVEL function requires -x switch",-1); + return; + } + if(sqlite3_value_type(*argv)==SQLITE_NULL) return; + s=load_level(sqlite3_value_int(*argv)); + if(s) sqlite3_result_error(cxt,s,-1); +} static void fn_modstate(sqlite3_context*cxt,int argc,sqlite3_value**argv) { sqlite3_result_int(cxt,SDL_GetModState()); } @@ -115,10 +142,14 @@ } a=sqlite3_value_int64(*argv)&0xFFFFFFFF; if(a>=nobjects || !objects[a] || (objects[a]->dir&IOF_DEAD)) return; // result is null if object does not exist sqlite3_result_int64(cxt,a|((sqlite3_int64)objects[a]->generation<<32)); } + +static void fn_pfsize(sqlite3_context*cxt,int argc,sqlite3_value**argv) { + sqlite3_result_int(cxt,*(Uint8*)sqlite3_user_data(cxt)); +} static void fn_picture_size(sqlite3_context*cxt,int argc,sqlite3_value**argv) { sqlite3_result_int(cxt,picture_size); } @@ -400,28 +431,315 @@ .xNext=vt1_classes_next, .xUpdate=vt1_classes_update, ); static int vt1_objects_column(sqlite3_vtab_cursor*pcur,sqlite3_context*cxt,int n) { - return SQLITE_OK; -} - -static int vt1_objects_filter(sqlite3_vtab_cursor*pcur,int idxNum,const char*idxStr,int argc,sqlite3_value**argv) { - return SQLITE_OK; -} - -static int vt1_objects_index(sqlite3_vtab*vt,sqlite3_index_info*info) { - + Cursor*cur=(void*)pcur; + switch(n) { + case 0: // ID + sqlite3_result_int64(cxt,cur->rowid); + break; + case 1: // CLASS + sqlite3_result_int(cxt,objects[cur->rowid]->class); + break; + case 2: // MISC1 + sqlite3_result_int64(cxt,ValueTo64(objects[cur->rowid]->misc1)); + break; + case 3: // MISC2 + sqlite3_result_int64(cxt,ValueTo64(objects[cur->rowid]->misc2)); + break; + case 4: // MISC3 + sqlite3_result_int64(cxt,ValueTo64(objects[cur->rowid]->misc3)); + break; + case 5: // IMAGE + sqlite3_result_int(cxt,objects[cur->rowid]->image); + break; + case 6: // DIR + sqlite3_result_int(cxt,objects[cur->rowid]->dir&7); + break; + case 7: // X + sqlite3_result_int(cxt,objects[cur->rowid]->x); + break; + case 8: // Y + sqlite3_result_int(cxt,objects[cur->rowid]->y); + break; + case 9: // UP + if(objects[cur->rowid]->up!=VOIDLINK) sqlite3_result_int64(cxt,objects[cur->rowid]->up); + break; + case 10: // DOWN + if(objects[cur->rowid]->down!=VOIDLINK) sqlite3_result_int64(cxt,objects[cur->rowid]->down); + break; + case 11: // DENSITY + sqlite3_result_int(cxt,objects[cur->rowid]->density); + break; + } return SQLITE_OK; } static int vt1_objects_next(sqlite3_vtab_cursor*pcur) { + Cursor*cur=(void*)pcur; + if(cur->unique) { + eof: + cur->eof=1; + return SQLITE_OK; + } + again: + if(cur->arg[0]&0x0008) { + // Ordered by ID + if(cur->arg[1] || !objects[cur->rowid]) { + for(;;) { + if(++cur->rowid>=nobjects) { + cur->eof=1; + break; + } + if(objects[cur->rowid]) break; + } + } + cur->arg[1]=1; + } else if((cur->arg[0]&0x0006) && !cur->arg[1]) { + // Find top/bottom at location + cur->arg[1]=1; + atxy: + cur->rowid=playfield[cur->arg[2]+cur->arg[3]*64-65]; + if(cur->rowid==VOIDLINK) goto nextxy; + if(cur->arg[0]&0x0020) { + while(cur->rowid!=VOIDLINK && objects[cur->rowid]->up!=VOIDLINK) cur->rowid=objects[cur->rowid]->up; + } + } else if(cur->arg[0]&0x0020) { + // Go down + cur->rowid=objects[cur->rowid]->down; + if(cur->rowid==VOIDLINK) goto nextxy; + } else if(cur->arg[0]&0x0040) { + // Go up + cur->rowid=objects[cur->rowid]->up; + if(cur->rowid==VOIDLINK) { + nextxy: + if(cur->arg[0]&0x1000) { + cur->arg[2]+=cur->arg[0]&0x0400?-1:1; + if(cur->arg[0]&0x0002) goto eof; + if(cur->arg[2]<1 || cur->arg[2]>pfwidth) { + if(cur->arg[0]&0x0004) goto eof; + cur->arg[2]=cur->arg[0]&0x0400?pfwidth:1; + cur->arg[3]+=cur->arg[0]&0x4000?-1:1; + if(cur->arg[3]<1 || cur->arg[3]>pfheight) goto eof; + } + } else { + cur->arg[3]+=cur->arg[0]&0x4000?-1:1; + if(cur->arg[0]&0x0004) goto eof; + if(cur->arg[3]<1 || cur->arg[3]>pfheight) { + if(cur->arg[0]&0x0002) goto eof; + cur->arg[3]=cur->arg[0]&0x4000?pfheight:1; + cur->arg[2]+=cur->arg[0]&0x0400?-1:1; + if(cur->arg[2]<1 || cur->arg[2]>pfwidth) goto eof; + } + } + goto atxy; + } + } else { + // This shouldn't happen + return SQLITE_INTERNAL; + } + if(!cur->eof && (objects[cur->rowid]->dir&IOF_DEAD)) goto again; return SQLITE_OK; } + +static int vt1_objects_filter(sqlite3_vtab_cursor*pcur,int idxNum,const char*idxStr,int argc,sqlite3_value**argv) { + Cursor*cur=(void*)pcur; + int i; + Uint32 t; + cur->rowid=-1; + cur->unique=0; + cur->eof=0; + cur->arg[0]=idxNum; + cur->arg[1]=0; + cur->arg[2]=cur->arg[3]=1; + if(!nobjects) { + cur->eof=1; + return SQLITE_OK; + } + if(idxStr) for(i=0;idxStr[i];i++) switch(idxStr[i]) { + case 'a': + cur->rowid=sqlite3_value_int64(argv[i]); + cur->unique=1; + break; + case 'b': + if(cur->rowidrowid=sqlite3_value_int64(argv[i]); + cur->arg[1]=1; + if(cur->unique) cur->eof=1; + } + break; + case 'c': + if(cur->rowid<=sqlite3_value_int64(argv[i])) { + cur->rowid=sqlite3_value_int64(argv[i]); + cur->arg[1]=0; + if(cur->unique) cur->eof=1; + } + break; + case 'd': + cur->arg[2]=sqlite3_value_int(argv[i]); + if(cur->arg[2]<1 || cur->arg[2]>64) cur->eof=1; + break; + case 'e': + cur->arg[3]=sqlite3_value_int(argv[i]); + if(cur->arg[2]<1 || cur->arg[2]>64) cur->eof=1; + break; + case 'f': + if(sqlite3_value_type(argv[i])==SQLITE_NULL) { + cur->arg[0]=idxNum&=~0x0010; + } else { + t=sqlite3_value_int64(argv[i]); + if(t>=nobjects || t<0 || !objects[t]) { + cur->eof=1; + break; + } + cur->rowid=objects[t]->down; + if(cur->rowid==VOIDLINK) cur->eof=1; + cur->unique=1; + } + break; + case 'g': + if(sqlite3_value_type(argv[i])==SQLITE_NULL) { + cur->arg[0]=idxNum&=~0x0010; + } else { + t=sqlite3_value_int64(argv[i]); + if(t>=nobjects || t<0 || !objects[t]) { + cur->eof=1; + break; + } + cur->rowid=objects[t]->up; + if(cur->rowid==VOIDLINK) cur->eof=1; + cur->unique=1; + } + break; + } + if(cur->unique) { + if(cur->rowid<0 || cur->rowid>=nobjects || !objects[cur->rowid]) cur->eof=1; + return SQLITE_OK; + } + if(cur->eof) return SQLITE_OK; + if(idxNum&0x0400) cur->arg[2]=pfwidth; + if(idxNum&0x4000) cur->arg[3]=pfheight; + if(cur->rowid==-1) cur->rowid=0; + return vt1_objects_next(pcur); +} + +static int vt1_objects_index(sqlite3_vtab*vt,sqlite3_index_info*info) { + sqlite3_str*str=sqlite3_str_new(0); + int arg=0; + int i,j; + info->estimatedCost=100000.0; + for(i=0;inConstraint;i++) if(info->aConstraint[i].usable) { + j=info->aConstraint[i].op; + switch(info->aConstraint[i].iColumn) { + case -1: case 0: // ID + if(info->idxNum&0x0017) break; + if(j==SQLITE_INDEX_CONSTRAINT_EQ || j==SQLITE_INDEX_CONSTRAINT_IS) { + info->idxNum|=0x0001; + info->aConstraintUsage[i].omit=1; + info->aConstraintUsage[i].argvIndex=++arg; + info->idxFlags=SQLITE_INDEX_SCAN_UNIQUE; + sqlite3_str_appendchar(str,1,'a'); + info->estimatedCost/=10000.0; + } else if(j==SQLITE_INDEX_CONSTRAINT_GT || j==SQLITE_INDEX_CONSTRAINT_GE) { + info->idxNum|=0x0008; + info->aConstraintUsage[i].omit=1; + info->aConstraintUsage[i].argvIndex=++arg; + sqlite3_str_appendchar(str,1,j==SQLITE_INDEX_CONSTRAINT_GT?'b':'c'); + info->estimatedCost/=1200.0; + } + break; + case 7: // X + if(info->idxNum&0x0013) break; + if(j==SQLITE_INDEX_CONSTRAINT_EQ || j==SQLITE_INDEX_CONSTRAINT_IS) { + info->idxNum|=0x0002; + info->aConstraintUsage[i].omit=1; + info->aConstraintUsage[i].argvIndex=++arg; + sqlite3_str_appendchar(str,1,'d'); + info->estimatedCost/=64.0; + } + break; + case 8: // Y + if(info->idxNum&0x0015) break; + if(j==SQLITE_INDEX_CONSTRAINT_EQ || j==SQLITE_INDEX_CONSTRAINT_IS) { + info->idxNum|=0x0004; + info->aConstraintUsage[i].omit=1; + info->aConstraintUsage[i].argvIndex=++arg; + sqlite3_str_appendchar(str,1,'e'); + info->estimatedCost/=64.0; + } + break; + case 9: // UP + if(info->idxNum&0x0019) break; + if(j==SQLITE_INDEX_CONSTRAINT_IS && !(info->idxNum&0x000E)) { + info->idxNum|=0x0010; + info->aConstraintUsage[i].omit=1; + info->aConstraintUsage[i].argvIndex=++arg; + sqlite3_str_appendchar(str,1,'f'); + info->estimatedCost/=80.0; + } + break; + case 10: // DOWN + if(info->idxNum&0x0019) break; + if(j==SQLITE_INDEX_CONSTRAINT_IS && !(info->idxNum&0x000E)) { + info->idxNum|=0x0010; + info->aConstraintUsage[i].omit=1; + info->aConstraintUsage[i].argvIndex=++arg; + sqlite3_str_appendchar(str,1,'g'); + info->estimatedCost/=80.0; + } + break; + } + } + if(info->nOrderBy==1) { + if(info->aOrderBy->iColumn==0 && !info->aOrderBy->desc && !(info->idxNum&~0x0008)) info->orderByConsumed=1; + if(info->aOrderBy->iColumn==-1 && !info->aOrderBy->desc && !(info->idxNum&~0x0008)) info->orderByConsumed=1; + if(info->aOrderBy->iColumn==7 && !(info->idxNum&~0x0004)) info->orderByConsumed=1,info->idxNum|=info->aOrderBy->desc?0x0400:0x0800; + if(info->aOrderBy->iColumn==8 && !(info->idxNum&~0x0002)) info->orderByConsumed=1,info->idxNum|=info->aOrderBy->desc?0x4000:0x8000; + if(info->aOrderBy->iColumn==11 && info->idxNum==0x0006) info->orderByConsumed=1,info->idxNum|=info->aOrderBy->desc?0x0040:0x0020; + } else if(info->nOrderBy==2 && !(info->idxNum&~0x0066)) { + if(info->aOrderBy[0].iColumn==7 && info->aOrderBy[1].iColumn==8) { + info->orderByConsumed=1; + info->idxNum|=info->aOrderBy[0].desc?0x0400:0x0800; + info->idxNum|=info->aOrderBy[1].desc?0x4000:0x8000; + } else if(info->aOrderBy[0].iColumn==8 && info->aOrderBy[1].iColumn==7) { + info->orderByConsumed=1; + info->idxNum|=info->aOrderBy[0].desc?0x4000:0x8000; + info->idxNum|=info->aOrderBy[1].desc?0x0400:0x0800; + info->idxNum|=0x1000; + } + } else if(info->nOrderBy==3 && info->aOrderBy[2].iColumn==11 && !(info->idxNum&~0x0006)) { + if(info->aOrderBy[0].iColumn==7 && info->aOrderBy[1].iColumn==8) { + info->orderByConsumed=1; + info->idxNum|=info->aOrderBy[0].desc?0x0400:0x0800; + info->idxNum|=info->aOrderBy[1].desc?0x4000:0x8000; + info->idxNum|=info->aOrderBy[2].desc?0x0040:0x0020; + } else if(info->aOrderBy[0].iColumn==8 && info->aOrderBy[1].iColumn==7) { + info->orderByConsumed=1; + info->idxNum|=info->aOrderBy[0].desc?0x4000:0x8000; + info->idxNum|=info->aOrderBy[1].desc?0x0400:0x0800; + info->idxNum|=0x1000; + info->idxNum|=info->aOrderBy[2].desc?0x0040:0x0020; + } + } + if(info->orderByConsumed) info->estimatedCost-=0.5; + switch(info->idxNum&0x0006) { + case 0x0002: info->idxNum&=~0x1000; break; + case 0x0004: info->idxNum|=0x1000; break; + } + if(!info->idxNum) info->idxNum=0x0008; + if((info->idxNum&0x0006) && !(info->idxNum&0x0060)) info->idxNum|=0x0040; + if((info->idxNum&0xCC00) && !(info->idxNum&0x0069)) info->idxNum|=0x0040; + arg=sqlite3_str_errcode(str); + info->idxStr=sqlite3_str_finish(str); + info->needToFreeIdxStr=1; + return arg; +} static int vt1_objects_update(sqlite3_vtab*vt,int argc,sqlite3_value**argv,sqlite3_int64*rowid) { if(!main_options['e']) return SQLITE_LOCKED; + return SQLITE_OK; } Module(vt_objects, .xBestIndex=vt1_objects_index, @@ -432,16 +750,20 @@ ); 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,"CVALUE",1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_cvalue,0,0); + sqlite3_create_function(userdb,"HEROMESH_TYPE",1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_heromesh_type,0,0); sqlite3_create_function(userdb,"LEVEL_CACHEID",0,SQLITE_UTF8|SQLITE_DETERMINISTIC,ptr0,fn_cacheid,0,0); + sqlite3_create_function(userdb,"LOAD_LEVEL",1,SQLITE_UTF8,0,fn_load_level,0,0); sqlite3_create_function(userdb,"MODSTATE",0,SQLITE_UTF8,0,fn_modstate,0,0); - sqlite3_create_function(userdb,"CVALUE",1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_cvalue,0,0); sqlite3_create_function(userdb,"MVALUE",1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_mvalue,0,0); sqlite3_create_function(userdb,"NVALUE",1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_zero_extend,0,0); sqlite3_create_function(userdb,"OVALUE",1,SQLITE_UTF8,0,fn_ovalue,0,0); + sqlite3_create_function(userdb,"PFHEIGHT",0,SQLITE_UTF8,&pfheight,fn_pfsize,0,0); + sqlite3_create_function(userdb,"PFWIDTH",0,SQLITE_UTF8,&pfwidth,fn_pfsize,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); Index: heromesh.h ================================================================== --- heromesh.h +++ heromesh.h @@ -8,15 +8,16 @@ #define boolxrm(a,b) (*a=='1'||*a=='y'||*a=='t'||*a=='Y'||*a=='T'?1:*a=='0'||*a=='n'||*a=='f'||*a=='N'||*a=='F'?0:b) #define TY_NUMBER 0 #define TY_CLASS 1 #define TY_MESSAGE 2 -#define TY_SOUND 3 -#define TY_USOUND 4 -#define TY_STRING 5 -#define TY_LEVELSTRING 6 +#define TY_LEVELSTRING 3 +#define TY_STRING 4 +#define TY_SOUND 5 +#define TY_USOUND 6 #define TY_MAXTYPE 15 +// The level file format requires type codes 0 to 3 to be as is; other codes may change. typedef struct { union { Sint32 s; Uint32 u; @@ -28,10 +29,11 @@ #define NVALUE(x) SVALUE(x,TY_NUMBER) #define CVALUE(x) UVALUE(x,TY_CLASS) #define MVALUE(x) UVALUE(x,TY_MESSAGE) #define ZVALUE(x) UVALUE(x,TY_STRING) #define OVALUE(x) UVALUE(x,objects[x]->generation) +#define ValueTo64(v) (((sqlite3_int64)((v).u))|(((sqlite3_int64)((v).t))<<32)) #define N_MESSAGES 23 extern const char*const standard_message_names[]; extern const char*const standard_sound_names[]; extern const char*const heromesh_key_names[256]; @@ -62,10 +64,11 @@ #define StackProtection() 0 #endif unsigned char*read_lump(int sol,int lvl,long*sz,sqlite3_value**us); void write_lump(int sol,int lvl,long sz,const unsigned char*data); +const char*load_level(int lvl); void set_cursor(int id); #define FIL_SOLUTION 1 #define FIL_LEVEL 0 #define LUMP_LEVEL_IDX (-1) Index: main.c ================================================================== --- main.c +++ main.c @@ -175,10 +175,131 @@ sqlite3_bind_blob64(st,4,data,sz,0); while((e=sqlite3_step(st))==SQLITE_ROW); if(e!=SQLITE_DONE) fatal("SQL error (%d): %s\n",e,sqlite3_errmsg(userdb)); sqlite3_finalize(st); } + +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; + unsigned char*buf=lvl>=0?read_lump(FIL_LEVEL,lvl,&sz,0):0; + unsigned char*p=buf; + unsigned char*end=buf+sz; + int i,n,x,y,z; + Uint32 o; + Uint32 mru[2]; + if(lvl<0) return "Invalid level ID"; + if(!buf) return "Cannot find level"; + annihilate(); + generation_number=TY_MAXTYPE+1; + p+=4; // skip level version and level code for now + pfwidth=(*p++&63)+1; + pfheight=(*p++&63)+1; + while(*p && pclass); + if(o==VOIDLINK) goto bad3; + objects[o]->image=objects[*mru]->image; + objects[o]->misc1=objects[*mru]->misc1; + objects[o]->misc2=objects[*mru]->misc2; + objects[o]->misc3=objects[*mru]->misc3; + objects[o]->dir=objects[*mru]->dir; + objects[o]->x=++x; + objects[o]->y=y; + if(x>pfwidth) goto bad2; + pflink(o); + --n; + } else { + if(p>=end) goto bad1; + z=*p++; + if(z==0xFF) break; + if(z&0x20) x=*p++; + if(z&0x10) y=*p++; + if(z&0x40) x++; + if(!x || !y || x>pfwidth || y>pfheight) goto bad2; + if(z&0x80) { + // MRU + n=playfield[x+y*64-65]==VOIDLINK?0:1; + if(mru[n]==VOIDLINK) goto bad1; + o=objalloc(objects[mru[n]]->class); + if(o==VOIDLINK) goto bad3; + objects[o]->image=objects[mru[n]]->image; + objects[o]->misc1=objects[mru[n]]->misc1; + objects[o]->misc2=objects[mru[n]]->misc2; + objects[o]->misc3=objects[mru[n]]->misc3; + objects[o]->dir=objects[mru[n]]->dir; + objects[o]->x=x; + objects[o]->y=y; + pflink(o); + n=z&15; + } else { + // Not MRU + n=playfield[x+y*64-65]; + n=n==VOIDLINK?0:objects[n]->down==VOIDLINK?1:2; + i=*p++; + i|=*p++<<8; + o=objalloc(i&0x3FFF); + if(o==VOIDLINK) goto bad3; + if(n!=2) mru[n]=o; + if(i&0x8000) { + n=objects[o]->class; + for(i=0;inimages;i++) { + if(classes[n]->images[i]&0x8000) { + objects[o]->image=i; + break; + } + } + } else { + objects[o]->image=*p++; + } + objects[o]->dir=z&7; + if(z&0x08) { + z=*p++; + if(z&0xC0) { + // Misc1 + objects[o]->misc1=UVALUE(p[0]|(p[1]<<8),(z>>0)&3); + p+=2; + } + if((z&0xC0)!=0x40) { + // Misc2 + objects[o]->misc2=UVALUE(p[0]|(p[1]<<8),(z>>2)&3); + p+=2; + } + if(!((z&0xC0)%0xC0)) { + // Misc3 + objects[o]->misc1=UVALUE(p[0]|(p[1]<<8),(z>>4)&3); + p+=2; + } + } + objects[o]->x=x; + objects[o]->y=y; + pflink(o); + n=0; + } + } + } + // skip level strings for now + if(p>end) goto bad1; + free(buf); + return 0; +bad1: + free(buf); + return "Corrupted level data"; +bad2: + free(buf); + return "Object out of bounds"; +bad3: + free(buf); + return "Bad object in level"; +} static void flush_usercache_1(int sol) { sqlite3_int64 uc_id=sol?solutionuc:leveluc; FILE*fp=sol?solutionfp:levelfp; int fd=fileno(fp); @@ -524,20 +645,21 @@ } } static void do_sql_mode(void) { int m=sqlite3_limit(userdb,SQLITE_LIMIT_SQL_LENGTH,-1); - char*txt=malloc(m); + char*txt; int n=0; int c; int bail=1; if(m>1000000) m=1000000; txt=malloc(m+2); if(!txt) fatal("Allocation failed\n"); for(;;) { c=fgetc(stdin); if(c=='\n' || c==EOF) { + if(!n && c==EOF) break; if(!n) continue; if(*txt=='#') { n=0; } else if(*txt=='.') { txt[n]=0; @@ -554,10 +676,11 @@ } else { txt[n]=0; if(sqlite3_complete(txt)) { n=sqlite3_exec(userdb,txt,test_sql_callback,0,0); if(bail && n) fatal("SQL error (%d): %s\n",n,sqlite3_errmsg(userdb)); + else if(n) fprintf(stderr,"SQL error (%d): %s\n",n,sqlite3_errmsg(userdb)); n=0; } else { txt[n++]='\n'; } } @@ -634,14 +757,15 @@ test_mode(); return 0; } init_usercache(); load_classes(); + optionquery[1]=Q_maxObjects; + max_objects=strtoll(xrm_get_resource(resourcedb,optionquery,optionquery,2)?:"",0,0)?:0xFFFF0000L; + annihilate(); if(main_options['x']) { fprintf(stderr,"Ready for executing SQL statements.\n"); do_sql_mode(); return 0; } - optionquery[1]=Q_maxObjects; - max_objects=strtoll(xrm_get_resource(resourcedb,optionquery,optionquery,2)?:"",0,0)?:0xFFFF0000L; return 0; // for(;;) { if(main_options['e']) run_editor(); else run_game(); } }