Index: class.c ================================================================== --- class.c +++ class.c @@ -247,14 +247,14 @@ if(classes[c]->nmsg<=m) return 0xFFFF; return classes[c]->messages[m]; } static void set_message_ptr(int c,int m,int p) { - if(m>classes[c]->nmsg) { + if(m>=classes[c]->nmsg) { classes[c]->messages=realloc(classes[c]->messages,(m+1)*sizeof(Uint16)); if(!classes[c]->messages) fatal("Allocation failed\n"); - while(m>classes[c]->nmsg) classes[c]->messages[classes[c]->nmsg++]=0xFFFF; + while(m>=classes[c]->nmsg) classes[c]->messages[classes[c]->nmsg++]=0xFFFF; } classes[c]->messages[m]=p; } static int look_class_name(void) { @@ -902,14 +902,14 @@ for(;;) { nxttok(); if(Tokenf(TF_MACRO)) ParseError("Unexpected macro\n"); if(Tokenf(TF_INT)) { numeric: - if(!(tokenv&~0xFF)) AddInst(tokenv); + if(!(tokenv&~0xFFL)) AddInst(tokenv); else if(!((tokenv-1)&tokenv)) AddInst(0x87E0+__builtin_ctz(tokenv)); - else if(!(tokenv&~0xFFFF)) AddInst2(OP_INT16,tokenv); - else if(-256<(Sint32)tokenv) AddInst(tokenv&0x01FF); + else if(!(tokenv&~0xFFFFL)) AddInst2(OP_INT16,tokenv); + else if((tokenv&0x80000000L) && -256<(Sint32)tokenv) AddInst(tokenv&0x01FF); else AddInst(OP_INT32),AddInst2(tokenv>>16,tokenv); } else if(Tokenf(TF_NAME)) { switch(tokenv) { AbbrevOp(OP_ADD,0x00); AbbrevOp(OP_SUB,0x08); @@ -1030,11 +1030,11 @@ FlowPop(OP_FOR); AddInst(OP_NEXT); cl->codes[flowptr[flowdepth]]=ptr; break; case OP_STRING: - + AddInst2(OP_STRING,pool_string(tokenstr)); break; default: if(Tokenf(TF_ABNORMAL)) ParseError("Invalid instruction token\n"); if(compat && Tokenf(TF_COMPAT)) ++tokenv; AddInstF(tokenv,tokent); @@ -1072,10 +1072,11 @@ default: ParseError("Invalid parenthesized instruction\n"); } } else if(tokent==TF_CLOSE) { if(peepcodes[ptr-1]==OP_RET) break; + if(peepcodes[ptr-1]&0xFF00)==0x1E00) break; if(Inst8bit()) ChangeInst(+=0x1E00); else AddInst(OP_RET); break; } else if(Tokenf(TF_EOF)) { ParseError("Unexpected end of file\n"); @@ -1119,13 +1120,13 @@ for(i=0;i=0x2000 && hash[i].id<0x3000) printf(" %%%s = 0x%04X\n",hash[i].txt,hash[i].id); } } if(endptr && cl->codes) { - printf(" Codes:\n"); + printf(" Codes:"); for(i=0;icodes[i]); } putchar('\n'); } printf("---\n\n"); @@ -1166,15 +1167,14 @@ nxttok(); if(tokent!=TF_CLOSE) ParseError("Close parentheses expected\n"); return 1<<12; } for(i=0;i<25;i++) { - nxttok(); if(!Tokenf(TF_INT) || (tokenv&~1)) ParseError("Expected 0 or 1\n"); if(tokenv) n|=1<<(i+4-2*(i%5)); + nxttok(); } - nxttok(); if(tokent!=TF_CLOSE) ParseError("Close parentheses expected\n"); return n; } static void class_def_hard(Uint16*data) { @@ -1186,11 +1186,11 @@ } else if(tokent==TF_OPEN) { nxttok(); if(!Tokenf(TF_DIR) || tokenv>7 || (tokenv&1)) ParseError("Expected even absolute direction\n"); i=tokenv>>1; nxttok(); - if(tokent!=TF_INT || (tokenv&~0xFFFF)) ParseError("Sixteen-bit number expected\n"); + if(tokent!=TF_INT || (tokenv&~0xFFFF)) ParseError("Hardness/sharpness must be a 16-bit number\n"); data[i]=tokenv; nxttok(); if(tokent!=TF_CLOSE) ParseError("Close parentheses expected\n"); } else if(tokent==TF_INT) { if(tokenv&~0xFFFF) ParseError("Hardness/sharpness must be a 16-bit number\n"); @@ -1200,15 +1200,134 @@ } } } static inline Uint8 class_def_shovable(void) { - + Uint8 n=0; + nxttok(); + if(tokent==TF_INT) { + n=tokenv; + nxttok(); + if(tokent!=TF_CLOSE) ParseError("Close parentheses expected\n"); + return n; + } + for(;;) { + if(tokent==TF_CLOSE) return n; + if(!Tokenf(TF_DIR) || tokenv>7 || (tokenv&1)) ParseError("Expected even absolute direction\n"); + n|=1<7 || (tokenv&1)) ParseError("Expected even absolute direction\n"); + i=tokenv; + n&=~(3<=0x2FFD) ParseError("Help text is too long\n"); + strcpy(txt+n,tokenstr); + n+=i; + } + if(!n) { + free(txt); + return 0; + } + txt[n]=0; + return realloc(txt,n+1)?:txt; +} + +static void class_def_image(int cla) { + Class*cl=classes[cla]; + Uint16*img=malloc(256*sizeof(Uint16)); + sqlite3_stmt*st; + if(cl->nimages || cl->images) ParseError("Duplicate (Image) block\n"); + if(!img) fatal("Allocation failed\n"); + if(userdb && sqlite3_prepare_v2(userdb,"SELECT `ID` FROM `PICTURES` WHERE `NAME` = ?1;",-1,&st,0)) fatal("SQL error: %s\n",sqlite3_errmsg(userdb)); + for(;;) { + nxttok(); + if(tokent==TF_CLOSE) break; + if(cl->nimages==255) ParseError("Too many images in class\n"); + if(!Tokenf(TF_NAME) || tokenv!=OP_STRING) ParseError("String expected\n"); + if(userdb) { + sqlite3_bind_text(st,1,tokenstr,-1,0); + if(sqlite3_step(st)==SQLITE_ROW) { + img[cl->nimages++]=sqlite3_column_int(st,0)|0x8000; + } else { + ParseError("A picture named \"%s\" does not exist\n",tokenstr); + } + sqlite3_reset(st); + sqlite3_clear_bindings(st); + } else { + img[cl->nimages++]=0; + } + } + if(userdb) sqlite3_finalize(st); + if(!cl->nimages) { + free(img); + return; + } + cl->images=realloc(img,cl->nimages*sizeof(Uint16))?:img; +} + +static void class_def_defaultimage(int cla) { + Class*cl=classes[cla]; + int i; + for(i=0;inimages;i++) cl->images[i]&=0x7FFF; + for(;;) { + nxttok(); + if(tokent==TF_OPEN) { + nxttok(); + if(tokent==TF_INT) { + if(tokenv<0 || tokenv>=cl->nimages) ParseError("Image number out of range\n"); + i=tokenv; + nxttok(); + if(tokent!=TF_INT) ParseError("Number expected\n"); + if(tokenv=cl->nimages) ParseError("Image number out of range\n"); + while(i<=tokenv) cl->images[i++]|=0x8000; + } else if(tokent!=TF_CLOSE) { + ParseError("Number expected\n"); + } + } else if(tokent==TF_CLOSE) { + break; + } else if(tokent==TF_INT) { + if(tokenv<0 || tokenv>=cl->nimages) ParseError("Image number out of range\n"); + cl->images[tokenv]|=0x8000; + } else { + ParseError("Expected ( or ) or number\n"); + } + } } static void class_definition(int cla) { Hash*hash=calloc(LOCAL_HASH_SIZE,sizeof(Hash)); Class*cl=classes[cla]; @@ -1232,20 +1351,22 @@ } else if(Tokenf(TF_OPEN)) { nxttok(); if(Tokenf(TF_NAME)) { switch(tokenv) { case OP_IMAGE: - + class_def_image(cla); break; case OP_DEFAULTIMAGE: - + class_def_defaultimage(cla); break; case OP_HELP: - + if(cl->gamehelp) ParseError("Duplicate (Help) block\n"); + cl->gamehelp=class_def_help(); break; case OP_EDITORHELP: - + if(cl->edithelp) ParseError("Duplicate (EditorHelp) block\n"); + cl->edithelp=class_def_help(); break; case OP_HEIGHT: cl->height=class_def_number(); break; case OP_WEIGHT: @@ -1334,11 +1455,11 @@ break; } else { ParseError("Invalid directly inside of a class definition\n"); } } - end_label_stack(classes[0]->codes,hash); + end_label_stack(cl->codes,hash); if(!cl->nimages) cl->oflags|=OF_INVISIBLE; if(main_options['C']) dump_class(cla,ptr,hash); if(main_options['H']) { for(i=0;i CFLAGS +test "xx$CFLAGS" = "x`cat CFLAGS`" || rm bindings.o class.o picture.o +echo "x$CFLAGS" > CFLAGS test "x$EXE" = "x" && EXE=~/bin/heromesh test instruc -nt instruc.h && node instruc.js > instruc.h test instruc.js -nt instruc.h && node instruc.js > instruc.h test names.js -nt names.h && node names.js > names.h test quarks -nt quarks.h && node quarks.js > quarks.h Index: instruc ================================================================== --- instruc +++ instruc @@ -199,11 +199,11 @@ FlushObj GetInventory HeightAt IgnoreKey .,IntMove ; move without initializing Inertia -,JumpTo +.,JumpTo ,Loc ; same as: Xloc Yloc LocateMe LoseLevel MaxInventory ; error if more than that many slots in inventory .,Move Index: instruc.h ================================================================== --- instruc.h +++ instruc.h @@ -289,10 +289,12 @@ #define OP_INTMOVE_C 34949 #define OP_INTMOVE_D 41093 #define OP_INTMOVE_CD 43141 #define OP_JUMPTO 32902 #define OP_JUMPTO_C 34950 +#define OP_JUMPTO_D 41094 +#define OP_JUMPTO_CD 43142 #define OP_LOC 32903 #define OP_LOC_C 34951 #define OP_LOCATEME 32904 #define OP_LOSELEVEL 32905 #define OP_MAXINVENTORY 32906 @@ -438,11 +440,11 @@ {"Input",8683630}, {"IntMove",10584197}, {"Invisible",8618074}, {"JAYAYAYNG",8389416}, {"JUMPED",8389128}, -{"JumpTo",8487046}, +{"JumpTo",10584198}, {"KEWEL",8389422}, {"KEY",8389129}, {"KLECK",8389387}, {"KLINKK",8389385}, {"Key",8421484}, Index: main.c ================================================================== --- main.c +++ main.c @@ -28,13 +28,13 @@ static const char schema[]= "BEGIN;" "PRAGMA APPLICATION_ID(1296388936);" "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, `OFFSET` INT, `DATA` BLOB, `USERSTATE` BLOB);" + "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 TEMPORARY TABLE `PICTURES`(`ID` INTEGER PRIMARY KEY, `NAME` TEXT, `OFFSET` INT);" + "CREATE TEMPORARY TABLE `PICTURES`(`ID` INTEGER PRIMARY KEY, `NAME` TEXT COLLATE NOCASE, `OFFSET` INT);" "CREATE TEMPORARY TABLE `VARIABLES`(`ID` INTEGER PRIMARY KEY, `NAME` TEXT);" "COMMIT;" ; sqlite3*userdb; @@ -189,10 +189,14 @@ 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); } + +static void flush_usercache(void) { + +} static void init_usercache(void) { sqlite3_stmt*st; int z; sqlite3_int64 t1,t2; @@ -442,10 +446,57 @@ case SDL_QUIT: exit(0); break; } } + +static void do_sql_mode(void) { + int m=sqlite3_limit(userdb,SQLITE_LIMIT_SQL_LENGTH,-1); + char*txt=malloc(m); + 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) continue; + if(*txt=='#') { + n=0; + } else if(*txt=='.') { + txt[n]=0; + n=0; + switch(txt[1]) { + case 'b': bail=strtol(txt+2,0,0); break; + case 'f': sqlite3_db_cacheflush(userdb); sqlite3_db_release_memory(userdb); break; + case 'i': puts(sqlite3_db_filename(userdb,"main")); break; + case 'q': exit(0); break; + case 'u': flush_usercache(); break; + case 'x': sqlite3_enable_load_extension(userdb,strtol(txt+2,0,0)); break; + default: fatal("Invalid dot command .%c\n",txt[1]); + } + } 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)); + n=0; + } else { + txt[n++]='\n'; + } + } + if(c==EOF) break; + } else { + txt[n++]=c; + } + if(n>=m) fatal("Too long SQL statement\n"); + } + if(n) fatal("Unterminated SQL statement\n"); + free(txt); +} int main(int argc,char**argv) { int optind=1; while(argc>optind && argv[optind][0]=='-') { int i; @@ -481,8 +532,13 @@ test_mode(); return 0; } init_usercache(); load_classes(); + if(main_options['x']) { + fprintf(stderr,"Ready for executing SQL statements.\n"); + do_sql_mode(); + return 0; + } return 0; } Index: picture.c ================================================================== --- picture.c +++ picture.c @@ -281,10 +281,11 @@ curpic=malloc(i*i); break; } if(!curpic) fatal("Allocation failed\n"); picture_size=decide_picture_size(nwantsize,wantsize,havesize,n); + if(main_options['x']) goto done; if(sqlite3_prepare_v2(userdb,"SELECT `ID`, `OFFSET` FROM `PICTURES`;",-1,&st,0)) fatal("Unable to prepare SQL statement while loading pictures: %s\n",sqlite3_errmsg(userdb)); optionquery[1]=Q_screenFlags; v=xrm_get_resource(resourcedb,optionquery,optionquery,2); i=v&&strchr(v,'h'); @@ -298,16 +299,18 @@ } sqlite3_finalize(st); fclose(fp); sqlite3_exec(userdb,"COMMIT;",0,0,0); SDL_SetColorKey(picts,SDL_SRCCOLORKEY|SDL_RLEACCEL,0); +done: fprintf(stderr,"Done\n"); } void init_screen(void) { const char*v; int w,h,i; + if(main_options['x']) return; optionquery[1]=Q_screenWidth; w=strtol(xrm_get_resource(resourcedb,optionquery,optionquery,2)?:"800",0,10); optionquery[1]=Q_screenHeight; h=strtol(xrm_get_resource(resourcedb,optionquery,optionquery,2)?:"600",0,10); optionquery[1]=Q_screenFlags;