Index: TODO ================================================================== --- TODO +++ TODO @@ -10,11 +10,10 @@ * String data * A ,PopUp command to use a popup with arguments starting from a mark * "Goto message" instruction (?) * Returning a class from COLLIDE/COLLIDEBY to transform * Coordinate input (may be suitable for some kind of games) - * A way to change the order of objects execution * Editor * Mouse dragging * Level index editor * Table of contents for levels * Can define your own columns @@ -29,10 +28,11 @@ * Bookmarks * Message trace menu to enable/disable * Bugs * Figure out why the $SeekerCloser class doesn't seem to work properly * Level 232 of SUPERHRO puzzle set (the Lava shouldn't expand? why?) + * Animation stopping unexpectedly (until a key is pushed) * Display solution comments/timestamp * VCR mode * Command-line switch for batch import/export levels * SQL * Implement the GROUP column in the CLASSES table @@ -47,5 +47,6 @@ * Option to auto display level titles * Testing * Bizarro world * Deferred movement * Sweep, SweepEx, HitMe + * Overriding order of execution Index: class.c ================================================================== --- class.c +++ class.c @@ -2169,11 +2169,11 @@ orders=realloc(orders,ptr*sizeof(Uint16))?:orders; } static void set_class_orders(void) { int i,j,k; - for(i=1;icflags&(CF_GROUP|CF_NOCLASS2))) { + for(i=1;inmsg || classes[0]->nmsg) || !(classes[i]->cflags&(CF_GROUP|CF_NOCLASS2))) { for(j=1;jmisc4&(1UL<<(k&0x1F))) goto found; break; case 0x1020 ... 0x103F: if(classes[i]->misc5&(1UL<<(k&0x1F))) goto found; break; Index: class.doc ================================================================== --- class.doc +++ class.doc @@ -287,11 +287,13 @@ (Misc7 ) Define user flags as Misc7 bits; the first defined flag is bit0. Up to 32 flags can be defined in this way. (Order ) - (Not fully implemented yet.) + See the section below about order of execution. Normally, order of + execution (for broadcasts and some other things) is in the reverse order + of creation; the (Order) block allows you to override this order. (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. @@ -2470,14 +2472,10 @@ Used for debugging. === Order of execution === -(The below describes a feature that is not implemented yet; currently -only the syntax is implemented. When it is completed, this note will be -removed and further descriptions will be added below.) - You can specify the order of execution of objects by class by a global (Order) block. Inside of this block is a list of sub-lists; each sub-list is delimited by parentheses. Each sub-list starts with a flag name, which may be a user flag, or Input, @@ -2496,10 +2494,15 @@ The order of execution is then first all objects not listed in the (Order) block, and then for each sub-list in the (Order) block, the objects that meet that criteria, in that order. (If it meets multiple criteria, only the first one that meets that criteria is used.) +Note: If a value used for the criteria changes after the INIT or CREATE +message of that object returns, then it can result in an unstable (but +still fully deterministic) order when new objects are created. For this +reason, you should only use criteria based on values which don't change. + === Compatibility === Compatible objects have the following differences from the default: Index: exec.c ================================================================== --- exec.c +++ exec.c @@ -666,10 +666,106 @@ } if(obj_layer_at(b,x,y)!=VOIDLINK) r|=0x01; } return r; } + +static void set_order(Uint32 obj) { + // To avoid confusing order of execution at the wrong time, + // calling this function is limited to only certain times. + Object*o=objects[obj]; + Uint8 ord=classes[objects[obj]->class]->order; + Uint8 u; + Sint32 v0,v1; + Uint16 p=orders[ord]+1; + Uint32 n=firstobj; + for(;;) { + if(n==obj || n==VOIDLINK) goto notfound; + u=classes[objects[n]->class]->order; + if(udensity; v1=objects[n]->density; goto compare; + case OP_DENSITY_C: v1=o->density; v0=objects[n]->density; goto compare; + case OP_IMAGE: v0=o->image; v1=objects[n]->image; goto compare; + case OP_IMAGE_C: v1=o->image; v0=objects[n]->image; goto compare; + case OP_MISC1: + if(o->misc1.t || objects[n]->misc1.t) Throw("Type mismatch in order criteria"); + v0=o->misc1.s; v1=objects[n]->misc1.s; goto compare; + case OP_MISC1_C: + if(o->misc1.t || objects[n]->misc1.t) Throw("Type mismatch in order criteria"); + v1=o->misc1.s; v0=objects[n]->misc1.s; goto compare; + case OP_MISC2: + if(o->misc2.t || objects[n]->misc2.t) Throw("Type mismatch in order criteria"); + v0=o->misc2.s; v1=objects[n]->misc2.s; goto compare; + case OP_MISC2_C: + if(o->misc2.t || objects[n]->misc2.t) Throw("Type mismatch in order criteria"); + v1=o->misc2.s; v0=objects[n]->misc2.s; goto compare; + case OP_MISC3: + if(o->misc3.t || objects[n]->misc3.t) Throw("Type mismatch in order criteria"); + v0=o->misc3.s; v1=objects[n]->misc3.s; goto compare; + case OP_MISC3_C: + if(o->misc3.t || objects[n]->misc3.t) Throw("Type mismatch in order criteria"); + v1=o->misc3.s; v0=objects[n]->misc3.s; goto compare; + case OP_MISC4: + if(o->misc4.t || objects[n]->misc4.t) Throw("Type mismatch in order criteria"); + v0=o->misc4.s; v1=objects[n]->misc4.s; goto compare; + case OP_MISC4_C: + if(o->misc4.t || objects[n]->misc4.t) Throw("Type mismatch in order criteria"); + v1=o->misc4.s; v0=objects[n]->misc4.s; goto compare; + case OP_MISC5: + if(o->misc5.t || objects[n]->misc5.t) Throw("Type mismatch in order criteria"); + v0=o->misc5.s; v1=objects[n]->misc5.s; goto compare; + case OP_MISC5_C: + if(o->misc5.t || objects[n]->misc5.t) Throw("Type mismatch in order criteria"); + v1=o->misc5.s; v0=objects[n]->misc5.s; goto compare; + case OP_MISC6: + if(o->misc6.t || objects[n]->misc6.t) Throw("Type mismatch in order criteria"); + v0=o->misc6.s; v1=objects[n]->misc6.s; goto compare; + case OP_MISC6_C: + if(o->misc6.t || objects[n]->misc6.t) Throw("Type mismatch in order criteria"); + v1=o->misc6.s; v0=objects[n]->misc6.s; goto compare; + case OP_MISC7: + if(o->misc7.t || objects[n]->misc7.t) Throw("Type mismatch in order criteria"); + v0=o->misc7.s; v1=objects[n]->misc7.s; goto compare; + case OP_MISC7_C: + if(o->misc7.t || objects[n]->misc7.t) Throw("Type mismatch in order criteria"); + v1=o->misc7.s; v0=objects[n]->misc7.s; goto compare; + case OP_TEMPERATURE: v0=o->temperature; v1=objects[n]->temperature; goto compare; + case OP_TEMPERATURE_C: v1=o->temperature; v0=objects[n]->temperature; goto compare; + case OP_XLOC: v0=o->x; v1=objects[n]->x; goto compare; + case OP_XLOC_C: v1=o->x; v0=objects[n]->x; goto compare; + case OP_YLOC: v0=o->y; v1=objects[n]->y; goto compare; + case OP_YLOC_C: v1=o->y; v0=objects[n]->y; goto compare; + compare: + if(v0==v1) { + p++; + goto criteria; + } + if(v0>v1) goto found; + break; + default: fatal("Internal confusion: Invalid order criteria (%d)\n",orders[p]); + } + } + n=objects[n]->next; + } + found: + // Now it has been found; insert this object previous to the found object, removing from its existing slot. + // (Objects are executed in reverse order, so previous in the linked list means executed next) + if(firstobj==obj) firstobj=o->next; + if(lastobj==obj) lastobj=o->prev; + if(o->prev!=VOIDLINK) objects[o->prev]->next=o->next; + if(o->next!=VOIDLINK) objects[o->next]->prev=o->prev; + o->prev=objects[n]->prev; + o->next=n; + objects[n]->prev=obj; + if(o->prev==VOIDLINK) firstobj=obj; + if(objects[n]->next==VOIDLINK) lastobj=n; + notfound: + objects[obj]->oflags|=OF_ORDERED; +} static Uint32 create(Uint32 from,Uint16 c,Uint32 x,Uint32 y,Uint32 im,Uint32 d) { Uint32 m,n; int i,xx,yy; Object*o; @@ -701,10 +797,11 @@ if(p->arrivals&(1<x),NVALUE(o->y),v); m=p->up; } } if(o->oflags&OF_DESTROYED) return VOIDLINK; + if(classes[objects[n]->class]->order) set_order(n); m=objects[n]->up; if(m!=VOIDLINK) { v=send_message(VOIDLINK,n,MSG_SUNK,NVALUE(0),NVALUE(0),v); while(m!=VOIDLINK) { send_message(n,m,MSG_FLOATED,NVALUE(0),NVALUE(0),v); @@ -3148,10 +3245,11 @@ // Finished return 0; } const char*init_level(void) { + Uint32 n; if(setjmp(my_env)) return my_error; clear_inventory(); if(main_options['t']) { printf("[Level %d restarted]\n",level_id); if(!traced_obj.t) { @@ -3175,10 +3273,15 @@ all_flushed=0; lastimage_processing=0; vstackptr=0; move_number=0; current_key=0; - broadcast(VOIDLINK,0,MSG_INIT,NVALUE(0),NVALUE(0),NVALUE(0),0); + n=lastobj; + while(n!=VOIDLINK && !(objects[n]->oflags&OF_ORDERED)) { + send_message(VOIDLINK,n,MSG_INIT,NVALUE(0),NVALUE(0),NVALUE(0)); + if(classes[objects[n]->class]->order && !(objects[n]->oflags&OF_DESTROYED)) set_order(n); + n=objects[n]->prev; + } broadcast(VOIDLINK,0,MSG_POSTINIT,NVALUE(0),NVALUE(0),NVALUE(0),0); if(gameover) return 0; return execute_turn(0); } Index: heromesh.h ================================================================== --- heromesh.h +++ heromesh.h @@ -142,10 +142,11 @@ #define OF_KEYCLEARED 0x0100 #define OF_DESTROYED 0x0200 #define OF_BIZARRO 0x0400 #define OF_MOVED2 0x0800 #define OF_MOVING 0x1000 +#define OF_ORDERED 0x2000 typedef struct { const char*name; const char*edithelp; // not present if CF_GROUP const char*gamehelp; // not present if CF_GROUP