diff -r fe799b5d601b -r 8e4f4b72c132 hedgewars/GSHandlers.inc --- a/hedgewars/GSHandlers.inc Sun Oct 31 18:28:12 2010 +0100 +++ b/hedgewars/GSHandlers.inc Sun Oct 31 19:16:54 2010 +0100 @@ -3342,8 +3342,8 @@ procedure doStepPortal(Gear: PGear); var iterator, conPortal: PGear; - s, acptRadius, nx, ny, ox, oy, poffs, noffs, pspeed, nspeed: hwFloat; - hasdxy: Boolean; + s, r, nx, ny, ox, oy, poffs, noffs, pspeed, nspeed: hwFloat; + hasdxy, isbullet: Boolean; begin doPortalColorSwitch(); @@ -3388,9 +3388,9 @@ break; // don't port portals or other gear that wouldn't make sense - if (iterator^.Kind = gtPortal) or (iterator^.Kind = gtRope) - or (iterator^.Kind = gtRCPlane) or (iterator^.PortalCounter > 20) then - continue; + if (iterator^.Kind in [gtPortal, gtRope, gtRCPlane]) + or (iterator^.PortalCounter > 20) then + continue; // don't port hogs on rope if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) @@ -3403,13 +3403,13 @@ continue; // this is the max range we accept incoming gears in - acptRadius := Int2hwFloat(iterator^.Radius+Gear^.Radius); + r := Int2hwFloat(iterator^.Radius+Gear^.Radius); // too far away? - if (iterator^.X < Gear^.X - acptRadius) - or (iterator^.X > Gear^.X + acptRadius) - or (iterator^.Y < Gear^.Y - acptRadius) - or (iterator^.Y > Gear^.Y + acptRadius) then + if (iterator^.X < Gear^.X - r) + or (iterator^.X > Gear^.X + r) + or (iterator^.Y < Gear^.Y - r) + or (iterator^.Y > Gear^.Y + r) then continue; hasdxy := ((iterator^.dX.QWordValue <> 0) or (iterator^.dY.QWordValue <> 0)); @@ -3426,23 +3426,27 @@ oy:= iterator^.dY; end; - // won't port stuff that moves away from me! + // won't port stuff that does not move towards the front/portal entrance if not (Gear^.dX*ox + Gear^.dY*oy).isNegative then continue; - if (iterator^.Kind <> gtCake) then + isbullet:= (iterator^.Kind in [gtShotgunShot, gtDEagleShot, gtSniperRifleShot, gtSineGunShot]); + + r:= int2hwFloat(iterator^.Radius); + + if not isbullet and (iterator^.Kind <> gtCake) then begin // wow! good candidate there, let's see if the distance and direction is okay! if hasdxy then begin - s := int2hwFloat(iterator^.Radius) / Distance(iterator^.dX, iterator^.dY); + s := r / Distance(iterator^.dX, iterator^.dY); ox:= iterator^.X + s * iterator^.dX; oy:= iterator^.Y + s * iterator^.dY; end else begin ox:= iterator^.X; - oy:= iterator^.Y + Int2hwFloat(iterator^.Radius); + oy:= iterator^.Y + r; end; if (hwRound(Distance(Gear^.X-ox,Gear^.Y-oy)) > Gear^.Radius + 1 ) then @@ -3459,19 +3463,21 @@ if noTrap and (iterator^.dY.QWordValue < _0_08.QWordValue) then continue; *) - iterator^.Active := true; - iterator^.State := iterator^.State or gstMoving; - DeleteCI(iterator); - - // Until loops are reliably broken - inc(iterator^.PortalCounter); - - // find out how much speed parallel to the portal vector - // the gear has, also get the vector offset - pspeed:= (Gear^.dX * iterator^.dX + Gear^.dY * iterator^.dY); + // calc gear offset in portal vector direction ox := (iterator^.X - Gear^.X); oy := (iterator^.Y - Gear^.Y); poffs:= (Gear^.dX * ox + Gear^.dY * oy); + + if poffs < _0 then + continue; + + // don't port stuff that isn't really close; + if not isbullet and (poffs > (r + _3)) then + continue; + + if isbullet then + poffs:= _1_5; + // create a normal of the portal vector, but ... nx := Gear^.dY; ny := Gear^.dX; @@ -3481,12 +3487,37 @@ else ny.isNegative := not ny.isNegative; - // now let's find out how much speed the gear has in the - // direction of that normal + // calc gear offset in portal normal vector direction + noffs:= (nx * ox + ny * oy); + + // don't port stuff that misses the portal entrance + if noffs > (r + _1_5) then + continue; + + // 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; + + // + // gears that make it till here will definately be ported + // + + iterator^.Active := true; + iterator^.State := iterator^.State or gstMoving; + DeleteCI(iterator); + + // 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); - noffs:= (nx * ox + ny * oy); - - // now let's project those back to the connected portal's vectors + + // creating normal vector of connected (exit) portal nx := conPortal^.dY; ny := conPortal^.dX; if conPortal^.Elasticity.isNegative then @@ -3498,11 +3529,15 @@ iterator^.dX := -pspeed * conPortal^.dX + nspeed * nx; iterator^.dY := -pspeed * conPortal^.dY + nspeed * ny; if iterator^.Kind = gtCake then - poffs := poffs * _0_5; + poffs := poffs * _0_5 + else + if poffs < r + _1_5 then + poffs := r + _1_5; iterator^.X := conPortal^.X + poffs * conPortal^.dX + noffs * nx; iterator^.Y := conPortal^.Y + poffs * conPortal^.dY + noffs * ny; - FollowGear := iterator; + if not isbullet then + FollowGear := iterator; //AddFileLog('portal''d'); { @@ -3510,6 +3545,20 @@ iterator^.dX := s * iterator^.dX; iterator^.dY := s * iterator^.dY; } + // This jiggles gears, to ensure a portal connection just placed under a gear takes effect. + iterator:= GearsList; + while iterator <> nil do + begin + if iterator^.Kind <> gtPortal then + begin + iterator^.Active:= true; + if iterator^.dY.QWordValue = _0.QWordValue then iterator^.dY.isNegative:= false; + iterator^.State:= iterator^.State or gstMoving; + DeleteCI(iterator); + inc(iterator^.dY.QWordValue,10); + end; + iterator:= iterator^.NextGear + end; if Gear^.Health > 1 then dec(Gear^.Health);