Index: class.c ================================================================== --- class.c +++ class.c @@ -58,10 +58,11 @@ char*txt; } Hash; /* Global hash: + 1000-10FF = User flags 2800-2FFF = Variables 8000-BFFF = Functions C000-FFFF = Macros Local hash: 2000-27FF = Variables @@ -114,11 +115,11 @@ static Uint16*labelptr; #define ParseError(a,...) fatal("On line %d: " a,linenum,##__VA_ARGS__) static const unsigned char chkind[256]={ - ['$']=1, ['!']=1, ['\'']=1, ['#']=1, ['@']=1, ['%']=1, ['&']=1, [':']=1, + ['$']=1, ['!']=1, ['\'']=1, ['#']=1, ['@']=1, ['%']=1, ['&']=1, [':']=1, ['^']=1, ['0'...'9']=2, ['-']=2, ['+']=2, ['A'...'Z']=3, ['a'...'z']=3, ['_']=3, ['?']=3, ['.']=3, ['*']=3, ['/']=3, }; #define MIN_VERSION 0 @@ -552,10 +553,14 @@ return; } } ParseError("Invalid Hero Mesh key name: %s\n",tokenstr); break; + case '^': + tokent=TF_NAME|TF_ABNORMAL|fl; + tokenv=OP_USERFLAG; + break; } } static void define_macro(Uint16 name,Uint8 q) { int i; @@ -926,10 +931,20 @@ z=array_size; if(z+x*y>0xFFFE) ParseError("Out of array memory\n"); array_size+=x*y; return z|((y-1)<<16)|((x-1)<<26); } + +static void define_user_flags(Uint16 ca,Uint16 cb) { + for(;;) { + nxttok(); + if(tokent==TF_CLOSE) break; + if(!Tokenf(TF_NAME) || tokenv!=OP_USERFLAG) ParseError("User flag or close parenthesis expected\n"); + if(ca>cb) ParseError("Too many user flags of this kind\n"); + if(look_hash(glohash,HASH_SIZE,0x1000,0x10FF,ca++,"user flags")) ParseError("Duplicate definition of ^%s\n",tokenstr); + } +} static void begin_label_stack(void) { labelstack=0; labelptr=malloc(0x8000*sizeof(Uint16)); if(!labelptr) fatal("Allocation failed\n"); @@ -1116,10 +1131,39 @@ FlowPush(OP_BEGIN); AddInst(OP_TMARK); AddInst(OP_IF); FlowPush(OP_WHILE); peep=++ptr; + break; + case OP_USERFLAG: + // Opcodes 0x1F00-0x1F1F read a bit; opcodes 0x1F20-0x1F3F set/clear a bit + x=look_hash(glohash,HASH_SIZE,0x1000,0x10FF,0,"user flags"); + if(!x) ParseError("User flag ^%s not defined\n",tokenstr); + if(x<0x1020) y=OP_MISC4; + else if(x<0x1040) y=OP_MISC5; + else if(x<0x1060) y=OP_MISC6; + else if(x<0x1080) y=OP_MISC7; + else y=OP_COLLISIONLAYERS; + if(Tokenf(TF_EQUAL)) { + if(x>=0x1080) ParseError("Flag ^%s is read-only\n",tokenstr); + if(Tokenf(TF_COMMA)) { + AddInst(OP_OVER); + AddInst(y+0x0800); + AddInst(0x1F20|(x&0x1F)); + AddInst(y+0x1800); + } else { + AddInst(y); + AddInst(0x1F20|(x&0x1F)); + AddInst(y+0x1000); + } + } else if(Tokenf(TF_COMMA)) { + AddInst(y+0x0800); + AddInst(0x1F00|(x&0x1F)); + } else { + AddInst(y); + AddInst(0x1F00|(x&0x1F)); + } break; default: if(Tokenf(TF_ABNORMAL)) ParseError("Invalid instruction token\n"); if(compat && Tokenf(TF_COMPAT) && Tokenf(TF_EQUAL)) ++tokenv; AddInstF(tokenv,tokent); @@ -1420,10 +1464,20 @@ } else { ParseError("Expected ( or ) or number\n"); } } } + +static void class_user_flag(Class*cl) { + int x=look_hash(glohash,HASH_SIZE,0x1000,0x10FF,0,"user flags"); + if(!x) ParseError("User flag ^%s not defined\n",tokenstr); + if(x<0x1020) cl->misc4|=1L<<(x&0x1F); + else if(x<0x1040) cl->misc5|=1L<<(x&0x1F); + else if(x<0x1060) cl->misc6|=1L<<(x&0x1F); + else if(x<0x1080) cl->misc7|=1L<<(x&0x1F); + else cl->collisionLayers|=1<<(x&0x1F); +} static void class_definition(int cla,sqlite3_stmt*vst) { Hash*hash=calloc(LOCAL_HASH_SIZE,sizeof(Hash)); Class*cl=classes[cla]; int ptr=0; @@ -1567,10 +1621,11 @@ case OP_INVISIBLE: cl->oflags|=OF_INVISIBLE; break; case OP_VISUALONLY: cl->oflags|=OF_VISUALONLY; break; case OP_STEALTHY: cl->oflags|=OF_STEALTHY; break; case OP_USERSTATE: cl->oflags|=OF_USERSTATE; break; case OP_SHOVABLE: cl->shovable=0x55; break; + case OP_USERFLAG: class_user_flag(cl); break; default: ParseError("Invalid directly inside of a class definition\n"); } } else if(Tokenf(TF_CLOSE)) { break; } else { @@ -1755,10 +1810,15 @@ if(tokent!=TF_INT) ParseError("Number expected\n"); max_volume=tokenv; nxttok(); if(tokent!=TF_CLOSE) ParseError("Expected close parenthesis\n"); break; + case OP_MISC4: define_user_flags(0x1000,0x101F); break; + case OP_MISC5: define_user_flags(0x1020,0x103F); break; + case OP_MISC6: define_user_flags(0x1040,0x105F); break; + case OP_MISC7: define_user_flags(0x1060,0x107F); break; + case OP_COLLISIONLAYERS: define_user_flags(0x1C80,0x1C87); break; default: ParseError("Invalid top level definition: %s\n",tokenstr); } } else { ParseError("Invalid top level definition\n"); Index: class.doc ================================================================== --- class.doc +++ class.doc @@ -42,10 +42,11 @@ : Label % Local variable # User message ! User sound & User function + ^ User flag Comments are also allowed; these start with a semicolon (outside of a string literal) and end at the next line break. @@ -202,10 +203,30 @@ (Background []) Set the background colour, from 0 to 255. The default value is 1. You can optionally specify a second number, which is the background colour for the inventory; if not specified, uses the same colour for both. +(CollisionLayers ) + Define user flags as CollisionLayers bits; the first defined flag is + bit0. Up to 8 flags can be defined in this way. + +(Misc4 ) + Define user flags as Misc4 bits; the first defined flag is bit0. Up to + 32 flags can be defined in this way. + +(Misc5 ) + Define user flags as Misc5 bits; the first defined flag is bit0. Up to + 32 flags can be defined in this way. + +(Misc6 ) + Define user flags as Misc6 bits; the first defined flag is bit0. Up to + 32 flags can be defined in this way. + +(Misc7 ) + Define user flags as Misc7 bits; the first defined flag is bit0. Up to + 32 flags can be defined in this way. + (Synchronize ) Define an animation slot for synchronized animation. The slot number can be 0 to 7, the length is the number of images in the sequence, and the speed is the number of centiseconds between frames. @@ -244,10 +265,15 @@ the initial value for variables of objects of this class. Outside of code blocks, named constants are not normally interchangeable with the numbers having the same value. + + Set a user flag bit in the definition of Misc4, Misc5, Misc6, Misc7, or + CollisionLayers of this class. You must previously define this user flag + as a global definition. + Abstract (Not implemented yet.) (Arrivals InPlace) This is an abbreviation for (Arrivals 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 @@ -696,10 +722,16 @@ A user-defined variable. This variable cannot be accessed on other objects other than this one. You can give it any name with a percentage sign at first. User variables are initialized to zero, and need not be declared anywhere. +^xyz : bool [c] + A user-defined flag, which is one bit in Misc4, Misc5, Misc6, Misc7, or + CollisionLayers. If it is CollisionLayers, then it is read-only; other + flags are read/write. User defined flags must be defined first (globally) + before they can be used. + Arrivals : int32 Only the low 25-bits are used. Each bit which is set indicates that it cares if other objects arrive around it at that relative location, where bit0 is two paces northeast, bit1 is to the west of that, etc, and then bit4 two paces northwest of this object, and bit5 starts on the next Index: exec.c ================================================================== --- exec.c +++ exec.c @@ -1434,10 +1434,12 @@ case 0x1A00 ... 0x1A7F: StackReq(1,1); t1=Pop(); Numeric(t1); Push(NVALUE(t1.s<(code[ptr-1]&0x7F)?1:0)); break; // ,lt case 0x1A80 ... 0x1AFF: StackReq(1,1); t1=Pop(); Numeric(t1); Push(NVALUE(t1.s>(code[ptr-1]&0x7F)?1:0)); break; // ,gt case 0x1B00 ... 0x1B7F: StackReq(1,1); t1=Pop(); Numeric(t1); Push(NVALUE(t1.s<=(code[ptr-1]&0x7F)?1:0)); break; // ,le case 0x1B80 ... 0x1BFF: StackReq(1,1); t1=Pop(); Numeric(t1); Push(NVALUE(t1.s>=(code[ptr-1]&0x7F)?1:0)); break; // ,ge case 0x1E00 ... 0x1EFF: StackReq(0,1); Push(NVALUE(code[ptr-1]&0xFF)); return; // ret + case 0x1F00 ... 0x1F1F: StackReq(1,1); t1=Pop(); Numeric(t1); Push(NVALUE(t1.u&(1L<<(code[ptr-1]&31))?1:0)); break; // tbit + case 0x1F20 ... 0x1F3F: StackReq(2,1); t2=Pop(); t1=Pop(); Numeric(t2); i=code[ptr-1]&31; if(v_bool(t1)) t2.u|=1L<uservars[code[ptr-1]&0x7FF]); break; case 0x2800 ... 0x28FF: StackReq(0,1); Push(globals[code[ptr-1]&0x7FF]); break; case 0x3000 ... 0x37FF: NoIgnore(); StackReq(1,0); o->uservars[code[ptr-1]&0x7FF]=Pop(); break; case 0x3800 ... 0x38FF: NoIgnore(); StackReq(1,0); globals[code[ptr-1]&0x7FF]=Pop(); break; case 0x4000 ... 0x7FFF: StackReq(0,1); Push(CVALUE(code[ptr-1]-0x4000)); break; Index: instruc ================================================================== --- instruc +++ instruc @@ -273,6 +273,7 @@ *Label *String *Int16 *Int32 *Dispatch +*UserFlag Index: instruc.h ================================================================== --- instruc.h +++ instruc.h @@ -382,10 +382,11 @@ #define OP_LABEL 32963 #define OP_STRING 32964 #define OP_INT16 32965 #define OP_INT32 32966 #define OP_DISPATCH 32967 +#define OP_USERFLAG 32968 #ifdef HEROMESH_CLASS static const Op_Names op_names[]={ {"*",8486937}, {"+",8421399}, {"-",8421400},