diff -r f89b8d0afbe1 -r bf13068194b3 hedgewars/GSHandlers.inc --- a/hedgewars/GSHandlers.inc Mon Nov 01 19:13:00 2010 -0400 +++ b/hedgewars/GSHandlers.inc Tue Nov 02 13:17:01 2010 +0100 @@ -3343,7 +3343,7 @@ var iterator, conPortal: PGear; s, r, nx, ny, ox, oy, poffs, noffs, pspeed, nspeed: hwFloat; - hasdxy, isbullet: Boolean; + hasdxy, isbullet, iscake: Boolean; begin doPortalColorSwitch(); @@ -3389,10 +3389,12 @@ // don't port portals or other gear that wouldn't make sense if (iterator^.Kind in [gtPortal, gtRope, gtRCPlane]) - or (iterator^.PortalCounter > 20) then + or (iterator^.PortalCounter > 32) then continue; // don't port hogs on rope + // TODO: this will also prevent hogs while falling after rope use from + // falling through portals... fix that! if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) and (iterator = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtRope) then @@ -3412,11 +3414,14 @@ or (iterator^.Y > Gear^.Y + r) then continue; - hasdxy := ((iterator^.dX.QWordValue <> 0) or (iterator^.dY.QWordValue <> 0)); - - // in case the object is not moving, let's asume it's moving towards the portal + hasdxy := (((iterator^.dX.QWordValue <> 0) or (iterator^.dY.QWordValue <> 0)) + or ((iterator^.State or gstMoving) = 0)); + + // in case the object is not moving, let's asume it's falling towards the portal if not hasdxy then begin + if Gear^.Y < iterator^.Y then + continue; ox:= Gear^.X - iterator^.X; oy:= Gear^.Y - iterator^.Y; end @@ -3426,15 +3431,24 @@ oy:= iterator^.dY; end; + // cake will need extra treatment... it's so delicious and moist! + iscake:= (iterator^.Kind = gtCake); + // won't port stuff that does not move towards the front/portal entrance - if not (Gear^.dX*ox + Gear^.dY*oy).isNegative then + if iscake then + begin + if not ((iterator^.X - Gear^.X)*ox + (iterator^.Y - Gear^.Y)*oy).isNegative then + continue; + end + else + if not (Gear^.dX*ox + Gear^.dY*oy).isNegative then continue; isbullet:= (iterator^.Kind in [gtShotgunShot, gtDEagleShot, gtSniperRifleShot, gtSineGunShot]); r:= int2hwFloat(iterator^.Radius); - if not isbullet and (iterator^.Kind <> gtCake) then + if not (isbullet or iscake) then begin // wow! good candidate there, let's see if the distance and direction is okay! if hasdxy then @@ -3453,16 +3467,6 @@ continue; end; -(* - noTrap := ((not Gear^.dY.isNegative or (Gear^.dY.QWordValue = 0)) - // can't be entered from above - or ((conPortal^.dY.isNegative and not (conPortal^.dY.QWordValue = 0)))); - // can't be left downwards; - - // prevent getting stuck in a ground portal loop - if noTrap and (iterator^.dY.QWordValue < _0_08.QWordValue) then - continue; *) - // calc gear offset in portal vector direction ox := (iterator^.X - Gear^.X); oy := (iterator^.Y - Gear^.Y); @@ -3475,9 +3479,6 @@ // gears that make it till here will definately be ported // - if isbullet then - poffs:= _1_5; - // create a normal of the portal vector, but ... nx := Gear^.dY; ny := Gear^.dX; @@ -3490,24 +3491,26 @@ // calc gear offset in portal normal vector direction noffs:= (nx * ox + ny * oy); - // move stuff with high normal offset close to the portal's center - if not isbullet then - begin - s := hwAbs(noffs) + r - int2hwFloat(Gear^.Radius); - if s > _0 then - noffs:= noffs - SignAs(s,noffs) - end; - - iterator^.Active := true; - iterator^.State := iterator^.State or gstMoving; - DeleteCI(iterator); + // avoid gravity related loops of not really moving gear + if not iscake and (Gear^.dY.isNegative) and (conPortal^.dY.isNegative) + and ((iterator^.dX.QWordValue + iterator^.dY.QWordValue) < _0_08.QWordValue) + and (iterator^.PortalCounter > 0) then + continue; // Until loops are reliably broken inc(iterator^.PortalCounter); // calc gear speed along to the vector and the normal vector of the portal - pspeed:= (Gear^.dX * iterator^.dX + Gear^.dY * iterator^.dY); - nspeed:= (nx * iterator^.dX + ny * iterator^.dY); + if hasdxy then + begin + pspeed:= (Gear^.dX * iterator^.dX + Gear^.dY * iterator^.dY); + nspeed:= (nx * iterator^.dX + ny * iterator^.dY); + end + else + begin + pspeed:= hwAbs(cGravity * oy); + nspeed:= _0; + end; // creating normal vector of connected (exit) portal nx := conPortal^.dY; @@ -3517,17 +3520,45 @@ else ny.isNegative := not ny.isNegative; + // inverse cake's normal movement direction, + // as if it just walked through a hole + if iscake then + nspeed.isNegative:= not nspeed.isNegative; + //AddFileLog('poffs:'+cstr(poffs)+' noffs:'+cstr(noffs)+' pspeed:'+cstr(pspeed)+' nspeed:'+cstr(nspeed)); iterator^.dX := -pspeed * conPortal^.dX + nspeed * nx; iterator^.dY := -pspeed * conPortal^.dY + nspeed * ny; - if iterator^.Kind = gtCake then - poffs := poffs * _0_5 - else - if poffs < r + _1_5 then - poffs := r + _1_5; + + // make the gear's exit position close to the portal while + // still respecting the movement direction + + // determine the distance (in exit vector direction) + // that we want the gear at + if iscake then + ox:= (r - _0_7) + else + ox:= (r + _1_9); + s:= ox / poffs; + poffs:= ox; + if (nspeed.QWordValue <> 0) and (pspeed > _0) then + noffs:= noffs * s * (nspeed / pspeed); + + // move stuff with high normal offset closer to the portal's center + if not isbullet then + begin + s := hwAbs(noffs) + r - int2hwFloat(Gear^.Radius); + if s > _0 then + noffs:= noffs - SignAs(s,noffs) + end; + iterator^.X := conPortal^.X + poffs * conPortal^.dX + noffs * nx; iterator^.Y := conPortal^.Y + poffs * conPortal^.dY + noffs * ny; + if not hasdxy and not (conPortal^.dY.isNegative) then + begin + iterator^.dY:= iterator^.dY + hwAbs(cGravity * (iterator^.Y - conPortal^.Y)) + end; + if not isbullet then FollowGear := iterator; //AddFileLog('portal''d'); @@ -3547,7 +3578,7 @@ if iterator^.dY.QWordValue = _0.QWordValue then iterator^.dY.isNegative:= false; iterator^.State:= iterator^.State or gstMoving; DeleteCI(iterator); - inc(iterator^.dY.QWordValue,10); + //inc(iterator^.dY.QWordValue,10); end; iterator:= iterator^.NextGear end;