Fix a bug screwing team selection up in network game
(REMOVETEAM message doesn't have teamID, and after
removing the team QMap still contains old info, when
add and remove team with the same name, total hedgehogs
number will be decreased by first team hh number)
(*
* Hedgewars, a free turn based strategy game
* Copyright (c) 2004-2008 Andrey Korotaev <unC0Rr@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*)
procedure doStepDrowningGear(Gear: PGear); forward;
function CheckGearDrowning(Gear: PGear): boolean;
begin
if cWaterLine < hwRound(Gear^.Y) + Gear^.Radius then
begin
CheckGearDrowning:= true;
Gear^.State:= gstDrowning;
Gear^.doStep:= @doStepDrowningGear;
PlaySound(sndSplash, false)
end else
CheckGearDrowning:= false
end;
procedure CheckCollision(Gear: PGear);
begin
if TestCollisionXwithGear(Gear, hwSign(Gear^.X)) or TestCollisionYwithGear(Gear, hwSign(Gear^.Y))
then Gear^.State:= Gear^.State or gstCollision
else Gear^.State:= Gear^.State and not gstCollision
end;
procedure CheckHHDamage(Gear: PGear);
var dmg: Longword;
begin
if _0_4 < Gear^.dY then
begin
if _0_6 < Gear^.dY then
PlaySound(sndOw4, false)
else
PlaySound(sndOw1, false);
dmg:= 1 + hwRound((hwAbs(Gear^.dY) - _0_4) * 70);
inc(Gear^.Damage, dmg);
AddDamageTag(hwRound(Gear^.X), hwRound(Gear^.Y) + cHHRadius, dmg, Gear);
end
end;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
procedure CalcRotationDirAngle(Gear: PGear);
var dAngle: real;
begin
dAngle:= (hwAbs(Gear^.dX) + hwAbs(Gear^.dY)).QWordValue / $80000000;
if not Gear^.dX.isNegative then
Gear^.DirAngle:= Gear^.DirAngle + dAngle
else
Gear^.DirAngle:= Gear^.DirAngle - dAngle;
if Gear^.DirAngle < 0 then Gear^.DirAngle:= Gear^.DirAngle + 360
else if 360 < Gear^.DirAngle then Gear^.DirAngle:= Gear^.DirAngle - 360
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepDrowningGear(Gear: PGear);
begin
AllInactive:= false;
Gear^.Y:= Gear^.Y + cDrownSpeed;
if hwRound(Gear^.Y) > Gear^.Radius + cWaterLine + cVisibleWater then DeleteGear(Gear)
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepFallingGear(Gear: PGear);
var isFalling: boolean;
begin
Gear^.State:= Gear^.State and not gstCollision;
if Gear^.dY.isNegative then
begin
isFalling:= true;
if TestCollisionYwithGear(Gear, -1) then
begin
Gear^.dX:= Gear^.dX * Gear^.Friction;
Gear^.dY:= - Gear^.dY * Gear^.Elasticity;
Gear^.State:= Gear^.State or gstCollision
end
end else
if TestCollisionYwithGear(Gear, 1) then
begin
isFalling:= false;
Gear^.dX:= Gear^.dX * Gear^.Friction;
Gear^.dY:= - Gear^.dY * Gear^.Elasticity;
Gear^.State:= Gear^.State or gstCollision
end else isFalling:= true;
if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
begin
Gear^.dX:= - Gear^.dX * Gear^.Elasticity;
Gear^.dY:= Gear^.dY * Gear^.Elasticity;
Gear^.State:= Gear^.State or gstCollision
end;
if isFalling then Gear^.dY:= Gear^.dY + cGravity;
Gear^.X:= Gear^.X + Gear^.dX;
Gear^.Y:= Gear^.Y + Gear^.dY;
CheckGearDrowning(Gear);
if (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) < _0_0002) and
(not isFalling) then
Gear^.State:= Gear^.State and not gstMoving
else
Gear^.State:= Gear^.State or gstMoving
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepBomb(Gear: PGear);
var i: LongInt;
dX, dY: hwFloat;
begin
AllInactive:= false;
doStepFallingGear(Gear);
dec(Gear^.Timer);
if Gear^.Timer = 0 then
begin
case Gear^.Kind of
gtAmmo_Bomb: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
gtClusterBomb: begin
doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, EXPLAutoSound);
for i:= 0 to 4 do
begin
dX:= rndSign(GetRandom * _0_1);
dY:= (GetRandom - _3) * _0_08;
AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtCluster, 0, dX, dY, 25);
end
end;
gtWatermelon: begin
doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 75, EXPLAutoSound);
for i:= 0 to 5 do
begin
dX:= rndSign(GetRandom * _0_1);
dY:= (GetRandom - _2) * _0_2;
AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtMelonPiece, 0, dX, dY, 75)^.DirAngle:= i * 60;
end
end;
gtHellishBomb: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 90, EXPLAutoSound);
end;
DeleteGear(Gear);
exit
end;
CalcRotationDirAngle(Gear);
if Gear^.Kind = gtHellishBomb then
begin
if Gear^.Timer = 3000 then PlaySound(sndHellish, false);
if (GameTicks and $3F) = 0 then
if (Gear^.State and gstCollision) = 0 then
AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtEvilTrace, 0, _0, _0, 0);
end;
if (Gear^.State and (gstCollision or gstMoving)) = (gstCollision or gstMoving) then
if (hwAbs(Gear^.dX) > _0_1) or
(hwAbs(Gear^.dY) > _0_1) then
PlaySound(sndGrenadeImpact, false)
end;
procedure doStepWatermelon(Gear: PGear);
begin
AllInactive:= false;
PlaySound(sndMelon, false);
Gear^.doStep:= @doStepBomb
end;
procedure doStepCluster(Gear: PGear);
begin
AllInactive:= false;
doStepFallingGear(Gear);
if (Gear^.State and gstCollision) <> 0 then
begin
doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Timer, EXPLAutoSound);
DeleteGear(Gear);
exit
end;
if Gear^.Kind = gtMelonPiece then
CalcRotationDirAngle(Gear)
else
if (GameTicks and $1F) = 0 then
AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtSmokeTrace, 0, _0, _0, 0)
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepGrenade(Gear: PGear);
begin
AllInactive:= false;
Gear^.dX:= Gear^.dX + cWindSpeed;
doStepFallingGear(Gear);
if (Gear^.State and gstCollision) <> 0 then
begin
doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
DeleteGear(Gear);
exit
end;
if (GameTicks and $3F) = 0 then
AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtSmokeTrace, 0, _0, _0, 0)
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepHealthTagWork(Gear: PGear);
begin
if Gear^.Kind = gtHealthTag then
AllInactive:= false;
dec(Gear^.Timer);
Gear^.Y:= Gear^.Y + Gear^.dY;
if Gear^.Timer = 0 then
begin
if Gear^.Kind = gtHealthTag then
PHedgehog(Gear^.Hedgehog)^.Gear^.Active:= true; // to let current hh die
DeleteGear(Gear)
end
end;
procedure doStepHealthTagWorkUnderWater(Gear: PGear);
begin
AllInactive:= false;
Gear^.Y:= Gear^.Y - _0_08;
if hwRound(Gear^.Y) < cWaterLine + 10 then
DeleteGear(Gear)
end;
procedure doStepHealthTag(Gear: PGear);
var s: shortstring;
font: THWFont;
begin
if Gear^.Kind = gtHealthTag then
begin
AllInactive:= false;
font:= fnt16;
Gear^.dY:= -_0_08
end else
begin
font:= fntSmall;
Gear^.dY:= -_0_02
end;
str(Gear^.State, s);
Gear^.Tex:= RenderStringTex(s, PHedgehog(Gear^.Hedgehog)^.Team^.Clan^.Color, font);
if hwRound(Gear^.Y) < cWaterLine then Gear^.doStep:= @doStepHealthTagWork
else Gear^.doStep:= @doStepHealthTagWorkUnderWater;
Gear^.Y:= Gear^.Y - int2hwFloat(Gear^.Tex^.h)
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepGrave(Gear: PGear);
begin
AllInactive:= false;
if Gear^.dY.isNegative then
if TestCollisionY(Gear, -1) then Gear^.dY:= _0;
if not Gear^.dY.isNegative then
if TestCollisionY(Gear, 1) then
begin
Gear^.dY:= - Gear^.dY * Gear^.Elasticity;
if Gear^.dY > - _1div1024 then
begin
Gear^.Active:= false;
exit
end else if Gear^.dY < - _0_03 then PlaySound(sndGraveImpact, false)
end;
Gear^.Y:= Gear^.Y + Gear^.dY;
CheckGearDrowning(Gear);
Gear^.dY:= Gear^.dY + cGravity
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepUFOWork(Gear: PGear);
var t: hwFloat;
y: LongInt;
begin
AllInactive:= false;
t:= Distance(Gear^.dX, Gear^.dY);
Gear^.dX:= Gear^.Elasticity * (Gear^.dX + _0_000004 * (TargetPoint.X - hwRound(Gear^.X)));
Gear^.dY:= Gear^.Elasticity * (Gear^.dY + _0_000004 * (TargetPoint.Y - hwRound(Gear^.Y)));
t:= t / Distance(Gear^.dX, Gear^.dY);
Gear^.dX:= Gear^.dX * t;
Gear^.dY:= Gear^.dY * t;
Gear^.X:= Gear^.X + Gear^.dX;
Gear^.Y:= Gear^.Y + Gear^.dY;
if (GameTicks and $3F) = 0 then
begin
y:= hwRound(Gear^.Y);
if y + Gear^.Radius < cWaterLine then
AddGear(hwRound(Gear^.X), y, gtSmokeTrace, 0, _0, _0, 0);
end;
CheckCollision(Gear);
dec(Gear^.Timer);
if ((Gear^.State and gstCollision) <> 0) or (Gear^.Timer = 0) then
begin
StopSound(sndUFO);
doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
DeleteGear(Gear);
end;
end;
procedure doStepUFO(Gear: PGear);
begin
AllInactive:= false;
Gear^.X:= Gear^.X + Gear^.dX;
Gear^.Y:= Gear^.Y + Gear^.dY;
Gear^.dY:= Gear^.dY + cGravity;
CheckCollision(Gear);
if (Gear^.State and gstCollision) <> 0 then
begin
doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
DeleteGear(Gear);
exit
end;
dec(Gear^.Timer);
if Gear^.Timer = 0 then
begin
PlaySound(sndUFO, true);
Gear^.Timer:= 5000;
Gear^.doStep:= @doStepUFOWork
end;
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepShotIdle(Gear: PGear);
begin
AllInactive:= false;
inc(Gear^.Timer);
if Gear^.Timer > 75 then
begin
DeleteGear(Gear);
AfterAttack
end
end;
procedure doStepShotgunShot(Gear: PGear);
var i: LongWord;
begin
AllInactive:= false;
if ((Gear^.State and gstAnimation) = 0) then
begin
dec(Gear^.Timer);
if Gear^.Timer = 0 then
begin
PlaySound(sndShotgunFire, false);
Gear^.State:= Gear^.State or gstAnimation
end;
exit
end
else inc(Gear^.Timer);
i:= 200;
repeat
Gear^.X:= Gear^.X + Gear^.dX;
Gear^.Y:= Gear^.Y + Gear^.dY;
CheckCollision(Gear);
if (Gear^.State and gstCollision) <> 0 then
begin
Gear^.X:= Gear^.X + Gear^.dX * 8;
Gear^.Y:= Gear^.Y + Gear^.dY * 8;
ShotgunShot(Gear);
Gear^.doStep:= @doStepShotIdle;
exit
end;
dec(i)
until i = 0;
if (Gear^.X < _0) or (Gear^.Y < _0) or (Gear^.X > _2048) or (Gear^.Y > _1024) then
Gear^.doStep:= @doStepShotIdle
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepDEagleShotWork(Gear: PGear);
var i, x, y: LongWord;
oX, oY: hwFloat;
begin
AllInactive:= false;
inc(Gear^.Timer);
i:= 80;
oX:= Gear^.X;
oY:= Gear^.Y;
repeat
Gear^.X:= Gear^.X + Gear^.dX;
Gear^.Y:= Gear^.Y + Gear^.dY;
x:= hwRound(Gear^.X);
y:= hwRound(Gear^.Y);
if ((y and $FFFFFC00) = 0) and ((x and $FFFFF800) = 0)
and (Land[y, x] <> 0) then inc(Gear^.Damage);
if Gear^.Damage > 5 then AmmoShove(Gear, 7, 20);
dec(i)
until (i = 0) or (Gear^.Damage > Gear^.Health);
if Gear^.Damage > 0 then
begin
DrawTunnel(oX, oY, Gear^.dX, Gear^.dY, 82 - i, 1);
dec(Gear^.Health, Gear^.Damage);
Gear^.Damage:= 0
end;
if (Gear^.Health <= 0) or (Gear^.X < _0) or (Gear^.Y < _0) or (Gear^.X > _2048) or (Gear^.Y > _1024) then
Gear^.doStep:= @doStepShotIdle
end;
procedure doStepDEagleShot(Gear: PGear);
begin
PlaySound(sndGun, false);
Gear^.doStep:= @doStepDEagleShotWork
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepActionTimer(Gear: PGear);
begin
dec(Gear^.Timer);
case Gear^.Kind of
gtATStartGame: begin
AllInactive:= false;
if Gear^.Timer = 0 then
AddCaption(trmsg[sidStartFight], $FFFFFF, capgrpGameState);
end;
gtATSmoothWindCh: begin
if Gear^.Timer = 0 then
begin
if WindBarWidth < Gear^.Tag then inc(WindBarWidth)
else if WindBarWidth > Gear^.Tag then dec(WindBarWidth);
if WindBarWidth <> Gear^.Tag then Gear^.Timer:= 10;
end
end;
gtATFinishGame: begin
AllInactive:= false;
if Gear^.Timer = 0 then
begin
SendIPC('N');
SendIPC('q');
GameState:= gsExit
end
end;
end;
if Gear^.Timer = 0 then DeleteGear(Gear)
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepPickHammerWork(Gear: PGear);
var i, ei: LongInt;
HHGear: PGear;
begin
AllInactive:= false;
HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
dec(Gear^.Timer);
if (Gear^.Timer = 0)or((Gear^.Message and gm_Destroy) <> 0)or((HHGear^.State and gstHHDriven) = 0) then
begin
StopSound(sndPickhammer);
DeleteGear(Gear);
AfterAttack;
exit
end;
if (Gear^.Timer mod 33) = 0 then
begin
HHGear^.State:= HHGear^.State or gstNoDamage;
doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y) + 7, 6, EXPLDontDraw);
HHGear^.State:= HHGear^.State and not gstNoDamage
end;
if (Gear^.Timer mod 47) = 0 then
begin
i:= hwRound(Gear^.X) - Gear^.Radius - LongInt(GetRandom(2));
ei:= hwRound(Gear^.X) + Gear^.Radius + LongInt(GetRandom(2));
while i <= ei do
begin
DrawExplosion(i, hwRound(Gear^.Y) + 3, 3);
inc(i, 1)
end;
Gear^.X:= Gear^.X + Gear^.dX;
Gear^.Y:= Gear^.Y + _1_9;
SetAllHHToActive;
end;
if TestCollisionYwithGear(Gear, 1) then
begin
Gear^.dY:= _0;
SetLittle(HHGear^.dX);
HHGear^.dY:= _0;
end else
begin
Gear^.dY:= Gear^.dY + cGravity;
Gear^.Y:= Gear^.Y + Gear^.dY;
if Gear^.Y > _1024 then Gear^.Timer:= 1
end;
Gear^.X:= Gear^.X + HHGear^.dX;
HHGear^.X:= Gear^.X;
HHGear^.Y:= Gear^.Y - int2hwFloat(cHHRadius);
if (Gear^.Message and gm_Attack) <> 0 then
if (Gear^.State and gsttmpFlag) <> 0 then Gear^.Timer:= 1 else else
if (Gear^.State and gsttmpFlag) = 0 then Gear^.State:= Gear^.State or gsttmpFlag;
if ((Gear^.Message and gm_Left) <> 0) then Gear^.dX:= - _0_3 else
if ((Gear^.Message and gm_Right) <> 0) then Gear^.dX:= _0_3
else Gear^.dX:= _0;
end;
procedure doStepPickHammer(Gear: PGear);
var i, y: LongInt;
ar: TRangeArray;
HHGear: PGear;
begin
i:= 0;
HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
y:= hwRound(Gear^.Y) - cHHRadius * 2;
while y < hwRound(Gear^.Y) do
begin
ar[i].Left := hwRound(Gear^.X) - Gear^.Radius - LongInt(GetRandom(2));
ar[i].Right:= hwRound(Gear^.X) + Gear^.Radius + LongInt(GetRandom(2));
inc(y, 2);
inc(i)
end;
DrawHLinesExplosions(@ar, 3, hwRound(Gear^.Y) - cHHRadius * 2, 2, Pred(i));
Gear^.dY:= HHGear^.dY;
DeleteCI(HHGear);
PlaySound(sndPickhammer, true);
doStepPickHammerWork(Gear);
Gear^.doStep:= @doStepPickHammerWork
end;
////////////////////////////////////////////////////////////////////////////////
var BTPrevAngle, BTSteps: LongInt;
procedure doStepBlowTorchWork(Gear: PGear);
var HHGear: PGear;
b: boolean;
begin
AllInactive:= false;
dec(Gear^.Timer);
HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
HedgehogChAngle(HHGear);
b:= false;
if abs(LongInt(HHGear^.Angle) - BTPrevAngle) > 7 then
begin
Gear^.dX:= SignAs(AngleSin(HHGear^.Angle) * _0_5, HHGear^.dX);
Gear^.dY:= AngleCos(HHGear^.Angle) * ( - _0_5);
BTPrevAngle:= HHGear^.Angle;
b:= true
end;
if Gear^.Timer mod cHHStepTicks = 0 then
begin
b:= true;
if Gear^.dX.isNegative then HHGear^.Message:= (HHGear^.Message or gm_Left) and not gm_Right
else HHGear^.Message:= (HHGear^.Message or gm_Right) and not gm_Left;
HHGear^.State:= HHGear^.State and not gstAttacking;
HedgehogStep(HHGear);
HHGear^.State:= HHGear^.State or gstAttacking;
inc(BTSteps);
if BTSteps = 7 then
begin
BTSteps:= 0;
Gear^.X:= HHGear^.X + Gear^.dX * (cHHRadius + cBlowTorchC);
Gear^.Y:= HHGear^.Y + Gear^.dY * (cHHRadius + cBlowTorchC);
HHGear^.State:= HHGear^.State or gstNoDamage;
AmmoShove(Gear, 2, 14);
HHGear^.State:= HHGear^.State and not gstNoDamage
end;
if (HHGear^.State and gstMoving) <> 0 then Gear^.Timer:= 0
end;
if b then
DrawTunnel(HHGear^.X - Gear^.dX * cHHRadius, HHGear^.Y - _4 - Gear^.dY * cHHRadius + hwAbs(Gear^.dY) * 7,
Gear^.dX, Gear^.dY,
cHHRadius * 5, cHHRadius * 2 + 6);
if (Gear^.Timer = 0) or ((HHGear^.Message and gm_Attack) <> 0) then
begin
HHGear^.Message:= 0;
DeleteGear(Gear);
AfterAttack
end
end;
procedure doStepBlowTorch(Gear: PGear);
var HHGear: PGear;
begin
BTPrevAngle:= High(LongInt);
BTSteps:= 0;
HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
HHGear^.Message:= 0;
Gear^.doStep:= @doStepBlowTorchWork
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepRopeWork(Gear: PGear);
const flCheck: boolean = false;
var HHGear: PGear;
len, cs, cc, tx, ty, nx, ny: hwFloat;
lx, ly: LongInt;
procedure DeleteMe;
begin
with HHGear^ do
begin
Message:= Message and not gm_Attack;
State:= State or gstMoving;
end;
DeleteGear(Gear)
end;
begin
HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
if ((HHGear^.State and gstHHDriven) = 0)
or (CheckGearDrowning(HHGear)) then
begin
DeleteMe;
exit
end;
Gear^.dX:= HHGear^.X - Gear^.X;
Gear^.dY:= HHGear^.Y - Gear^.Y;
if (Gear^.Message and gm_Left <> 0) then HHGear^.dX:= HHGear^.dX - _0_0002 else
if (Gear^.Message and gm_Right <> 0) then HHGear^.dX:= HHGear^.dX + _0_0002;
if not TestCollisionYwithGear(HHGear, 1) then HHGear^.dY:= HHGear^.dY + cGravity;
cs:= Gear^.dY + HHGear^.dY;
cc:= Gear^.dX + HHGear^.dX;
len:= _1 / Distance(cc, cs);
cc:= cc * len; // rope vector plus hedgehog direction vector normalized
cs:= cs * len;
nx:= hwAbs(cs) * hwSign(HHGear^.dX) * 7; // hedgehog direction normalized with length 7
ny:= hwAbs(cc) * hwSign(HHGear^.dY) * 7;
flCheck:= not flCheck;
if flCheck then // check whether rope needs dividing
begin
len:= Gear^.Elasticity - _20;
while len > _5 do
begin
tx:= cc*len;
ty:= cs*len;
lx:= hwRound(Gear^.X + tx + nx);
ly:= hwRound(Gear^.Y + ty + ny);
if ((ly and $FFFFFC00) = 0) and ((lx and $FFFFF800) = 0) and (Land[ly, lx] <> 0) then
begin
with RopePoints.ar[RopePoints.Count] do
begin
X:= Gear^.X;
Y:= Gear^.Y;
if RopePoints.Count = 0 then RopePoints.HookAngle:= DxDy2Angle(Gear^.dY, Gear^.dX);
b:= (cc * HHGear^.dY) > (cs * HHGear^.dX);
dLen:= len
end;
Gear^.X:= Gear^.X + tx;
Gear^.Y:= Gear^.Y + ty;
inc(RopePoints.Count);
TryDo(RopePoints.Count <= MAXROPEPOINTS, 'Rope points overflow', true);
Gear^.Elasticity:= Gear^.Elasticity - len;
Gear^.Friction:= Gear^.Friction - len;
break
end;
len:= len - _0_2
end;
end else
if RopePoints.Count > 0 then // check whether the last dividing point could be removed
begin
tx:= RopePoints.ar[Pred(RopePoints.Count)].X;
ty:= RopePoints.ar[Pred(RopePoints.Count)].Y;
if RopePoints.ar[Pred(RopePoints.Count)].b xor ((tx - Gear^.X) * (ty - HHGear^.Y) > (tx - HHGear^.X) * (ty - Gear^.Y)) then
begin
dec(RopePoints.Count);
Gear^.X:=RopePoints.ar[RopePoints.Count].X;
Gear^.Y:=RopePoints.ar[RopePoints.Count].Y;
Gear^.Elasticity:= Gear^.Elasticity + RopePoints.ar[RopePoints.Count].dLen;
Gear^.Friction:= Gear^.Friction + RopePoints.ar[RopePoints.Count].dLen
end
end;
Gear^.dX:= HHGear^.X - Gear^.X;
Gear^.dY:= HHGear^.Y - Gear^.Y;
cs:= Gear^.dY + HHGear^.dY;
cc:= Gear^.dX + HHGear^.dX;
len:= _1 / Distance(cc, cs);
cc:= cc * len;
cs:= cs * len;
HHGear^.dX:= HHGear^.X;
HHGear^.dY:= HHGear^.Y;
if ((Gear^.Message and gm_Down) <> 0) and (Gear^.Elasticity < Gear^.Friction) then
if not (TestCollisionXwithGear(HHGear, hwSign(Gear^.dX))
or TestCollisionYwithGear(HHGear, hwSign(Gear^.dY))) then Gear^.Elasticity:= Gear^.Elasticity + _0_3;
if ((Gear^.Message and gm_Up) <> 0) and (Gear^.Elasticity > _30) then
if not (TestCollisionXwithGear(HHGear, -hwSign(Gear^.dX))
or TestCollisionYwithGear(HHGear, -hwSign(Gear^.dY))) then Gear^.Elasticity:= Gear^.Elasticity - _0_3;
HHGear^.X:= Gear^.X + cc*Gear^.Elasticity;
HHGear^.Y:= Gear^.Y + cs*Gear^.Elasticity;
HHGear^.dX:= HHGear^.X - HHGear^.dX;
HHGear^.dY:= HHGear^.Y - HHGear^.dY;
if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then
HHGear^.dX:= -_0_6 * HHGear^.dX;
if TestCollisionYwithGear(HHGear, hwSign(HHGear^.dY)) then
HHGear^.dY:= -_0_6 * HHGear^.dY;
len:= Distance(HHGear^.dX, HHGear^.dY);
if len > _0_8 then
begin
len:= _0_8 / len;
HHGear^.dX:= HHGear^.dX * len;
HHGear^.dY:= HHGear^.dY * len;
end;
if (Gear^.Message and gm_Attack) <> 0 then
if (Gear^.State and gsttmpFlag) <> 0 then DeleteMe else
else if (Gear^.State and gsttmpFlag) = 0 then Gear^.State:= Gear^.State or gsttmpFlag;
end;
procedure doStepRopeAttach(Gear: PGear);
var HHGear: PGear;
tx, ty, tt: hwFloat;
begin
Gear^.X:= Gear^.X - Gear^.dX;
Gear^.Y:= Gear^.Y - Gear^.dY;
Gear^.Elasticity:= Gear^.Elasticity + _1;
HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
DeleteCI(HHGear);
if (HHGear^.State and gstMoving) <> 0 then
if TestCollisionYwithGear(HHGear, 1) then
begin
CheckHHDamage(HHGear);
HHGear^.dY:= _0;
HHGear^.State:= HHGear^.State and not (gstMoving or gstHHJumping);
end else
begin
if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then SetLittle(HHGear^.dX);
HHGear^.X:= HHGear^.X + HHGear^.dX;
HHGear^.Y:= HHGear^.Y + HHGear^.dY;
Gear^.X:= Gear^.X + HHGear^.dX;
Gear^.Y:= Gear^.Y + HHGear^.dY;
HHGear^.dY:= HHGear^.dY + cGravity;
tt:= Gear^.Elasticity;
tx:= _0;
ty:= _0;
while tt > _20 do
begin
if TestCollisionXwithXYShift(Gear, tx, hwRound(ty), -hwSign(Gear^.dX))
or TestCollisionYwithXYShift(Gear, hwRound(tx), hwRound(ty), -hwSign(Gear^.dY)) then
begin
Gear^.X:= Gear^.X + tx;
Gear^.Y:= Gear^.Y + ty;
Gear^.Elasticity:= tt;
Gear^.doStep:= @doStepRopeWork;
with HHGear^ do State:= State and not gstAttacking;
tt:= _0
end;
tx:= tx + Gear^.dX + Gear^.dX;
ty:= ty + Gear^.dY + Gear^.dY;
tt:= tt - _2;
end;
end;
CheckCollision(Gear);
if (Gear^.State and gstCollision) <> 0 then
begin
Gear^.doStep:= @doStepRopeWork;
with HHGear^ do State:= State and not (gstAttacking or gstHHHJump);
OnUsedAmmo(PHedgehog(HHGear^.Hedgehog)^);
ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^);
if Gear^.Elasticity < _10 then
Gear^.Elasticity:= _10000;
end;
if (Gear^.Elasticity > Gear^.Friction) or ((Gear^.Message and gm_Attack) = 0) then
begin
with PHedgehog(Gear^.Hedgehog)^.Gear^ do
begin
State:= State and not gstAttacking;
Message:= Message and not gm_Attack
end;
DeleteGear(Gear)
end
end;
procedure doStepRope(Gear: PGear);
begin
Gear^.dX:= - Gear^.dX;
Gear^.dY:= - Gear^.dY;
Gear^.doStep:= @doStepRopeAttach
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepSmokeTrace(Gear: PGear);
begin
inc(Gear^.Timer);
if Gear^.Timer > 64 then
begin
Gear^.Timer:= 0;
dec(Gear^.State)
end;
Gear^.dX:= Gear^.dX + cWindSpeed;
Gear^.X:= Gear^.X + Gear^.dX;
if Gear^.State = 0 then DeleteGear(Gear)
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepExplosionWork(Gear: PGear);
begin
inc(Gear^.Timer);
if Gear^.Timer > 75 then
begin
inc(Gear^.State);
Gear^.Timer:= 0;
if Gear^.State > 5 then DeleteGear(Gear)
end;
end;
procedure doStepExplosion(Gear: PGear);
var i: LongWord;
begin
for i:= 0 to 31 do AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtFire);
for i:= 0 to 8 do AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtExplPart);
for i:= 0 to 8 do AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtExplPart2);
Gear^.doStep:= @doStepExplosionWork
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepMine(Gear: PGear);
begin
if (Gear^.State and gstMoving) <> 0 then
begin
DeleteCI(Gear);
doStepFallingGear(Gear);
if (Gear^.State and gstMoving) = 0 then
begin
AddGearCI(Gear);
Gear^.dX:= _0;
Gear^.dY:= _0
end;
CalcRotationDirAngle(Gear);
AllInactive:= false
end else
if ((GameTicks and $3F) = 25) then
doStepFallingGear(Gear);
if ((Gear^.State and gsttmpFlag) <> 0) then
if ((Gear^.State and gstAttacking) = 0) then
begin
if ((GameTicks and $1F) = 0) then
if CheckGearNear(Gear, gtHedgehog, 46, 32) <> nil then Gear^.State:= Gear^.State or gstAttacking
end else // gstAttacking <> 0
begin
AllInactive:= false;
if (Gear^.Timer and $FF) = 0 then PlaySound(sndMineTick, false);
if Gear^.Timer = 0 then
begin
doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
DeleteGear(Gear);
exit
end;
dec(Gear^.Timer);
end else // gsttmpFlag = 0
if TurnTimeLeft = 0 then Gear^.State:= Gear^.State or gsttmpFlag;
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepDynamite(Gear: PGear);
begin
doStepFallingGear(Gear);
AllInactive:= false;
if Gear^.Timer mod 166 = 0 then inc(Gear^.Tag);
if Gear^.Timer = 0 then
begin
doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 75, EXPLAutoSound);
DeleteGear(Gear);
exit
end;
dec(Gear^.Timer);
end;
///////////////////////////////////////////////////////////////////////////////
procedure doStepCase(Gear: PGear);
var i, x, y: LongInt;
begin
if (Gear^.Message and gm_Destroy) > 0 then
begin
DeleteGear(Gear);
FreeActionsList;
SetAllToActive; // something (hh, mine, etc...) could be on top of the case
with CurrentHedgehog^ do
if Gear <> nil then Gear^.Message:= Gear^.Message and not (gm_LJump or gm_HJump);
exit
end;
if Gear^.Damage > 0 then
begin
x:= hwRound(Gear^.X);
y:= hwRound(Gear^.Y);
DeleteGear(Gear);
if Gear^.Kind = gtCase then
begin
doMakeExplosion(x, y, 25, EXPLAutoSound);
for i:= 0 to 63 do
AddGear(x, y, gtFlame, 0, _0, _0, 0);
end;
exit
end;
if (Gear^.dY.QWordValue <> 0) or (not TestCollisionYwithGear(Gear, 1)) then
begin
AllInactive:= false;
Gear^.dY:= Gear^.dY + cGravity;
Gear^.Y:= Gear^.Y + Gear^.dY;
if (Gear^.dY.isNegative) and TestCollisionYwithGear(Gear, -1) then Gear^.dY:= _0 else
if (not Gear^.dY.isNegative) and TestCollisionYwithGear(Gear, 1) then
begin
Gear^.dY:= - Gear^.dY * Gear^.Elasticity;
if Gear^.dY > - _0_001 then Gear^.dY:= _0
else if Gear^.dY < - _0_03 then PlaySound(sndGraveImpact, false);
end;
CheckGearDrowning(Gear);
end;
if (Gear^.dY.QWordValue = 0) then AddGearCI(Gear)
else if (Gear^.dY.QWordValue <> 0) then DeleteCI(Gear)
end;
////////////////////////////////////////////////////////////////////////////////
const cSorterWorkTime = 640;
var thexchar: array[0..cMaxTeams] of
record
dy, ny, dw: LongInt;
team: PTeam;
SortFactor: QWord;
end;
currsorter: PGear = nil;
procedure doStepTeamHealthSorterWork(Gear: PGear);
var i: LongInt;
begin
AllInactive:= false;
dec(Gear^.Timer);
if (Gear^.Timer and 15) = 0 then
for i:= 0 to Pred(TeamsCount) do
with thexchar[i] do
begin
{$WARNINGS OFF}
team^.DrawHealthY:= ny + dy * Gear^.Timer div 640;
team^.TeamHealthBarWidth:= team^.NewTeamHealthBarWidth + dw * Gear^.Timer div cSorterWorkTime;
{$WARNINGS ON}
end;
if (Gear^.Timer = 0) or (currsorter <> Gear) then
begin
if currsorter = Gear then currsorter:= nil;
DeleteGear(Gear)
end
end;
procedure doStepTeamHealthSorter(Gear: PGear);
var i: Longword;
b: boolean;
t: LongInt;
begin
AllInactive:= false;
for t:= 0 to Pred(TeamsCount) do
with thexchar[t] do
begin
dy:= TeamsArray[t]^.DrawHealthY;
dw:= TeamsArray[t]^.TeamHealthBarWidth - TeamsArray[t]^.NewTeamHealthBarWidth;
team:= TeamsArray[t];
SortFactor:= TeamsArray[t]^.Clan^.ClanHealth;
SortFactor:= (SortFactor shl 3) + TeamsArray[t]^.Clan^.ClanIndex;
SortFactor:= (SortFactor shl 30) + TeamsArray[t]^.TeamHealth;
end;
if TeamsCount > 1 then
repeat
b:= true;
for t:= 0 to TeamsCount - 2 do
if (thexchar[t].SortFactor > thexchar[Succ(t)].SortFactor) then
begin
thexchar[cMaxTeams]:= thexchar[t];
thexchar[t]:= thexchar[Succ(t)];
thexchar[Succ(t)]:= thexchar[cMaxTeams];
b:= false
end
until b;
t:= - 4;
for i:= 0 to Pred(TeamsCount) do
with thexchar[i] do
begin
dec(t, team^.HealthTex^.h + 2);
ny:= t;
dy:= dy - ny
end;
Gear^.Timer:= cSorterWorkTime;
Gear^.doStep:= @doStepTeamHealthSorterWork;
currsorter:= Gear
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepIdle(Gear: PGear);
begin
AllInactive:= false;
dec(Gear^.Timer);
if Gear^.Timer = 0 then
begin
DeleteGear(Gear);
AfterAttack
end
end;
procedure doStepShover(Gear: PGear);
var HHGear: PGear;
begin
HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
HHGear^.State:= HHGear^.State or gstNoDamage;
DeleteCI(HHGear);
AmmoShove(Gear, 30, 115);
HHGear^.State:= HHGear^.State and not gstNoDamage;
Gear^.Timer:= 250;
Gear^.doStep:= @doStepIdle
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepWhip(Gear: PGear);
var HHGear: PGear;
i: LongInt;
begin
HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
HHGear^.State:= HHGear^.State or gstNoDamage;
DeleteCI(HHGear);
for i:= 0 to 3 do
begin
AmmoShove(Gear, 30, 25);
Gear^.X:= Gear^.X + Gear^.dX * 5
end;
HHGear^.State:= HHGear^.State and not gstNoDamage;
Gear^.Timer:= 250;
Gear^.doStep:= @doStepIdle
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepFlame(Gear: PGear);
begin
AllInactive:= false;
if not TestCollisionYwithGear(Gear, 1) then
begin
if hwAbs(Gear^.dX - cWindSpeed) > _0_1 then
Gear^.dX:= (Gear^.dX - cWindSpeed) * _0_5 + cWindSpeed;
Gear^.dY:= Gear^.dY + cGravity;
if Gear^.dY > _0_1 then Gear^.dY:= Gear^.dY * _0_995;
Gear^.X:= Gear^.X + Gear^.dX;
Gear^.Y:= Gear^.Y + Gear^.dY;
if not (Gear^.Y < _1024) then
begin
DeleteGear(Gear);
exit
end
end else begin
if Gear^.Timer > 0 then dec(Gear^.Timer)
else begin
Gear^.Radius:= 5;
AmmoShove(Gear, 3, 100);
Gear^.Radius:= 1;
doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 4, EXPLNoDamage);
dec(Gear^.Health);
Gear^.Timer:= 1250 - Gear^.Tag * 12
end
end;
//if (((GameTicks div 8) mod 64) = Gear^.Tag) then
// AmmoFlameWork(Gear);
if Gear^.Health = 0 then
DeleteGear(Gear)
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepFirePunchWork(Gear: PGear);
var HHGear: PGear;
begin
AllInactive:= false;
if ((Gear^.Message and gm_Destroy) <> 0) then
begin
DeleteGear(Gear);
AfterAttack;
exit
end;
HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
if hwRound(HHGear^.Y) <= Gear^.Tag - 2 then
begin
Gear^.Tag:= hwRound(HHGear^.Y);
DrawTunnel(HHGear^.X - int2hwFloat(cHHRadius), HHGear^.Y - _1, _0_5, _0, cHHRadius * 4, 2);
HHGear^.State:= HHGear^.State or gstNoDamage;
Gear^.Y:= HHGear^.Y;
AmmoShove(Gear, 30, 40);
HHGear^.State:= HHGear^.State and not gstNoDamage
end;
HHGear^.dY:= HHGear^.dY + cGravity;
if not (HHGear^.dY.isNegative) then
begin
HHGear^.State:= HHGear^.State or gstMoving;
DeleteGear(Gear);
AfterAttack;
exit
end;
HHGear^.Y:= HHGear^.Y + HHGear^.dY
end;
procedure doStepFirePunch(Gear: PGear);
var HHGear: PGear;
begin
AllInactive:= false;
HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
DeleteCI(HHGear);
HHGear^.X:= int2hwFloat(hwRound(HHGear^.X)) - _0_5;
HHGear^.dX:= SignAs(cLittle, Gear^.dX);
HHGear^.dY:= - _0_3;
Gear^.X:= HHGear^.X;
Gear^.dX:= SignAs(_0_45, Gear^.dX);
Gear^.dY:= - _0_9;
Gear^.doStep:= @doStepFirePunchWork;
DrawTunnel(HHGear^.X - int2hwFloat(cHHRadius), HHGear^.Y + _1, _0_5, _0, cHHRadius * 4, 5);
PlaySound(TSound(ord(sndFirePunch1) + GetRandom(6)), false)
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepParachuteWork(Gear: PGear);
var HHGear: PGear;
begin
HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
inc(Gear^.Timer);
if TestCollisionYwithGear(HHGear, 1)
or ((HHGear^.State and gstHHDriven) = 0)
or CheckGearDrowning(HHGear)
or ((Gear^.Message and gm_Attack) <> 0) then
begin
with HHGear^ do
begin
Message:= 0;
SetLittle(dX);
dY:= _0;
State:= State or gstMoving;
end;
DeleteGear(Gear);
exit
end;
if not TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then
HHGear^.X:= HHGear^.X + cWindSpeed * 200;
if (Gear^.Message and gm_Left) <> 0 then HHGear^.X:= HHGear^.X - cMaxWindSpeed * 40
else if (Gear^.Message and gm_Right) <> 0 then HHGear^.X:= HHGear^.X + cMaxWindSpeed * 40;
if (Gear^.Message and gm_Up) <> 0 then HHGear^.Y:= HHGear^.Y - cGravity * 40
else if (Gear^.Message and gm_Down) <> 0 then HHGear^.Y:= HHGear^.Y + cGravity * 40;
HHGear^.Y:= HHGear^.Y + cGravity * 100;
Gear^.X:= HHGear^.X;
Gear^.Y:= HHGear^.Y
end;
procedure doStepParachute(Gear: PGear);
var HHGear: PGear;
begin
HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
DeleteCI(HHGear);
OnUsedAmmo(PHedgehog(HHGear^.Hedgehog)^);
ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^);
HHGear^.State:= HHGear^.State and not (gstAttacking or gstAttacked or gstMoving);
HHGear^.Message:= HHGear^.Message and not gm_Attack;
Gear^.doStep:= @doStepParachuteWork;
Gear^.Message:= HHGear^.Message;
doStepParachuteWork(Gear)
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepAirAttackWork(Gear: PGear);
begin
AllInactive:= false;
Gear^.X:= Gear^.X + cAirPlaneSpeed * Gear^.Tag;
if (Gear^.Health > 0)and(not (Gear^.X < Gear^.dX))and(Gear^.X < Gear^.dX + cAirPlaneSpeed) then
begin
dec(Gear^.Health);
case Gear^.State of
0: FollowGear:= AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, cBombsSpeed * Gear^.Tag, _0, 0);
1: FollowGear:= AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtMine, 0, cBombsSpeed * Gear^.Tag, _0, 0);
end;
Gear^.dX:= Gear^.dX + int2hwFloat(30 * Gear^.Tag)
end;
if (GameTicks and $3F) = 0 then
AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtSmokeTrace, 0, _0, _0, 0);
if (hwRound(Gear^.X) > 3072) or (hwRound(Gear^.X) < -1024) then DeleteGear(Gear)
end;
procedure doStepAirAttack(Gear: PGear);
begin
AllInactive:= false;
if Gear^.X.QWordValue = 0 then Gear^.Tag:= 1
else Gear^.Tag:= -1;
Gear^.X:= _1024 - _2048 * Gear^.Tag;
Gear^.Y:= -_300;
Gear^.dX:= int2hwFloat(TargetPoint.X - 5 * Gear^.Tag * 15);
if int2hwFloat(TargetPoint.Y) - Gear^.Y > _0 then
Gear^.dX:= Gear^.dX - cBombsSpeed * hwSqrt((int2hwFloat(TargetPoint.Y) - Gear^.Y) * 2 / cGravity) * Gear^.Tag;
Gear^.Health:= 6;
Gear^.doStep:= @doStepAirAttackWork;
PlaySound(sndIncoming, false)
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepAirBomb(Gear: PGear);
begin
AllInactive:= false;
doStepFallingGear(Gear);
if (Gear^.State and gstCollision) <> 0 then
begin
doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, EXPLAutoSound);
DeleteGear(Gear);
exit
end;
if (GameTicks and $3F) = 0 then
AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtSmokeTrace, 0, _0, _0, 0)
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepGirder(Gear: PGear);
var HHGear: PGear;
begin
AllInactive:= false;
HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
if not TryPlaceOnLand(TargetPoint.X - SpritesData[sprAmGirder].Width div 2,
TargetPoint.Y - SpritesData[sprAmGirder].Height div 2,
sprAmGirder, Gear^.State, true) then
begin
HHGear^.Message:= HHGear^.Message and not gm_Attack;
HHGear^.State:= HHGear^.State and not gstAttacking;
HHGear^.State:= HHGear^.State or gstHHChooseTarget;
DeleteGear(Gear);
isCursorVisible:= true
end
else begin
DeleteGear(Gear);
AfterAttack
end;
TargetPoint.X:= NoPointX
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepTeleportAfter(Gear: PGear);
var HHGear: PGear;
begin
HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
HHGear^.Y:= HHGear^.Y + HHGear^.dY; // hedgehog falling to collect cases
HHGear^.dY:= HHGear^.dY + cGravity;
if TestCollisionYwithGear(HHGear, 1)
or CheckGearDrowning(HHGear) then
begin
DeleteGear(Gear);
AfterAttack
end
end;
procedure doStepTeleportAnim(Gear: PGear);
begin
inc(Gear^.Timer);
if Gear^.Timer = 65 then
begin
Gear^.Timer:= 0;
inc(Gear^.Pos);
if Gear^.Pos = 11 then
Gear^.doStep:= @doStepTeleportAfter
end
end;
procedure doStepTeleport(Gear: PGear);
var HHGear: PGear;
begin
AllInactive:= false;
HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
if not TryPlaceOnLand(TargetPoint.X - SpritesData[sprHHTelepMask].Width div 2,
TargetPoint.Y - SpritesData[sprHHTelepMask].Height div 2,
sprHHTelepMask, 0, false) then
begin
HHGear^.Message:= HHGear^.Message and not gm_Attack;
HHGear^.State:= HHGear^.State and not gstAttacking;
HHGear^.State:= HHGear^.State or gstHHChooseTarget;
DeleteGear(Gear);
isCursorVisible:= true
end
else begin
DeleteCI(HHGear);
SetAllHHToActive;
Gear^.doStep:= @doStepTeleportAnim;
Gear^.X:= HHGear^.X;
Gear^.Y:= HHGear^.Y;
HHGear^.X:= int2hwFloat(TargetPoint.X);
HHGear^.Y:= int2hwFloat(TargetPoint.Y);
HHGear^.State:= HHGear^.State or gstMoving
end;
TargetPoint.X:= NoPointX
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepSwitcherWork(Gear: PGear);
var HHGear: PGear;
Msg, State: Longword;
begin
AllInactive:= false;
if ((Gear^.Message and not gm_Switch) <> 0) or (TurnTimeLeft = 0) then
begin
HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
Msg:= Gear^.Message and not gm_Switch;
DeleteGear(Gear);
OnUsedAmmo(PHedgehog(HHGear^.Hedgehog)^);
ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^);
HHGear:= CurrentHedgehog^.Gear;
ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^);
HHGear^.Message:= Msg;
exit
end;
if (Gear^.Message and gm_Switch) <> 0 then
begin
HHGear:= CurrentHedgehog^.Gear;
HHGear^.Message:= HHGear^.Message and not gm_Switch;
Gear^.Message:= Gear^.Message and not gm_Switch;
State:= HHGear^.State;
HHGear^.State:= 0;
HHGear^.Active:= false;
HHGear^.Z:= cHHZ;
RemoveGearFromList(HHGear);
InsertGearToList(HHGear);
repeat
CurrentTeam^.CurrHedgehog:= Succ(CurrentTeam^.CurrHedgehog) mod (CurrentTeam^.HedgehogsNumber);
until (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear <> nil);
CurrentHedgehog:= @CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog];
HHGear:= CurrentHedgehog^.Gear;
HHGear^.State:= State;
HHGear^.Active:= true;
FollowGear:= HHGear;
HHGear^.Z:= cCurrHHZ;
RemoveGearFromList(HHGear);
InsertGearToList(HHGear);
Gear^.X:= HHGear^.X;
Gear^.Y:= HHGear^.Y
end;
end;
procedure doStepSwitcher(Gear: PGear);
var HHGear: PGear;
begin
Gear^.doStep:= @doStepSwitcherWork;
HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
with HHGear^ do
begin
State:= State and not gstAttacking;
Message:= Message and not gm_Attack
end
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepMortar(Gear: PGear);
var dX, dY: hwFloat;
i: LongInt;
dxn, dyn: boolean;
begin
AllInactive:= false;
dxn:= Gear^.dX.isNegative;
dyn:= Gear^.dY.isNegative;
doStepFallingGear(Gear);
if (Gear^.State and gstCollision) <> 0 then
begin
doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, EXPLAutoSound);
Gear^.dX.isNegative:= not dxn;
Gear^.dY.isNegative:= not dyn;
for i:= 0 to 4 do
begin
dX:= Gear^.dX + (GetRandom - _0_5) * _0_03;
dY:= Gear^.dY + (GetRandom - _0_5) * _0_03;
AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtCluster, 0, dX, dY, 25);
end;
DeleteGear(Gear);
exit
end;
if (GameTicks and $3F) = 0 then
AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtSmokeTrace, 0, _0, _0, 0)
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepKamikazeWork(Gear: PGear);
const upd: Longword = 0;
var i: LongWord;
HHGear: PGear;
begin
AllInactive:= false;
HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
HHGear^.State:= HHGear^.State or gstNoDamage;
DeleteCI(HHGear);
i:= 2;
repeat
Gear^.X:= Gear^.X + HHGear^.dX;
Gear^.Y:= Gear^.Y + HHGear^.dY;
HHGear^.X:= Gear^.X;
HHGear^.Y:= Gear^.Y;
inc(Gear^.Damage, 2);
// if TestCollisionXwithGear(HHGear, hwSign(Gear^.dX))
// or TestCollisionYwithGear(HHGear, hwSign(Gear^.dY)) then inc(Gear^.Damage, 3);
dec(i)
until (i = 0) or (Gear^.Damage > Gear^.Health);
inc(upd);
if upd > 3 then
begin
if Gear^.Health < 1500 then Gear^.Pos:= 2;
AmmoShove(Gear, 30, 40);
DrawTunnel(HHGear^.X - HHGear^.dX * 10,
HHGear^.Y - _2 - HHGear^.dY * 10 + hwAbs(HHGear^.dY) * 2,
HHGear^.dX,
HHGear^.dY,
20 + cHHRadius * 2,
cHHRadius * 2 + 6);
upd:= 0
end;
if Gear^.Health < Gear^.Damage then
begin
doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, EXPLAutoSound);
AfterAttack;
DeleteGear(Gear);
DeleteGear(HHGear);
end else
begin
dec(Gear^.Health, Gear^.Damage);
Gear^.Damage:= 0
end
end;
procedure doStepKamikazeIdle(Gear: PGear);
begin
AllInactive:= false;
dec(Gear^.Timer);
if Gear^.Timer = 0 then
begin
Gear^.Pos:= 1;
PlaySound(sndKamikaze, false);
Gear^.doStep:= @doStepKamikazeWork
end
end;
procedure doStepKamikaze(Gear: PGear);
var HHGear: PGear;
begin
AllInactive:= false;
HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
HHGear^.dX:= Gear^.dX;
HHGear^.dY:= Gear^.dY;
Gear^.dX:= SignAs(_0_45, Gear^.dX);
Gear^.dY:= - _0_9;
Gear^.Timer:= 550;
Gear^.doStep:= @doStepKamikazeIdle
end;
////////////////////////////////////////////////////////////////////////////////
const cakeh = 27;
cakeDmg = 75;
var CakePoints: array[0..Pred(cakeh)] of record x, y: hwFloat; end;
CakeI: Longword;
procedure doStepCakeExpl(Gear: PGear);
begin
inc(Gear^.Tag);
if Gear^.Tag < 2250 then exit;
doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), cakeDmg, EXPLAutoSound);
AfterAttack;
DeleteGear(Gear)
end;
procedure doStepCakeDown(Gear: PGear);
var gi: PGear;
dmg: LongInt;
begin
AllInactive:= false;
inc(Gear^.Tag);
if Gear^.Tag < 100 then exit;
Gear^.Tag:= 0;
if Gear^.Pos = 0 then
begin
gi:= GearsList;
while gi <> nil do
begin
dmg:= cakeDmg * 2 - hwRound(Distance(gi^.X - Gear^.X, gi^.Y - Gear^.Y));
if (dmg > 1) and (gi^.Kind = gtHedgehog) then
gi^.State:= gi^.State or gstWinner;
gi:= gi^.NextGear
end;
Gear^.doStep:= @doStepCakeExpl;
PlaySound(sndCake, false)
end else dec(Gear^.Pos)
end;
procedure doStepCakeWork(Gear: PGear);
const dirs: array[0..3] of TPoint = ((x: 0; y: -1), (x: 1; y: 0),(x: 0; y: 1),(x: -1; y: 0));
var xx, yy, xxn, yyn: LongInt;
da: LongInt;
tdx, tdy: hwFloat;
procedure PrevAngle;
begin
Gear^.Angle:= (LongInt(Gear^.Angle) + 4 - dA) mod 4
end;
procedure NextAngle;
begin
Gear^.Angle:= (LongInt(Gear^.Angle) + 4 + dA) mod 4
end;
begin
inc(Gear^.Tag);
if Gear^.Tag < 7 then exit;
dA:= hwSign(Gear^.dX);
xx:= dirs[Gear^.Angle].x;
yy:= dirs[Gear^.Angle].y;
xxn:= dirs[(LongInt(Gear^.Angle) + 4 + dA) mod 4].x;
yyn:= dirs[(LongInt(Gear^.Angle) + 4 + dA) mod 4].y;
if (xx = 0) then
if TestCollisionYwithGear(Gear, yy) then
PrevAngle
else begin
Gear^.Tag:= 0;
Gear^.Y:= Gear^.Y + int2hwFloat(yy);
if not TestCollisionXwithGear(Gear, xxn) then NextAngle
end;
if (yy = 0) then
if TestCollisionXwithGear(Gear, xx) then
PrevAngle
else begin
Gear^.Tag:= 0;
Gear^.X:= Gear^.X + int2hwFloat(xx);
if not TestCollisionYwithGear(Gear, yyn) then NextAngle
end;
if Gear^.Tag = 0 then
begin
CakeI:= (CakeI + 1) mod cakeh;
tdx:= CakePoints[CakeI].x - Gear^.X;
tdy:= - CakePoints[CakeI].y + Gear^.Y;
CakePoints[CakeI].x:= Gear^.X;
CakePoints[CakeI].y:= Gear^.Y;
Gear^.DirAngle:= DxDy2Angle(tdx, tdy);
end;
dec(Gear^.Health);
if (Gear^.Health = 0) or ((Gear^.Message and gm_Attack) <> 0) then
begin
FollowGear:= Gear;
Gear^.doStep:= @doStepCakeDown
end
end;
procedure doStepCakeUp(Gear: PGear);
var i: Longword;
begin
AllInactive:= false;
inc(Gear^.Tag);
if Gear^.Tag < 100 then exit;
Gear^.Tag:= 0;
if Gear^.Pos = 6 then
begin
for i:= 0 to Pred(cakeh) do
begin
CakePoints[i].x:= Gear^.X;
CakePoints[i].y:= Gear^.Y
end;
CakeI:= 0;
Gear^.doStep:= @doStepCakeWork
end else inc(Gear^.Pos)
end;
procedure doStepCakeFall(Gear: PGear);
begin
AllInactive:= false;
Gear^.dY:= Gear^.dY + cGravity;
if TestCollisionYwithGear(Gear, 1) then
Gear^.doStep:= @doStepCakeUp
else
begin
Gear^.Y:= Gear^.Y + Gear^.dY;
if CheckGearDrowning(Gear) then AfterAttack
end
end;
procedure doStepCake(Gear: PGear);
var HHGear: PGear;
begin
AllInactive:= false;
HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
HHGear^.Message:= HHGear^.Message and (not gm_Attack);
DeleteCI(HHGear);
FollowGear:= Gear;
Gear^.doStep:= @doStepCakeFall
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepSeductionWork(Gear: PGear);
var x, y: LongInt;
begin
AllInactive:= false;
Gear^.X:= Gear^.X + Gear^.dX;
Gear^.Y:= Gear^.Y + Gear^.dY;
x:= hwRound(Gear^.X);
y:= hwRound(Gear^.Y);
if ((y and $FFFFFC00) = 0) and ((x and $FFFFF800) = 0) then
if (Land[y, x] <> 0) then
begin
Gear^.dX.isNegative:= not Gear^.dX.isNegative;
Gear^.dY.isNegative:= not Gear^.dY.isNegative;
Gear^.dX:= Gear^.dX * _1_5;
Gear^.dY:= Gear^.dY * _1_5 - _0_3;
AmmoShove(Gear, 0, 40);
AfterAttack;
DeleteGear(Gear)
end
else
else
begin
AfterAttack;
DeleteGear(Gear)
end
end;
procedure doStepSeductionWear(Gear: PGear);
begin
AllInactive:= false;
inc(Gear^.Timer);
if Gear^.Timer > 250 then
begin
Gear^.Timer:= 0;
inc(Gear^.Pos)
end;
if Gear^.Pos = 8 then
Gear^.doStep:= @doStepSeductionWork
end;
procedure doStepSeduction(Gear: PGear);
begin
AllInactive:= false;
DeleteCI(PHedgehog(Gear^.Hedgehog)^.Gear);
Gear^.doStep:= @doStepSeductionWear
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepWaterUp(Gear: PGear);
var i: LongWord;
begin
AllInactive:= false;
inc(Gear^.Timer);
if Gear^.Timer = 17 then
Gear^.Timer:= 0
else
exit;
if cWaterLine > 0 then
begin
dec(cWaterLine);
for i:= 0 to 2047 do
Land[cWaterLine, i]:= 0;
SetAllToActive
end;
inc(Gear^.Tag);
if (Gear^.Tag = 51) or (cWaterLine = 0) then
DeleteGear(Gear)
end;