hedgewars/uGearsUtils.pas
changeset 10354 56bd029245fc
parent 10274 07adc8b6288c
child 10356 7d1044267b83
equal deleted inserted replaced
10352:2af2309207b0 10354:56bd029245fc
   355         Gear^.DirAngle := Gear^.DirAngle + 360
   355         Gear^.DirAngle := Gear^.DirAngle + 360
   356     else if 360 < Gear^.DirAngle then
   356     else if 360 < Gear^.DirAngle then
   357         Gear^.DirAngle := Gear^.DirAngle - 360
   357         Gear^.DirAngle := Gear^.DirAngle - 360
   358 end;
   358 end;
   359 
   359 
       
   360 procedure DrownGear(Gear: PGear);
       
   361 begin
       
   362 Gear^.doStep := @doStepDrowningGear;
       
   363 
       
   364 Gear^.Timer := 5000; // how long game should wait
       
   365 end;
       
   366 
   360 function CheckGearDrowning(var Gear: PGear): boolean;
   367 function CheckGearDrowning(var Gear: PGear): boolean;
   361 var
   368 var
   362     skipSpeed, skipAngle, skipDecay: hwFloat;
   369     skipSpeed, skipAngle, skipDecay, hwTmp: hwFloat;
   363     i, maxDrops, X, Y: LongInt;
   370     i, maxDrops, X, Y, dist2Water: LongInt;
   364     vdX, vdY: real;
   371     vdX, vdY, tmp: real;
   365     particle, splash: PVisualGear;
   372     particle, splash: PVisualGear;
   366     isSubmersible: boolean;
   373     isSubmersible, isImpactH, isImpactRight, isLeaving: boolean;
   367     s: ansistring;
   374     s: ansistring;
   368 begin
   375 begin
   369     // probably needs tweaking. might need to be in a case statement based upon gear type
   376     // probably needs tweaking. might need to be in a case statement based upon gear type
       
   377     X:= hwRound(Gear^.X);
   370     Y:= hwRound(Gear^.Y);
   378     Y:= hwRound(Gear^.Y);
   371     if cWaterLine < Y + Gear^.Radius then
   379 
   372         begin
   380     dist2Water:= cWaterLine - (Y + Gear^.Radius);
       
   381     isImpactH:= false;
       
   382 
       
   383     if WorldEdge = weSea then
       
   384         begin
       
   385         i:= dist2Water;
       
   386         dist2Water:= min(dist2Water, min(X - Gear^.Radius - leftX, rightX - (X + Gear^.Radius)));
       
   387         isImpactH:= i <> dist2Water;
       
   388         end;
       
   389 
       
   390     if dist2Water < 0 then
       
   391         begin
       
   392         // invisible gears will just be deleted
       
   393         // unless they are generic fallers, then they will be "respawned"
   373         if Gear^.State and gstInvisible <> 0 then
   394         if Gear^.State and gstInvisible <> 0 then
   374             begin
   395             begin
   375             if Gear^.Kind = gtGenericFaller then
   396             if Gear^.Kind = gtGenericFaller then
   376                 begin
   397                 begin
   377                 Gear^.X:= int2hwFloat(GetRandom(rightX-leftX)+leftX);
   398                 Gear^.X:= int2hwFloat(GetRandom(rightX-leftX)+leftX);
   384             end;
   405             end;
   385         isSubmersible:= ((Gear = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) and (CurAmmoGear^.State and gstSubmersible <> 0)) or (Gear^.State and gstSubmersible <> 0);
   406         isSubmersible:= ((Gear = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) and (CurAmmoGear^.State and gstSubmersible <> 0)) or (Gear^.State and gstSubmersible <> 0);
   386         skipSpeed := _0_25;
   407         skipSpeed := _0_25;
   387         skipAngle := _1_9;
   408         skipAngle := _1_9;
   388         skipDecay := _0_87;
   409         skipDecay := _0_87;
   389         X:= hwRound(Gear^.X);
   410         vdX:= abs(hwFloat2Float(Gear^.dX));
   390         vdX:= hwFloat2Float(Gear^.dX);
   411         vdY:= abs(hwFloat2Float(Gear^.dY));
   391         vdY:= hwFloat2Float(Gear^.dY);
   412 
   392         // this could perhaps be a tiny bit higher.
   413         // skipping
   393         if  (cWaterLine + 64 + Gear^.Radius > Y) and (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > skipSpeed)
   414 
   394         and (hwAbs(Gear^.dX) > skipAngle * hwAbs(Gear^.dY)) then
   415         // check for -1 depth because if deeper, then it already had its chance of skipping
       
   416         if  (dist2Water = -1) and (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > skipSpeed)
       
   417         and ( ((not isImpactH) and (hwAbs(Gear^.dX) > skipAngle * hwAbs(Gear^.dY)))
       
   418           or (isImpactH and (hwAbs(Gear^.dY) > skipAngle * hwAbs(Gear^.dX))) ) then
   395             begin
   419             begin
   396             Gear^.dY.isNegative := true;
   420             // if skipping we move the gear out of water
       
   421             if isImpactH then
       
   422                 begin
       
   423                 Gear^.dX.isNegative := (not Gear^.dX.isNegative);
       
   424                 Gear^.X:= Gear^.X + Gear^.dX;
       
   425                 end
       
   426             else
       
   427                 begin
       
   428                 Gear^.dY.isNegative := (not Gear^.dY.isNegative);
       
   429                 Gear^.Y:= Gear^.Y + Gear^.dY;
       
   430                 end;
   397             Gear^.dY := Gear^.dY * skipDecay;
   431             Gear^.dY := Gear^.dY * skipDecay;
   398             Gear^.dX := Gear^.dX * skipDecay;
   432             Gear^.dX := Gear^.dX * skipDecay;
   399             CheckGearDrowning := false;
   433             CheckGearDrowning := false;
   400             PlaySound(sndSkip)
   434             PlaySound(sndSkip)
   401             end
   435             end
   402         else
   436         else // not skipping
   403             begin
   437             begin
   404             if not isSubmersible then
   438             if not isSubmersible then
   405                 begin
   439                 begin
   406                 CheckGearDrowning := true;
   440                 CheckGearDrowning := true;
   407                 Gear^.State := gstDrowning;
   441                 Gear^.State := gstDrowning;
   416                             ResurrectHedgehog(Gear);
   450                             ResurrectHedgehog(Gear);
   417                             exit(true)
   451                             exit(true)
   418                             end
   452                             end
   419                         else
   453                         else
   420                             begin
   454                             begin
   421                             Gear^.doStep := @doStepDrowningGear;
   455                             DrownGear(Gear);
   422                             Gear^.State := Gear^.State and (not gstHHDriven);
   456                             Gear^.State := Gear^.State and (not gstHHDriven);
   423                             s:= ansistring(Gear^.Hedgehog^.Name);
   457                             s:= ansistring(Gear^.Hedgehog^.Name);
   424                             AddCaption(FormatA(GetEventString(eidDrowned), s), cWhiteColor, capgrpMessage);
   458                             AddCaption(FormatA(GetEventString(eidDrowned), s), cWhiteColor, capgrpMessage);
   425                             end
   459                             end
   426                         end
   460                         end
   427                     else
   461                     else
   428                         Gear^.doStep := @doStepDrowningGear;
   462                         DrownGear(Gear);
   429                         if Gear^.Kind = gtFlake then
   463                     if Gear^.Kind = gtFlake then
   430                             exit(true) // skip splashes
   464                         exit(true); // skip splashes
   431                 end
   465                 end
       
   466             // drown submersible grears if far below map
   432             else if (Y > cWaterLine + cVisibleWater*4) and
   467             else if (Y > cWaterLine + cVisibleWater*4) and
   433                     ((Gear <> CurrentHedgehog^.Gear) or (CurAmmoGear = nil) or (CurAmmoGear^.State and gstSubmersible = 0)) then
   468                     ((Gear <> CurrentHedgehog^.Gear) or (CurAmmoGear = nil) or (CurAmmoGear^.State and gstSubmersible = 0)) then
   434                 Gear^.doStep:= @doStepDrowningGear;
   469                 DrownGear(Gear);
   435             if ((not isSubmersible) and (Y < cWaterLine + 64 + Gear^.Radius))
   470 
   436             or (isSubmersible and (Y < cWaterLine + 2 + Gear^.Radius) and (Gear = CurAmmoGear) and ((CurAmmoGear^.Pos = 0)
   471             isImpactRight:= isImpactH and (abs(X - leftX) > abs(rightX - X));
   437             and (CurAmmoGear^.dY < _0_01))) then
   472             isLeaving:= (isSubmersible and (dist2Water = -2 * Gear^.Radius) and (Gear = CurAmmoGear) and (CurAmmoGear^.Pos = 0)
   438                 if Gear^.Density * Gear^.dY > _1 then
   473             and (((not isImpactH) and CurAmmoGear^.dY.isNegative) or (isImpactH and (isImpactRight = CurAmmoGear^.dX.isNegative))));
       
   474 
       
   475             // splash sound
       
   476 
       
   477             if ((not isSubmersible) and (dist2Water = -1))
       
   478             or isLeaving then
       
   479                 begin
       
   480                 // adjust water impact sound on gear speed and density
       
   481                 if isImpactH then
       
   482                     hwTmp:= hwAbs(Gear^.Density * Gear^.dX)
       
   483                 else
       
   484                     hwTmp:= hwAbs(Gear^.Density * Gear^.dY);
       
   485 
       
   486                 if hwTmp > _1 then
   439                     PlaySound(sndSplash)
   487                     PlaySound(sndSplash)
   440                 else if Gear^.Density * Gear^.dY > _0_5 then
   488                 else if hwTmp > _0_5 then
   441                     PlaySound(sndSkip)
   489                     PlaySound(sndSkip)
   442                 else
   490                 else
   443                     PlaySound(sndDroplet2);
   491                     PlaySound(sndDroplet2);
       
   492                 end;
   444             end;
   493             end;
   445 
   494 
       
   495         // splash animation
       
   496 
   446         if ((cReducedQuality and rqPlainSplash) = 0)
   497         if ((cReducedQuality and rqPlainSplash) = 0)
   447         and (((not isSubmersible) and (Y < cWaterLine + 64 + Gear^.Radius))
   498         and (((not isSubmersible) and (dist2Water = -1))
   448         or (isSubmersible and (Y < cWaterLine + 2 + Gear^.Radius) and (Gear = CurAmmoGear) and ((CurAmmoGear^.Pos = 0)
   499         or isLeaving) then
   449         and (CurAmmoGear^.dY < _0_01)))) then
       
   450             begin
   500             begin
   451             splash:= AddVisualGear(X, cWaterLine, vgtSplash);
   501             splash:= AddVisualGear(X, Y, vgtSplash);
   452             if splash <> nil then
   502             if splash <> nil then
       
   503                 begin
       
   504                 if isImpactH then
       
   505                     begin
       
   506                     splash^.Scale:= abs(hwFloat2Float((Gear^.Density / _3) * Gear^.dX));
       
   507                     if isImpactRight then
       
   508                         splash^.Angle:= -90
       
   509                     else
       
   510                         splash^.Angle:=  90;
       
   511                     end
       
   512                 else
       
   513                     splash^.Scale:= abs(hwFloat2Float(Gear^.Density / _3 * Gear^.dY));
   453                 with splash^ do
   514                 with splash^ do
   454                 begin
   515                     begin
   455                 Scale:= hwFloat2Float(Gear^.Density / _3 * Gear^.dY);
   516                     if Scale > 1 then Scale:= power(Scale,0.3333)
   456                 if Scale > 1 then Scale:= power(Scale,0.3333)
   517                     else Scale:= Scale + ((1-Scale) / 2);
   457                 else Scale:= Scale + ((1-Scale) / 2);
   518                     if Scale > 1 then Timer:= round(min(Scale*0.0005/cGravityf,4))
   458                 if Scale > 1 then Timer:= round(min(Scale*0.0005/cGravityf,4))
   519                     else Timer:= 1;
   459                 else Timer:= 1;
   520                     // Low Gravity
   460                 // Low Gravity
   521                     FrameTicks:= FrameTicks*Timer;
   461                 FrameTicks:= FrameTicks*Timer;
   522                     end;
   462                 end;
   523                 end;
       
   524 
       
   525             // eject water drops
   463 
   526 
   464             maxDrops := (hwRound(Gear^.Density) * 3) div 2 + round(vdX * hwRound(Gear^.Density) * 6) + round(vdY * hwRound(Gear^.Density) * 6);
   527             maxDrops := (hwRound(Gear^.Density) * 3) div 2 + round(vdX * hwRound(Gear^.Density) * 6) + round(vdY * hwRound(Gear^.Density) * 6);
   465             for i:= max(maxDrops div 3, min(32, Random(maxDrops))) downto 0 do
   528             for i:= max(maxDrops div 3, min(32, Random(maxDrops))) downto 0 do
   466                 begin
   529                 begin
   467                 particle := AddVisualGear(X - 3 + Random(7), cWaterLine, vgtDroplet);
   530                 if isImpactH then
       
   531                     begin
       
   532                     if isImpactRight then
       
   533                         particle := AddVisualGear(RightX, Y - 3 + Random(7), vgtDroplet)
       
   534                     else
       
   535                         particle := AddVisualGear(LeftX, Y - 3 + Random(7), vgtDroplet)
       
   536                     end
       
   537                 else
       
   538                     particle := AddVisualGear(X - 3 + Random(7), cWaterLine, vgtDroplet);
       
   539 
   468                 if particle <> nil then
   540                 if particle <> nil then
   469                     with particle^ do
   541                     with particle^ do
   470                         begin
   542                         begin
   471                         dX := dX - vdX / 10;
   543                         // dX and dY were initialized to have a random value on creation (see uVisualGearsList)
   472                         dY := dY - vdY / 5;
   544                         if isImpactH then
       
   545                             begin
       
   546                             tmp:= dX;
       
   547                             if isImpactRight then
       
   548                                 dX:=  dY - vdX / 5
       
   549                             else
       
   550                                 dX:= -dy + vdX / 5;
       
   551                             dY:= tmp * (1 + vdY / 10);
       
   552                             end
       
   553                         else
       
   554                             begin
       
   555                             dX:= dX * (1 + vdX / 10);
       
   556                             dY:= dY - vdY / 5;
       
   557                             end;
       
   558 
   473                         if splash <> nil then
   559                         if splash <> nil then
   474                             begin
   560                             begin
   475                             if splash^.Scale > 1 then
   561                             if splash^.Scale > 1 then
   476                                 begin
   562                                 begin
   477                                 dX:= dX * power(splash^.Scale,0.3333); // tone down the droplet height further
   563                                 dX:= dX * power(splash^.Scale,0.3333); // tone down the droplet height further
   480                             else
   566                             else
   481                                 begin
   567                                 begin
   482                                 dX:= dX * splash^.Scale;
   568                                 dX:= dX * splash^.Scale;
   483                                 dY:= dY * splash^.Scale
   569                                 dY:= dY * splash^.Scale
   484                                 end
   570                                 end
   485                             end
   571                             end;
   486                         end
   572                         end
   487                 end
   573                 end
   488             end;
   574             end;
   489         if isSubmersible and (Gear = CurAmmoGear) and (CurAmmoGear^.Pos = 0) then
   575         if isSubmersible and (Gear = CurAmmoGear) and (CurAmmoGear^.Pos = 0) then
   490             CurAmmoGear^.Pos := 1000
   576             CurAmmoGear^.Pos := 1000
  1248 * From the depths (same as from sky, but from sea, with submersible flag set)
  1334 * From the depths (same as from sky, but from sea, with submersible flag set)
  1249 
  1335 
  1250 Trying to make the checks a little broader than on first pass to catch things that don't move normally.
  1336 Trying to make the checks a little broader than on first pass to catch things that don't move normally.
  1251 *)
  1337 *)
  1252 function WorldWrap(var Gear: PGear): boolean;
  1338 function WorldWrap(var Gear: PGear): boolean;
  1253 var tdx: hwFloat;
  1339 //var tdx: hwFloat;
  1254 begin
  1340 begin
  1255 WorldWrap:= false;
  1341 WorldWrap:= false;
  1256 if WorldEdge = weNone then exit(false);
  1342 if WorldEdge = weNone then exit(false);
  1257 if (hwRound(Gear^.X) < LongInt(leftX)) or
  1343 if (hwRound(Gear^.X) < LongInt(leftX)) or
  1258    (hwRound(Gear^.X) > LongInt(rightX)) then
  1344    (hwRound(Gear^.X) > LongInt(rightX)) then
  1279             Gear^.dX.isNegative:= true;
  1365             Gear^.dX.isNegative:= true;
  1280             Gear^.X:= int2hwfloat(rightX-Gear^.Radius)
  1366             Gear^.X:= int2hwfloat(rightX-Gear^.Radius)
  1281             end;
  1367             end;
  1282         if (Gear^.Radius > 2) and (Gear^.dX.QWordValue > _0_001.QWordValue) then
  1368         if (Gear^.Radius > 2) and (Gear^.dX.QWordValue > _0_001.QWordValue) then
  1283             PlaySound(sndMelonImpact)
  1369             PlaySound(sndMelonImpact)
  1284         end
  1370         end{
  1285     else if WorldEdge = weSea then
  1371     else if WorldEdge = weSea then
  1286         begin
  1372         begin
  1287         if (hwRound(Gear^.Y) > cWaterLine) and (Gear^.State and gstSubmersible <> 0) then
  1373         if (hwRound(Gear^.Y) > cWaterLine) and (Gear^.State and gstSubmersible <> 0) then
  1288             Gear^.State:= Gear^.State and (not gstSubmersible)
  1374             Gear^.State:= Gear^.State and (not gstSubmersible)
  1289         else
  1375         else
  1294             tdx:= Gear^.dX;
  1380             tdx:= Gear^.dX;
  1295             Gear^.dX:= -Gear^.dY;
  1381             Gear^.dX:= -Gear^.dY;
  1296             Gear^.dY:= tdx;
  1382             Gear^.dY:= tdx;
  1297             Gear^.dY.isNegative:= true
  1383             Gear^.dY.isNegative:= true
  1298             end
  1384             end
  1299         end;
  1385         end};
  1300 (*
  1386 (*
  1301 * Window in the sky (Gear moved high into the sky, Y is used to determine X) [unfortunately, not a safe thing to do. shame, I thought aerial bombardment would be kinda neat
  1387 * Window in the sky (Gear moved high into the sky, Y is used to determine X) [unfortunately, not a safe thing to do. shame, I thought aerial bombardment would be kinda neat
  1302 This one would be really easy to freeze game unless it was flagged unfortunately.
  1388 This one would be really easy to freeze game unless it was flagged unfortunately.
  1303 
  1389 
  1304     else
  1390     else