2
2
* Hedgewars, a free turn based strategy game
3
* Copyright (c) 2004-2010 Andrey Korotaev <unC0Rr@gmail.com>
3
* Copyright (c) 2004-2011 Andrey Korotaev <unC0Rr@gmail.com>
5
5
* This program is free software; you can redistribute it and/or modify
6
6
* it under the terms of the GNU General Public License as published by
19
19
{$INCLUDE "options.inc"}
23
* This unit defines the behavior of gears.
25
* Gears are "things"/"objects" that may be visible to the player or not,
26
* but always have an effect on the course of the game.
28
* E.g.: weapons, hedgehogs, etc.
30
* Note: The visual appearance of gears is defined in the unit "uGearsRender".
32
* Note: Gears that do not have an effect on the game but are just visual
33
* effects are called "Visual Gears" and defined in the respective unit!
23
36
uses SDLh, uConsts, uFloat, uTypes;
25
38
procedure initModule;
26
39
procedure freeModule;
27
40
function AddGear(X, Y: LongInt; Kind: TGearType; State: Longword; dX, dY: hwFloat; Timer: LongWord): PGear;
28
function SpawnCustomCrateAt(x, y: LongInt; crate: TCrateType; content: Longword ): PGear;
41
function SpawnCustomCrateAt(x, y: LongInt; crate: TCrateType; content: Longword ): PGear;
42
function SpawnFakeCrateAt(x, y: LongInt; crate: TCrateType; explode: boolean; poison: boolean ): PGear;
43
function GetAmmo: TAmmoType;
44
function GetUtility: TAmmoType;
29
45
procedure ResurrectHedgehog(gear: PGear);
46
procedure HideHog(HH: PHedgehog);
47
procedure RestoreHog(HH: PHedgehog);
30
48
procedure ProcessGears;
31
49
procedure EndTurnCleanup;
32
procedure ApplyDamage(Gear: PGear; Damage: Longword; Source: TDamageSource);
50
procedure ApplyDamage(Gear: PGear; AttackerHog: PHedgehog; Damage: Longword; Source: TDamageSource);
33
51
procedure SetAllToActive;
34
52
procedure SetAllHHToActive;
35
53
procedure DrawGears;
50
68
uCommands, uUtils, uTextures, uRenderUtils, uGearsRender, uCaptions, uDebug, uLandTexture;
53
procedure doMakeExplosion(X, Y, Radius: LongInt; Mask: LongWord); forward;
54
procedure doMakeExplosion(X, Y, Radius: LongInt; Mask, Tint: LongWord); forward;
71
procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword; const Tint: LongWord = $FFFFFFFF); forward;
55
72
procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt); forward;
56
73
//procedure AmmoFlameWork(Ammo: PGear); forward;
57
74
function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): TPGearArray; forward;
60
77
procedure AfterAttack; forward;
61
78
procedure HedgehogStep(Gear: PGear); forward;
62
79
procedure doStepHedgehogMoving(Gear: PGear); forward;
63
procedure HedgehogChAngle(Gear: PGear); forward;
80
procedure HedgehogChAngle(HHGear: PGear); forward;
64
81
procedure ShotgunShot(Gear: PGear); forward;
65
82
procedure PickUp(HH, Gear: PGear); forward;
66
procedure HHSetWeapon(Gear: PGear); forward;
83
procedure HHSetWeapon(HHGear: PGear); forward;
67
84
procedure doStepCase(Gear: PGear); forward;
86
// For better maintainability the step handlers of gears are stored in
88
// Note: step handlers of gears that are hedgehogs are in a different file
89
// than the handlers for all other gears.
69
90
{$INCLUDE "GSHandlers.inc"}
70
91
{$INCLUDE "HHHandlers.inc"}
186
207
AddFileLog('AddGear: #' + inttostr(Counter) + ' (' + inttostr(x) + ',' + inttostr(y) + '), d(' + floattostr(dX) + ',' + floattostr(dY) + ') type = ' + EnumToStr(Kind));
190
210
FillChar(gear^, sizeof(TGear), 0);
191
211
gear^.X:= int2hwFloat(X);
192
212
gear^.Y:= int2hwFloat(Y);
213
gear^.Target.X:= NoPointX;
193
214
gear^.Kind := Kind;
194
215
gear^.State:= State;
195
216
gear^.Active:= true;
198
219
gear^.doStep:= doStepHandlers[Kind];
199
220
gear^.CollisionIndex:= -1;
200
221
gear^.Timer:= Timer;
202
222
gear^.FlightTime:= 0;
203
223
gear^.uid:= Counter;
204
224
gear^.SoundChannel:= -1;
205
225
gear^.ImpactSound:= sndNone;
206
226
gear^.nImpactSounds:= 0;
227
// Define ammo association, if any.
228
gear^.AmmoType:= GearKindAmmoTypeMap[Kind];
229
if Ammoz[Gear^.AmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0 then gear^.Z:= cHHZ+1
230
else gear^.Z:= cUsualZ;
208
if CurrentTeam <> nil then
232
if CurrentHedgehog <> nil then
210
234
gear^.Hedgehog:= CurrentHedgehog;
211
235
gear^.IntersectGear:= CurrentHedgehog^.Gear
218
242
gear^.ImpactSound:= sndGrenadeImpact;
268
296
DirAngle:= random * 360;
269
297
dx.isNegative:= GetRandom(2) = 0;
270
298
dx.QWordValue:= GetRandom(100000000);
271
299
dy.isNegative:= false;
272
300
dy.QWordValue:= GetRandom(70000000);
301
State:= State or gstInvisible;
273
302
if GetRandom(2) = 0 then dx := -dx;
274
303
Health:= random(vobFrameTicks);
275
304
Timer:= random(vobFramesCount);
557
615
t:= max(Gear^.Damage, Gear^.Health);
558
616
Gear^.Damage:= t;
559
if (cWaterOpacity < $FF) and (hwRound(Gear^.Y) < cWaterLine + 256) then
617
if ((not SuddenDeathDmg and (cWaterOpacity < $FF)) or (SuddenDeathDmg and (cWaterOpacity < $FF))) and (hwRound(Gear^.Y) < cWaterLine + 256) then
560
618
spawnHealthTagForHH(Gear, t);
561
uStats.HedgehogDamaged(Gear)
564
621
team:= Gear^.Hedgehog^.Team;
565
622
if CurrentHedgehog^.Gear = Gear then
566
625
FreeActionsList; // to avoid ThinkThread on drawned gear
626
if ((Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) <> 0) and (CurrentHedgehog^.MultiShootAttacks > 0) then OnUsedAmmo(CurrentHedgehog^);
568
629
Gear^.Hedgehog^.Gear:= nil;
569
630
if Gear^.Hedgehog^.King then
579
640
TeamGoneEffect(team^.Clan^.Teams[i]^)
644
// should be not CurrentHedgehog, but hedgehog of the last gear which caused damage to this hog
645
// same stand for CheckHHDamage
646
if (Gear^.LastDamage <> nil) then
647
uStats.HedgehogDamaged(Gear, Gear^.LastDamage, 0, true)
649
uStats.HedgehogDamaged(Gear, CurrentHedgehog, 0, true);
583
652
RecountTeamHealth(team);
584
653
if (CurrentHedgehog <> nil) and CurrentHedgehog^.Effects[heResurrectable] and not Gear^.Hedgehog^.Effects[heResurrectable] then
589
658
Team^.AIKillsTex := RenderStringTex(inttostr(Team^.stats.AIKills), Team^.Clan^.Color, fnt16);
593
with Gear^ do AddFileLog('Delete: #' + inttostr(uid) + ' (' + inttostr(hwRound(x)) + ',' + inttostr(hwRound(y)) + '), d(' + floattostr(dX) + ',' + floattostr(dY) + ') type = ' + EnumToStr(Kind));
662
AddFileLog('Delete: #' + inttostr(uid) + ' (' + inttostr(hwRound(x)) + ',' + inttostr(hwRound(y)) + '), d(' + floattostr(dX) + ',' + floattostr(dY) + ') type = ' + EnumToStr(Kind));
596
664
if CurAmmoGear = Gear then CurAmmoGear:= nil;
597
665
if FollowGear = Gear then FollowGear:= nil;
666
if lastGearByUID = Gear then lastGearByUID := nil;
598
667
RemoveGearFromList(Gear);
792
861
if (cWaterRise <> 0) or (cHealthDecrease <> 0) then
794
if (TotalRounds = cSuddenDTurns) and not SuddenDeathDmg and not isInMultiShoot then
863
if (TotalRounds = cSuddenDTurns) and not SuddenDeath and not isInMultiShoot then
796
SuddenDeathDmg:= true;
866
if cHealthDecrease <> 0 then
868
SuddenDeathDmg:= true;
871
ScreenFade:= sfFromWhite;
872
ScreenFadeValue:= sfMax;
877
glClearColor(SDSkyColor.r * (SDTint/255) / 255, SDSkyColor.g * (SDTint/255) / 255, SDSkyColor.b * (SDTint/255) / 255, 0.99);
797
879
AddCaption(trmsg[sidSuddenDeath], cWhiteColor, capgrpGameState);
798
playSound(sndSuddenDeath)
880
playSound(sndSuddenDeath);
800
884
else if (TotalRounds < cSuddenDTurns) and not isInMultiShoot then
848
932
else if ((GameFlags and gfInfAttack) <> 0) then
850
934
if delay2 = 0 then
851
delay2:= cInactDelay * 4
935
delay2:= cInactDelay * 50
856
if ((delay2 mod cInactDelay) = 0) and (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) then
940
if ((delay2 mod cInactDelay) = 0) and (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) and not CurrentHedgehog^.Unplaced then
942
if (CurrentHedgehog^.Gear^.State and gstAttacked <> 0) and (Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0) then
944
CurrentHedgehog^.Gear^.State:= CurrentHedgehog^.Gear^.State or gstHHChooseTarget;
945
isCursorVisible := true
857
947
CurrentHedgehog^.Gear^.State:= CurrentHedgehog^.Gear^.State and not gstAttacked;
858
949
if delay2 = 0 then
951
if (CurrentHedgehog^.Gear <> nil) and (CurrentHedgehog^.Gear^.State and gstAttacked = 0) and (CurAmmoGear = nil) then SweepDirty;
862
953
AliveCount:= 0; // shorter version of check for win to allow typical step activity to proceed
863
954
for i:= 0 to Pred(ClansCount) do
881
973
and (not PlacingHogs)
882
974
and (CurrentHedgehog^.Gear <> nil)
883
975
and ((CurrentHedgehog^.Gear^.State and gstAttacked) = 0) then
884
PlaySound(sndHurry, CurrentTeam^.voicepack);
976
AddVoice(sndHurry, CurrentTeam^.voicepack);
885
977
if ReadyTimeLeft > 0 then
887
979
if ReadyTimeLeft = 2000 then
888
PlaySound(sndComeonthen, CurrentTeam^.voicepack);
980
AddVoice(sndComeonthen, CurrentTeam^.voicepack);
889
981
dec(ReadyTimeLeft)
902
995
if ((GameTicks and $FFFF) = $FFFF) then
904
997
if (not CurrentTeam^.ExtDriven) then
1000
AddFileLog('hiTicks increment message sent')
907
1003
if (not CurrentTeam^.ExtDriven) or CurrentTeam^.hasGone then
908
1004
inc(hiTicks) // we do not recieve a message for this
976
1072
RecountTeamHealth(TeamsArray[i])
979
procedure ApplyDamage(Gear: PGear; Damage: Longword; Source: TDamageSource);
1075
procedure ApplyDamage(Gear: PGear; AttackerHog: PHedgehog; Damage: Longword; Source: TDamageSource);
980
1076
var s: shortstring;
981
1077
vampDmg, tmpDmg, i: Longword;
982
1078
vg: PVisualGear;
984
if (Gear^.Kind = gtHedgehog) and (Damage>=1) then
1080
if Damage = 0 then exit; // nothing to apply
1082
if (Gear^.Kind = gtHedgehog) then
1084
Gear^.LastDamage := AttackerHog;
1086
Gear^.Hedgehog^.Team^.Clan^.Flawless:= false;
986
1087
HHHurt(Gear^.Hedgehog, Source);
987
1088
AddDamageTag(hwRound(Gear^.X), hwRound(Gear^.Y), Damage, Gear^.Hedgehog^.Team^.Clan^.Color);
988
1089
tmpDmg:= min(Damage, max(0,Gear^.Health-Gear^.Damage));
1005
1106
while i < vampDmg do
1007
vg:= AddVisualGear(hwRound(CurrentHedgehog^.Gear^.X), hwRound(CurrentHedgehog^.Gear^.Y), vgtHealth);
1008
if vg <> nil then vg^.Frame:= 10;
1108
vg:= AddVisualGear(hwRound(CurrentHedgehog^.Gear^.X), hwRound(CurrentHedgehog^.Gear^.Y), vgtStraightShot);
1113
State:= ord(sprHealth)
1015
1121
not CurrentHedgehog^.Gear^.Invulnerable then
1016
1122
begin // this cannot just use Damage or it interrupts shotgun and gets you called stupid
1017
1123
inc(CurrentHedgehog^.Gear^.Karma, tmpDmg);
1124
CurrentHedgehog^.Gear^.LastDamage := CurrentHedgehog;
1018
1125
spawnHealthTagForHH(CurrentHedgehog^.Gear, tmpDmg);
1127
uStats.HedgehogDamaged(Gear, AttackerHog, Damage, false);
1129
end else if Gear^.Kind <> gtStructure then // not gtHedgehog nor gtStructure
1131
Gear^.Hedgehog:= AttackerHog;
1022
1133
inc(Gear^.Damage, Damage);
1023
1135
ScriptCall('onGearDamage', Gear^.UID, Damage);
1055
1167
Gear:= GearsList;
1056
1168
while Gear <> nil do
1058
x:= hwRound(Gear^.X) + WorldDx;
1059
y:= hwRound(Gear^.Y) + WorldDy;
1060
RenderGear(Gear, x, y);
1170
if Gear^.State and gstInvisible = 0 then
1172
x:= hwRound(Gear^.X) + WorldDx;
1173
y:= hwRound(Gear^.Y) + WorldDy;
1174
RenderGear(Gear, x, y);
1061
1176
Gear:= Gear^.NextGear
1078
1193
procedure AddMiscGears;
1082
1197
AddGear(0, 0, gtATStartGame, 0, _0, _0, 2000);
1084
if (TrainingFlags and tfSpawnTargets) <> 0 then
1086
TrainingTargetGear:= AddGear(0, 0, gtTarget, 0, _0, _0, 0);
1087
FindPlace(TrainingTargetGear, false, 0, LAND_WIDTH);
1090
for i:= 0 to Pred(cLandMines) do
1201
while (i < cLandMines) {and (Gear <> nil)} do // disable this check until better solution found
1092
1203
Gear:= AddGear(0, 0, gtMine, 0, _0, _0, 0);
1093
1204
FindPlace(Gear, false, 0, LAND_WIDTH);
1095
for i:= 0 to Pred(cExplosives) do
1210
while (i < cExplosives){ and (Gear <> nil)} do
1097
1212
Gear:= AddGear(0, 0, gtExplosives, 0, _0, _0, 0);
1098
1213
FindPlace(Gear, false, 0, LAND_WIDTH);
1101
1217
if (GameFlags and gfLowGravity) <> 0 then
1124
1240
if not hasBorder and ((Theme = 'Snow') or (Theme = 'Christmas')) then
1126
1242
for i:= 0 to Pred(vobCount*2) do
1127
AddGear(GetRandom(LAND_WIDTH+1024)-512, LAND_HEIGHT - GetRandom(1024), gtFlake, 0, _0, _0, 0);
1128
disableLandBack:= true
1243
AddGear(GetRandom(LAND_WIDTH+1024)-512, LAND_HEIGHT - GetRandom(LAND_HEIGHT div 2), gtFlake, 0, _0, _0, 0);
1244
//disableLandBack:= true
1132
procedure doMakeExplosion(X, Y, Radius: LongInt; Mask: LongWord);
1134
doMakeExplosion(X, Y, Radius, Mask, $FFFFFFFF);
1137
procedure doMakeExplosion(X, Y, Radius: LongInt; Mask, Tint: LongWord);
1248
procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword; const Tint: LongWord);
1138
1249
var Gear: PGear;
1139
1250
dmg, dmgRadius, dmgBase: LongInt;
1140
1251
fX, fY: hwFloat;
1141
1252
vg: PVisualGear;
1142
1253
i, cnt: LongInt;
1144
TargetPoint.X:= NoPointX;
1145
{$IFDEF DEBUGFILE}if Radius > 4 then AddFileLog('Explosion: at (' + inttostr(x) + ',' + inttostr(y) + ')');{$ENDIF}
1255
if Radius > 4 then AddFileLog('Explosion: at (' + inttostr(x) + ',' + inttostr(y) + ')');
1146
1256
if Radius > 25 then KickFlakes(Radius, X, Y);
1148
1258
if ((Mask and EXPLNoGfx) = 0) then
1181
1292
// Run the calcs only once we know we have a type that will need damage
1182
1293
if hwRound(hwAbs(Gear^.X-fX)+hwAbs(Gear^.Y-fY)) < dmgBase then
1183
dmg:= dmgBase - hwRound(Distance(Gear^.X - fX, Gear^.Y - fY));
1294
dmg:= dmgBase - max(hwRound(Distance(Gear^.X - fX, Gear^.Y - fY)),Gear^.Radius);
1184
1295
if dmg > 1 then
1186
1297
dmg:= ModifyDamage(min(dmg div 2, Radius), Gear);
1187
//{$IFDEF DEBUGFILE}AddFileLog('Damage: ' + inttostr(dmg));{$ENDIF}
1298
//AddFileLog('Damage: ' + inttostr(dmg));
1188
1299
if (Mask and EXPLNoDamage) = 0 then
1190
1301
if not Gear^.Invulnerable then
1191
ApplyDamage(Gear, dmg, dsExplosion)
1302
ApplyDamage(Gear, AttackingHog, dmg, dsExplosion)
1193
1304
Gear^.State:= Gear^.State or gstWinner;
1228
1339
if (GameFlags and gfSolidLand) = 0 then
1230
1341
cnt:= DrawExplosion(X, Y, Radius) div 1608; // approx 2 16x16 circles to erase per chunk
1342
if (cnt > 0) and (SpritesData[sprChunk].Texture <> nil) then
1232
1343
for i:= 0 to cnt do
1233
1344
AddVisualGear(X, Y, vgtChunk)
1239
1350
procedure ShotgunShot(Gear: PGear);
1352
dmg, r, dist: LongInt;
1243
1355
Gear^.Radius:= cShotgunRadius;
1245
1357
while t <> nil do
1247
dmg:= ModifyDamage(min(Gear^.Radius + t^.Radius - hwRound(Distance(Gear^.X - t^.X, Gear^.Y - t^.Y)), 25), t);
1249
1359
case t^.Kind of
1256
if (not t^.Invulnerable) then
1257
ApplyDamage(t, dmg, dsBullet)
1259
Gear^.State:= Gear^.State or gstWinner;
1367
//addFileLog('ShotgunShot radius: ' + inttostr(Gear^.Radius) + ', t^.Radius = ' + inttostr(t^.Radius) + ', distance = ' + inttostr(dist) + ', dmg = ' + inttostr(dmg));
1369
r:= Gear^.Radius + t^.Radius;
1371
dx.isNegative:= false;
1373
dy.isNegative:= false;
1374
if r-hwRound(dx+dy) > 0 then
1376
dist:= hwRound(Distance(dx, dy));
1377
dmg:= ModifyDamage(min(r - dist, 25), t);
1381
if (not t^.Invulnerable) then
1382
ApplyDamage(t, Gear^.Hedgehog, dmg, dsBullet)
1384
Gear^.State:= Gear^.State or gstWinner;
1262
t^.dX:= t^.dX + Gear^.dX * dmg * _0_01 + SignAs(cHHKick, Gear^.dX);
1263
t^.dY:= t^.dY + Gear^.dY * dmg * _0_01;
1264
t^.State:= t^.State or gstMoving;
1387
t^.dX:= t^.dX + Gear^.dX * dmg * _0_01 + SignAs(cHHKick, Gear^.dX);
1388
t^.dY:= t^.dY + Gear^.dY * dmg * _0_01;
1389
t^.State:= t^.State or gstMoving;
1396
r:= Gear^.Radius + t^.Radius;
1398
dx.isNegative:= false;
1400
dy.isNegative:= false;
1401
if r-hwRound(dx+dy) > 0 then
1403
dist:= hwRound(Distance(dx, dy));
1404
dmg:= ModifyDamage(min(r - dist, 25), t);
1273
1413
t:= t^.NextGear
1284
1424
t:= CheckGearsCollision(Ammo);
1285
1425
// Just to avoid hogs on rope dodging fire.
1286
if (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtRope) and
1426
if (CurAmmoGear <> nil) and ((CurAmmoGear^.Kind = gtRope) or (CurAmmoGear^.Kind = gtJetpack) or (CurAmmoGear^.Kind = gtBirdy)) and
1287
1427
(CurrentHedgehog^.Gear <> nil) and (CurrentHedgehog^.Gear^.CollisionIndex = -1) and
1288
1428
(sqr(hwRound(Ammo^.X) - hwRound(CurrentHedgehog^.Gear^.X)) + sqr(hwRound(Ammo^.Y) - hwRound(CurrentHedgehog^.Gear^.Y)) <= sqr(cHHRadius + Ammo^.Radius)) then
1301
1441
tmpDmg:= ModifyDamage(Damage, Gear);
1302
1442
if (Gear^.State and gstNoDamage) = 0 then
1305
1445
if (Ammo^.Kind = gtDEagleShot) or (Ammo^.Kind = gtSniperRifleShot) then
1307
1447
VGear := AddVisualGear(hwround(Ammo^.X), hwround(Ammo^.Y), vgtBulletHit);
1308
1448
if VGear <> nil then VGear^.Angle := DxDy2Angle(-Ammo^.dX, Ammo^.dY);
1311
1451
if (Gear^.Kind = gtHedgehog) and (Ammo^.State and gsttmpFlag <> 0) and (Ammo^.Kind = gtShover) then Gear^.FlightTime:= 1;
1313
1453
case Gear^.Kind of
1320
1461
if (Ammo^.Kind = gtDrill) then begin Ammo^.Timer:= 0; exit; end;
1321
1462
if (not Gear^.Invulnerable) then
1322
ApplyDamage(Gear, tmpDmg, dsShove)
1463
ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg, dsShove)
1324
1465
Gear^.State:= Gear^.State or gstWinner;
1325
if (Gear^.Kind = gtExplosives) and (Ammo^.Kind = gtBlowtorch) then ApplyDamage(Gear, tmpDmg * 100, dsUnknown); // crank up damage for explosives + blowtorch
1466
if (Gear^.Kind = gtExplosives) and (Ammo^.Kind = gtBlowtorch) then
1468
if (Ammo^.Hedgehog^.Gear <> nil) then Ammo^.Hedgehog^.Gear^.State:= Ammo^.Hedgehog^.Gear^.State and not gstNotKickable;
1469
ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg * 100, dsUnknown); // crank up damage for explosives + blowtorch
1327
1472
DeleteCI(Gear);
1328
1473
if (Gear^.Kind = gtHedgehog) and Gear^.Hedgehog^.King then
1423
1568
function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): TPGearArray;
1427
1574
GearsNear := nil;
1428
1575
t := GearsList;
1429
while t <> nil do begin
1430
if (t^.Kind = Kind) then begin
1431
if (X - t^.X)*(X - t^.X) + (Y - t^.Y)*(Y-t^.Y) <
1432
int2hwFloat(r)*int2hwFloat(r) then
1579
and ((X - t^.X)*(X - t^.X) + (Y - t^.Y)*(Y-t^.Y) < int2hwFloat(r)) then
1434
SetLength(GearsNear, Length(GearsNear)+1);
1435
GearsNear[High(GearsNear)] := t;
1581
l:= Length(GearsNear);
1582
SetLength(GearsNear, l + 1);
1438
1585
t := t^.NextGear;
1539
1686
FollowGear := AddGear(x, y, gtCase, 0, _0, _0, 0);
1540
1687
cCaseFactor := 0;
1542
if (content > ord(High(TAmmoType))) then content := ord(High(TAmmoType));
1689
if (crate <> HealthCrate) and (content > ord(High(TAmmoType))) then content := ord(High(TAmmoType));
1545
1692
HealthCrate: begin
1546
FollowGear^.Health := cHealthCaseAmount;
1547
1693
FollowGear^.Pos := posCaseHealth;
1694
FollowGear^.Health := content;
1548
1695
AddCaption(GetEventString(eidNewHealthPack), cWhiteColor, capgrpAmmoInfo);
1550
1697
AmmoCrate: begin
1564
1711
SpawnCustomCrateAt := FollowGear;
1714
function SpawnFakeCrateAt(x, y: LongInt; crate: TCrateType; explode: boolean; poison: boolean): PGear;
1716
FollowGear := AddGear(x, y, gtCase, 0, _0, _0, 0);
1718
FollowGear^.Pos := posCaseDummy;
1720
if explode then FollowGear^.Pos := FollowGear^.Pos + posCaseExplode;
1721
if poison then FollowGear^.Pos := FollowGear^.Pos + posCasePoison;
1725
FollowGear^.Pos := FollowGear^.Pos + posCaseHealth;
1726
AddCaption(GetEventString(eidNewHealthPack), cWhiteColor, capgrpAmmoInfo);
1729
FollowGear^.Pos := FollowGear^.Pos + posCaseAmmo;
1730
AddCaption(GetEventString(eidNewAmmoPack), cWhiteColor, capgrpAmmoInfo);
1733
FollowGear^.Pos := FollowGear^.Pos + posCaseUtility;
1734
AddCaption(GetEventString(eidNewUtilityPack), cWhiteColor, capgrpAmmoInfo);
1738
if ( (x = 0) and (y = 0) ) then FindPlace(FollowGear, true, 0, LAND_WIDTH);
1740
SpawnFakeCrateAt := FollowGear;
1743
function GetAmmo: TAmmoType;
1744
var t, aTot: LongInt;
1749
for i:= Low(TAmmoType) to High(TAmmoType) do
1750
if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then
1751
inc(aTot, Ammoz[i].Probability);
1761
if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then
1762
dec(t, Ammoz[i].Probability)
1768
function GetUtility: TAmmoType;
1769
var t, uTot: LongInt;
1774
for i:= Low(TAmmoType) to High(TAmmoType) do
1775
if (Ammoz[i].Ammo.Propz and ammoprop_Utility) <> 0 then
1776
inc(uTot, Ammoz[i].Probability);
1786
if (Ammoz[i].Ammo.Propz and ammoprop_Utility) <> 0 then
1787
dec(t, Ammoz[i].Probability)
1567
1795
procedure SpawnBoxOfSmth;
1568
1796
var t, aTot, uTot, a, h: LongInt;
1615
1843
FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0);
1616
1844
t:= GetRandom(t);
1617
1845
i:= Low(TAmmoType);
1621
if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then
1622
dec(t, Ammoz[i].Probability)
1624
1846
FollowGear^.Pos:= posCaseAmmo;
1625
1847
FollowGear^.AmmoType:= i;
1626
1848
AddCaption(GetEventString(eidNewAmmoPack), cWhiteColor, capgrpAmmoInfo);
1634
1856
FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0);
1635
1857
t:= GetRandom(t);
1636
1858
i:= Low(TAmmoType);
1640
if (Ammoz[i].Ammo.Propz and ammoprop_Utility) <> 0 then
1641
dec(t, Ammoz[i].Probability)
1643
1859
FollowGear^.Pos:= posCaseUtility;
1644
1860
FollowGear^.AmmoType:= i;
1645
1861
AddCaption(GetEventString(eidNewUtilityPack), cWhiteColor, capgrpAmmoInfo);
1652
1868
FindPlace(FollowGear, true, 0, LAND_WIDTH);
1654
1870
if (FollowGear <> nil) then
1655
PlaySound(sndReinforce, CurrentTeam^.voicepack)
1871
AddVoice(sndReinforce, CurrentTeam^.voicepack)
1830
2051
if (x < 4) and (TeamsArray[t] <> nil) then
1832
2053
// if team matches current hedgehog team, default to current hedgehog
1833
if (i = 0) and (CurrentHedgehog^.Team = TeamsArray[t]) then hh:= CurrentHedgehog
2054
if (i = 0) and (CurrentHedgehog <> nil) and (CurrentHedgehog^.Team = TeamsArray[t]) then hh:= CurrentHedgehog
1836
2057
// otherwise use the first living hog or the hog amongs the remaining ones indicated by i
1850
if hh <> nil then Gear:= AddVisualGear(0, 0, vgtSpeechBubble);
1853
Gear^.Hedgehog:= hh;
1855
Gear^.FrameTicks:= x
2073
Gear:= AddVisualGear(0, 0, vgtSpeechBubble);
2076
Gear^.Hedgehog:= hh;
2078
Gear^.FrameTicks:= x
1857
2081
//else ParseCommand('say ' + text, true)