diff -r b49ed5673727 -r 46a2694867bc hedgewars/GSHandlers.inc --- a/hedgewars/GSHandlers.inc Wed May 05 22:03:10 2010 +0000 +++ b/hedgewars/GSHandlers.inc Thu May 06 01:41:07 2010 +0000 @@ -3044,16 +3044,52 @@ end; //////////////////////////////////////////////////////////////////////////////// +procedure doPortalColorSwitch(); +var flags: LongWord; +begin + if (CurrentHedgehog <> nil) + and (CurrentHedgehog^.Gear <> nil) + and ((CurrentHedgehog^.Gear^.Message and gm_Switch) <> 0) then + With CurrentHedgehog^ do + if (Ammo^[CurSlot, CurAmmo].AmmoType = amPortalGun) then + begin + CurrentHedgehog^.Gear^.Message:= CurrentHedgehog^.Gear^.Message and not gm_Switch; + + flags:= Ammo^[CurSlot, CurAmmo].Timer and not 2; + if (flags and 1) = 0 then + Ammo^[CurSlot, CurAmmo].Timer:= flags or 1 + else + Ammo^[CurSlot, CurAmmo].Timer:= flags and not 1; + end; +end; + procedure doStepPortal(Gear: PGear); var iterator, conPortal: PGear; - s, acptRadius: hwFloat; + s, acptRadius, cdxy: hwFloat; noTrap, hasdxy: Boolean; begin + doPortalColorSwitch(); + // destroy portal if ground it was attached too is gone - if (Land[hwRound(Gear^.Y), hwRound(Gear^.X)] and $FF00) = 0 then deleteGear(Gear); + if ((Land[hwRound(Gear^.Y), hwRound(Gear^.X)] and $FF00) = 0) + or (Gear^.Timer < 1) + or (hwRound(Gear^.Y) > cWaterLine) then + begin + deleteGear(Gear); + EXIT; + end; + + if (TurnTimeLeft < 1) + or (Gear^.Health < 1) then + dec(Gear^.Timer); + + if Gear^.Timer < 10000 then + gear^.RenderTimer:= true; // abort if there is no other portal connected to this one - if Gear^.IntersectGear = nil then + if (Gear^.IntersectGear = nil) then + exit; + if ((Gear^.IntersectGear^.Tag and 1) = 0) then // or if it's still moving; exit; conPortal:= Gear^.IntersectGear; @@ -3073,15 +3109,14 @@ // don't port portals or other gear that wouldn't make sense if (iterator^.Kind = gtPortal) + or (iterator^.Kind = gtRope) or (iterator^.Kind = gtHealthTag) then continue; - -{ - if (((iterator^.State and gstMoving) = 0) // we don't port non-moving stuff IF the portal entry... - and (iterator^.Active = false) - and ) then //... + + // don't port hogs on rope + if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) + and (iterator = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtRope) then continue; -} if (iterator^.Radius > Gear^.Radius) then continue; // sorry, you're too fat! @@ -3105,45 +3140,79 @@ continue; noTrap:= ((not Gear^.dY.isNegative or (Gear^.dY.QWordValue = 0)) // can't be entered from above - or ((conPortal^.dY.isNegative or (conPortal^.dY.QWordValue = 0)))); // can't be left downwards; - + or ((conPortal^.dY.isNegative and not (conPortal^.dY.QWordValue = 0)))); // can't be left downwards; - // lets see if this one is just stuck in a stuck-loop - if noTrap and (iterator^.dY.QWordValue < _0_1.QWordValue) then + // prevent getting stuck in a ground portal loop + if noTrap and (iterator^.dY.QWordValue < _0_08.QWordValue) then continue; - + iterator^.Active:= true; iterator^.State:= iterator^.State or gstMoving; DeleteCI(iterator); - s:= (_1+(Int2hwFloat(Gear^.Radius))) / Distance(conPortal^.dX, conPortal^.dY); +// TODO: more accurate porting + cdxy:= Distance(conPortal^.dX, conPortal^.dY); + s:= (Int2hwFloat(Gear^.Radius)) / cdxy; + iterator^.X:= conPortal^.X + s * conPortal^.dX; iterator^.Y:= conPortal^.Y + s * conPortal^.dY; - s:= Distance(iterator^.dX, iterator^.dY) / Distance(conPortal^.dX, conPortal^.dY); + + s:= Distance(iterator^.dX, iterator^.dY) / cdxy; + iterator^.dX:= s * conPortal^.dX; iterator^.dY:= s * conPortal^.dY; + + FollowGear:= iterator; + + s:= _0_2 + _0_008 * Gear^.Health; + iterator^.dX:= s * iterator^.dX; + iterator^.dY:= s * iterator^.dY; - if iterator^.dY.isNegative and (iterator^.dY.QWordValue <> 0) then - iterator^.dY:= iterator^.dY + hwAbs(Int2hwFloat(iterator^.Radius) / iterator^.dY) * cGravity; + if Gear^.Health > 1 then + begin + dec(Gear^.Health); + dec(iterator^.Health); + end; // breaks (some) loops if Distance(iterator^.dX, iterator^.dY) > _0_96 then begin iterator^.dX:= iterator^.dX + signAs(cGravity * getRandom(1000),iterator^.dX); iterator^.dY:= iterator^.dY + signAs(cGravity * getRandom(1000),iterator^.dY); - s:= _0_995 / Distance(iterator^.dX, iterator^.dY); + s:= _0_96 / Distance(iterator^.dX, iterator^.dY); iterator^.dX:= s * iterator^.dX; iterator^.dY:= s * iterator^.dX; end; - - iterator:= iterator^.NextGear; end; end; procedure doStepMovingPortal(Gear: PGear); var x, y, tx, ty: LongInt;//, bx, by, tangle: LongInt; s, dx, dy: hwFloat; + +procedure loadNewPortalBall(oldPortal: PGear; destroyGear: Boolean); +var flags: LongWord; begin +if CurrentHedgehog <> nil then + With CurrentHedgehog^ do + if (Ammo^[CurSlot, CurAmmo].AmmoType = amPortalGun) then + begin + flags:= Ammo^[CurSlot, CurAmmo].Timer; + + if destroyGear xor ((oldPortal^.Tag and 2) = 0) then + flags:= flags or 1 + else + flags:= flags and not 1; + + Ammo^[CurSlot, CurAmmo].Timer:= flags and not 2; // make the ball visible + end; + +if destroyGear then deleteGear(oldPortal); +end; + +begin +doPortalColorSwitch(); + Gear^.X:= Gear^.X + Gear^.dX; Gear^.Y:= Gear^.Y + Gear^.dY; x:= hwRound(Gear^.X); @@ -3152,30 +3221,24 @@ if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] > 255) then begin - if not calcSlopeTangent(Gear, x, y, tx, ty, 255) then - begin - deleteGear(Gear); - EXIT; - end; - - // reject shots at too irregular terrain - if DistanceI(tx,ty) < _12 then - begin - deleteGear(Gear); - EXIT; - end; + if not calcSlopeTangent(Gear, x, y, tx, ty, 255) + or (DistanceI(tx,ty) < _12) then // reject shots at too irregular terrain + begin + loadNewPortalBall(Gear, true); + EXIT; + end; - // making a normal, normalized vector + // making a normalized normal vector s:= _1/DistanceI(tx,ty); dx:= -s * ty; dy:= s * tx; // make sure the vector is pointing outwards if not (Gear^.dX*dx + Gear^.dY*dy).isNegative then - begin + begin dx:= -dx; dy:= -dy; - end; + end; Gear^.dX:= dx; Gear^.dY:= dy; @@ -3183,33 +3246,60 @@ Gear^.DirAngle:= DxDy2Angle(-dy,dx); if not Gear^.dX.isNegative then Gear^.DirAngle:= 180-Gear^.DirAngle; - if ((Gear^.IntersectGear <> nil) and (hwRound(Distance(Gear^.X - Gear^.IntersectGear^.X,Gear^.Y-Gear^.IntersectGear^.Y)) < Gear^.Radius*2)) + if ((Gear^.IntersectGear = nil) + or (hwRound(Distance(Gear^.X - Gear^.IntersectGear^.X,Gear^.Y-Gear^.IntersectGear^.Y)) >= Gear^.Radius*2)) then begin - if CurrentHedgehog <> nil then - if Gear^.IntersectGear = nil then CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 1 - else if Gear^.Tag = 2 then CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 2 - else CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 1; - deleteGear(Gear) + loadNewPortalBall(Gear, false); + inc(Gear^.Tag); + Gear^.doStep:= @doStepPortal; end else - begin - if CurrentHedgehog <> nil then - if Gear^.Tag = 2 then CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 1 - else CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 2; - inc(Gear^.Tag); - Gear^.doStep:= @doStepPortal; - if Gear^.IntersectGear <> nil then Gear^.IntersectGear^.IntersectGear:= Gear; - end + loadNewPortalBall(Gear, true); end -else if (y > cWaterLine + cVisibleWater + Gear^.Radius) or (y < -LAND_WIDTH) or (x > LAND_WIDTH + LAND_WIDTH) or (x < -LAND_WIDTH) then +else if (y > cWaterLine) or (y < -LAND_WIDTH) + or (x > 2*LAND_WIDTH) or (x < -LAND_WIDTH) then + loadNewPortalBall(Gear, true); +end; + +procedure doStepPortalShot(newPortal: PGear); +var iterator: PGear; +begin +newPortal^.IntersectGear:= nil; + +if CurrentHedgehog <> nil then + With CurrentHedgehog^ do begin - if CurrentHedgehog <> nil then - if Gear^.IntersectGear = nil then CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 1 - else if Gear^.Tag = 2 then CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 2 - else CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 1; - deleteGear(Gear); + // make portal gun look unloaded + Ammo^[CurSlot, CurAmmo].Timer:= Ammo^[CurSlot, CurAmmo].Timer or 2; + + // set portal to the currently chosen color + if ((Ammo^[CurSlot, CurAmmo].Timer and 1) <> 0) then + newPortal^.Tag:= newPortal^.Tag or 2; + + iterator:= GearsList; + while iterator <> nil do + begin + if (iterator^.Kind = gtPortal) then + if (iterator <> newPortal) then + begin + if (iterator^.Tag and 2) = (newPortal^.Tag and 2) then + begin + iterator:= iterator^.PrevGear; + deleteGear(iterator^.NextGear); + continue; + end + else + begin // link portals with each other + newPortal^.IntersectGear:= iterator; + iterator^.IntersectGear:= newPortal; + iterator^.Health:= newPortal^.Health; + end; + end; + iterator:= iterator^.NextGear + end; end; +newPortal^.doStep:= @doStepMovingPortal; end; procedure doStepPiano(Gear: PGear);