Index: class.c ================================================================== --- class.c +++ class.c @@ -13,10 +13,11 @@ #include #include #include "sqlite3.h" #include "smallxrm.h" #include "heromesh.h" +#include "names.h" #define TF_COMMA 0x0001 // has a comma modifier #define TF_EQUAL 0x0002 // has an equal sign modifier #define TF_ABNORMAL 0x0004 // with TF_NAME, not directly an opcode #define TF_COMPAT 0x0008 // add 1 to opcode in compatibility mode @@ -45,10 +46,11 @@ Sint32 max_volume=10000; Uint8 back_color=1; Uint8 inv_back_color=9; char**stringpool; AnimationSlot anim_slot[8]; +Uint8 keymask[256/8]; #define HASH_SIZE 8888 #define LOCAL_HASH_SIZE 5555 typedef struct { Uint16 id; @@ -1357,10 +1359,11 @@ Hash*hash=calloc(LOCAL_HASH_SIZE,sizeof(Hash)); Class*cl=classes[cla]; int ptr=0; int compat=0; int i; + char disp=0; if(!hash) fatal("Allocation failed\n"); if(!cl) fatal("Confusion of class definition somehow\n"); if(cl->cflags&(CF_NOCLASS1|CF_NOCLASS2)) { cl->cflags=0; } else { @@ -1373,11 +1376,31 @@ ParseError("Unexpected end of file\n"); } else if(Tokenf(TF_MACRO)) { ParseError("Unexpected macro token\n"); } else if(Tokenf(TF_OPEN)) { nxttok(); - if(Tokenf(TF_NAME)) { + if(Tokenf(TF_KEY)) { + if(!disp) { + cl->codes=realloc(cl->codes,0x10000*sizeof(Uint16)); + if(!cl->codes) fatal("Allocation failed\n"); + if(get_message_ptr(cla,MSG_KEY)!=0xFFFF) ParseError("Class $%s has a KEY message already\n",cl->name); + if(ptr>0xFDFF) ParseError("Out of code space\n"); + disp=1; + set_message_ptr(cla,MSG_KEY,ptr); + cl->codes[ptr]=OP_DISPATCH; + for(i=1;i<256;i++) cl->codes[ptr+i]=0; + ptr+=256; + } + i=tokenv&255; + cl->codes[cl->messages[MSG_KEY]+i]=ptr; + if(cl->cflags&CF_INPUT) { + nxttok(); + if(tokent!=TF_NAME || tokenv!=OP_IGNOREKEY) keymask[i>>3]|=1<<(i&7); + pushback=1; + } + ptr=parse_instructions(cla,ptr,hash,compat); + } else if(Tokenf(TF_NAME)) { switch(tokenv) { case OP_IMAGE: class_def_image(cla); break; case OP_DEFAULTIMAGE: Index: class.doc ================================================================== --- class.doc +++ class.doc @@ -383,11 +383,20 @@ ( ) Make a code block whose entry point is the specified message. ( ) - (This is not implemented yet.) + Add a code block for key dispatch. This cannot be combined with a KEY + message in the same class; it causes the KEY message to be automatically + defined for this class. If this class has the Input flag and the first + instruction is not IgnoreKey, then it is entered into an internal list + of key codes to not ignore. Otherwise, the automatic KEY messages (for + all classes with them, not only this one) will have the effect of the + IgnoreKey instruction when an unrecognized key is specified. You can + still call the KEY message by yourself; Arg1 is the key code, and if + Arg3 is true then the implicit IgnoreKey will not be executed (although + any explicit IgnoreKey will still work). === Data types === The following data types are available: @@ -403,11 +412,12 @@ * Object: A reference to an object. There are no literals of this type. * String: A string in quotation marks. There are no string manipulation functions; the only thing that can be done with a string is to display it. -* Sound: A sound. +* Sound: A named sound effect. Values of this type cannot be compared with +anything, even other values of the same type. Some things are not their own types, and are other uses of numbers: * Null: A null class or null object is represented as zero. Index: exec.c ================================================================== --- exec.c +++ exec.c @@ -1240,10 +1240,22 @@ quiz_obj.u=from; } if(*t==31 && t[1]) t+=2; else t+=1; } } + +static int v_dispatch(const Uint16*code) { + int i=msgvars.arg1.u; + if(msgvars.arg1.t!=TY_NUMBER) Throw("Type mismatch"); + if(msgvars.arg1.u&~0xFF) { + if(current_key && !v_bool(msgvars.arg3)) key_ignored=all_flushed=1; + return 0; + } + if(!i) return 0; + if(current_key && !v_bool(msgvars.arg3) && !(keymask[i>>3]&(1<<(i&7)))) key_ignored=all_flushed=1; + return code[i]; +} // Here is where the execution of a Free Hero Mesh bytecode subroutine is executed. #define NoIgnore() do{ changed=1; }while(0) #define GetVariableOf(a,b) (i=v_object(Pop()),i==VOIDLINK?NVALUE(0):b(objects[i]->a)) #define GetVariableOrAttributeOf(a,b) (t2=Pop(),t2.t==TY_CLASS?NVALUE(classes[t2.u]->a):(i=v_object(t2),i==VOIDLINK?NVALUE(0):b(objects[i]->a))) @@ -1372,10 +1384,11 @@ case OP_DESTROYED_C: StackReq(1,1); t1=Pop(); Push(NVALUE(v_destroyed(t1))); break; case OP_DIR: StackReq(0,1); Push(NVALUE(o->dir)); break; case OP_DIR_C: StackReq(1,1); Push(GetVariableOf(dir,NVALUE)); break; case OP_DIR_E: NoIgnore(); StackReq(1,0); t1=Pop(); Numeric(t1); o->dir=resolve_dir(obj,t1.u); break; case OP_DIR_EC: NoIgnore(); StackReq(2,0); t1=Pop(); Numeric(t1); i=v_object(Pop()); if(i!=VOIDLINK) objects[i]->dir=resolve_dir(i,t1.u); break; + case OP_DISPATCH: ptr=v_dispatch(code+ptr-1); if(!ptr) return; break; case OP_DISTANCE: StackReq(0,1); Push(NVALUE(o->distance)); break; case OP_DISTANCE_C: StackReq(1,1); Push(GetVariableOf(distance,NVALUE)); break; case OP_DISTANCE_E: StackReq(1,0); t1=Pop(); Numeric(t1); o->distance=t1.u; break; case OP_DISTANCE_EC: StackReq(2,0); t1=Pop(); Numeric(t1); i=v_object(Pop()); if(i!=VOIDLINK) objects[i]->distance=t1.u; break; case OP_DIV: StackReq(2,1); t2=Pop(); DivideBy(t2); t1=Pop(); Numeric(t1); Push(NVALUE(t1.u/t2.u)); break; Index: heromesh.h ================================================================== --- heromesh.h +++ heromesh.h @@ -161,10 +161,11 @@ extern int max_animation; // max steps in animation queue (default 32) extern Sint32 max_volume; // max total volume to allow moving diagonally (default 10000) extern Uint8 back_color,inv_back_color; extern char**stringpool; extern AnimationSlot anim_slot[8]; +extern Uint8 keymask[256/8]; Uint16 get_message_ptr(int c,int m); void load_classes(void); // == bindings == Index: instruc ================================================================== --- instruc +++ instruc @@ -252,6 +252,7 @@ *Local *Label *String *Int16 *Int32 +*Dispatch Index: instruc.h ================================================================== --- instruc.h +++ instruc.h @@ -365,10 +365,11 @@ #define OP_LOCAL 32946 #define OP_LABEL 32947 #define OP_STRING 32948 #define OP_INT16 32949 #define OP_INT32 32950 +#define OP_DISPATCH 32951 #ifdef HEROMESH_CLASS static const Op_Names op_names[]={ {"*",8486935}, {"+",8421397}, {"-",8421398},