Index: class.doc ================================================================== --- class.doc +++ class.doc @@ -1123,11 +1123,12 @@ SetInventory ( class image value -- ) ** Sets an inventory item with the specified class and image number to the specified value (which must be a number). If there is no inventory item with that exact class and image, an inventory item will be added, - otherwise the existing one is updated to the new value. + otherwise the existing one is updated to the new value. Inventory values + are always unsigned 16-bit numbers. Sound ( sound interruptflag -- ) Play a sound; if the interrupt flag is zero then it does not interrupt existing sounds but otherwise it does. It is not an error if the values of the arguments are not valid. Index: exec.c ================================================================== --- exec.c +++ exec.c @@ -30,10 +30,12 @@ Uint8 pfwidth,pfheight; Sint8 gameover,key_ignored; Uint8 generation_number_inc; Uint32 move_number; unsigned char*quiz_text; +Inventory*inventory; +Uint32 ninventory; typedef struct { Uint16 msg; Uint32 from; Value arg1,arg2,arg3; @@ -175,10 +177,16 @@ } free(o); objects[n]=0; generation_number_inc=1; } + +static inline void clear_inventory(void) { + free(inventory); + inventory=0; + ninventory=0; +} static inline Uint8 resolve_dir(Uint32 n,Uint32 d) { return d<8?d:(objects[n]->dir+d)&7; } @@ -544,11 +552,11 @@ if(x<1 || y<1 || x>pfwidth || y>pfheight) return VOIDLINK; if(!(classes[c]->oflags&OF_BIZARRO) && (i=classes[c]->collisionLayers) && (xx=collisions_at(x,y)&i)) { if(collide_with(xx,VOIDLINK,x,y,c)&0x01) return VOIDLINK; } n=objalloc(c); - if(n==VOIDLINK) return VOIDLINK; + if(n==VOIDLINK) Throw("Error creating object"); o=objects[n]; o->x=x; o->y=y; o->image=im; o->dir=d; @@ -946,10 +954,50 @@ static inline Value v_send_self(Uint32 from,Value msg,Value arg1,Value arg2,Value arg3) { if(msg.t!=TY_MESSAGE) Throw("Type mismatch"); return send_message(from,from,msg.u,arg1,arg2,arg3); } + +static void v_delete_inventory(Value cl,Value im) { + int i; + if(!cl.t && !cl.u) return; + if(cl.t!=TY_CLASS || im.t!=TY_NUMBER) Throw("Type mismatch"); + for(i=0;i=max_objects) Throw("Inventory exceeds max_objects"); + for(i=0;iclass]->collisionLayers)); break; case OP_COMPATIBLE: StackReq(0,1); if(classes[o->class]->cflags&CF_COMPATIBLE) Push(NVALUE(1)); else Push(NVALUE(0)); break; case OP_COMPATIBLE_C: StackReq(1,1); GetClassFlagOf(CF_COMPATIBLE); break; case OP_CREATE: NoIgnore(); StackReq(5,1); t5=Pop(); t4=Pop(); t3=Pop(); t2=Pop(); t1=Pop(); Push(v_create(obj,t1,t2,t3,t4,t5)); break; case OP_CREATE_D: NoIgnore(); StackReq(5,0); t5=Pop(); t4=Pop(); t3=Pop(); t2=Pop(); t1=Pop(); v_create(obj,t1,t2,t3,t4,t5); break; + case OP_DELINVENTORY: StackReq(2,0); t2=Pop(); t1=Pop(); v_delete_inventory(t1,t2); break; case OP_DELTA: StackReq(2,1); t2=Pop(); Numeric(t2); t1=Pop(); Numeric(t1); Push(NVALUE(t1.u>t2.u?t1.u-t2.u:t2.u-t1.u)); break; case OP_DENSITY: StackReq(0,1); Push(NVALUE(o->density)); break; case OP_DENSITY_C: StackReq(1,1); Push(GetVariableOrAttributeOf(density,NVALUE)); break; case OP_DENSITY_E: NoIgnore(); StackReq(1,0); t1=Pop(); Numeric(t1); change_density(obj,t1.s); break; case OP_DENSITY_E16: NoIgnore(); StackReq(1,0); t1=Pop(); Numeric(t1); change_density(obj,t1.s&0xFFFF); break; @@ -1211,10 +1260,11 @@ case OP_FLUSHOBJ_C: NoIgnore(); StackReq(1,0); i=v_object(Pop()); if(i!=VOIDLINK) flush_object(i); break; case OP_FOR: NoIgnore(); StackReq(3,1); t3=Pop(); t2=Pop(); t1=Pop(); ptr=v_for(code,ptr,t1,t2,t3); break; case OP_FROM: StackReq(0,1); Push(OVALUE(msgvars.from)); break; case OP_GE: StackReq(2,1); t2=Pop(); t1=Pop(); Push(NVALUE(v_unsigned_greater(t2,t1)?0:1)); break; case OP_GE_C: StackReq(2,1); t2=Pop(); t1=Pop(); Push(NVALUE(v_signed_greater(t2,t1)?0:1)); break; + case OP_GETINVENTORY: StackReq(2,2); t2=Pop(); t1=Pop(); v_get_inventory(t1,t2); break; case OP_GOTO: ptr=code[ptr]; break; case OP_GT: StackReq(2,1); t2=Pop(); t1=Pop(); Push(NVALUE(v_unsigned_greater(t1,t2)?1:0)); break; case OP_GT_C: StackReq(2,1); t2=Pop(); t1=Pop(); Push(NVALUE(v_signed_greater(t1,t2)?1:0)); break; case OP_HARD: StackReq(1,1); j=v_sh_dir(Pop()); Push(NVALUE(o->hard[j])); break; case OP_HARD_C: StackReq(2,1); j=v_sh_dir(Pop()); Push(GetVariableOrAttributeOf(hard[j],NVALUE)); break; @@ -1268,10 +1318,11 @@ case OP_LOSELEVEL: gameover=-1; Throw(0); break; case OP_LSH: StackReq(2,1); t2=Pop(); Numeric(t2); t1=Pop(); Numeric(t1); Push(NVALUE(t2.u&~31?0:t1.u<t1.u) Throw("Inventory overflow"); break; case OP_MOD: StackReq(2,1); t2=Pop(); DivideBy(t2); t1=Pop(); Numeric(t1); Push(NVALUE(t1.u%t2.u)); break; case OP_MOD_C: StackReq(2,1); t2=Pop(); DivideBy(t2); t1=Pop(); Numeric(t1); Push(NVALUE(t1.s%t2.s)); break; case OP_MOVE: NoIgnore(); StackReq(1,1); t1=Pop(); Numeric(t1); o->inertia=o->strength; Push(NVALUE(move_dir(obj,obj,t1.u))); break; case OP_MOVE_C: NoIgnore(); StackReq(2,1); t1=Pop(); Numeric(t1); i=v_object(Pop()); if(i==VOIDLINK) Push(NVALUE(0)); else { objects[i]->inertia=o->strength; Push(NVALUE(move_dir(obj,i,t1.u))); } break; case OP_MOVE_D: NoIgnore(); StackReq(1,0); t1=Pop(); Numeric(t1); o->inertia=o->strength; move_dir(obj,obj,t1.u); break; @@ -1322,10 +1373,11 @@ case OP_SEND_CD: StackReq(4,0); t4=Pop(); t3=Pop(); t2=Pop(); t1=Pop(); v_send_message(obj,t1,t2,t3,t4,NVALUE(0)); break; case OP_SENDEX: StackReq(4,1); t5=Pop(); t4=Pop(); t3=Pop(); t2=Pop(); Push(v_send_self(obj,t2,t3,t4,t5)); break; case OP_SENDEX_C: StackReq(5,1); t5=Pop(); t4=Pop(); t3=Pop(); t2=Pop(); t1=Pop(); Push(v_send_message(obj,t1,t2,t3,t4,t5)); break; case OP_SENDEX_D: StackReq(4,0); t5=Pop(); t4=Pop(); t3=Pop(); t2=Pop(); v_send_self(obj,t2,t3,t4,t5); break; case OP_SENDEX_CD: StackReq(5,0); t5=Pop(); t4=Pop(); t3=Pop(); t2=Pop(); t1=Pop(); v_send_message(obj,t1,t2,t3,t4,t5); break; + case OP_SETINVENTORY: StackReq(3,0); t3=Pop(); t2=Pop(); t1=Pop(); v_set_inventory(t1,t2,t3); break; case OP_SHAPE: StackReq(0,1); Push(NVALUE(o->shape)); break; case OP_SHAPE_C: StackReq(1,1); Push(GetVariableOrAttributeOf(shape,NVALUE)); break; case OP_SHAPE_E: NoIgnore(); StackReq(1,0); t1=Pop(); Numeric(t1); o->shape=t1.u; break; case OP_SHAPE_EC: NoIgnore(); StackReq(2,0); t1=Pop(); Numeric(t1); i=v_object(Pop()); if(i!=VOIDLINK) objects[i]->shape=t1.u; break; case OP_SHAPEDIR: StackReq(1,1); j=v_sh_dir(Pop()); Push(NVALUE((o->shape>>(j+j))&3)); break; @@ -1505,10 +1557,11 @@ } nobjects=0; free(objects); objects=0; gameover=0; + clear_inventory(); } static void execute_animation(Uint32 obj) { Object*o=objects[obj]; Animation*a=o->anim; @@ -1684,10 +1737,11 @@ return 0; } const char*init_level(void) { if(setjmp(my_env)) return my_error; + clear_inventory(); if(main_options['t']) { printf("[Level %d restarted]\n",level_id); if(!traced_obj.t) { const char*s; optionquery[1]=Q_traceObject; Index: heromesh.h ================================================================== --- heromesh.h +++ heromesh.h @@ -215,10 +215,15 @@ } Object; // Some objects may remain in memory for animation purposes even after they have been // destroyed. In this case, their "generation" value is zero, and they will always // have the OF_DESTROYED flag. + +typedef struct { + Uint16 class,value; + Uint8 image; +} Inventory; extern Uint32 max_objects; extern Uint32 generation_number; extern Object**objects; extern Uint32 nobjects; @@ -228,10 +233,12 @@ extern Uint8 pfwidth,pfheight; extern Sint8 gameover,key_ignored; extern Uint8 generation_number_inc; extern Uint32 move_number; extern unsigned char*quiz_text; +extern Inventory*inventory; +extern Uint32 ninventory; const char*value_string_ptr(Value v); void pfunlink(Uint32 n); void pflink(Uint32 n); Uint32 objalloc(Uint16 c);