diff -r 856570ddd409 -r 8a40ce061d94 hedgewars/uGearsHandlersMess.pas --- a/hedgewars/uGearsHandlersMess.pas Mon Jan 15 12:15:56 2018 -0500 +++ b/hedgewars/uGearsHandlersMess.pas Wed Jan 31 13:42:52 2018 -0500 @@ -139,6 +139,9 @@ //procedure doStepCreeper(Gear: PGear); procedure doStepKnife(Gear: PGear); procedure doStepDuck(Gear: PGear); +procedure doStepMinigunWork(Gear: PGear); +procedure doStepMinigun(Gear: PGear); +procedure doStepMinigunBullet(Gear: PGear); var upd: Longword; @@ -1234,16 +1237,45 @@ end; end; +procedure LineShoveHelp(Gear: PGear; oX, oY, tX, tY, dX, dY: hwFloat; count: LongWord); +var dmg,power: LongInt; +begin + if ((Gear^.Kind = gtMinigunBullet) or (Gear^.Damage > 0)) + and (hwSqr(tX - oX) + hwSqr(tY - oY) > _0_25) then + begin + if (Gear^.AmmoType = amDEagle) or (Gear^.AmmoType = amMinigun) then + dmg:= Gear^.Boom + else + dmg:= Gear^.Timer * Gear^.Boom div 100000; + if (Gear^.AmmoType = amMinigun) then + power:= 10 + else + power:= 20; + AmmoShoveLine(Gear, dmg, power, oX, oY, tX, tY); + end; + if Gear^.Damage > 0 then + begin + DrawTunnel(oX, oY, dX, dY, count, 1); + dec(Gear^.Health, Gear^.Damage); + Gear^.Damage := 0 + end; +end; + procedure doStepBulletWork(Gear: PGear); var i, x, y, iInit: LongWord; oX, oY, tX, tY, tDx, tDy: hwFloat; VGear: PVisualGear; + LandFlags: Word; + isDigging: Boolean; + isDead: Boolean; begin AllInactive := false; inc(Gear^.Timer); - iInit := 80; + iInit := 100; i := iInit; + isDigging := false; + isDead := false; oX := Gear^.X; oY := Gear^.Y; repeat @@ -1255,7 +1287,7 @@ tDy:= Gear^.dY; if (Gear^.PortalCounter < 30) and WorldWrap(Gear) then begin - DrawTunnel(oX, oY, tDx, tDy, iInit + 2 - i, 1); + LineShoveHelp(Gear, oX, oY, tX, tY, tDx, tDy, iInit + 2 - i); SpawnBulletTrail(Gear, tX, tY); iInit:= i; oX:= Gear^.X; @@ -1268,38 +1300,45 @@ x := hwRound(Gear^.X); y := hwRound(Gear^.Y); - if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] <> 0) then - inc(Gear^.Damage); - // let's interrupt before a collision to give portals a chance to catch the bullet - if (Gear^.Damage = 1) and (Gear^.Tag = 0) and (not CheckLandValue(x, y, lfLandMask)) then + if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) then + begin + LandFlags:= Land[y, x]; + if LandFlags <> 0 then inc(Gear^.Damage); + isDigging:= (LandFlags and lfLandMask) <> 0; + end; + // let's interrupt before a collision with land to give portals a chance to catch the bullet + if isDigging and (Gear^.Tag = 0) then begin Gear^.Tag := 1; - Gear^.Damage := 0; + dec(Gear^.Damage); Gear^.X := Gear^.X - Gear^.dX; Gear^.Y := Gear^.Y - Gear^.dY; CheckGearDrowning(Gear); break; end - else + else if (not isDigging) then Gear^.Tag := 0; - if Gear^.Damage > 5 then - begin - if Gear^.AmmoType = amDEagle then - AmmoShove(Gear, Gear^.Boom, 20) - else - AmmoShove(Gear, Gear^.Timer * Gear^.Boom div 100000, 20); + //Shove static gears to remove the mask and stop damaging the bullet + if (not isDigging) and (Gear^.Damage > 5) and (Gear^.Kind <> gtMinigunBullet) then + begin + LineShoveHelp(Gear, oX, oY, tX, tY, tDx, tDy, iInit + 2 - i); + SpawnBulletTrail(Gear, tX, tY); + iInit:= i; + oX:= Gear^.X; + oY:= Gear^.Y; end; + CheckGearDrowning(Gear); + case Gear^.Kind of + gtMinigunBullet: isDead:= isDigging; + gtDEagleShot, gtSniperRifleShot: isDead:= Gear^.Damage >= Gear^.Health; + end; dec(i) - until (i = 0) or (Gear^.Damage > Gear^.Health) or ((Gear^.State and gstDrowning) <> 0); - - if Gear^.Damage > 0 then - begin - DrawTunnel(oX, oY, Gear^.dX, Gear^.dY, iInit + 2 - i, 1); - dec(Gear^.Health, Gear^.Damage); - Gear^.Damage := 0 - end; + until (i = 0) or (isDead) or ((Gear^.State and gstDrowning) <> 0); + + LineShoveHelp(Gear, oX, oY, Gear^.X, Gear^.Y, + Gear^.dX, Gear^.dY, iInit + 2 - i); if ((Gear^.State and gstDrowning) <> 0) and (Gear^.Health > 0) then begin @@ -1318,7 +1357,7 @@ Gear^.Health:= 0; end; - if (Gear^.Health <= 0) + if (isDead) or (hwRound(Gear^.X) and LAND_WIDTH_MASK <> 0) or (hwRound(Gear^.Y) and LAND_HEIGHT_MASK <> 0) then begin @@ -1330,7 +1369,15 @@ // Bullet Hit 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 begin - VGear := AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBulletHit); + if Gear^.Kind = gtMinigunBullet then + begin + doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 5, + Gear^.Hedgehog, EXPLNoDamage{ or EXPLDontDraw or EXPLNoGfx}); + VGear := AddVisualGear(hwRound(Gear^.X + Gear^.dX * 5), hwRound(Gear^.Y + Gear^.dY * 5), vgtBulletHit); + end + else + VGear := AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtBulletHit); + if VGear <> nil then begin VGear^.Angle := DxDy2Angle(-Gear^.dX, Gear^.dY); @@ -1338,6 +1385,8 @@ end; spawnBulletTrail(Gear, Gear^.X, Gear^.Y); + if Gear^.Kind = gtMinigunBullet then + ClearHitOrderLeq(Gear^.Tag); Gear^.doStep := @doStepShotIdle end; end; @@ -1357,8 +1406,7 @@ end; procedure doStepSniperRifleShot(Gear: PGear); -var - HHGear: PGear; +var HHGear: PGear; shell: PVisualGear; begin @@ -4454,7 +4502,7 @@ // Make duck go into “falling” mode again iterator^.Pos:= 0; - isbullet:= (iterator^.Kind in [gtShotgunShot, gtDEagleShot, gtSniperRifleShot, gtSineGunShot]); + isbullet:= (iterator^.Kind in [gtShotgunShot, gtDEagleShot, gtSniperRifleShot, gtSineGunShot, gtMinigunBullet]); r:= int2hwFloat(iterator^.Radius); @@ -4481,7 +4529,7 @@ continue; end; - if (iterator^.Kind = gtDEagleShot) or (iterator^.Kind = gtSniperRifleShot) then + if (iterator^.Kind in [gtDEagleShot, gtSniperRifleShot, gtMinigunBullet]) then begin // draw bullet trail spawnBulletTrail(iterator, iterator^.X, iterator^.Y); @@ -6564,6 +6612,95 @@ dec(Gear^.Timer); end; +//////////////////////////////////////////////////////////////////////////////// +procedure doStepMinigunWork(Gear: PGear); +var HHGear: PGear; + i: LongWord; + shell: PVisualGear; + bullet: PGear; + rx, ry: hwFloat; + gX, gY: LongInt; +begin + AllInactive:= false; + HHGear := Gear^.Hedgehog^.Gear; + if HHGear = nil then + begin + ClearHitOrder(); + DeleteGear(gear); + exit + end; + + HedgehogChAngle(HHGear); + + dec(Gear^.Timer); + if (Gear^.Timer mod 50) = 0 then + begin + Gear^.Tag := ((Gear^.Tag - 1) and 1) + 2; + + gX := hwRound(Gear^.X) + GetLaunchX(amMinigun, hwSign(HHGear^.dX), HHGear^.Angle); + gY := hwRound(Gear^.Y) + GetLaunchY(amMinigun, HHGear^.Angle); + rx := rndSign(getRandomf * _0_2); + ry := rndSign(getRandomf * _0_2); + + bullet:= AddGear(gx, gy, gtMinigunBullet, 0, SignAs(AngleSin(HHGear^.Angle) * _0_8, HHGear^.dX) + rx, AngleCos(HHGear^.Angle) * ( - _0_8) + ry, 0); + bullet^.CollisionMask:= lfNotCurrentMask; + bullet^.WDTimer := Gear^.WDTimer; + Inc(Gear^.WDTimer); + + shell := AddVisualGear(hwRound(Gear^.x), hwRound(Gear^.y), vgtShell); + if shell <> nil then + begin + shell^.dX := gear^.dX.QWordValue / -17179869184; + shell^.dY := gear^.dY.QWordValue / -17179869184; + shell^.Frame := 0 + end; + end; + + if (Gear^.Timer = 0) or ((HHGear^.State and gstHHDriven) = 0) then + begin + HHGear^.State := HHGear^.State and (not gstNotKickable); + ClearHitOrder(); + DeleteGear(Gear); + AfterAttack + end +end; + +procedure doStepMinigun(Gear: PGear); +var HHGear: PGear; +begin + dec(Gear^.Timer); + if (Gear^.Timer mod 100) = 0 then + Gear^.Tag := (Gear^.Tag + 1) and 1; + + if Gear^.Timer = 0 then + begin + Gear^.Tag := 2; + HHGear := Gear^.Hedgehog^.Gear; + HHGear^.Message := HHGear^.Message and (not (gmUp or gmDown)); + HHGear^.State := HHGear^.State or gstNotKickable; + + Gear^.Timer := 3501; + Gear^.WDTimer := 0; // Order of the next bullet; + ClearHitOrder(); + Gear^.doStep := @doStepMinigunWork + end; +end; + +//////////////////////////////////////////////////////////////////////////////// + +procedure doStepMinigunBullet(Gear: PGear); +begin + Gear^.Data:= nil; + // remember who fired this + if (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) then + Gear^.Data:= Pointer(Gear^.Hedgehog^.Gear); + + PlaySound(sndGun); + Gear^.X := Gear^.X + Gear^.dX * 2; + Gear^.Y := Gear^.Y + Gear^.dY * 2; + Gear^.doStep := @doStepBulletWork +end; + (* This didn't end up getting used, but, who knows, might be reasonable for javellin or something // Make the knife initial angle based on the hog attack angle, or is that too hard?