Index: class.c ================================================================== --- class.c +++ class.c @@ -120,10 +120,11 @@ #define MAC_BAND 0xFFC5 #define MAC_BOR 0xFFC6 #define MAC_BXOR 0xFFC7 #define MAC_BNOT 0xFFC8 #define MAC_CAT 0xFFC9 +#define MAC_BIT 0xFFCA #define MAC_VERSION 0xFFE0 #define MAC_DEFINE 0xFFE1 #define MAC_INCLUDE 0xFFE2 #define MAC_CALL 0xFFE3 #define MAC_UNDEFINED 0xFFFF @@ -765,10 +766,21 @@ } s[n]=0; strcpy(tokenstr,s); free(s); ReturnToken(TF_NAME|TF_ABNORMAL,OP_STRING); + case MAC_BIT: + n=0; + for(;;) { + nxttok(); + if(tokent==TF_MACRO+TF_CLOSE) break; + if(tokent!=TF_INT) ParseError("Number expected\n"); + n|=1<MAX_VERSION) ParseError("Version number out of range\n"); nxttok1(); @@ -1016,10 +1028,13 @@ break; case OP_NEXT: FlowPop(OP_FOR); AddInst(OP_NEXT); cl->codes[flowptr[flowdepth]]=ptr; + break; + case OP_STRING: + break; default: if(Tokenf(TF_ABNORMAL)) ParseError("Invalid instruction token\n"); if(compat && Tokenf(TF_COMPAT)) ++tokenv; AddInstF(tokenv,tokent); @@ -1113,10 +1128,88 @@ } putchar('\n'); } printf("---\n\n"); } + +static inline Uint32 class_def_number(void) { + Uint32 n; + nxttok(); + if(!Tokenf(TF_INT)) fatal("Number expected\n"); + n=tokenv; + nxttok(); + if(tokent!=TF_CLOSE) fatal("Close parentheses expected\n"); + return n; +} + +static Uint32 class_def_misc(void) { + Uint32 n=0; + for(;;) { + nxttok(); + if(tokent==TF_CLOSE) return n; + if(Tokenf(TF_INT)) { + n|=tokenv; + } else if(Tokenf(TF_NAME) && !(tokenv&~255)) { + n|=tokenv; + } else if(Tokenf(TF_NAME) && tokenv>=OP_BITCONSTANT && tokenv<=OP_BITCONSTANT_LAST) { + n|=1L<<(tokenv&31); + } else { + fatal("Number expected"); + } + } +} + +static Uint32 class_def_arrivals(void) { + Uint32 n=0; + int i; + nxttok(); + if(Tokenf(TF_NAME) && tokenv==OP_INPLACE) { + 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(); + if(tokent!=TF_CLOSE) ParseError("Close parentheses expected\n"); + return n; +} + +static void class_def_hard(Uint16*data) { + int i; + for(;;) { + nxttok(); + if(tokent==TF_CLOSE) { + return; + } 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"); + 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"); + data[0]=data[1]=data[2]=data[3]=tokenv; + } else { + ParseError("Expected ( or ) or number\n"); + } + } +} + +static inline Uint8 class_def_shovable(void) { + +} + +static inline Uint8 class_def_shape(void) { + +} static void class_definition(int cla) { Hash*hash=calloc(LOCAL_HASH_SIZE,sizeof(Hash)); Class*cl=classes[cla]; int ptr=0; @@ -1134,15 +1227,97 @@ nxttok(); if(Tokenf(TF_EOF)) { ParseError("Unexpected end of file\n"); } else if(Tokenf(TF_MACRO)) { ParseError("Unexpected macro token\n"); - } else if(Tokenf(TF_CLOSE)) { - break; } else if(Tokenf(TF_OPEN)) { nxttok(); - + if(Tokenf(TF_NAME)) { + switch(tokenv) { + case OP_IMAGE: + + break; + case OP_DEFAULTIMAGE: + + break; + case OP_HELP: + + break; + case OP_EDITORHELP: + + break; + case OP_HEIGHT: + cl->height=class_def_number(); + break; + case OP_WEIGHT: + cl->weight=class_def_number(); + break; + case OP_CLIMB: + cl->climb=class_def_number(); + break; + case OP_DENSITY: + cl->density=class_def_number(); + break; + case OP_VOLUME: + cl->volume=class_def_number(); + break; + case OP_STRENGTH: + cl->strength=class_def_number(); + break; + case OP_TEMPERATURE: + cl->temperature=class_def_number(); + break; + case OP_MISC4: + cl->misc4=class_def_misc(); + break; + case OP_MISC5: + cl->misc5=class_def_misc(); + break; + case OP_MISC6: + cl->misc6=class_def_misc(); + break; + case OP_MISC7: + cl->misc7=class_def_misc(); + break; + case OP_ARRIVALS: + cl->arrivals=class_def_arrivals(); + break; + case OP_DEPARTURES: + cl->departures=class_def_arrivals(); + break; + case OP_HARD: + class_def_hard(cl->hard); + break; + case OP_SHARP: + class_def_hard(cl->sharp); + break; + case OP_SHAPE: + cl->shape=class_def_shape(); + break; + case OP_SHOVABLE: + cl->shovable=class_def_shovable(); + break; + case OP_SUBS: + ptr=parse_instructions(cla,ptr,hash,compat); + break; + case OP_LABEL: + pushback=1; + ptr=parse_instructions(cla,ptr,hash,compat); + break; + case 0x0200 ... 0x02FF: + set_message_ptr(cla,tokenv&255,ptr); + ptr=parse_instructions(cla,ptr,hash,compat); + break; + case 0xC000 ... 0xFFFF: + set_message_ptr(cla,tokenv+256-0xC000,ptr); + ptr=parse_instructions(cla,ptr,hash,compat); + break; + default: ParseError("Invalid directly inside of a class definition\n"); + } + } else { + ParseError("Invalid directly inside of a class definition\n"); + } } else if(Tokenf(TF_NAME)) { switch(tokenv) { case OP_PLAYER: cl->cflags|=CF_PLAYER; break; case OP_INPUT: cl->cflags|=CF_INPUT; break; case OP_COMPATIBLE: cl->cflags|=CF_COMPATIBLE; compat=1; break; @@ -1153,28 +1328,64 @@ case OP_STEALTHY: cl->oflags|=OF_STEALTHY; break; case OP_USERSTATE: cl->oflags|=OF_USERSTATE; break; case OP_SHOVABLE: cl->shovable=0x55; break; default: ParseError("Invalid directly inside of a class definition\n"); } + } else if(Tokenf(TF_CLOSE)) { + break; } else { ParseError("Invalid directly inside of a class definition\n"); } } end_label_stack(classes[0]->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=0x4000) fatal("Malformed CLASS.DEF lump\n"); + i+=2; + p=data+i; + while(i=0x4100) fatal("Malformed CLASS.DEF lump\n"); + n-=256; + i+=2; + p=data+i; + while(iname=classes[0]->edithelp=classes[0]->gamehelp=0; classes[0]->codes=classes[0]->messages=classes[0]->images=0; classes[0]->nmsg=0; memset(functions,-1,sizeof(functions)); + load_class_numbers(); for(;;) { nxttok(); if(tokent==TF_EOF) goto done; if(tokent!=TF_OPEN) ParseError("Expected open parenthesis\n"); nxttok(); @@ -1289,6 +1502,7 @@ for(i=0;icflags&CF_NOCLASS1)) fatal("Class $%s mentioned but not defined\n",classes[i]->name); if(macros) for(i=0;i4 && i<10 && !sqlite3_stricmp(buf+i-4,suffix)) { for(z=0;z'9') goto nomatch; if(*buf=='0' && i!=5) goto nomatch; sqlite3_bind_int(st,2,strtol(buf,0,10)); - } else if(i==9 && !sqlite3_stricmp(buf,"CLASS.DEF")) { + } else if(i==9 && suffix[1]=='L' && !sqlite3_stricmp(buf,"CLASS.DEF")) { sqlite3_bind_int(st,2,LUMP_CLASS_DEF); - } else if(i==9 && !sqlite3_stricmp(buf,"LEVEL.IDX")) { + } 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); } done: sqlite3_finalize(st); if(z=sqlite3_exec(userdb,"COMMIT;",0,0,0)) fatal("SQL error (%d): %s\n",z,sqlite3_errmsg(userdb)); return id; @@ -178,10 +182,11 @@ sqlite3_int64 t1,t2; char*nam1; char*nam2; char*nam3; struct stat fst; + fprintf(stderr,"Initializing user cache...\n"); if(z=sqlite3_prepare_v2(userdb,"SELECT `ID`, `TIME` FROM `USERCACHEINDEX` WHERE `NAME` = ?1;",-1,&st,0)) fatal("SQL error (%d): %s\n",z,sqlite3_errmsg(userdb)); nam1=sqlite3_mprintf("%s.level",basefilename); if(!nam1) fatal("Allocation failed\n"); nam2=realpath(nam1,0); if(!nam2) fatal("Cannot find real path of '%s': %m\n",nam1); @@ -218,19 +223,20 @@ fatal("SQL error (%d): %s\n",z,sqlite3_errmsg(userdb)); } sqlite3_finalize(st); if(stat(nam2,&fst)) fatal("Unable to stat '%s': %m\n",nam2); if(!fst.st_size) fatal("File '%s' has zero size\n",nam2); - if(fst.st_mtime>t1 || fst.st_ctime>t1) reset_usercache(levelfp,nam2,&fst,".LVL"); + if(fst.st_mtime>t1 || fst.st_ctime>t1) leveluc=reset_usercache(levelfp,nam2,&fst,".LVL"); if(stat(nam3,&fst)) fatal("Unable to stat '%s': %m\n",nam3); if(!fst.st_size) fatal("File '%s' has zero size\n",nam2); - if(fst.st_mtime>t1 || fst.st_ctime>t1) reset_usercache(levelfp,nam2,&fst,".LVL"); + if(fst.st_mtime>t2 || fst.st_ctime>t2) solutionuc=reset_usercache(solutionfp,nam3,&fst,".SOL"); free(nam2); free(nam3); if(z=sqlite3_prepare_v3(userdb,"SELECT * FROM `USERCACHEDATA` WHERE `FILE` = ?1 AND `LEVEL` = ?2;",-1,SQLITE_PREPARE_PERSISTENT,&readusercachest,0)) { fatal("SQL error (%d): %s\n",z,sqlite3_errmsg(userdb)); } + fprintf(stderr,"Done\n"); } static void init_sql(void) { char*s; char*p; @@ -457,9 +463,10 @@ load_pictures(); if(main_options['T']) { test_mode(); return 0; } + init_usercache(); load_classes(); return 0; }