Index: class.doc ================================================================== --- class.doc +++ class.doc @@ -1452,20 +1452,28 @@ bit23 * Reserved for future. bit24 * - Reserved for future. + Allows sliding to the left regardless of Height; the other attributes + still need to be correct (unless bit26 is set). The game engine sets + this bit if the Climb/Height is OK for moving. bit25 * - Reserved for future. + Allows sliding to the right regardless of Height; the other attributes + still need to be correct (unless bit27 is set). The game engine sets + this bit if the Climb/Height is OK for moving. -bit26 - Available for your own use; preserved across restarts. +bit26 * + Allows hitting to the left regardless of Shape, Volume, etc. In order + to actually move when sliding to the left, both bit24 and bit26 must + be set, and bit7 must be clear. -bit27 - Available for your own use; preserved across restarts. +bit27 * + Allows hitting to the right regardless of Shape, Volume, etc. In order + to actually move when sliding to the right, both bit25 and bit27 must + be set, and bit7 must be clear. bit28 Available for your own use. bit29 Index: exec.c ================================================================== --- exec.c +++ exec.c @@ -726,10 +726,19 @@ } // The OF_MOVED flag is set elsewhere, not here o->oflags&=~OF_DONE; return 1; } + +static inline int slide_test(Object*o,Object*oF,Uint32 d1,Uint32 d2,Uint32 vol) { + // Checks if sliding is possible, except the height of the target location. + Uint8 m=(o->shape&(1<shape&(1<<(4^d1))); + if(!(m&(m-1))) return 0; + if(!(o->shovable&(1<x+x_delta[d2],o->y+y_delta[d2])<=o->climb) return 1; + return vol+volume_at(o->x+x_delta[d2],o->y+y_delta[d2])<=max_volume; +} static int move_dir(Uint32 from,Uint32 obj,Uint32 dir) { // This function is complicated, and there may be mistakes. Object*o; Object*oE; @@ -746,18 +755,18 @@ o->inertia-=o->weight; restart: if(hit&0x100000) dir=o->dir; objF=obj_dir(obj,dir); if(objF==VOIDLINK) goto fail; - if(hit) hit=(hit&0x0C000000)|0x800; + if(hit) hit=0x800; oF=objects[objF]; + objLF=obj_dir(obj,(dir+1)&7); + objRF=obj_dir(obj,(dir-1)&7); if(height_at(oF->x,oF->y)<=o->climb) hit|=0x200000; if(dir&1) { // Diagonal movement hit|=0x80000; - objLF=obj_dir(obj,(dir+1)&7); - objRF=obj_dir(obj,(dir-1)&7); vol=o->volume; if(objLF!=VOIDLINK) vol+=volume_at(objects[objLF]->x,objects[objLF]->y); if(objRF!=VOIDLINK) vol+=volume_at(objects[objRF]->x,objects[objRF]->y); if(vol<=max_volume) { objE=objF; @@ -766,16 +775,16 @@ oE=objects[objE]; if(oE->height>0) { hit&=0xFC287000; v=send_message(objE,obj,MSG_HIT,NVALUE(oE->x),NVALUE(oE->y),NVALUE(hit)); if(v.t) Throw("Type mismatch in HIT/HITBY"); - hit|=v.u&(classes[o->class]->cflags&CF_COMPATIBLE?0xFC098F7F:-1); + hit|=v.u&(classes[o->class]->cflags&CF_COMPATIBLE?0xF0098F7F:-1); if(hit&8) goto fail; if(!(hit&0x11)) { v=send_message(obj,objE,MSG_HITBY,NVALUE(o->x),NVALUE(o->y),NVALUE(hit)); if(v.t) Throw("Type mismatch in HIT/HITBY"); - hit|=v.u&(classes[oE->class]->cflags&CF_COMPATIBLE?0xFC098F7F:-1); + hit|=v.u&(classes[oE->class]->cflags&CF_COMPATIBLE?0xF0098F7F:-1); if(hit&8) goto fail; } } objE=obj_below(objE); } @@ -810,25 +819,39 @@ } } } else { // Orthogonal movement if(!oF) goto fail; + if(o->shape) { + // Check if attributes allow sliding + vol=o->volume+volume_at(oF->x,oF->y); + if(objLF!=VOIDLINK && slide_test(o,oF,dir,(dir+2)&7,vol)) { + hit|=0x4000000; + oE=objects[objLF]; + if(height_at(oE->x,oE->y)<=o->climb) hit|=0x1000000; + } + if(objRF!=VOIDLINK && slide_test(o,oF,dir|1,(dir-2)&7,vol)) { + hit|=0x8000000; + oE=objects[objRF]; + if(height_at(oE->x,oE->y)<=o->climb) hit|=0x2000000; + } + } objE=objF; while(objE!=VOIDLINK) { if(o->oflags&(OF_DESTROYED|OF_VISUALONLY)) break; oE=objects[objE]; if(oE->height>0) { hit&=~7; // HIT/HITBY messages v=send_message(objE,obj,MSG_HIT,NVALUE(oE->x),NVALUE(oE->y),NVALUE(hit)); if(v.t) Throw("Type mismatch in HIT/HITBY"); - hit|=v.u&(classes[o->class]->cflags&CF_COMPATIBLE?0xFC098F7F:-1); + hit|=v.u&(classes[o->class]->cflags&CF_COMPATIBLE?0xF0098F7F:-1); if(hit&8) goto fail; if(!(hit&0x11)) { v=send_message(obj,objE,MSG_HITBY,NVALUE(o->x),NVALUE(o->y),NVALUE(hit)); if(v.t) Throw("Type mismatch in HIT/HITBY"); - hit|=v.u&(classes[oE->class]->cflags&CF_COMPATIBLE?0xFC098F7F:-1); + hit|=v.u&(classes[oE->class]->cflags&CF_COMPATIBLE?0xF0098F7F:-1); } if(hit&0x108) goto fail; // Hardness/sharpness if(!(hit&0x22)) { if(o->sharp[dir>>1]>oE->hard[(dir^4)>>1] && !v_bool(destroy(obj,objE,2))) hit|=0x8004; @@ -854,11 +877,79 @@ if(move_to(from,obj,oF->x,oF->y)) goto success; else goto fail; } // Sliding if(hit&0x80) goto fail; hit|=0x10000; - + if(hit&0x8000000) { + hit&=0xF010000; + objE=objRF; + while(objE!=VOIDLINK) { + if(o->oflags&(OF_DESTROYED|OF_VISUALONLY)) break; + oE=objects[objE]; + if(oE->height>0) { + hit&=~7; + // HIT/HITBY messages + v=send_message(objE,obj,MSG_HIT,NVALUE(oE->x),NVALUE(oE->y),NVALUE(hit)); + if(v.t) Throw("Type mismatch in HIT/HITBY"); + hit|=v.u&(classes[o->class]->cflags&CF_COMPATIBLE?0xF0098F7F:-1); + if(hit&8) goto otherside; + if(!(hit&0x11)) { + v=send_message(obj,objE,MSG_HITBY,NVALUE(o->x),NVALUE(o->y),NVALUE(hit)); + if(v.t) Throw("Type mismatch in HIT/HITBY"); + hit|=v.u&(classes[oE->class]->cflags&CF_COMPATIBLE?0xF0098F7F:-1); + } + if(hit&0x108) goto otherside; + // Hardness/sharpness + if(!(hit&0x22)) { + if(o->sharp[dir>>1]>oE->hard[(dir^4)>>1] && !v_bool(destroy(obj,objE,2))) hit|=0x8004; + if(oE->sharp[(dir^4)>>1]>o->hard[dir>>1] && !v_bool(destroy(objE,obj,1))) hit|=0x4C; + } + } + if(hit&0x600) goto otherside; + objE=obj_below(objE); + } + if((hit&0x48000)==0x8000) goto restart; + if((hit&0x2000000) && !(hit&0x400080)) { + if(hit&0x20000) goto success; + if(move_to(from,obj,objects[objRF]->x,objects[objRF]->y)) goto success; + } + } + otherside: + if(hit&0x4000000) { + hit&=0xF010000; + objE=objLF; + while(objE!=VOIDLINK) { + if(o->oflags&(OF_DESTROYED|OF_VISUALONLY)) break; + oE=objects[objE]; + if(oE->height>0) { + hit&=~7; + // HIT/HITBY messages + v=send_message(objE,obj,MSG_HIT,NVALUE(oE->x),NVALUE(oE->y),NVALUE(hit)); + if(v.t) Throw("Type mismatch in HIT/HITBY"); + hit|=v.u&(classes[o->class]->cflags&CF_COMPATIBLE?0xF0098F7F:-1); + if(hit&8) goto fail; + if(!(hit&0x11)) { + v=send_message(obj,objE,MSG_HITBY,NVALUE(o->x),NVALUE(o->y),NVALUE(hit)); + if(v.t) Throw("Type mismatch in HIT/HITBY"); + hit|=v.u&(classes[oE->class]->cflags&CF_COMPATIBLE?0xF0098F7F:-1); + } + if(hit&0x108) goto fail; + // Hardness/sharpness + if(!(hit&0x22)) { + if(o->sharp[dir>>1]>oE->hard[(dir^4)>>1] && !v_bool(destroy(obj,objE,2))) hit|=0x8004; + if(oE->sharp[(dir^4)>>1]>o->hard[dir>>1] && !v_bool(destroy(objE,obj,1))) hit|=0x4C; + } + } + if(hit&0x600) goto fail; + objE=obj_below(objE); + } + if((hit&0x48000)==0x8000) goto restart; + if((hit&0x1000000) && !(hit&0x400080)) { + if(hit&0x20000) goto success; + if(move_to(from,obj,objects[objLF]->x,objects[objLF]->y)) goto success; + } + } } fail: if(hit&0x1000) goto success; o->inertia=0; return 0; success: if(!(hit&0x4000)) o->oflags|=OF_MOVED; return 1; }