Index: exec.c ================================================================== --- exec.c +++ exec.c @@ -688,11 +688,11 @@ restart: if(hit&0x100000) dir=o->dir; objF=obj_dir(obj,dir); if(objF==VOIDLINK) goto fail; oF=objects[objF]; - hF=height_at(oF->x,oF->y); + hF=oF?height_at(oF->x,oF->y):0; if(dir&1) { // Diagonal movement objLF=obj_dir(obj,(dir+1)&7); objRF=obj_dir(obj,(dir-1)&7); vol=o->volume; @@ -700,11 +700,11 @@ if(objRF!=VOIDLINK) vol+=volume_at(objects[objRF]->x,objects[objRF]->y); if(vol<=max_volume) { objE=objF; while(objE!=VOIDLINK) { oE=objects[objE]; - if(oE->height>0 && !(oE->oflags&(OF_VISUALONLY|OF_DESTROYED))) { + if(oE->height>0) { v=send_message(objE,obj,MSG_HIT,NVALUE(oE->x),NVALUE(oE->y),NVALUE(hit|0x80000)); if(v.t) Throw("Type mismatch in HIT/HITBY"); hit=v.u&(classes[o->class]->cflags&CF_COMPATIBLE?0xFC098F7F:-1); if(hit&8) goto fail; if(!(hit&0x11)) { @@ -717,29 +717,30 @@ objE=obj_below(objE); } if(!(hit&0x402008)) { if(hF<=o->climb || (hit&0x200000)) { if(hit&0x20000) goto success; + if(!oF) goto fail; if(move_to(from,obj,oF->x,oF->y)) goto success; else goto fail; } } } else { // Volume is too much; hit the objects it won't go between objE=objLF; while(objE!=VOIDLINK) { oE=objects[objE]; - if(oE->height>0 && !(oE->oflags&(OF_VISUALONLY|OF_DESTROYED))) { + if(oE->height>0) { v=send_message(objE,obj,MSG_HIT,NVALUE(oE->x),NVALUE(oE->y),NVALUE(0x80008)); if(v.t) Throw("Type mismatch in HIT/HITBY"); if(!(v.u&1)) v=send_message(obj,objE,MSG_HITBY,NVALUE(o->x),NVALUE(o->y),NVALUE(v.u|0x80008)); } objE=obj_below(objE); } objE=objRF; while(objE!=VOIDLINK) { oE=objects[objE]; - if(oE->height>0 && !(oE->oflags&(OF_VISUALONLY|OF_DESTROYED))) { + if(oE->height>0) { v=send_message(objE,obj,MSG_HIT,NVALUE(oE->x),NVALUE(oE->y),NVALUE(0x80008)); if(v.t) Throw("Type mismatch in HIT/HITBY"); if(!(v.u&1)) v=send_message(obj,objE,MSG_HITBY,NVALUE(o->x),NVALUE(o->y),NVALUE(v.u|0x80008)); } objE=obj_below(objE); @@ -749,11 +750,11 @@ // Orthogonal movement if(hit) hit=(hit&0x0C000000)|0x800; objE=objF; while(objE!=VOIDLINK) { oE=objects[objE]; - if(oE->height>0 && !(oE->oflags&(OF_VISUALONLY|OF_DESTROYED))) { + 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); @@ -785,10 +786,11 @@ if(hit&0x2008) goto fail; if((hit&0x48000)==0x8000) goto restart; if(!(hit&0x400000)) { if(hF<=o->climb || (hit&0x200000)) { if(hit&0x20000) goto success; + if(!oF) goto fail; if(move_to(from,obj,oF->x,oF->y)) goto success; else goto fail; } } // Sliding if(hit&0x80) goto fail; @@ -1492,14 +1494,14 @@ free(objects); objects=0; gameover=0; } -static Uint8 execute_animation(Uint8 clock,Uint32 obj) { +static void execute_animation(Uint32 obj) { Object*o=objects[obj]; Animation*a=o->anim; - if(!(a->step[a->lstep].flag&ANI_ONCE)) return clock; + if(!(a->step[a->lstep].flag&ANI_ONCE)) return; if(a->ltime>=a->step[a->lstep].speed) { a->ltime=0; if(o->image==a->step[a->lstep].end) { a->status&=~ANISTAT_LOGICAL; if(classes[o->class]->cflags&CF_COMPATIBLE) lastimage_processing=1; @@ -1507,22 +1509,23 @@ lastimage_processing=0; } else { if(a->step[a->lstep].start>a->step[a->lstep].end) --o->image; else ++o->image; } } - if(!(a->status&ANISTAT_LOGICAL) || !(a->step[a->lstep].flag&ANI_ONCE)) return clock; - if(clock>a->step[a->lstep].speed-a->ltime) return a->step[a->lstep].speed-a->ltime; - return clock; } const char*execute_turn(int key) { Uint8 busy,clock; Uint32 m,n,turn; Object*o; Value v; int i; - if(!key) return 0; + if(!key) { + // This is part of initialization; if anything triggered, it must be executed now + all_flushed=1; + goto trig; + } if(setjmp(my_env)) return my_error; if(quiz_text) { sqlite3_free(quiz_text); quiz_text=0; if(key_ignored) { @@ -1595,11 +1598,11 @@ if(o->arrived) { send_message(VOIDLINK,n,MSG_ARRIVED,NVALUE(0),NVALUE(0),NVALUE(turn)); o->arrived=0; busy=1; } - if(o->anim && (o->anim->status&ANISTAT_LOGICAL)) clock=execute_animation(clock,n); + if(o->anim && (o->anim->status&ANISTAT_LOGICAL)) execute_animation(n); if(o->oflags&(OF_BUSY|OF_USERSIGNAL)) busy=1; } else { o->departed2=o->departed; o->departed=0; o->arrived2=o->arrived; @@ -1616,11 +1619,11 @@ if(o->oflags&OF_MOVED2) send_message(VOIDLINK,n,MSG_MOVED,NVALUE(0),NVALUE(0),NVALUE(turn)),busy=1; if(o->departed2) send_message(VOIDLINK,n,MSG_DEPARTED,NVALUE(o->departed2),NVALUE(0),NVALUE(turn)),busy=1; if(o->arrived2) send_message(VOIDLINK,n,MSG_ARRIVED,NVALUE(o->arrived2),NVALUE(0),NVALUE(turn)),busy=1; o->oflags&=~OF_MOVED2; o->arrived2=o->departed2=0; - if(o->anim && (o->anim->status&ANISTAT_LOGICAL)) clock=execute_animation(clock,n); + if(o->anim && (o->anim->status&ANISTAT_LOGICAL)) execute_animation(n); if(o->oflags&(OF_BUSY|OF_USERSIGNAL)) busy=1; } n=o->prev; } // Ending phase @@ -1634,22 +1637,30 @@ } turn++; if(!busy) all_flushed=1; } // Clock phase - if(!clock) clock=1; + n=lastobj; + while(n!=VOIDLINK) { + o=objects[n]; + if(o->arrived || o->departed) goto trig; + if(o->oflags&OF_MOVED) goto trig; + if(o->anim && (o->anim->status&ANISTAT_LOGICAL) && (o->anim->step[o->anim->lstep].flag&ANI_ONCE)) { + if(o->anim->ltime>=o->anim->step[o->anim->lstep].speed) goto trig; + if(clock>o->anim->step[o->anim->lstep].speed-o->anim->ltime) clock=o->anim->step[o->anim->lstep].speed-o->anim->ltime; + } + n=o->prev; + } n=lastobj; while(n!=VOIDLINK) { o=objects[n]; if(o->oflags&(OF_BUSY|OF_USERSIGNAL|OF_MOVED)) busy=1; if(o->arrived || o->departed) busy=1; - if(o->anim && (o->anim->status&ANISTAT_LOGICAL)) { - if(o->anim->step[o->anim->lstep].flag&ANI_ONCE) { - i=o->anim->ltime+clock; - o->anim->ltime=i>255?255:i; - busy=1; - } + if(o->anim && (o->anim->status&ANISTAT_LOGICAL) && (o->anim->step[o->anim->lstep].flag&ANI_ONCE)) { + i=o->anim->ltime+clock; + o->anim->ltime=i>255?255:i; + busy=1; } n=o->prev; } if(busy) goto trig; // Cleanup phase @@ -1672,8 +1683,8 @@ vstackptr=0; move_number=0; current_key=0; broadcast(VOIDLINK,0,MSG_INIT,NVALUE(0),NVALUE(0),NVALUE(0),0); broadcast(VOIDLINK,0,MSG_POSTINIT,NVALUE(0),NVALUE(0),NVALUE(0),0); - if(generation_number<=TY_MAXTYPE) return "Too many generations of objects"; - return 0; + if(gameover) return 0; + return execute_turn(0); } Index: game.c ================================================================== --- game.c +++ game.c @@ -491,11 +491,11 @@ SDL_SetTimer(0,0); return; } if(inputs_count) { //TODO: Check for solution replay - for(i=0;i