hedgewars/uGearsHandlersRope.pas
branchhedgeroid
changeset 15515 7030706266df
parent 14658 4aec7d17ef7d
equal deleted inserted replaced
7861:bc7b6aa5d67a 15515:7030706266df
     1 (*
     1 (*
     2  * Hedgewars, a free turn based strategy game
     2  * Hedgewars, a free turn based strategy game
     3  * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
     3  * Copyright (c) 2004-2015 Andrey Korotaev <unC0Rr@gmail.com>
     4  *
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation; version 2 of the License
     7  * the Free Software Foundation; version 2 of the License
     8  *
     8  *
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    12  * GNU General Public License for more details.
    13  *
    13  *
    14  * You should have received a copy of the GNU General Public License
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program; if not, write to the Free Software
    15  * along with this program; if not, write to the Free Software
    16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
    16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    17  *)
    17  *)
    18 
    18 
    19 {$INCLUDE "options.inc"}
    19 {$INCLUDE "options.inc"}
    20 unit uGearsHandlersRope;
    20 unit uGearsHandlersRope;
    21 interface
    21 interface
    26 
    26 
    27 implementation
    27 implementation
    28 uses uConsts, uFloat, uCollisions, uVariables, uGearsList, uSound, uGearsUtils,
    28 uses uConsts, uFloat, uCollisions, uVariables, uGearsList, uSound, uGearsUtils,
    29     uAmmos, uDebug, uUtils, uGearsHedgehog, uGearsRender;
    29     uAmmos, uDebug, uUtils, uGearsHedgehog, uGearsRender;
    30 
    30 
       
    31 const
       
    32     IsNilHHFatal = false;
       
    33 
    31 procedure doStepRopeAfterAttack(Gear: PGear);
    34 procedure doStepRopeAfterAttack(Gear: PGear);
    32 var 
    35 var
    33     HHGear: PGear;
    36     HHGear: PGear;
       
    37     tX:     hwFloat;
    34 begin
    38 begin
    35     HHGear := Gear^.Hedgehog^.Gear;
    39     HHGear := Gear^.Hedgehog^.Gear;
       
    40     if HHGear = nil then
       
    41         begin
       
    42         OutError('ERROR: doStepRopeAfterAttack called while HHGear = nil', IsNilHHFatal);
       
    43         DeleteGear(Gear);
       
    44         exit()
       
    45         end
       
    46     else if not CurrentTeam^.ExtDriven and (FollowGear <> nil) then FollowGear := HHGear;
       
    47 
       
    48     tX:= HHGear^.X;
       
    49     if WorldWrap(HHGear) and (WorldEdge = weWrap) and
       
    50        ((TestCollisionXwithGear(HHGear, 1) <> 0) or (TestCollisionXwithGear(HHGear, -1) <> 0))  then
       
    51         begin
       
    52         HHGear^.X:= tX;
       
    53         HHGear^.dX.isNegative:= hwRound(tX) > leftX + HHGear^.Radius * 2
       
    54         end;
       
    55 
       
    56     if (HHGear^.Hedgehog^.CurAmmoType = amParachute) and (HHGear^.dY > _0_39) then
       
    57         begin
       
    58         DeleteGear(Gear);
       
    59         ApplyAmmoChanges(HHGear^.Hedgehog^);
       
    60         HHGear^.Message:= HHGear^.Message or gmLJump;
       
    61         exit
       
    62         end;
       
    63 
    36     if ((HHGear^.State and gstHHDriven) = 0)
    64     if ((HHGear^.State and gstHHDriven) = 0)
    37     or (CheckGearDrowning(HHGear))
    65     or (CheckGearDrowning(HHGear))
    38     or (TestCollisionYwithGear(HHGear, 1) <> 0) then
    66     or (TestCollisionYwithGear(HHGear, 1) <> 0) then
    39         begin
    67         begin
    40         DeleteGear(Gear);
    68         DeleteGear(Gear);
       
    69         if (TestCollisionYwithGear(HHGear, 1) <> 0) and (GetAmmoEntry(HHGear^.Hedgehog^, amRope)^.Count >= 1) and ((Ammoz[HHGear^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) and (HHGear^.Hedgehog^.MultiShootAttacks = 0) then
       
    70             HHGear^.Hedgehog^.CurAmmoType:= amRope;
    41         isCursorVisible := false;
    71         isCursorVisible := false;
    42         ApplyAmmoChanges(HHGear^.Hedgehog^);
    72         ApplyAmmoChanges(HHGear^.Hedgehog^);
    43         exit
    73         exit
    44         end;
    74         end;
    45 
    75 
    46     HedgehogChAngle(HHGear);
    76     HedgehogChAngle(HHGear);
    47 
    77 
    48     if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then
    78     if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) <> 0 then
    49         SetLittle(HHGear^.dX);
    79         SetLittle(HHGear^.dX);
    50 
    80 
    51     if HHGear^.dY.isNegative and (TestCollisionYwithGear(HHGear, -1) <> 0) then
    81     if HHGear^.dY.isNegative and (TestCollisionYwithGear(HHGear, -1) <> 0) then
    52         HHGear^.dY := _0;
    82         HHGear^.dY := _0;
    53     HHGear^.X := HHGear^.X + HHGear^.dX;
    83     HHGear^.X := HHGear^.X + HHGear^.dX;
    54     HHGear^.Y := HHGear^.Y + HHGear^.dY;
    84     HHGear^.Y := HHGear^.Y + HHGear^.dY;
    55     HHGear^.dY := HHGear^.dY + cGravity;
    85     HHGear^.dY := HHGear^.dY + cGravity;
    56     
    86 
    57     if (GameFlags and gfMoreWind) <> 0 then
    87     if (GameFlags and gfMoreWind) <> 0 then
    58         HHGear^.dX := HHGear^.dX + cWindSpeed / HHGear^.Density;
    88         HHGear^.dX := HHGear^.dX + cWindSpeed / HHGear^.Density;
    59 
    89 
    60     if (Gear^.Message and gmAttack) <> 0 then
    90     if (Gear^.Message and gmAttack) <> 0 then
    61         begin
    91         begin
    94     Gear^.Elasticity := _0;
   124     Gear^.Elasticity := _0;
    95     Gear^.doStep := @doStepRopeAfterAttack
   125     Gear^.doStep := @doStepRopeAfterAttack
    96 end;
   126 end;
    97 
   127 
    98 procedure doStepRopeWork(Gear: PGear);
   128 procedure doStepRopeWork(Gear: PGear);
    99 var 
   129 var
   100     HHGear: PGear;
   130     HHGear: PGear;
   101     len, tx, ty, nx, ny, ropeDx, ropeDy, mdX, mdY: hwFloat;
   131     len, tx, ty, nx, ny, ropeDx, ropeDy, mdX, mdY: hwFloat;
   102     lx, ly, cd: LongInt;
   132     lx, ly, cd: LongInt;
   103     haveCollision,
   133     haveCollision,
   104     haveDivided: boolean;
   134     haveDivided: boolean;
   105 
   135     wrongSide: boolean;
   106 begin
   136 begin
   107     if GameTicks mod 4 <> 0 then exit;
       
   108 
       
   109     HHGear := Gear^.Hedgehog^.Gear;
   137     HHGear := Gear^.Hedgehog^.Gear;
   110 
   138     if HHGear = nil then
   111     if ((HHGear^.State and gstHHDriven) = 0)
   139         begin
   112        or (CheckGearDrowning(HHGear)) or (Gear^.PortalCounter <> 0) then
   140         OutError('ERROR: doStepRopeWork called while HHGear = nil', IsNilHHFatal);
       
   141         DeleteGear(Gear);
       
   142         exit()
       
   143         end
       
   144     else if not CurrentTeam^.ExtDriven and (FollowGear <> nil) then FollowGear := HHGear;
       
   145 
       
   146     if ((HHGear^.State and gstHHDriven) = 0) or
       
   147         (CheckGearDrowning(HHGear)) or (Gear^.PortalCounter <> 0) then
   113         begin
   148         begin
   114         PlaySound(sndRopeRelease);
   149         PlaySound(sndRopeRelease);
   115         RopeDeleteMe(Gear, HHGear);
   150         RopeDeleteMe(Gear, HHGear);
   116         exit
   151         exit
   117         end;
   152         end;
   118 
   153 
       
   154     if GameTicks mod 4 <> 0 then exit;
       
   155 
       
   156     tX:= HHGear^.X;
       
   157     if WorldWrap(HHGear) and (WorldEdge = weWrap) and
       
   158        ((TestCollisionXwithGear(HHGear, 1) <> 0) or (TestCollisionXwithGear(HHGear, -1) <> 0))  then
       
   159         begin
       
   160         PlaySound(sndRopeRelease);
       
   161         RopeDeleteMe(Gear, HHGear);
       
   162         HHGear^.X:= tX;
       
   163         HHGear^.dX.isNegative:= hwRound(tX) > leftX + HHGear^.Radius * 2;
       
   164         exit
       
   165         end;
       
   166 
       
   167     tX:= HHGear^.X;
   119     HHGear^.dX.QWordValue:= HHGear^.dX.QWordValue shl 2;
   168     HHGear^.dX.QWordValue:= HHGear^.dX.QWordValue shl 2;
   120     HHGear^.dY.QWordValue:= HHGear^.dY.QWordValue shl 2;
   169     HHGear^.dY.QWordValue:= HHGear^.dY.QWordValue shl 2;
   121     if (Gear^.Message and gmLeft  <> 0) and (not TestCollisionXwithGear(HHGear, -1)) then
   170     if (Gear^.Message and gmLeft  <> 0) and (TestCollisionXwithGear(HHGear, -1) = 0) then
   122         HHGear^.dX := HHGear^.dX - _0_0032;
   171         HHGear^.dX := HHGear^.dX - _0_0032;
   123 
   172 
   124     if (Gear^.Message and gmRight <> 0) and (not TestCollisionXwithGear(HHGear,  1)) then
   173     if (Gear^.Message and gmRight <> 0) and (TestCollisionXwithGear(HHGear,  1) = 0) then
   125         HHGear^.dX := HHGear^.dX + _0_0032;
   174         HHGear^.dX := HHGear^.dX + _0_0032;
   126 
   175 
   127     // vector between hedgehog and rope attaching point
   176     // vector between hedgehog and rope attaching point
   128     ropeDx := HHGear^.X - Gear^.X;
   177     ropeDx := HHGear^.X - Gear^.X;
   129     ropeDy := HHGear^.Y - Gear^.Y;
   178     ropeDy := HHGear^.Y - Gear^.Y;
   130 
   179 
   131     if TestCollisionYwithGear(HHGear, 1) = 0 then
   180     if TestCollisionYwithXYShift(HHGear, 0, 1, 1) = 0 then
   132         begin
   181         begin
   133 
   182 
   134         // depending on the rope vector we know which X-side to check for collision
   183         // depending on the rope vector we know which X-side to check for collision
   135         // in order to find out if the hog can still be moved by gravity
   184         // in order to find out if the hog can still be moved by gravity
   136         if ropeDx.isNegative = RopeDy.IsNegative then
   185         if ropeDx.isNegative = RopeDy.IsNegative then
   137             cd:= -1
   186             cd:= -1
   138         else
   187         else
   139             cd:= 1;
   188             cd:= 1;
   140 
   189 
   141         // apply gravity if there is no obstacle
   190         // apply gravity if there is no obstacle
   142         if not TestCollisionXwithGear(HHGear, cd) then
   191         if TestCollisionXwithXYShift(HHGear, _2*cd, 0, cd, true) = 0 then
   143             HHGear^.dY := HHGear^.dY + cGravity * 16;
   192             HHGear^.dY := HHGear^.dY + cGravity * 16;
   144 
   193 
   145         if (GameFlags and gfMoreWind) <> 0 then
   194         if (GameFlags and gfMoreWind) <> 0 then
   146             // apply wind if there's no obstacle
   195             // apply wind if there's no obstacle
   147             if not TestCollisionXwithGear(HHGear, hwSign(cWindSpeed)) then
   196             if TestCollisionXwithGear(HHGear, hwSign(cWindSpeed)) = 0 then
   148                 HHGear^.dX := HHGear^.dX + cWindSpeed * 16 / HHGear^.Density;
   197                 HHGear^.dX := HHGear^.dX + cWindSpeed * 16 / HHGear^.Density;
   149         end;
   198         end;
   150 
   199 
   151     mdX := ropeDx + HHGear^.dX;
   200     mdX := ropeDx + HHGear^.dX;
   152     mdY := ropeDy + HHGear^.dY;
   201     mdY := ropeDy + HHGear^.dY;
   162     /////
   211     /////
   163     tx := HHGear^.X;
   212     tx := HHGear^.X;
   164     ty := HHGear^.Y;
   213     ty := HHGear^.Y;
   165 
   214 
   166     if ((Gear^.Message and gmDown) <> 0) and (Gear^.Elasticity < Gear^.Friction) then
   215     if ((Gear^.Message and gmDown) <> 0) and (Gear^.Elasticity < Gear^.Friction) then
   167         if not (TestCollisionXwithGear(HHGear, hwSign(ropeDx))
   216         if not ((TestCollisionXwithXYShift(HHGear, _2*hwSign(ropeDx), 0, hwSign(ropeDx), true) <> 0)
   168         or (TestCollisionYwithGear(HHGear, hwSign(ropeDy)) <> 0)) then
   217         or ((ropeDy.QWordValue <> 0) and (TestCollisionYwithXYShift(HHGear, 0, hwSign(ropeDy), hwSign(ropeDy)) <> 0))) then
   169             Gear^.Elasticity := Gear^.Elasticity + _1_2;
   218             Gear^.Elasticity := Gear^.Elasticity + _1_2;
   170 
   219 
   171     if ((Gear^.Message and gmUp) <> 0) and (Gear^.Elasticity > _30) then
   220     if ((Gear^.Message and gmUp) <> 0) and (Gear^.Elasticity > _30) then
   172         if not (TestCollisionXwithGear(HHGear, -hwSign(ropeDx))
   221         if not ((TestCollisionXwithXYShift(HHGear, -_2*hwSign(ropeDx), 0, -hwSign(ropeDx), true) <> 0)
   173         or (TestCollisionYwithGear(HHGear, -hwSign(ropeDy)) <> 0)) then
   222         or ((ropeDy.QWordValue <> 0) and (TestCollisionYwithXYShift(HHGear, 0, -hwSign(ropeDy), -hwSign(ropeDy)) <> 0))) then
   174             Gear^.Elasticity := Gear^.Elasticity - _1_2;
   223             Gear^.Elasticity := Gear^.Elasticity - _1_2;
   175 
   224 
   176     HHGear^.X := Gear^.X + mdX * Gear^.Elasticity;
   225     HHGear^.X := Gear^.X + mdX * Gear^.Elasticity;
   177     HHGear^.Y := Gear^.Y + mdY * Gear^.Elasticity;
   226     HHGear^.Y := Gear^.Y + mdY * Gear^.Elasticity;
   178 
   227 
   179     HHGear^.dX := HHGear^.X - tx;
   228     HHGear^.dX := HHGear^.X - tx;
   180     HHGear^.dY := HHGear^.Y - ty;
   229     HHGear^.dY := HHGear^.Y - ty;
   181     ////
       
   182 
       
   183 
   230 
   184     haveDivided := false;
   231     haveDivided := false;
   185     // check whether rope needs dividing
   232     // check whether rope needs dividing
   186 
   233 
   187     len := Gear^.Elasticity - _5;
   234     len := Gear^.Elasticity - _5;
   192 
   239 
   193     while len > _3 do
   240     while len > _3 do
   194         begin
   241         begin
   195         lx := hwRound(nx);
   242         lx := hwRound(nx);
   196         ly := hwRound(ny);
   243         ly := hwRound(ny);
   197         if ((ly and LAND_HEIGHT_MASK) = 0) and ((lx and LAND_WIDTH_MASK) = 0) and ((Land[ly, lx] and $FF00) <> 0) then
   244         if ((ly and LAND_HEIGHT_MASK) = 0) and ((lx and LAND_WIDTH_MASK) = 0) and (Land[ly, lx] > lfAllObjMask) then
   198             begin
   245             begin
   199             ny := _1 / Distance(ropeDx, ropeDy);
   246             tx := _1 / Distance(ropeDx, ropeDy);
   200             // old rope pos
   247             // old rope pos
   201             nx := ropeDx * ny;
   248             nx := ropeDx * tx;
   202             ny := ropeDy * ny;
   249             ny := ropeDy * tx;
   203 
   250 
   204             with RopePoints.ar[RopePoints.Count] do
   251             with RopePoints.ar[RopePoints.Count] do
   205                 begin
   252                 begin
   206                 X := Gear^.X;
   253                 X := Gear^.X;
   207                 Y := Gear^.Y;
   254                 Y := Gear^.Y;
   208                 if RopePoints.Count = 0 then
   255                 if RopePoints.Count = 0 then
   209                     RopePoints.HookAngle := DxDy2Angle(Gear^.dY, Gear^.dX);
   256                     RopePoints.HookAngle := DxDy2Angle(Gear^.dY, Gear^.dX);
   210                 b := (nx * HHGear^.dY) > (ny * HHGear^.dX);
   257                 b := (nx * HHGear^.dY) > (ny * HHGear^.dX);
       
   258                 sx:= Gear^.dX.isNegative;
       
   259                 sy:= Gear^.dY.isNegative;
       
   260                 sb:= Gear^.dX.QWordValue < Gear^.dY.QWordValue;
   211                 dLen := len
   261                 dLen := len
   212                 end;
   262                 end;
   213                 
   263 
   214             with RopePoints.rounded[RopePoints.Count] do
   264             with RopePoints.rounded[RopePoints.Count] do
   215                 begin
   265                 begin
   216                 X := hwRound(Gear^.X);
   266                 X := hwRound(Gear^.X);
   217                 Y := hwRound(Gear^.Y);
   267                 Y := hwRound(Gear^.Y);
   218                 end;
   268                 end;
   219 
   269 
   220             Gear^.X := Gear^.X + nx * len;
   270             Gear^.X := Gear^.X + nx * len;
   221             Gear^.Y := Gear^.Y + ny * len;
   271             Gear^.Y := Gear^.Y + ny * len;
   222             inc(RopePoints.Count);
   272             inc(RopePoints.Count);
   223             TryDo(RopePoints.Count <= MAXROPEPOINTS, 'Rope points overflow', true);
   273             if checkFails(RopePoints.Count <= MAXROPEPOINTS, 'Rope points overflow', true) then exit;
   224             Gear^.Elasticity := Gear^.Elasticity - len;
   274             Gear^.Elasticity := Gear^.Elasticity - len;
   225             Gear^.Friction := Gear^.Friction - len;
   275             Gear^.Friction := Gear^.Friction - len;
   226             haveDivided := true;
   276             haveDivided := true;
   227             break
   277             break
   228             end;
   278             end;
   238             begin
   288             begin
   239             tx := RopePoints.ar[Pred(RopePoints.Count)].X;
   289             tx := RopePoints.ar[Pred(RopePoints.Count)].X;
   240             ty := RopePoints.ar[Pred(RopePoints.Count)].Y;
   290             ty := RopePoints.ar[Pred(RopePoints.Count)].Y;
   241             mdX := tx - Gear^.X;
   291             mdX := tx - Gear^.X;
   242             mdY := ty - Gear^.Y;
   292             mdY := ty - Gear^.Y;
   243             if RopePoints.ar[Pred(RopePoints.Count)].b xor (mdX * (ty - HHGear^.Y) > (tx - HHGear^.X) * mdY) then
   293             ropeDx:= tx - HHGear^.X;
       
   294             ropeDy:= ty - HHGear^.Y;
       
   295             if RopePoints.ar[Pred(RopePoints.Count)].b xor (mdX * ropeDy > ropeDx * mdY) then
   244                 begin
   296                 begin
   245                 dec(RopePoints.Count);
   297                 dec(RopePoints.Count);
   246                 Gear^.X := RopePoints.ar[RopePoints.Count].X;
   298                 Gear^.X := tx;
   247                 Gear^.Y := RopePoints.ar[RopePoints.Count].Y;
   299                 Gear^.Y := ty;
   248                 Gear^.Elasticity := Gear^.Elasticity + RopePoints.ar[RopePoints.Count].dLen;
   300 
   249                 Gear^.Friction := Gear^.Friction + RopePoints.ar[RopePoints.Count].dLen;
   301                 // oops, opposite quadrant, don't restore hog position in such case, just remove the point
   250 
   302                 wrongSide:= (ropeDx.isNegative = RopePoints.ar[RopePoints.Count].sx)
   251                 // restore hog position
   303                     and (ropeDy.isNegative = RopePoints.ar[RopePoints.Count].sy);
   252                 len := _1 / Distance(mdX, mdY);
   304 
   253                 mdX := mdX * len;
   305                 // previous check could be inaccurate in vertical/horizontal rope positions,
   254                 mdY := mdY * len;
   306                 // so perform this check also, even though odds are 1 to 415927 to hit this
   255 
   307                 if (not wrongSide)
   256                 HHGear^.X := Gear^.X - mdX * Gear^.Elasticity;
   308                     and ((ropeDx.isNegative = RopePoints.ar[RopePoints.Count].sx)
   257                 HHGear^.Y := Gear^.Y - mdY * Gear^.Elasticity;
   309                       <> (ropeDy.isNegative = RopePoints.ar[RopePoints.Count].sy)) then
       
   310                     if RopePoints.ar[RopePoints.Count].sb then
       
   311                         wrongSide:= ropeDy.isNegative = RopePoints.ar[RopePoints.Count].sy
       
   312                         else
       
   313                         wrongSide:= ropeDx.isNegative = RopePoints.ar[RopePoints.Count].sx;
       
   314 
       
   315                 if wrongSide then
       
   316                     begin
       
   317                     Gear^.Elasticity := Gear^.Elasticity - RopePoints.ar[RopePoints.Count].dLen;
       
   318                     Gear^.Friction := Gear^.Friction - RopePoints.ar[RopePoints.Count].dLen;
       
   319                     end else
       
   320                     begin
       
   321                     Gear^.Elasticity := Gear^.Elasticity + RopePoints.ar[RopePoints.Count].dLen;
       
   322                     Gear^.Friction := Gear^.Friction + RopePoints.ar[RopePoints.Count].dLen;
       
   323 
       
   324                     // restore hog position
       
   325                     len := _1 / Distance(mdX, mdY);
       
   326                     mdX := mdX * len;
       
   327                     mdY := mdY * len;
       
   328 
       
   329                     HHGear^.X := Gear^.X - mdX * Gear^.Elasticity;
       
   330                     HHGear^.Y := Gear^.Y - mdY * Gear^.Elasticity;
       
   331                     end;
   258                 end
   332                 end
   259             end;
   333             end;
   260 
   334 
   261     haveCollision := false;
   335     haveCollision := false;
   262     if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then
   336     if TestCollisionXwithXYShift(HHGear, _2*hwSign(HHGear^.dX), 0, hwSign(HHGear^.dX), true) <> 0 then
   263         begin
   337         begin
   264         HHGear^.dX := -_0_6 * HHGear^.dX;
   338         HHGear^.dX := -_0_6 * HHGear^.dX;
   265         haveCollision := true
   339         haveCollision := true
   266         end;
   340         end;
   267     if TestCollisionYwithGear(HHGear, hwSign(HHGear^.dY)) <> 0 then
   341     if TestCollisionYwithXYShift(HHGear, 0, 1*hwSign(HHGear^.dY), hwSign(HHGear^.dY)) <> 0 then
   268         begin
   342         begin
   269         HHGear^.dY := -_0_6 * HHGear^.dY;
   343         HHGear^.dY := -_0_6 * HHGear^.dY;
   270         haveCollision := true
   344         haveCollision := true
   271         end;
   345         end;
   272 
   346 
   341 procedure RopeRemoveFromAmmo(Gear, HHGear: PGear);
   415 procedure RopeRemoveFromAmmo(Gear, HHGear: PGear);
   342 begin
   416 begin
   343     if (Gear^.State and gstAttacked) = 0 then
   417     if (Gear^.State and gstAttacked) = 0 then
   344         begin
   418         begin
   345         OnUsedAmmo(HHGear^.Hedgehog^);
   419         OnUsedAmmo(HHGear^.Hedgehog^);
   346         Gear^.State := Gear^.State or gstAttacked
   420         Gear^.State := Gear^.State or gstAttacked;
   347         end;
   421         ApplyAmmoChanges(HHGear^.Hedgehog^);
   348     ApplyAmmoChanges(HHGear^.Hedgehog^)
   422         end;
   349 end;
   423 end;
   350 
   424 
   351 procedure doStepRopeAttach(Gear: PGear);
   425 procedure doStepRopeAttach(Gear: PGear);
   352 var 
   426 var
   353     HHGear: PGear;
   427     HHGear: PGear;
   354     tx, ty, tt: hwFloat;
   428     tx, ty, tt: hwFloat;
   355 begin
   429 begin
   356     Gear^.X := Gear^.X - Gear^.dX;
   430     Gear^.X := Gear^.X - Gear^.dX;
   357     Gear^.Y := Gear^.Y - Gear^.dY;
   431     Gear^.Y := Gear^.Y - Gear^.dY;
   358     Gear^.Elasticity := Gear^.Elasticity + _1;
   432     Gear^.Elasticity := Gear^.Elasticity + _1;
   359 
   433 
   360     HHGear := Gear^.Hedgehog^.Gear;
   434     HHGear := Gear^.Hedgehog^.Gear;
       
   435     if HHGear = nil then
       
   436         begin
       
   437         OutError('ERROR: doStepRopeAttach called while HHGear = nil', IsNilHHFatal);
       
   438         DeleteGear(Gear);
       
   439         exit()
       
   440         end
       
   441     else if not CurrentTeam^.ExtDriven and (FollowGear <> nil) then FollowGear := HHGear;
       
   442 
       
   443     // Destroy rope if it touched bouncy or world wrap world edge.
       
   444     // TODO: Allow to shoot rope through the world wrap edge and rope normally.
       
   445     if (WorldWrap(Gear) and (WorldEdge = weWrap)) or
       
   446        ((WorldEdge = weBounce) and ((hwRound(Gear^.X) <= LeftX) or (hwRound(Gear^.X) >= RightX))) then
       
   447         begin
       
   448         HHGear^.State := HHGear^.State and (not (gstAttacking or gstHHJumping or gstHHHJump));
       
   449         HHGear^.Message := HHGear^.Message and (not gmAttack);
       
   450         DeleteGear(Gear);
       
   451         if (GetAmmoEntry(HHGear^.Hedgehog^, amRope)^.Count >= 1) and ((Ammoz[HHGear^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) and (HHGear^.Hedgehog^.MultiShootAttacks = 0) then
       
   452             HHGear^.Hedgehog^.CurAmmoType:= amRope;
       
   453         isCursorVisible := false;
       
   454         ApplyAmmoChanges(HHGear^.Hedgehog^);
       
   455         exit()
       
   456         end;
       
   457 
   361     DeleteCI(HHGear);
   458     DeleteCI(HHGear);
   362 
   459 
   363     if (HHGear^.State and gstMoving) <> 0 then
   460     if (HHGear^.State and gstMoving) <> 0 then
   364         begin
   461         begin
   365         if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then
   462         doStepHedgehogMoving(HHGear);
   366             SetLittle(HHGear^.dX);
       
   367         if HHGear^.dY.isNegative and (TestCollisionYwithGear(HHGear, -1) <> 0) then
       
   368             HHGear^.dY := _0;
       
   369 
       
   370         HHGear^.X := HHGear^.X + HHGear^.dX;
       
   371         Gear^.X := Gear^.X + HHGear^.dX;
   463         Gear^.X := Gear^.X + HHGear^.dX;
   372 
   464         Gear^.Y := Gear^.Y + HHGear^.dY;
   373         if TestCollisionYwithGear(HHGear, 1) <> 0 then
   465 
   374             begin
   466         // hedgehog can teleport up to 5 pixels upwards when sliding,
   375             CheckHHDamage(HHGear);
   467         // so we have to give up the maintained rope length
   376             HHGear^.dY := _0
   468         // after doStepHedgehogMoving() call and recalculate
   377             //HHGear^.State:= HHGear^.State and (not (gstHHJumping or gstHHHJump));
   469         // it based on the gear and current hedgehog positions
   378             end
   470         Gear^.Elasticity:= int2hwFloat(hwRound(Distance(Gear^.X - HHGear^.X, Gear^.Y - HHGear^.Y) + _0_001));
   379         else
       
   380             begin
       
   381             HHGear^.Y := HHGear^.Y + HHGear^.dY;
       
   382             Gear^.Y := Gear^.Y + HHGear^.dY;
       
   383             HHGear^.dY := HHGear^.dY + cGravity;
       
   384             if (GameFlags and gfMoreWind) <> 0 then
       
   385                 HHGear^.dX := HHGear^.dX + cWindSpeed / HHGear^.Density
       
   386             end;
       
   387 
   471 
   388         tt := Gear^.Elasticity;
   472         tt := Gear^.Elasticity;
   389         tx := _0;
   473         tx := _0;
   390         ty := _0;
   474         ty := _0;
   391         while tt > _20 do
   475         while tt > _20 do
   392             begin
   476             begin
   393             if ((hwRound(Gear^.Y+ty) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X+tx) and LAND_WIDTH_MASK) = 0) and ((Land[hwRound(Gear^.Y+ty), hwRound(Gear^.X+tx)] and $FF00) <> 0) then
   477             if ((hwRound(Gear^.Y+ty) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X+tx) and LAND_WIDTH_MASK) = 0) and (Land[hwRound(Gear^.Y+ty), hwRound(Gear^.X+tx)] > lfAllObjMask) then
   394                 begin
   478                 begin
   395                 Gear^.X := Gear^.X + tx;
   479                 Gear^.X := Gear^.X + tx;
   396                 Gear^.Y := Gear^.Y + ty;
   480                 Gear^.Y := Gear^.Y + ty;
   397                 Gear^.Elasticity := tt;
   481                 Gear^.Elasticity := tt;
   398                 Gear^.doStep := @doStepRopeWork;
   482                 Gear^.doStep := @doStepRopeWork;
       
   483 
   399                 PlaySound(sndRopeAttach);
   484                 PlaySound(sndRopeAttach);
   400                 with HHGear^ do
   485                 with HHGear^ do
   401                     begin
   486                     begin
   402                     State := State and (not (gstAttacking or gstHHJumping or gstHHHJump));
   487                     State := State and (not (gstAttacking or gstHHJumping or gstHHHJump));
   403                     Message := Message and (not gmAttack)
   488                     Message := Message and (not gmAttack)
   404                     end;
   489                     end;
   405 
   490 
   406                 RopeRemoveFromAmmo(Gear, HHGear);
   491                 RopeRemoveFromAmmo(Gear, HHGear);
   407 
       
   408                 tt := _0;
       
   409                 exit
   492                 exit
   410                 end;
   493                 end;
   411             tx := tx + Gear^.dX + Gear^.dX;
   494             tx := tx + Gear^.dX + Gear^.dX;
   412             ty := ty + Gear^.dY + Gear^.dY;
   495             ty := ty + Gear^.dY + Gear^.dY;
   413             tt := tt - _2;
   496             tt := tt - _2;
   414             end;
   497             end;
   415         end;
   498         end;
   416 
   499 
   417     if Gear^.Elasticity < _20 then Gear^.CollisionMask:= $FF00
   500     if Gear^.Elasticity < _20 then Gear^.CollisionMask:= lfLandMask
   418     else Gear^.CollisionMask:= $FF7F;
   501     else Gear^.CollisionMask:= lfNotCurHogCrate; //lfNotObjMask or lfNotHHObjMask;
   419     CheckCollision(Gear);
   502     CheckCollision(Gear);
   420 
   503 
   421     if (Gear^.State and gstCollision) <> 0 then
   504     if (Gear^.State and gstCollision) <> 0 then
   422         if Gear^.Elasticity < _10 then
   505         if Gear^.Elasticity < _10 then
   423             Gear^.Elasticity := _10000
   506             Gear^.Elasticity := _10000
   445                 begin
   528                 begin
   446                 State := State and (not gstAttacking);
   529                 State := State and (not gstAttacking);
   447                 Message := Message and (not gmAttack)
   530                 Message := Message and (not gmAttack)
   448                 end;
   531                 end;
   449         DeleteGear(Gear);
   532         DeleteGear(Gear);
       
   533         if (GetAmmoEntry(HHGear^.Hedgehog^, amRope)^.Count >= 1) and ((Ammoz[HHGear^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) and (HHGear^.Hedgehog^.MultiShootAttacks = 0) then
       
   534             HHGear^.Hedgehog^.CurAmmoType:= amRope;
       
   535         isCursorVisible := false;
       
   536         ApplyAmmoChanges(HHGear^.Hedgehog^);
   450         exit;
   537         exit;
   451         end;
   538         end;
   452     if CheckGearDrowning(HHGear) then DeleteGear(Gear)
   539     if CheckGearDrowning(HHGear) then DeleteGear(Gear)
   453 end;
   540 end;
   454 
   541