hedgewars/uGearsHandlersMess.pas
branchios-develop
changeset 13418 ba39a1d396c0
parent 13413 419c5eab88eb
child 13468 f1d349a52bc7
equal deleted inserted replaced
13416:6e8b807bda4b 13418:ba39a1d396c0
    45 procedure doStepGrave(Gear: PGear);
    45 procedure doStepGrave(Gear: PGear);
    46 procedure doStepBeeWork(Gear: PGear);
    46 procedure doStepBeeWork(Gear: PGear);
    47 procedure doStepBee(Gear: PGear);
    47 procedure doStepBee(Gear: PGear);
    48 procedure doStepShotIdle(Gear: PGear);
    48 procedure doStepShotIdle(Gear: PGear);
    49 procedure doStepShotgunShot(Gear: PGear);
    49 procedure doStepShotgunShot(Gear: PGear);
    50 procedure spawnBulletTrail(Bullet: PGear; bulletX, bulletY: hwFloat);
    50 procedure spawnBulletTrail(Bullet: PGear; bulletX, bulletY: hwFloat; fadeIn: Boolean);
    51 procedure doStepBulletWork(Gear: PGear);
    51 procedure doStepBulletWork(Gear: PGear);
    52 procedure doStepDEagleShot(Gear: PGear);
    52 procedure doStepDEagleShot(Gear: PGear);
    53 procedure doStepSniperRifleShot(Gear: PGear);
    53 procedure doStepSniperRifleShot(Gear: PGear);
    54 procedure doStepActionTimer(Gear: PGear);
    54 procedure doStepActionTimer(Gear: PGear);
    55 procedure doStepPickHammerWork(Gear: PGear);
    55 procedure doStepPickHammerWork(Gear: PGear);
   137 procedure doStepAddAmmo(Gear: PGear);
   137 procedure doStepAddAmmo(Gear: PGear);
   138 procedure doStepGenericFaller(Gear: PGear);
   138 procedure doStepGenericFaller(Gear: PGear);
   139 //procedure doStepCreeper(Gear: PGear);
   139 //procedure doStepCreeper(Gear: PGear);
   140 procedure doStepKnife(Gear: PGear);
   140 procedure doStepKnife(Gear: PGear);
   141 procedure doStepDuck(Gear: PGear);
   141 procedure doStepDuck(Gear: PGear);
       
   142 procedure doStepMinigunWork(Gear: PGear);
       
   143 procedure doStepMinigun(Gear: PGear);
       
   144 procedure doStepMinigunBullet(Gear: PGear);
   142 
   145 
   143 var
   146 var
   144     upd: Longword;
   147     upd: Longword;
   145     snowLeft,snowRight: LongInt;
   148     snowLeft,snowRight: LongInt;
   146 
   149 
   252         HH^.Gear^.Active:= false;
   255         HH^.Gear^.Active:= false;
   253         State:= State and (not (gstHHDriven or gstAttacking or gstAttacked));
   256         State:= State and (not (gstHHDriven or gstAttacking or gstAttacked));
   254         Message := Message and (not gmAttack);
   257         Message := Message and (not gmAttack);
   255     end;
   258     end;
   256     HH^.GearHidden:= HH^.Gear;
   259     HH^.GearHidden:= HH^.Gear;
   257     HH^.Gear:= nil
   260     HH^.Gear:= nil;
       
   261     AddVisualGear(0, 0, vgtTeamHealthSorter);
   258 end;
   262 end;
   259 
   263 
   260 
   264 
   261 ////////////////////////////////////////////////////////////////////////////////
   265 ////////////////////////////////////////////////////////////////////////////////
   262 procedure doStepDrowningGear(Gear: PGear);
   266 procedure doStepDrowningGear(Gear: PGear);
  1124 
  1128 
  1125 ////////////////////////////////////////////////////////////////////////////////
  1129 ////////////////////////////////////////////////////////////////////////////////
  1126 procedure doStepShotIdle(Gear: PGear);
  1130 procedure doStepShotIdle(Gear: PGear);
  1127 begin
  1131 begin
  1128     AllInactive := false;
  1132     AllInactive := false;
  1129     inc(Gear^.Timer);
  1133     if (Gear^.Kind <> gtMinigunBullet) then
  1130     if Gear^.Timer > 75 then
  1134         begin
       
  1135         inc(Gear^.Timer);
       
  1136         if Gear^.Timer > 75 then
       
  1137             begin
       
  1138             DeleteGear(Gear);
       
  1139             AfterAttack
       
  1140             end
       
  1141         end
       
  1142     else
  1131         begin
  1143         begin
  1132         DeleteGear(Gear);
  1144         DeleteGear(Gear);
  1133         AfterAttack
  1145         end
  1134         end
  1146 end;
       
  1147 
       
  1148 procedure CreateShellForGear(Gear: PGear; startFrame: Longword);
       
  1149 var
       
  1150     shell: PVisualGear;
       
  1151 begin
       
  1152     shell := AddVisualGear(hwRound(Gear^.x), hwRound(Gear^.y), vgtShell);
       
  1153     if shell <> nil then
       
  1154     begin
       
  1155         shell^.dX := gear^.dX.QWordValue / -17179869184;
       
  1156         if (gear^.dX.isNegative) then
       
  1157             shell^.dX := -shell^.dX;
       
  1158         shell^.dY := gear^.dY.QWordValue / -17179869184;
       
  1159         shell^.Frame := startFrame;
       
  1160     end;
       
  1161 end;
       
  1162 
       
  1163 function ShotgunLineHitHelp(Gear: PGear; oX, oY, tX, tY: hwFloat): Boolean;
       
  1164 var i: LongInt;
       
  1165     Collisions: PGearArray;
       
  1166 begin
       
  1167     ShotgunLineHitHelp := false;
       
  1168     Collisions := CheckAllGearsLineCollision(Gear, oX, oY, tX, tY);
       
  1169     i := Collisions^.Count;
       
  1170     while i > 0 do
       
  1171         begin
       
  1172         dec(i);
       
  1173         if Collisions^.ar[i]^.Kind in
       
  1174             [gtMine, gtSMine, gtAirMine, gtKnife, gtCase, gtTarget, gtExplosives] then
       
  1175             begin
       
  1176             Gear^.X := Collisions^.ar[i]^.X;
       
  1177             Gear^.Y := Collisions^.ar[i]^.Y;
       
  1178             ShotgunShot(Gear);
       
  1179             Gear^.doStep := @doStepShotIdle;
       
  1180             ShotgunLineHitHelp := true;
       
  1181             exit;
       
  1182             end;
       
  1183         end;
  1135 end;
  1184 end;
  1136 
  1185 
  1137 procedure doStepShotgunShot(Gear: PGear);
  1186 procedure doStepShotgunShot(Gear: PGear);
  1138 var
  1187 var
  1139     i: LongWord;
  1188     i: LongWord;
  1140     shell: PVisualGear;
  1189     oX, oY, tmpX, tmpY: hwFloat;
  1141 begin
  1190 begin
  1142     AllInactive := false;
  1191     AllInactive := false;
  1143 
  1192 
  1144     if ((Gear^.State and gstAnimation) = 0) then
  1193     if ((Gear^.State and gstAnimation) = 0) then
  1145         begin
  1194         begin
  1146         dec(Gear^.Timer);
  1195         dec(Gear^.Timer);
  1147         if Gear^.Timer = 0 then
  1196         if Gear^.Timer = 0 then
  1148             begin
  1197             begin
  1149             PlaySound(sndShotgunFire);
  1198             PlaySound(sndShotgunFire);
  1150             shell := AddVisualGear(hwRound(Gear^.x), hwRound(Gear^.y), vgtShell);
  1199             CreateShellForGear(Gear, 0);
  1151             if shell <> nil then
       
  1152                 begin
       
  1153                 shell^.dX := gear^.dX.QWordValue / -17179869184;
       
  1154                 shell^.dY := gear^.dY.QWordValue / -17179869184;
       
  1155                 shell^.Frame := 0
       
  1156                 end;
       
  1157             Gear^.State := Gear^.State or gstAnimation
  1200             Gear^.State := Gear^.State or gstAnimation
  1158             end;
  1201             end;
  1159             exit
  1202             exit
  1160         end else
  1203         end else
  1161         if(Gear^.Hedgehog^.Gear = nil) or ((Gear^.Hedgehog^.Gear^.State and gstMoving) <> 0) then
  1204         if(Gear^.Hedgehog^.Gear = nil) or ((Gear^.Hedgehog^.Gear^.State and gstMoving) <> 0) then
  1165             exit
  1208             exit
  1166             end
  1209             end
  1167     else
  1210     else
  1168         inc(Gear^.Timer);
  1211         inc(Gear^.Timer);
  1169 
  1212 
  1170         i := 200;
  1213     i := 100;
       
  1214     oX := Gear^.X;
       
  1215     oY := Gear^.Y;
  1171     repeat
  1216     repeat
  1172         Gear^.X := Gear^.X + Gear^.dX;
  1217         if Gear^.Tag = 0 then
  1173         Gear^.Y := Gear^.Y + Gear^.dY;
  1218             begin
  1174         WorldWrap(Gear);
  1219             Gear^.X := Gear^.X + Gear^.dX;
       
  1220             Gear^.Y := Gear^.Y + Gear^.dY;
       
  1221             end;
       
  1222 
       
  1223         tmpX := Gear^.X;
       
  1224         tmpY := Gear^.Y;
       
  1225         if (Gear^.PortalCounter < 30) and WorldWrap(Gear) then
       
  1226             begin
       
  1227             inc(Gear^.PortalCounter);
       
  1228             if ShotgunLineHitHelp(Gear, oX, oY, tmpX, tmpY) then
       
  1229                 exit;
       
  1230             oX := Gear^.X;
       
  1231             oY := Gear^.Y;
       
  1232             end;
  1175         CheckCollision(Gear);
  1233         CheckCollision(Gear);
  1176         if (Gear^.State and gstCollision) <> 0 then
  1234 
  1177             begin
  1235         if ((Gear^.State and gstCollision) <> 0) then
  1178             Gear^.X := Gear^.X + Gear^.dX * 8;
  1236             begin
  1179             Gear^.Y := Gear^.Y + Gear^.dY * 8;
  1237             if Gear^.Tag = 0 then
  1180             ShotgunShot(Gear);
  1238                 begin
  1181             Gear^.doStep := @doStepShotIdle;
  1239                     //Try to align the shot with the land to give portals a chance to catch it
  1182             exit
  1240                     Gear^.X := Gear^.X + Gear^.dX * 2;
  1183             end;
  1241                     Gear^.Y := Gear^.Y + Gear^.dY * 2;
       
  1242                     Gear^.Tag := 1
       
  1243                 end
       
  1244                 else
       
  1245                 begin
       
  1246                     Gear^.X := Gear^.X + Gear^.dX * 6;
       
  1247                     Gear^.Y := Gear^.Y + Gear^.dY * 6;
       
  1248                     ShotgunShot(Gear);
       
  1249                     Gear^.doStep := @doStepShotIdle;
       
  1250                 end;
       
  1251                 exit
       
  1252             end
       
  1253         else
       
  1254             Gear^.Tag := 0;
  1184 
  1255 
  1185         CheckGearDrowning(Gear);
  1256         CheckGearDrowning(Gear);
  1186         if (Gear^.State and gstDrowning) <> 0 then
  1257         if (Gear^.State and gstDrowning) <> 0 then
  1187             begin
  1258             begin
  1188             Gear^.doStep := @doStepShotIdle;
  1259             Gear^.doStep := @doStepShotIdle;
  1189             exit
  1260             break;
  1190             end;
  1261             end;
  1191         dec(i)
  1262         dec(i)
  1192     until i = 0;
  1263     until i = 0;
       
  1264 
       
  1265     ShotgunLineHitHelp(Gear, oX, oY, Gear^.X, Gear^.Y);
       
  1266 
  1193     if (hwRound(Gear^.X) and LAND_WIDTH_MASK <> 0) or (hwRound(Gear^.Y) and LAND_HEIGHT_MASK <> 0) then
  1267     if (hwRound(Gear^.X) and LAND_WIDTH_MASK <> 0) or (hwRound(Gear^.Y) and LAND_HEIGHT_MASK <> 0) then
  1194         Gear^.doStep := @doStepShotIdle
  1268         Gear^.doStep := @doStepShotIdle
  1195 end;
  1269 end;
  1196 
  1270 
  1197 ////////////////////////////////////////////////////////////////////////////////
  1271 ////////////////////////////////////////////////////////////////////////////////
  1198 procedure spawnBulletTrail(Bullet: PGear; bulletX, bulletY: hwFloat);
  1272 procedure spawnBulletTrail(Bullet: PGear; bulletX, bulletY: hwFloat; fadeIn: Boolean);
  1199 var oX, oY: hwFloat;
  1273 var oX, oY: hwFloat;
       
  1274     fromX, fromY, toX, toY, dX, dY, bLength, stepLength: real;
  1200     VGear: PVisualGear;
  1275     VGear: PVisualGear;
       
  1276     i, steps: LongWord;
  1201 begin
  1277 begin
  1202     if Bullet^.PortalCounter = 0 then
  1278     if Bullet^.PortalCounter = 0 then
  1203         begin
  1279         begin
  1204         ox:= CurrentHedgehog^.Gear^.X + Int2hwFloat(GetLaunchX(CurrentHedgehog^.CurAmmoType, hwSign(CurrentHedgehog^.Gear^.dX), CurrentHedgehog^.Gear^.Angle));
  1280         ox:= CurrentHedgehog^.Gear^.X + Int2hwFloat(GetLaunchX(CurrentHedgehog^.CurAmmoType, hwSign(CurrentHedgehog^.Gear^.dX), CurrentHedgehog^.Gear^.Angle));
  1205         oy:= CurrentHedgehog^.Gear^.Y + Int2hwFloat(GetLaunchY(CurrentHedgehog^.CurAmmoType, CurrentHedgehog^.Gear^.Angle));
  1281         oy:= CurrentHedgehog^.Gear^.Y + Int2hwFloat(GetLaunchY(CurrentHedgehog^.CurAmmoType, CurrentHedgehog^.Gear^.Angle));
  1208         begin
  1284         begin
  1209         ox:= Bullet^.Elasticity;
  1285         ox:= Bullet^.Elasticity;
  1210         oy:= Bullet^.Friction;
  1286         oy:= Bullet^.Friction;
  1211         end;
  1287         end;
  1212 
  1288 
  1213         // Bullet trail
  1289     fromX:= hwFloat2Float(ox);
  1214         VGear := AddVisualGear(hwRound(ox), hwRound(oy), vgtLineTrail);
  1290     fromY:= hwFloat2Float(oy);
  1215 
  1291     toX:= hwFloat2Float(bulletX);
  1216         if VGear <> nil then
  1292     toY:= hwFloat2Float(bulletY);
  1217             begin
  1293 
  1218             VGear^.X:= hwFloat2Float(ox);
  1294     dX:= toX - fromX;
  1219             VGear^.Y:= hwFloat2Float(oy);
  1295     dY:= toY - fromY;
  1220             VGear^.dX:= hwFloat2Float(bulletX);
  1296     bLength:= sqrt(dX * dX + dY * dY);
  1221             VGear^.dY:= hwFloat2Float(bulletY);
  1297     dX:= dX / bLength;
  1222 
  1298     dY:= dY / bLength;
  1223             // reached edge of land. assume infinite beam. Extend it way out past camera
  1299 
  1224             if (hwRound(bulletX) and LAND_WIDTH_MASK <> 0)
  1300     if fadeIn then
  1225             or (hwRound(bulletY) and LAND_HEIGHT_MASK <> 0) then
  1301         begin
  1226                     // only extend if not under water
  1302         steps:= 10;
  1227                     if not CheckCoordInWater(hwRound(bulletX), hwRound(bulletY)) then
  1303         stepLength:= 12;
       
  1304         fromX:= fromX + dX * 45;
       
  1305         fromY:= fromY + dY * 45;
       
  1306         bLength:= bLength - 45;
       
  1307         end
       
  1308     else steps:= 1;
       
  1309 
       
  1310     for i:= 0 to steps - 1 do
       
  1311         begin
       
  1312             if i < steps - 1 then
       
  1313                 begin
       
  1314                 toX:= fromX + dX * minD(stepLength, bLength);
       
  1315                 toY:= fromY + dY * minD(stepLength, bLength);
       
  1316                 end
       
  1317             else if steps > 1 then
       
  1318                 begin
       
  1319                 toX:= fromX + dX * bLength;
       
  1320                 toY:= fromY + dY * bLength;
       
  1321                 end;
       
  1322 
       
  1323             if bLength > 0 then
       
  1324                 begin
       
  1325                 VGear := AddVisualGear(round(fromX), round(fromY), vgtLineTrail);
       
  1326                 if VGear <> nil then
       
  1327                     begin
       
  1328                     VGear^.X:= fromX;
       
  1329                     VGear^.Y:= fromY;
       
  1330                     VGear^.dX:= toX;
       
  1331                     VGear^.dY:= toY;
       
  1332                     VGear^.Tint:= $FFFFFF00 or ($FF * (i + 1) div (steps));
       
  1333 
       
  1334                     // reached edge of land. assume infinite beam. Extend it way out past camera
       
  1335                     if ((round(toX) and LAND_WIDTH_MASK <> 0) and (not (WorldEdge in [weBounce, weWrap])))
       
  1336                     or (round(toY) and LAND_HEIGHT_MASK <> 0) then
       
  1337                         // only extend if not under water
       
  1338                         if not CheckCoordInWater(round(toX), round(toY)) then
  1228                         begin
  1339                         begin
  1229                         VGear^.dX := VGear^.dX + max(LAND_WIDTH,4096) * (VGear^.dX - VGear^.X);
  1340                             VGear^.dX := VGear^.dX + max(LAND_WIDTH,4096) * (VGear^.dX - VGear^.X);
  1230                         VGear^.dY := VGear^.dY + max(LAND_WIDTH,4096) * (VGear^.dY - VGear^.Y);
  1341                             VGear^.dY := VGear^.dY + max(LAND_WIDTH,4096) * (VGear^.dY - VGear^.Y);
  1231                         end;
  1342                         end;
  1232 
  1343                     VGear^.Timer := 200;
  1233             VGear^.Timer := 200;
  1344                     end;
  1234             end;
  1345                 end;
       
  1346 
       
  1347             if i < steps - 1 then
       
  1348                 begin
       
  1349                 fromX:= toX;
       
  1350                 fromY:= toY;
       
  1351                 bLength:= bLength - stepLength;
       
  1352                 end
       
  1353         end;
       
  1354 end;
       
  1355 
       
  1356 procedure LineShoveHelp(Gear: PGear; oX, oY, tX, tY, dX, dY: hwFloat; count: LongWord);
       
  1357 var dmg,power: LongInt;
       
  1358 begin
       
  1359     if hwSqr(tX - oX) + hwSqr(tY - oY) > _0_25 then
       
  1360     begin
       
  1361         if (Gear^.AmmoType = amDEagle) or (Gear^.AmmoType = amMinigun) then
       
  1362             dmg:= Gear^.Boom
       
  1363         else
       
  1364             dmg:= Gear^.Timer * Gear^.Boom div 100000;
       
  1365         if (Gear^.AmmoType = amMinigun) then
       
  1366             power:= 10
       
  1367         else
       
  1368             power:= 20;
       
  1369         AmmoShoveLine(Gear, dmg, power, oX, oY, tX, tY);
       
  1370     end;
       
  1371     if Gear^.Damage > 0 then
       
  1372     begin
       
  1373         DrawTunnel(oX, oY, dX, dY, count, 1);
       
  1374         dec(Gear^.Health, Gear^.Damage);
       
  1375         Gear^.Damage := 0
       
  1376     end;
       
  1377 end;
       
  1378 
       
  1379 procedure CheckBulletDrowningHelp(Bullet: PGear);
       
  1380 var dX, dY: hwFloat;
       
  1381 begin
       
  1382     dX := Bullet^.dX;
       
  1383     dY := Bullet^.dY;
       
  1384     CheckGearDrowning(Bullet);
       
  1385     if (dX <> Bullet^.dX) or (dY <> Bullet^.dY) then
       
  1386     begin
       
  1387         SpawnBulletTrail(Bullet, Bullet^.X, Bullet^.Y, Bullet^.FlightTime = 0);
       
  1388         Bullet^.Elasticity := Bullet^.X;
       
  1389         Bullet^.Friction := Bullet^.Y;
       
  1390         Inc(Bullet^.PortalCounter);
       
  1391         Bullet^.FlightTime:= 1;
       
  1392     end;
       
  1393 end;
       
  1394 
       
  1395 procedure CreateBubblesForBullet(Gear: PGear);
       
  1396 var i, iInit: LongWord;
       
  1397 begin
       
  1398 if ((Gear^.State and gstDrowning) <> 0) and (Gear^.Health > 0) then
       
  1399     begin
       
  1400     // draw bubbles
       
  1401     if (not SuddenDeathDmg and (WaterOpacity < $FF)) or (SuddenDeathDmg and (SDWaterOpacity < $FF)) then
       
  1402         begin
       
  1403         case Gear^.Kind of
       
  1404             gtMinigunBullet: iInit:= Gear^.Health * 100;
       
  1405             gtDEagleShot, gtSniperRifleShot: iInit:= Gear^.Health * 4
       
  1406             end;
       
  1407         for i:=iInit downto 0 do
       
  1408             begin
       
  1409             if Random(6) = 0 then
       
  1410                 AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBubble);
       
  1411             Gear^.X := Gear^.X + Gear^.dX;
       
  1412             Gear^.Y := Gear^.Y + Gear^.dY;
       
  1413             end;
       
  1414         end;
       
  1415     // bullet dies underwater
       
  1416     Gear^.Health:= 0;
       
  1417     end;
  1235 end;
  1418 end;
  1236 
  1419 
  1237 procedure doStepBulletWork(Gear: PGear);
  1420 procedure doStepBulletWork(Gear: PGear);
  1238 var
  1421 var
  1239     i, x, y, iInit: LongWord;
  1422     i, x, y, iInit: LongWord;
  1240     oX, oY, tX, tY, tDx, tDy: hwFloat;
  1423     oX, oY, tX, tY, tDx, tDy: hwFloat;
  1241     VGear: PVisualGear;
  1424     VGear: PVisualGear;
       
  1425     LandFlags: Word;
       
  1426     isDigging: Boolean;
       
  1427     isDead: Boolean;
  1242 begin
  1428 begin
  1243     AllInactive := false;
  1429     AllInactive := false;
  1244     inc(Gear^.Timer);
  1430     inc(Gear^.Timer);
  1245     iInit := 80;
  1431     iInit := 100;
  1246     i := iInit;
  1432     i := iInit;
       
  1433     isDigging := false;
       
  1434     isDead := false;
  1247     oX := Gear^.X;
  1435     oX := Gear^.X;
  1248     oY := Gear^.Y;
  1436     oY := Gear^.Y;
  1249     repeat
  1437     repeat
  1250         Gear^.X := Gear^.X + Gear^.dX;
  1438         Gear^.X := Gear^.X + Gear^.dX;
  1251         Gear^.Y := Gear^.Y + Gear^.dY;
  1439         Gear^.Y := Gear^.Y + Gear^.dY;
  1253         tY:= Gear^.Y;
  1441         tY:= Gear^.Y;
  1254         tDx:= Gear^.dX;
  1442         tDx:= Gear^.dX;
  1255         tDy:= Gear^.dY;
  1443         tDy:= Gear^.dY;
  1256         if (Gear^.PortalCounter < 30) and WorldWrap(Gear) then
  1444         if (Gear^.PortalCounter < 30) and WorldWrap(Gear) then
  1257             begin
  1445             begin
  1258             DrawTunnel(oX, oY, tDx, tDy, iInit + 2 - i, 1);
  1446             LineShoveHelp(Gear, oX, oY, tX, tY, tDx, tDy, iInit + 2 - i);
  1259             SpawnBulletTrail(Gear, tX, tY);
  1447             SpawnBulletTrail(Gear, tX, tY, Gear^.FlightTime = 0);
       
  1448             Gear^.FlightTime:= 1;
  1260             iInit:= i;
  1449             iInit:= i;
  1261             oX:= Gear^.X;
  1450             oX:= Gear^.X;
  1262             oY:= Gear^.Y;
  1451             oY:= Gear^.Y;
  1263             inc(Gear^.PortalCounter);
  1452             inc(Gear^.PortalCounter);
  1264             Gear^.Elasticity:= Gear^.X;
  1453             Gear^.Elasticity:= Gear^.X;
  1265             Gear^.Friction:= Gear^.Y;
  1454             Gear^.Friction:= Gear^.Y;
  1266             SpawnBulletTrail(Gear, Gear^.X, Gear^.Y);
  1455             SpawnBulletTrail(Gear, Gear^.X, Gear^.Y, false);
       
  1456 
       
  1457             // bullets can now hurt the hog that fired them
       
  1458             if WorldEdge <> weSea then Gear^.Data:= nil;
  1267             end;
  1459             end;
  1268         x := hwRound(Gear^.X);
  1460         x := hwRound(Gear^.X);
  1269         y := hwRound(Gear^.Y);
  1461         y := hwRound(Gear^.Y);
  1270 
  1462 
  1271         if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] <> 0) then
  1463         if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) then
  1272             inc(Gear^.Damage);
  1464         begin
  1273         // let's interrupt before a collision to give portals a chance to catch the bullet
  1465             LandFlags:= Land[y, x];
  1274         if (Gear^.Damage = 1) and (Gear^.Tag = 0) and (not CheckLandValue(x, y, lfLandMask)) then
  1466             if LandFlags <> 0 then inc(Gear^.Damage);
       
  1467             isDigging:= (LandFlags and lfLandMask) <> 0;
       
  1468         end;
       
  1469         // let's interrupt before a collision with land to give portals a chance to catch the bullet
       
  1470         if isDigging and (Gear^.Tag = 0) then
  1275             begin
  1471             begin
  1276             Gear^.Tag := 1;
  1472             Gear^.Tag := 1;
  1277             Gear^.Damage := 0;
  1473             dec(Gear^.Damage);
  1278             Gear^.X := Gear^.X - Gear^.dX;
  1474             Gear^.X := Gear^.X - Gear^.dX;
  1279             Gear^.Y := Gear^.Y - Gear^.dY;
  1475             Gear^.Y := Gear^.Y - Gear^.dY;
  1280             CheckGearDrowning(Gear);
  1476             CheckBulletDrowningHelp(Gear);
  1281             break;
  1477             break;
  1282             end
  1478             end
  1283         else
  1479         else if (not isDigging) then
  1284             Gear^.Tag := 0;
  1480             Gear^.Tag := 0;
  1285 
  1481 
  1286         if Gear^.Damage > 5 then
  1482         //Shove static gears to remove the mask and stop damaging the bullet
  1287             begin
  1483         if (not isDigging) and (Gear^.Damage > 5) and (Gear^.Kind <> gtMinigunBullet) then
  1288             if Gear^.AmmoType = amDEagle then
  1484             begin
  1289                 AmmoShove(Gear, Gear^.Boom, 20)
  1485             LineShoveHelp(Gear, oX, oY, tX, tY, tDx, tDy, iInit + 2 - i);
       
  1486             SpawnBulletTrail(Gear, tX, tY, Gear^.FlightTime = 0);
       
  1487             Gear^.FlightTime:= 1;
       
  1488             iInit:= i;
       
  1489             oX:= Gear^.X;
       
  1490             oY:= Gear^.Y;
       
  1491             end;
       
  1492 
       
  1493         CheckBulletDrowningHelp(Gear);
       
  1494         case Gear^.Kind of
       
  1495             gtMinigunBullet: isDead:= isDigging or ((Gear^.State and gstDrowning) <> 0);
       
  1496             gtDEagleShot, gtSniperRifleShot: isDead:= (Gear^.Damage >= Gear^.Health) or ((Gear^.State and gstDrowning) <> 0)
       
  1497         end;
       
  1498         dec(i)
       
  1499     until (i = 0) or (isDead);
       
  1500 
       
  1501     LineShoveHelp(Gear, oX, oY, Gear^.X, Gear^.Y,
       
  1502                   Gear^.dX, Gear^.dY, iInit + 2 - i);
       
  1503 
       
  1504     CreateBubblesForBullet(Gear);
       
  1505 
       
  1506     x := hwRound(Gear^.X);
       
  1507     y := hwRound(Gear^.Y);
       
  1508     if (isDead) or (x and LAND_WIDTH_MASK <> 0) or (y and LAND_HEIGHT_MASK <> 0) then
       
  1509         begin
       
  1510         if (Gear^.Kind = gtSniperRifleShot) then
       
  1511             cLaserSightingSniper := false;
       
  1512         if (Ammoz[Gear^.AmmoType].Ammo.NumPerTurn <= CurrentHedgehog^.MultiShootAttacks) and (CurrentHedgehog^.Effects[heArtillery] = 2) then
       
  1513             CurrentHedgehog^.Effects[heArtillery]:= 0;
       
  1514 
       
  1515         // Bullet Hit
       
  1516         if ((Gear^.State and gstDrowning) = 0) and (x and LAND_WIDTH_MASK = 0) and (y and LAND_HEIGHT_MASK = 0) then
       
  1517             begin
       
  1518             if Gear^.Kind = gtMinigunBullet then
       
  1519                 begin
       
  1520                 doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 5,
       
  1521                                 Gear^.Hedgehog, EXPLNoDamage{ or EXPLDontDraw or EXPLNoGfx});
       
  1522                 VGear := AddVisualGear(hwRound(Gear^.X + Gear^.dX * 5), hwRound(Gear^.Y + Gear^.dY * 5), vgtBulletHit);
       
  1523                 end
  1290             else
  1524             else
  1291                 AmmoShove(Gear, Gear^.Timer * Gear^.Boom div 100000, 20);
  1525                 VGear := AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBulletHit);
  1292             end;
  1526 
  1293         CheckGearDrowning(Gear);
  1527             if VGear <> nil then
  1294         dec(i)
  1528                 begin
  1295     until (i = 0) or (Gear^.Damage > Gear^.Health) or ((Gear^.State and gstDrowning) <> 0);
  1529                 VGear^.Angle := DxDy2Angle(-Gear^.dX, Gear^.dY);
  1296 
       
  1297     if Gear^.Damage > 0 then
       
  1298         begin
       
  1299         DrawTunnel(oX, oY, Gear^.dX, Gear^.dY, iInit + 2 - i, 1);
       
  1300         dec(Gear^.Health, Gear^.Damage);
       
  1301         Gear^.Damage := 0
       
  1302         end;
       
  1303 
       
  1304     if ((Gear^.State and gstDrowning) <> 0) and (Gear^.Health > 0) then
       
  1305         begin
       
  1306         // draw bubbles
       
  1307         if (not SuddenDeathDmg and (WaterOpacity < $FF)) or (SuddenDeathDmg and (SDWaterOpacity < $FF)) then
       
  1308             begin
       
  1309             for i:=(Gear^.Health * 4) downto 0 do
       
  1310                 begin
       
  1311                 if Random(6) = 0 then
       
  1312                     AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBubble);
       
  1313                 Gear^.X := Gear^.X + Gear^.dX;
       
  1314                 Gear^.Y := Gear^.Y + Gear^.dY;
       
  1315                 end;
  1530                 end;
  1316             end;
  1531             end;
  1317         // bullet dies underwater
  1532 
  1318         Gear^.Health:= 0;
  1533         spawnBulletTrail(Gear, Gear^.X, Gear^.Y, Gear^.FlightTime = 0);
  1319         end;
  1534         Gear^.FlightTime:= 1;
  1320 
  1535         if Gear^.Kind = gtMinigunBullet then
  1321     if (Gear^.Health <= 0)
  1536             ClearHitOrderLeq(Gear^.Tag);
  1322         or (hwRound(Gear^.X) and LAND_WIDTH_MASK <> 0)
  1537 
  1323         or (hwRound(Gear^.Y) and LAND_HEIGHT_MASK <> 0) then
  1538         if (worldEdge = weSea) and (Gear^.Kind = gtMinigunBullet)
  1324             begin
  1539             and Gear^.Y.isNegative and Gear^.dY.isNegative
  1325             if (Gear^.Kind = gtSniperRifleShot) then
  1540             and (Gear^.Health > 0) and (not isZero(Gear^.dX)) then
  1326                 cLaserSightingSniper := false;
  1541         begin
  1327             if (Ammoz[Gear^.AmmoType].Ammo.NumPerTurn <= CurrentHedgehog^.MultiShootAttacks) and ((GameFlags and gfArtillery) = 0) then
  1542             if Gear^.dX.isNegative then
  1328                 cArtillery := false;
  1543                 begin
  1329 
  1544 
  1330         // Bullet Hit
  1545                 Gear^.X:= int2hwFloat(-1);
  1331             if ((Gear^.State and gstDrowning) = 0) and (hwRound(Gear^.X) and LAND_WIDTH_MASK = 0) and (hwRound(Gear^.Y) and LAND_HEIGHT_MASK = 0) then
  1546                 iInit:= x - leftX;
  1332                 begin
  1547                 end
  1333                 VGear := AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBulletHit);
  1548             else
  1334                 if VGear <> nil then
  1549                 begin
  1335                     begin
  1550                 Gear^.X:= int2hwFloat(LAND_WIDTH);
  1336                     VGear^.Angle := DxDy2Angle(-Gear^.dX, Gear^.dY);
  1551                 iInit:= rightX - x - 1;
  1337                     end;
       
  1338                 end;
  1552                 end;
  1339 
  1553             Gear^.Y:= Gear^.Y + Gear^.dY * hwAbs(int2hwFloat(iInit) / Gear^.dX);
  1340             spawnBulletTrail(Gear, Gear^.X, Gear^.Y);
  1554             CheckGearDrowning(Gear);
  1341             Gear^.doStep := @doStepShotIdle
  1555             CreateBubblesForBullet(Gear);
  1342             end;
  1556         end;
       
  1557         Gear^.doStep := @doStepShotIdle
       
  1558         end;
  1343 end;
  1559 end;
  1344 
  1560 
  1345 procedure doStepDEagleShot(Gear: PGear);
  1561 procedure doStepDEagleShot(Gear: PGear);
  1346 begin
  1562 begin
  1347     Gear^.Data:= nil;
  1563     Gear^.Data:= nil;
  1348     // remember who fired this
  1564     // remember who fired this
  1349     if (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) then
  1565     if (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) then
  1350         Gear^.Data:= Pointer(Gear^.Hedgehog^.Gear);
  1566         Gear^.Data:= Pointer(Gear^.Hedgehog^.Gear);
  1351 
  1567 
  1352     PlaySound(sndGun);
  1568     PlaySound(sndGun);
       
  1569     ClearHitOrder();
  1353     // add 2 initial steps to avoid problem with ammoshove related to calculation of radius + 1 radius as gear widths, and also just plain old weird angles
  1570     // add 2 initial steps to avoid problem with ammoshove related to calculation of radius + 1 radius as gear widths, and also just plain old weird angles
  1354     Gear^.X := Gear^.X + Gear^.dX * 2;
  1571     Gear^.X := Gear^.X + Gear^.dX * 2;
  1355     Gear^.Y := Gear^.Y + Gear^.dY * 2;
  1572     Gear^.Y := Gear^.Y + Gear^.dY * 2;
       
  1573     Gear^.FlightTime := 0;
  1356     Gear^.doStep := @doStepBulletWork
  1574     Gear^.doStep := @doStepBulletWork
  1357 end;
  1575 end;
  1358 
  1576 
  1359 procedure doStepSniperRifleShot(Gear: PGear);
  1577 procedure doStepSniperRifleShot(Gear: PGear);
  1360 var
  1578 var HHGear: PGear;
  1361     HHGear: PGear;
  1579 begin
  1362     shell: PVisualGear;
  1580 
  1363 begin
       
  1364 
       
  1365     cArtillery := true;
       
  1366     HHGear := Gear^.Hedgehog^.Gear;
  1581     HHGear := Gear^.Hedgehog^.Gear;
       
  1582     if (Gear^.Hedgehog^.Effects[heArtillery] <> 1) then
       
  1583         Gear^.Hedgehog^.Effects[heArtillery]:= 2;
  1367 
  1584 
  1368     if HHGear = nil then
  1585     if HHGear = nil then
  1369         begin
  1586         begin
  1370         DeleteGear(gear);
  1587         DeleteGear(gear);
  1371         exit
  1588         exit
  1385             dec(HHGear^.Angle,32)
  1602             dec(HHGear^.Angle,32)
  1386         end;
  1603         end;
  1387 
  1604 
  1388     if (HHGear^.Message and gmAttack) <> 0 then
  1605     if (HHGear^.Message and gmAttack) <> 0 then
  1389         begin
  1606         begin
  1390         shell := AddVisualGear(hwRound(Gear^.x), hwRound(Gear^.y), vgtShell);
  1607         CreateShellForGear(Gear, 1);
  1391         if shell <> nil then
       
  1392             begin
       
  1393             shell^.dX := gear^.dX.QWordValue / -8589934592;
       
  1394             shell^.dY := gear^.dY.QWordValue / -8589934592;
       
  1395             shell^.Frame := 1
       
  1396             end;
       
  1397         Gear^.State := Gear^.State or gstAnimation;
  1608         Gear^.State := Gear^.State or gstAnimation;
  1398         Gear^.dX := SignAs(AngleSin(HHGear^.Angle), HHGear^.dX) * _0_5;
  1609         Gear^.dX := SignAs(AngleSin(HHGear^.Angle), HHGear^.dX) * _0_5;
  1399         Gear^.dY := -AngleCos(HHGear^.Angle) * _0_5;
  1610         Gear^.dY := -AngleCos(HHGear^.Angle) * _0_5;
  1400         PlaySound(sndGun);
  1611         PlaySound(sndGun);
       
  1612         ClearHitOrder();
  1401         // add 2 initial steps to avoid problem with ammoshove related to calculation of radius + 1 radius as gear widths, and also just weird angles
  1613         // add 2 initial steps to avoid problem with ammoshove related to calculation of radius + 1 radius as gear widths, and also just weird angles
  1402         Gear^.X := Gear^.X + Gear^.dX * 2;
  1614         Gear^.X := Gear^.X + Gear^.dX * 2;
  1403         Gear^.Y := Gear^.Y + Gear^.dY * 2;
  1615         Gear^.Y := Gear^.Y + Gear^.dY * 2;
       
  1616         Gear^.FlightTime := 0;
  1404         Gear^.doStep := @doStepBulletWork;
  1617         Gear^.doStep := @doStepBulletWork;
  1405         end
  1618         end
  1406     else
  1619     else
  1407         if (GameTicks mod 32) = 0 then
  1620         if (GameTicks mod 32) = 0 then
  1408             if (GameTicks mod 4096) < 2048 then
  1621             if (GameTicks mod 4096) < 2048 then
  1803 var i,t,targDist,tmpDist: LongWord;
  2016 var i,t,targDist,tmpDist: LongWord;
  1804     targ, tmpG: PGear;
  2017     targ, tmpG: PGear;
  1805     trackSpeed, airFriction, tX, tY: hwFloat;
  2018     trackSpeed, airFriction, tX, tY: hwFloat;
  1806     isUnderwater: Boolean;
  2019     isUnderwater: Boolean;
  1807 begin
  2020 begin
       
  2021 	if (Gear^.State and gstFrozen) <> 0 then
       
  2022 		begin
       
  2023 		if Gear^.Damage > 0 then
       
  2024 			begin
       
  2025 			doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLAutoSound);
       
  2026 			DeleteGear(Gear)
       
  2027 			end;
       
  2028 		exit
       
  2029 		end;
  1808     isUnderwater:= CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y) + Gear^.Radius);
  2030     isUnderwater:= CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y) + Gear^.Radius);
  1809     if Gear^.Pos > 0 then
  2031     if Gear^.Pos > 0 then
  1810         begin
  2032         begin
  1811         airFriction:= _1;
  2033         airFriction:= _1;
  1812         if isUnderwater then
  2034         if isUnderwater then
  1912                 begin
  2134                 begin
  1913                 if targ <> nil then
  2135                 if targ <> nil then
  1914                     begin
  2136                     begin
  1915                     tX:=Gear^.X-targ^.X;
  2137                     tX:=Gear^.X-targ^.X;
  1916                     tY:=Gear^.Y-targ^.Y;
  2138                     tY:=Gear^.Y-targ^.Y;
  1917                     if (tX.Round+tY.Round < Gear^.Karma) and
  2139                     if (tX.Round+tY.Round < Gear^.Boom) and
  1918                        (hwRound(hwSqr(tX) + hwSqr(tY)) < sqr(Gear^.Karma)) then
  2140                        (hwRound(hwSqr(tX) + hwSqr(tY)) < sqr(Gear^.Boom)) then
  1919                     Gear^.State := Gear^.State or gstAttacking
  2141                     Gear^.State := Gear^.State or gstAttacking
  1920                     end
  2142                     end
  1921                 else if (Gear^.Angle > 0) and (CheckGearNear(Gear, gtHedgehog, Gear^.Karma, Gear^.Karma) <> nil) then
  2143                 else if (Gear^.Angle > 0) and (CheckGearNear(Gear, gtHedgehog, Gear^.Boom, Gear^.Boom) <> nil) then
  1922                     Gear^.State := Gear^.State or gstAttacking
  2144                     Gear^.State := Gear^.State or gstAttacking
  1923                 end
  2145                 end
  1924             end
  2146             end
  1925         else // gstAttacking <> 0
  2147         else // gstAttacking <> 0
  1926             begin
  2148             begin
  1932                 // recheck
  2154                 // recheck
  1933                 if targ <> nil then
  2155                 if targ <> nil then
  1934                     begin
  2156                     begin
  1935                     tX:=Gear^.X-targ^.X;
  2157                     tX:=Gear^.X-targ^.X;
  1936                     tY:=Gear^.Y-targ^.Y;
  2158                     tY:=Gear^.Y-targ^.Y;
  1937                     if (tX.Round+tY.Round < Gear^.Karma) and
  2159                     if (tX.Round+tY.Round < Gear^.Boom) and
  1938                        (hwRound(hwSqr(tX) + hwSqr(tY)) < sqr(Gear^.Karma)) then
  2160                        (hwRound(hwSqr(tX) + hwSqr(tY)) < sqr(Gear^.Boom)) then
  1939                         begin
  2161                         begin
  1940                         Gear^.Hedgehog:= CurrentHedgehog;
  2162                         Gear^.Hedgehog:= CurrentHedgehog;
  1941                         tmpG:= FollowGear;
  2163                         tmpG:= FollowGear;
  1942                         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Karma, Gear^.Hedgehog, EXPLAutoSound);
  2164                         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLAutoSound);
  1943                         FollowGear:= tmpG;
  2165                         FollowGear:= tmpG;
  1944                         DeleteGear(Gear);
  2166                         DeleteGear(Gear);
  1945                         exit
  2167                         exit
  1946                         end
  2168                         end
  1947                     end
  2169                     end
  1948                 else if (Gear^.Angle > 0) and (CheckGearNear(Gear, gtHedgehog, Gear^.Karma, Gear^.Karma) <> nil) then
  2170                 else if (Gear^.Angle > 0) and (CheckGearNear(Gear, gtHedgehog, Gear^.Boom, Gear^.Boom) <> nil) then
  1949                     begin
  2171                     begin
  1950                     Gear^.Hedgehog:= CurrentHedgehog;
  2172                     Gear^.Hedgehog:= CurrentHedgehog;
  1951                     doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Karma, Gear^.Hedgehog, EXPLAutoSound);
  2173                     doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Boom, Gear^.Hedgehog, EXPLAutoSound);
  1952                     DeleteGear(Gear);
  2174                     DeleteGear(Gear);
  1953                     exit
  2175                     exit
  1954                     end;
  2176                     end;
  1955                 Gear^.State:= Gear^.State and (not gstAttacking);
  2177                 Gear^.State:= Gear^.State and (not gstAttacking);
  1956                 Gear^.Timer:= Gear^.WDTimer
  2178                 Gear^.Timer:= Gear^.WDTimer
  3437                         dX:= _50 * cGravity * (Gear^.X - X) / _25
  3659                         dX:= _50 * cGravity * (Gear^.X - X) / _25
  3438                     else if (not (hwAbs(Gear^.X + int2hwFloat(RightX-LeftX) - X) > int2hwFloat(Gear^.Radius))) then
  3660                     else if (not (hwAbs(Gear^.X + int2hwFloat(RightX-LeftX) - X) > int2hwFloat(Gear^.Radius))) then
  3439                         dX:= _50 * cGravity * ((Gear^.X + int2hwFloat(RightX-LeftX)) - X) / _25
  3661                         dX:= _50 * cGravity * ((Gear^.X + int2hwFloat(RightX-LeftX)) - X) / _25
  3440                     else
  3662                     else
  3441                         dX:= _50 * cGravity * ((Gear^.X - int2hwFloat(RightX-LeftX)) - X) / _25;
  3663                         dX:= _50 * cGravity * ((Gear^.X - int2hwFloat(RightX-LeftX)) - X) / _25;
  3442                     dY:= -_450 * cGravity;
  3664                     dY:= -_450 * cMaxWindSpeed * 2;
  3443                     Active:= true;
  3665                     Active:= true;
  3444                     end
  3666                     end
  3445                 else if Hedgehog^.Effects[heFrozen] > 255 then
  3667                 else if Hedgehog^.Effects[heFrozen] > 255 then
  3446                     Hedgehog^.Effects[heFrozen]:= 255
  3668                     Hedgehog^.Effects[heFrozen]:= 255
  3447         end ;
  3669         end ;
  3762 
  3984 
  3763 const cAngleSpeed =   3;
  3985 const cAngleSpeed =   3;
  3764 var
  3986 var
  3765     HHGear: PGear;
  3987     HHGear: PGear;
  3766     i: LongInt;
  3988     i: LongInt;
       
  3989     s: ansistring;
  3767     dX, dY : hwFloat;
  3990     dX, dY : hwFloat;
  3768     fChanged: boolean;
  3991     fChanged: boolean;
  3769     trueAngle: Longword;
  3992     trueAngle: Longword;
  3770     t: PGear;
  3993     t: PGear;
  3771 begin
  3994 begin
  3840         if Gear^.Timer < 3500 then
  4063         if Gear^.Timer < 3500 then
  3841             AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEvilTrace)
  4064             AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEvilTrace)
  3842     else
  4065     else
  3843         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
  4066         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
  3844 
  4067 
  3845     if (HHGear <> nil) and ((HHGear^.Message and gmAttack) <> 0) and (Gear^.Health <> 0) then
  4068     if (HHGear <> nil) and ((HHGear^.Message and gmAttack) <> 0) then
  3846         begin
  4069         begin
  3847         HHGear^.Message := HHGear^.Message and (not gmAttack);
  4070         if (Gear^.Health) <> 0 then
  3848         AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, Gear^.dX * _0_5, Gear^.dY *
  4071             begin
  3849         _0_5, 0);
  4072             HHGear^.Message := HHGear^.Message and (not gmAttack);
  3850         dec(Gear^.Health)
  4073             AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, Gear^.dX * _0_5, Gear^.dY *
       
  4074             _0_5, 0);
       
  4075             dec(Gear^.Health)
       
  4076             end;
       
  4077         s:= ansistring(inttostr(Gear^.Health));
       
  4078         AddCaption(formatA(trmsg[sidRemaining], s), cWhiteColor, capgrpAmmostate);
  3851         end;
  4079         end;
  3852 
  4080 
  3853     if (HHGear <> nil) and ((HHGear^.Message and gmLJump) <> 0) and ((Gear^.State and gsttmpFlag) = 0) then
  4081     if (HHGear <> nil) and ((HHGear^.Message and gmLJump) <> 0) and ((Gear^.State and gsttmpFlag) = 0) then
  3854         begin
  4082         begin
  3855         Gear^.State := Gear^.State or gsttmpFlag;
  4083         Gear^.State := Gear^.State or gsttmpFlag;
  4083         Message := Message and (not (gmAttack or gmUp or gmPrecise or gmLeft or gmRight));
  4311         Message := Message and (not (gmAttack or gmUp or gmPrecise or gmLeft or gmRight));
  4084 
  4312 
  4085         if (dY < _0_1) and (dY > -_0_1) then
  4313         if (dY < _0_1) and (dY > -_0_1) then
  4086             begin
  4314             begin
  4087             Gear^.State := Gear^.State or gsttmpFlag;
  4315             Gear^.State := Gear^.State or gsttmpFlag;
       
  4316             dX := SignAs(_0, dX);
  4088             dY := dY - _0_2
  4317             dY := dY - _0_2
  4089             end
  4318             end
  4090         end
  4319         end
  4091 end;
  4320 end;
  4092 
  4321 
  4106 procedure doStepBirdyFly(Gear: PGear);
  4335 procedure doStepBirdyFly(Gear: PGear);
  4107 var
  4336 var
  4108     HHGear: PGear;
  4337     HHGear: PGear;
  4109     fuel, i: LongInt;
  4338     fuel, i: LongInt;
  4110     move: hwFloat;
  4339     move: hwFloat;
       
  4340     s: ansistring;
  4111 begin
  4341 begin
  4112     HHGear := Gear^.Hedgehog^.Gear;
  4342     HHGear := Gear^.Hedgehog^.Gear;
  4113     if HHGear = nil then
  4343     if HHGear = nil then
  4114         begin
  4344         begin
  4115         Gear^.Timer := 0;
  4345         Gear^.Timer := 0;
  4167             begin
  4397             begin
  4168             AddGear(hwRound(Gear^.X), hwRound(Gear^.Y) + 32, gtEgg, 0, Gear^.dX * _0_5, Gear^.dY, 0);
  4398             AddGear(hwRound(Gear^.X), hwRound(Gear^.Y) + 32, gtEgg, 0, Gear^.dX * _0_5, Gear^.dY, 0);
  4169             PlaySound(sndBirdyLay);
  4399             PlaySound(sndBirdyLay);
  4170             dec(Gear^.FlightTime)
  4400             dec(Gear^.FlightTime)
  4171             end;
  4401             end;
       
  4402         s:= ansistring(inttostr(Gear^.FlightTime));
       
  4403         AddCaption(formatA(trmsg[sidRemaining], s), cWhiteColor, capgrpAmmostate);
  4172         end;
  4404         end;
  4173 
  4405 
  4174     if HHGear^.Message and (gmUp or gmPrecise or gmLeft or gmRight) <> 0 then
  4406     if HHGear^.Message and (gmUp or gmPrecise or gmLeft or gmRight) <> 0 then
  4175         Gear^.State := Gear^.State and (not gsttmpFlag);
  4407         Gear^.State := Gear^.State and (not gsttmpFlag);
  4176 
  4408 
  4452 
  4684 
  4453         if iterator^.Kind = gtDuck then
  4685         if iterator^.Kind = gtDuck then
  4454             // Make duck go into “falling” mode again
  4686             // Make duck go into “falling” mode again
  4455             iterator^.Pos:= 0;
  4687             iterator^.Pos:= 0;
  4456 
  4688 
  4457         isbullet:= (iterator^.Kind in [gtShotgunShot, gtDEagleShot, gtSniperRifleShot, gtSineGunShot]);
  4689         isbullet:= (iterator^.Kind in [gtShotgunShot, gtDEagleShot, gtSniperRifleShot, gtSineGunShot, gtMinigunBullet]);
  4458 
  4690 
  4459         r:= int2hwFloat(iterator^.Radius);
  4691         r:= int2hwFloat(iterator^.Radius);
  4460 
  4692 
  4461         if not (isbullet or iscake) then
  4693         if not (isbullet or iscake) then
  4462             begin
  4694             begin
  4479 
  4711 
  4480             if (hwRound(Distance(Gear^.X-ox,Gear^.Y-oy)) > Gear^.Radius + 1 ) then
  4712             if (hwRound(Distance(Gear^.X-ox,Gear^.Y-oy)) > Gear^.Radius + 1 ) then
  4481                 continue;
  4713                 continue;
  4482             end;
  4714             end;
  4483 
  4715 
  4484         if (iterator^.Kind = gtDEagleShot) or (iterator^.Kind = gtSniperRifleShot) then
  4716         if (iterator^.Kind in [gtDEagleShot, gtSniperRifleShot, gtMinigunBullet]) then
  4485             begin
  4717             begin
  4486             // draw bullet trail
  4718             // draw bullet trail
  4487             spawnBulletTrail(iterator, iterator^.X, iterator^.Y);
  4719             spawnBulletTrail(iterator, iterator^.X, iterator^.Y, iterator^.FlightTime = 0);
       
  4720             iterator^.FlightTime := 1;
  4488             // the bullet can now hurt the hog that fired it
  4721             // the bullet can now hurt the hog that fired it
  4489             iterator^.Data:= nil;
  4722             iterator^.Data:= nil;
  4490             end;
  4723             end;
  4491 
  4724 
  4492         // calc gear offset in portal vector direction
  4725         // calc gear offset in portal vector direction
  4801             begin
  5034             begin
  4802             CurWeapon:= GetCurAmmoEntry(CurrentHedgehog^);
  5035             CurWeapon:= GetCurAmmoEntry(CurrentHedgehog^);
  4803             // let's save the HH's dX's direction so we can decide where the "top" of the portal hole
  5036             // let's save the HH's dX's direction so we can decide where the "top" of the portal hole
  4804             newPortal^.Elasticity.isNegative := CurrentHedgehog^.Gear^.dX.isNegative;
  5037             newPortal^.Elasticity.isNegative := CurrentHedgehog^.Gear^.dX.isNegative;
  4805             // when doing a backjump the dx is the opposite of the facing direction
  5038             // when doing a backjump the dx is the opposite of the facing direction
  4806             if ((Gear^.State and gstHHHJump) <> 0) and (not cArtillery) then
  5039             if ((Gear^.State and gstHHHJump) <> 0) and (Effects[heArtillery] = 0) then
  4807                 newPortal^.Elasticity.isNegative := not newPortal^.Elasticity.isNegative;
  5040                 newPortal^.Elasticity.isNegative := not newPortal^.Elasticity.isNegative;
  4808 
  5041 
  4809             // make portal gun look unloaded
  5042             // make portal gun look unloaded
  4810             if (CurWeapon <> nil) and (CurAmmoType = amPortalGun) then
  5043             if (CurWeapon <> nil) and (CurAmmoType = amPortalGun) then
  4811                 CurWeapon^.Timer := CurWeapon^.Timer or 2;
  5044                 CurWeapon^.Timer := CurWeapon^.Timer or 2;
  6000         begin
  6233         begin
  6001         HedgehogChAngle(HHGear);
  6234         HedgehogChAngle(HHGear);
  6002         ndX:= SignAs(AngleSin(HHGear^.Angle), HHGear^.dX) * _4;
  6235         ndX:= SignAs(AngleSin(HHGear^.Angle), HHGear^.dX) * _4;
  6003         ndY:= -AngleCos(HHGear^.Angle) * _4;
  6236         ndY:= -AngleCos(HHGear^.Angle) * _4;
  6004         if (ndX <> dX) or (ndY <> dY) or
  6237         if (ndX <> dX) or (ndY <> dY) or
  6005            ((Target.X <> NoPointX) and (Target.X and LAND_WIDTH_MASK = 0) and
  6238            (((Target.X <> NoPointX) and (Target.X and LAND_WIDTH_MASK = 0) and
  6006              (Target.Y and LAND_HEIGHT_MASK = 0) and ((Land[Target.Y, Target.X] = 0)) and
  6239              (Target.Y and LAND_HEIGHT_MASK = 0) and ((Land[Target.Y, Target.X] = 0)) and
  6007              (not CheckCoordInWater(Target.X, Target.Y))) then
  6240              (not CheckCoordInWater(Target.X, Target.Y))) and (CheckGearNear(gtAirMine, int2hwFloat(Target.X),int2hwFloat(Target.Y), Gear^.Radius*3, Gear^.Radius*3) = nil)) then
  6008             begin
  6241             begin
  6009             updateTarget(Gear, ndX, ndY);
  6242             updateTarget(Gear, ndX, ndY);
  6010             Timer := iceWaitCollision;
  6243             Timer := iceWaitCollision;
  6011             end
  6244             end
  6012         else
  6245         else
  6018             if Target.X = NoPointX then t:= hwRound(hwSqr(X-HHGear^.X)+hwSqr(Y-HHGear^.Y));
  6251             if Target.X = NoPointX then t:= hwRound(hwSqr(X-HHGear^.X)+hwSqr(Y-HHGear^.Y));
  6019 
  6252 
  6020             if Target.X <> NoPointX then
  6253             if Target.X <> NoPointX then
  6021                 begin
  6254                 begin
  6022                 CheckCollision(Gear);
  6255                 CheckCollision(Gear);
  6023                 if (State and gstCollision) <> 0 then
  6256                 if ((State and gstCollision) <> 0) or (CheckGearNear(gtAirMine, int2hwFloat(Target.X),int2hwFloat(Target.Y), Gear^.Radius*4, Gear^.Radius*4) <> nil) then
  6024                     begin
  6257                     begin
  6025                     if Timer = iceWaitCollision then
  6258                     if Timer = iceWaitCollision then
  6026                         begin
  6259                         begin
  6027                         Timer := iceCollideWithGround;
  6260                         Timer := iceCollideWithGround;
  6028                         Power := GameTicks;
  6261                         Power := GameTicks;
  6063                     // Freeze nearby mines/explosives/cases too
  6296                     // Freeze nearby mines/explosives/cases too
  6064                     iter := GearsList;
  6297                     iter := GearsList;
  6065                     while iter <> nil do
  6298                     while iter <> nil do
  6066                         begin
  6299                         begin
  6067                         if (iter^.State and gstFrozen = 0) and
  6300                         if (iter^.State and gstFrozen = 0) and
  6068                            ((iter^.Kind = gtExplosives) or (iter^.Kind = gtCase) or (iter^.Kind = gtMine) or (iter^.Kind = gtSMine)) and
  6301                            ((iter^.Kind = gtExplosives) or (iter^.Kind = gtAirMine) or (iter^.Kind = gtCase) or (iter^.Kind = gtMine) or (iter^.Kind = gtSMine)) and
  6069                            (abs(LongInt(iter^.X.Round) - target.x) + abs(LongInt(iter^.Y.Round) - target.y) + 2 < 2 * iceRadius)
  6302                            (abs(LongInt(iter^.X.Round) - target.x) + abs(LongInt(iter^.Y.Round) - target.y) + 2 < 2 * iceRadius)
  6070                            and (Distance(iter^.X - int2hwFloat(target.x), iter^.Y - int2hwFloat(target.y)) < int2hwFloat(iceRadius * 2)) then
  6303                            and (Distance(iter^.X - int2hwFloat(target.x), iter^.Y - int2hwFloat(target.y)) < int2hwFloat(iceRadius * 2)) then
  6071                             begin
  6304                             begin
  6072                             for t:= 0 to 5 do
  6305                             for t:= 0 to 5 do
  6073                                 begin
  6306                                 begin
  6107                                 begin
  6340                                 begin
  6108                                 DeleteCI(iter);
  6341                                 DeleteCI(iter);
  6109                                 iter^.State:= iter^.State or gstFrozen;
  6342                                 iter^.State:= iter^.State or gstFrozen;
  6110                                 AddCI(iter)
  6343                                 AddCI(iter)
  6111                                 end
  6344                                 end
       
  6345                             else if iter^.Kind = gtAirMine then
       
  6346                                 begin
       
  6347 								iter^.Damage:= 0;
       
  6348 								iter^.State:= iter^.State or gstFrozen;
       
  6349 								if (hwRound(iter^.X) < RightX) and (hwRound(iter^.X) > 0) and 
       
  6350 									(hwRound(iter^.Y) < LAND_HEIGHT) and (hwRound(iter^.Y) > 0) then
       
  6351 									begin
       
  6352 									iter^.X:= int2hwFloat(min(RightX-16,max(hwRound(iter^.X), 16)));
       
  6353 									iter^.Y:= int2hwFloat(min(LAND_HEIGHT-16,max(hwRound(iter^.Y),16)));
       
  6354 									ForcePlaceOnLand(hwRound(iter^.X)-16, hwRound(iter^.Y)-16, sprFrozenAirMine, 0, lfIce, $FFFFFFFF, false, false, false);	
       
  6355 									iter^.State:= iter^.State or gstInvisible
       
  6356 									end
       
  6357                                 end
  6112                             else // gtExplosives
  6358                             else // gtExplosives
  6113                                 begin
  6359                                 begin
  6114                                 iter^.State:= iter^.State or gstFrozen;
  6360                                 iter^.State:= iter^.State or gstFrozen;
  6115                                 iter^.Health:= iter^.Health + cBarrelHealth
  6361                                 iter^.Health:= iter^.Health + cBarrelHealth
  6116                                 end
  6362                                 end
  6119                         end;
  6365                         end;
  6120 
  6366 
  6121                     // FillRoundInLandWithIce(Target.X, Target.Y, iceRadius);
  6367                     // FillRoundInLandWithIce(Target.X, Target.Y, iceRadius);
  6122                     SetAllHHToActive;
  6368                     SetAllHHToActive;
  6123                     Timer := iceWaitCollision;
  6369                     Timer := iceWaitCollision;
       
  6370 					Power:= GameTicks
  6124                     end;
  6371                     end;
  6125 
  6372 
  6126                 if (Timer = iceCollideWithWater) and ((GameTicks - Power) > groundFreezingTime div 2) then
  6373                 if (Timer = iceCollideWithWater) and ((GameTicks - Power) > groundFreezingTime div 2) then
  6127                     begin
  6374                     begin
  6128                     PlaySound(sndHogFreeze);
  6375                     PlaySound(sndHogFreeze);
  6177                 begin
  6424                 begin
  6178                 Target.X:= gX;
  6425                 Target.X:= gX;
  6179                 Target.Y:= gY;
  6426                 Target.Y:= gY;
  6180                 X:= HHGear^.X;
  6427                 X:= HHGear^.X;
  6181                 Y:= HHGear^.Y
  6428                 Y:= HHGear^.Y
  6182                 end;
  6429                 end
       
  6430 			else
       
  6431 				begin
       
  6432 				iter:= CheckGearNear(Gear, gtAirMine, Gear^.Radius*2, Gear^.Radius*2);
       
  6433 				if (iter <> nil) and (iter^.State <> gstFrozen) then
       
  6434 					begin
       
  6435 					Target.X:= gX;
       
  6436 					Target.Y:= gY;
       
  6437 					X:= HHGear^.X;
       
  6438 					Y:= HHGear^.Y
       
  6439 					end 
       
  6440 				end;
  6183             if (gX > max(LAND_WIDTH,4096)*2) or
  6441             if (gX > max(LAND_WIDTH,4096)*2) or
  6184                     (gX < -max(LAND_WIDTH,4096)) or
  6442                     (gX < -max(LAND_WIDTH,4096)) or
  6185                     (gY < -max(LAND_HEIGHT,4096)) or
  6443                     (gY < -max(LAND_HEIGHT,4096)) or
  6186                     (gY > max(LAND_HEIGHT,4096)+512) then
  6444                     (gY > max(LAND_HEIGHT,4096)+512) then
  6187                 begin
  6445                 begin
  6199     gi: PGear;
  6457     gi: PGear;
  6200 begin
  6458 begin
  6201 if Gear^.Timer > 0 then dec(Gear^.Timer)
  6459 if Gear^.Timer > 0 then dec(Gear^.Timer)
  6202 else
  6460 else
  6203     begin
  6461     begin
  6204     if Gear^.Pos = posCaseUtility then
       
  6205         a:= GetUtility(Gear^.Hedgehog)
       
  6206     else
       
  6207         a:= GetAmmo(Gear^.Hedgehog);
       
  6208     CheckSum:= CheckSum xor GameTicks;
  6462     CheckSum:= CheckSum xor GameTicks;
  6209     gi := GearsList;
  6463     gi := GearsList;
  6210     while gi <> nil do
  6464     while gi <> nil do
  6211         begin
  6465         begin
  6212         with gi^ do CheckSum:= CheckSum xor X.round xor X.frac xor dX.round xor dX.frac xor Y.round xor Y.frac xor dY.round xor dY.frac;
  6466         with gi^ do CheckSum:= CheckSum xor X.round xor X.frac xor dX.round xor dX.frac xor Y.round xor Y.frac xor dY.round xor dY.frac;
  6213         AddRandomness(CheckSum);
  6467         AddRandomness(CheckSum);
  6214         if gi^.Kind = gtGenericFaller then gi^.State:= gi^.State and (not gstTmpFlag);
  6468         if (gi^.Kind = gtGenericFaller) and (gi^.Tag = 1) then
       
  6469             gi^.State:= gi^.State and (not gstTmpFlag);
  6215         gi := gi^.NextGear
  6470         gi := gi^.NextGear
  6216         end;
  6471         end;
       
  6472     if Gear^.Pos = posCaseUtility then
       
  6473          a:= GetUtility(Gear^.Hedgehog)
       
  6474     else a:= GetAmmo(Gear^.Hedgehog);
  6217     AddPickup(Gear^.Hedgehog^, a, Gear^.Power, hwRound(Gear^.X), hwRound(Gear^.Y));
  6475     AddPickup(Gear^.Hedgehog^, a, Gear^.Power, hwRound(Gear^.X), hwRound(Gear^.Y));
  6218     DeleteGear(Gear)
  6476     DeleteGear(Gear)
  6219     end;
  6477     end;
  6220 end;
  6478 end;
  6221 
  6479 
  6230         exit
  6488         exit
  6231         end;
  6489         end;
  6232 if (Gear^.State and gstTmpFlag <> 0) or (GameTicks and $7 = 0) then
  6490 if (Gear^.State and gstTmpFlag <> 0) or (GameTicks and $7 = 0) then
  6233     begin
  6491     begin
  6234     doStepFallingGear(Gear);
  6492     doStepFallingGear(Gear);
  6235     if (Gear^.State and gstInvisible <> 0) and (GameTicks and $FF = 0) and (hwRound(Gear^.X) < LongInt(leftX)) or (hwRound(Gear^.X) > LongInt(rightX)) or (hwRound(Gear^.Y) < LongInt(topY)) then
  6493     if (Gear^.Tag = 1) and (GameTicks and $FF = 0) and (hwRound(Gear^.X) < LongInt(leftX)) or (hwRound(Gear^.X) > LongInt(rightX)) or (hwRound(Gear^.Y) < LongInt(topY)) then
  6236         begin
  6494         begin
  6237         Gear^.X:= int2hwFloat(GetRandom(rightX-leftX)+leftX);
  6495         Gear^.X:= int2hwFloat(GetRandom(rightX-leftX)+leftX);
  6238         Gear^.Y:= int2hwFloat(GetRandom(LAND_HEIGHT-topY)+topY);
  6496         Gear^.Y:= int2hwFloat(GetRandom(LAND_HEIGHT-topY)+topY);
  6239         Gear^.dX:= _90-(GetRandomf*_360);
  6497         Gear^.dX:= _90-(GetRandomf*_360);
  6240         Gear^.dY:= _90-(GetRandomf*_360)
  6498         Gear^.dY:= _90-(GetRandomf*_360)
  6560         Gear^.RenderTimer:= true
  6818         Gear^.RenderTimer:= true
  6561     else
  6819     else
  6562         Gear^.RenderTimer:= false;
  6820         Gear^.RenderTimer:= false;
  6563 
  6821 
  6564     dec(Gear^.Timer);
  6822     dec(Gear^.Timer);
       
  6823 end;
       
  6824 
       
  6825 ////////////////////////////////////////////////////////////////////////////////
       
  6826 procedure doStepMinigunWork(Gear: PGear);
       
  6827 var HHGear: PGear;
       
  6828     bullet: PGear;
       
  6829     rx, ry: hwFloat;
       
  6830     gX, gY: LongInt;
       
  6831 begin
       
  6832     AllInactive:= false;
       
  6833     HHGear := Gear^.Hedgehog^.Gear;
       
  6834     if HHGear = nil then
       
  6835     begin
       
  6836         ClearHitOrder();
       
  6837         DeleteGear(gear);
       
  6838         exit
       
  6839     end;
       
  6840 
       
  6841     HedgehogChAngle(HHGear);
       
  6842 
       
  6843     dec(Gear^.Timer);
       
  6844     if (Gear^.Timer mod 50) = 0 then
       
  6845     begin
       
  6846         Gear^.Tag := ((Gear^.Tag - 1) and 1) + 2;
       
  6847 
       
  6848         gX := hwRound(Gear^.X) + GetLaunchX(amMinigun, hwSign(HHGear^.dX), HHGear^.Angle);
       
  6849         gY := hwRound(Gear^.Y) + GetLaunchY(amMinigun, HHGear^.Angle);
       
  6850         rx := rndSign(getRandomf * _0_2);
       
  6851         ry := rndSign(getRandomf * _0_2);
       
  6852 
       
  6853         bullet:= AddGear(gx, gy, gtMinigunBullet, 0, SignAs(AngleSin(HHGear^.Angle) * _0_8, HHGear^.dX) + rx, AngleCos(HHGear^.Angle) * ( - _0_8) + ry, 0);
       
  6854         bullet^.CollisionMask:= lfNotCurrentMask;
       
  6855         bullet^.WDTimer := Gear^.WDTimer;
       
  6856         Inc(Gear^.WDTimer);
       
  6857 
       
  6858         CreateShellForGear(Gear, Gear^.Tag and 1);
       
  6859     end;
       
  6860 
       
  6861     if (Gear^.Timer = 0) or ((HHGear^.State and gstHHDriven) = 0) then
       
  6862     begin
       
  6863         if (HHGear^.State and gstHHDriven) = 0 then
       
  6864             StopSound(sndMinigun);
       
  6865         HHGear^.State := HHGear^.State and (not gstNotKickable);
       
  6866         ClearHitOrder();
       
  6867         DeleteGear(Gear);
       
  6868         AfterAttack
       
  6869     end
       
  6870 end;
       
  6871 
       
  6872 procedure doStepMinigun(Gear: PGear);
       
  6873 var HHGear: PGear;
       
  6874 begin
       
  6875     dec(Gear^.Timer);
       
  6876     if (Gear^.Timer mod 100) = 0 then
       
  6877         Gear^.Tag := (Gear^.Tag + 1) and 1;
       
  6878 
       
  6879     if Gear^.Timer = 0 then
       
  6880         begin
       
  6881         Gear^.Tag := 2;
       
  6882         HHGear := Gear^.Hedgehog^.Gear;
       
  6883         HHGear^.Message := HHGear^.Message and (not (gmUp or gmDown));
       
  6884         HHGear^.State := HHGear^.State or gstNotKickable;
       
  6885 
       
  6886         Gear^.Timer := Gear^.Karma;
       
  6887         Gear^.WDTimer := 0; // Order of the next bullet;
       
  6888         ClearHitOrder();
       
  6889         Gear^.doStep := @doStepMinigunWork
       
  6890         end;
       
  6891 end;
       
  6892 
       
  6893 ////////////////////////////////////////////////////////////////////////////////
       
  6894 
       
  6895 procedure doStepMinigunBullet(Gear: PGear);
       
  6896 begin
       
  6897     Gear^.Data:= nil;
       
  6898     // remember who fired this
       
  6899     if (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) then
       
  6900         Gear^.Data:= Pointer(Gear^.Hedgehog^.Gear);
       
  6901 
       
  6902     Gear^.X := Gear^.X + Gear^.dX * 2;
       
  6903     Gear^.Y := Gear^.Y + Gear^.dY * 2;
       
  6904     Gear^.FlightTime := 0;
       
  6905     Gear^.doStep := @doStepBulletWork
  6565 end;
  6906 end;
  6566 
  6907 
  6567 (*
  6908 (*
  6568  This didn't end up getting used, but, who knows, might be reasonable for javellin or something
  6909  This didn't end up getting used, but, who knows, might be reasonable for javellin or something
  6569 // Make the knife initial angle based on the hog attack angle, or is that too hard?
  6910 // Make the knife initial angle based on the hog attack angle, or is that too hard?