diff -r 76e68c136a11 -r 8e8b908970c2 hedgewars/uGearsUtils.pas --- a/hedgewars/uGearsUtils.pas Thu Jun 27 14:37:03 2013 +0400 +++ b/hedgewars/uGearsUtils.pas Thu Jun 27 15:33:02 2013 +0400 @@ -20,7 +20,7 @@ unit uGearsUtils; interface -uses uTypes; +uses uTypes, uFloat; procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); inline; procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword; const Tint: LongWord); @@ -41,16 +41,31 @@ procedure CheckCollision(Gear: PGear); inline; procedure CheckCollisionWithLand(Gear: PGear); inline; +procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt); +function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): PGearArrayS; +procedure SpawnBoxOfSmth; +procedure ShotgunShot(Gear: PGear); + +procedure SetAllToActive; +procedure SetAllHHToActive; inline; +procedure SetAllHHToActive(Ice: boolean); + +function GetAmmo(Hedgehog: PHedgehog): TAmmoType; +function GetUtility(Hedgehog: PHedgehog): TAmmoType; + + + function MakeHedgehogsStep(Gear: PGear) : boolean; var doStepHandlers: array[TGearType] of TGearStepProcedure; implementation -uses uFloat, uSound, uCollisions, uUtils, uConsts, uVisualGears, uAIMisc, +uses uSound, uCollisions, uUtils, uConsts, uVisualGears, uAIMisc, uVariables, uLandGraphics, uScript, uStats, uCaptions, uTeams, uStore, - uLocale, uTextures, uRenderUtils, uRandom, SDLh, uDebug, uGears, - uGearsList, Math, uVisualGearsList; + uLocale, uTextures, uRenderUtils, uRandom, SDLh, uDebug, + uGearsList, Math, uVisualGearsList, uGearsHandlersMess, + uGearsHedgehog; procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); inline; begin @@ -766,4 +781,422 @@ end; end; + +procedure ShotgunShot(Gear: PGear); +var t: PGear; + dmg, r, dist: LongInt; + dx, dy: hwFloat; +begin +Gear^.Radius:= cShotgunRadius; +t:= GearsList; +while t <> nil do + begin + case t^.Kind of + gtHedgehog, + gtMine, + gtSMine, + gtKnife, + gtCase, + gtTarget, + gtExplosives: begin//, +// gtStructure: begin +//addFileLog('ShotgunShot radius: ' + inttostr(Gear^.Radius) + ', t^.Radius = ' + inttostr(t^.Radius) + ', distance = ' + inttostr(dist) + ', dmg = ' + inttostr(dmg)); + dmg:= 0; + r:= Gear^.Radius + t^.Radius; + dx:= Gear^.X-t^.X; + dx.isNegative:= false; + dy:= Gear^.Y-t^.Y; + dy.isNegative:= false; + if r-hwRound(dx+dy) > 0 then + begin + dist:= hwRound(Distance(dx, dy)); + dmg:= ModifyDamage(min(r - dist, 25), t); + end; + if dmg > 0 then + begin + if (not t^.Invulnerable) then + ApplyDamage(t, Gear^.Hedgehog, dmg, dsBullet) + else + Gear^.State:= Gear^.State or gstWinner; + + DeleteCI(t); + t^.dX:= t^.dX + Gear^.dX * dmg * _0_01 + SignAs(cHHKick, Gear^.dX); + t^.dY:= t^.dY + Gear^.dY * dmg * _0_01; + t^.State:= t^.State or gstMoving; + if t^.Kind = gtKnife then t^.State:= t^.State and (not gstCollision); + t^.Active:= true; + FollowGear:= t + end + end; + gtGrave: begin + dmg:= 0; + r:= Gear^.Radius + t^.Radius; + dx:= Gear^.X-t^.X; + dx.isNegative:= false; + dy:= Gear^.Y-t^.Y; + dy.isNegative:= false; + if r-hwRound(dx+dy) > 0 then + begin + dist:= hwRound(Distance(dx, dy)); + dmg:= ModifyDamage(min(r - dist, 25), t); + end; + if dmg > 0 then + begin + t^.dY:= - _0_1; + t^.Active:= true + end + end; + end; + t:= t^.NextGear + end; +if (GameFlags and gfSolidLand) = 0 then + DrawExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), cShotgunRadius) +end; + +procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt); +var t: PGearArray; + Gear: PGear; + i, j, tmpDmg: LongInt; + VGear: PVisualGear; +begin +t:= CheckGearsCollision(Ammo); +// Just to avoid hogs on rope dodging fire. +if (CurAmmoGear <> nil) and ((CurAmmoGear^.Kind = gtRope) or (CurAmmoGear^.Kind = gtJetpack) or (CurAmmoGear^.Kind = gtBirdy)) +and (CurrentHedgehog^.Gear <> nil) and (CurrentHedgehog^.Gear^.CollisionIndex = -1) +and (sqr(hwRound(Ammo^.X) - hwRound(CurrentHedgehog^.Gear^.X)) + sqr(hwRound(Ammo^.Y) - hwRound(CurrentHedgehog^.Gear^.Y)) <= sqr(cHHRadius + Ammo^.Radius)) then + begin + t^.ar[t^.Count]:= CurrentHedgehog^.Gear; + inc(t^.Count) + end; + +i:= t^.Count; + +if (Ammo^.Kind = gtFlame) and (i > 0) then + Ammo^.Health:= 0; +while i > 0 do + begin + dec(i); + Gear:= t^.ar[i]; + if ((Ammo^.Kind = gtFlame) or (Ammo^.Kind = gtBlowTorch)) and + (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.Effects[heFrozen] > 255) then + Gear^.Hedgehog^.Effects[heFrozen]:= max(255,Gear^.Hedgehog^.Effects[heFrozen]-10000); + tmpDmg:= ModifyDamage(Damage, Gear); + if (Gear^.State and gstNoDamage) = 0 then + begin + + if (Ammo^.Kind = gtDEagleShot) or (Ammo^.Kind = gtSniperRifleShot) then + begin + VGear := AddVisualGear(hwround(Ammo^.X), hwround(Ammo^.Y), vgtBulletHit); + if VGear <> nil then + VGear^.Angle := DxDy2Angle(-Ammo^.dX, Ammo^.dY); + end; + + if (Gear^.Kind = gtHedgehog) and (Ammo^.State and gsttmpFlag <> 0) and (Ammo^.Kind = gtShover) then + Gear^.FlightTime:= 1; + + + case Gear^.Kind of + gtHedgehog, + gtMine, + gtSMine, + gtKnife, + gtTarget, + gtCase, + gtExplosives: //, + //gtStructure: + begin + if (Ammo^.Kind = gtDrill) then + begin + Ammo^.Timer:= 0; + exit; + end; + if (not Gear^.Invulnerable) then + begin + if (Ammo^.Kind = gtKnife) and (tmpDmg > 0) then + for j:= 1 to max(1,min(3,tmpDmg div 5)) do + begin + VGear:= AddVisualGear(hwRound(Ammo^.X-((Ammo^.X-Gear^.X)/_2)), hwRound(Ammo^.Y-((Ammo^.Y-Gear^.Y)/_2)), vgtStraightShot); + if VGear <> nil then + with VGear^ do + begin + Tint:= $FFCC00FF; + Angle:= random(360); + dx:= 0.0005 * (random(100)); + dy:= 0.0005 * (random(100)); + if random(2) = 0 then + dx := -dx; + if random(2) = 0 then + dy := -dy; + FrameTicks:= 600+random(200); + State:= ord(sprStar) + end + end; + ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg, dsShove) + end + else + Gear^.State:= Gear^.State or gstWinner; + if (Gear^.Kind = gtExplosives) and (Ammo^.Kind = gtBlowtorch) then + begin + if (Ammo^.Hedgehog^.Gear <> nil) then + Ammo^.Hedgehog^.Gear^.State:= Ammo^.Hedgehog^.Gear^.State and (not gstNotKickable); + ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg * 100, dsUnknown); // crank up damage for explosives + blowtorch + end; + + if (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.King or (Gear^.Hedgehog^.Effects[heFrozen] > 0)) then + begin + Gear^.dX:= Ammo^.dX * Power * _0_005; + Gear^.dY:= Ammo^.dY * Power * _0_005 + end + else if ((Ammo^.Kind <> gtFlame) or (Gear^.Kind = gtHedgehog)) and (Power <> 0) then + begin + Gear^.dX:= Ammo^.dX * Power * _0_01; + Gear^.dY:= Ammo^.dY * Power * _0_01 + end; + + if (not isZero(Gear^.dX)) or (not isZero(Gear^.dY)) then + begin + Gear^.Active:= true; + DeleteCI(Gear); + Gear^.State:= Gear^.State or gstMoving; + if Gear^.Kind = gtKnife then Gear^.State:= Gear^.State and (not gstCollision); + // move the gear upwards a bit to throw it over tiny obstacles at start + if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then + begin + if not (TestCollisionXwithXYShift(Gear, _0, -3, hwSign(Gear^.dX)) + or (TestCollisionYwithGear(Gear, -1) <> 0)) then + Gear^.Y:= Gear^.Y - _1; + if not (TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX)) + or (TestCollisionYwithGear(Gear, -1) <> 0)) then + Gear^.Y:= Gear^.Y - _1; + if not (TestCollisionXwithXYShift(Gear, _0, -1, hwSign(Gear^.dX)) + or (TestCollisionYwithGear(Gear, -1) <> 0)) then + Gear^.Y:= Gear^.Y - _1; + end + end; + + + if (Ammo^.Kind <> gtFlame) or ((Ammo^.State and gsttmpFlag) = 0) then + FollowGear:= Gear + end; + end + end; + end; +if i <> 0 then + SetAllToActive +end; + + +function CountGears(Kind: TGearType): Longword; +var t: PGear; + count: Longword = 0; +begin + +t:= GearsList; +while t <> nil do + begin + if t^.Kind = Kind then + inc(count); + t:= t^.NextGear + end; +CountGears:= count; +end; + +procedure SetAllToActive; +var t: PGear; +begin +AllInactive:= false; +t:= GearsList; +while t <> nil do + begin + t^.Active:= true; + t:= t^.NextGear + end +end; + +procedure SetAllHHToActive; inline; +begin +SetAllHHToActive(true) +end; + + +procedure SetAllHHToActive(Ice: boolean); +var t: PGear; +begin +AllInactive:= false; +t:= GearsList; +while t <> nil do + begin + if (t^.Kind = gtHedgehog) or (t^.Kind = gtExplosives) then + begin + if (t^.Kind = gtHedgehog) and Ice then CheckIce(t); + t^.Active:= true + end; + t:= t^.NextGear + end +end; + + +var GearsNearArray : TPGearArray; +function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): PGearArrayS; +var + t: PGear; + s: Longword; +begin + r:= r*r; + s:= 0; + SetLength(GearsNearArray, s); + t := GearsList; + while t <> nil do + begin + if (t^.Kind = Kind) + and ((X - t^.X)*(X - t^.X) + (Y - t^.Y)*(Y-t^.Y) < int2hwFloat(r)) then + begin + inc(s); + SetLength(GearsNearArray, s); + GearsNearArray[s - 1] := t; + end; + t := t^.NextGear; + end; + + GearsNear.size:= s; + GearsNear.ar:= @GearsNearArray +end; + + +procedure SpawnBoxOfSmth; +var t, aTot, uTot, a, h: LongInt; + i: TAmmoType; +begin +if (PlacingHogs) or + (cCaseFactor = 0) + or (CountGears(gtCase) >= 5) + or (GetRandom(cCaseFactor) <> 0) then + exit; + +FollowGear:= nil; +aTot:= 0; +uTot:= 0; +for i:= Low(TAmmoType) to High(TAmmoType) do + if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then + inc(aTot, Ammoz[i].Probability) + else + inc(uTot, Ammoz[i].Probability); + +t:=0; +a:=aTot; +h:= 1; + +if (aTot+uTot) <> 0 then + if ((GameFlags and gfInvulnerable) = 0) then + begin + h:= cHealthCaseProb * 100; + t:= GetRandom(10000); + a:= (10000-h)*aTot div (aTot+uTot) + end + else + begin + t:= GetRandom(aTot+uTot); + h:= 0 + end; + + +if t 0) then + begin + FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0); + t:= GetRandom(t); + i:= Low(TAmmoType); + FollowGear^.Pos:= posCaseAmmo; + FollowGear^.AmmoType:= i; + AddCaption(GetEventString(eidNewAmmoPack), cWhiteColor, capgrpAmmoInfo); + end + end +else + begin + t:= uTot; + if (t > 0) then + begin + FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0); + t:= GetRandom(t); + i:= Low(TAmmoType); + FollowGear^.Pos:= posCaseUtility; + FollowGear^.AmmoType:= i; + AddCaption(GetEventString(eidNewUtilityPack), cWhiteColor, capgrpAmmoInfo); + end + end; + +// handles case of no ammo or utility crates - considered also placing booleans in uAmmos and altering probabilities +if (FollowGear <> nil) then + begin + FindPlace(FollowGear, true, 0, LAND_WIDTH); + + if (FollowGear <> nil) then + AddVoice(sndReinforce, CurrentTeam^.voicepack) + end +end; + + +function GetAmmo(Hedgehog: PHedgehog): TAmmoType; +var t, aTot: LongInt; + i: TAmmoType; +begin +Hedgehog:= Hedgehog; // avoid hint + +aTot:= 0; +for i:= Low(TAmmoType) to High(TAmmoType) do + if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then + inc(aTot, Ammoz[i].Probability); + +t:= aTot; +i:= Low(TAmmoType); +if (t > 0) then + begin + t:= GetRandom(t); + while t >= 0 do + begin + inc(i); + if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then + dec(t, Ammoz[i].Probability) + end + end; +GetAmmo:= i +end; + +function GetUtility(Hedgehog: PHedgehog): TAmmoType; +var t, uTot: LongInt; + i: TAmmoType; +begin + +uTot:= 0; +for i:= Low(TAmmoType) to High(TAmmoType) do + if ((Ammoz[i].Ammo.Propz and ammoprop_Utility) <> 0) + and ((Hedgehog^.Team^.HedgehogsNumber > 1) or (Ammoz[i].Ammo.AmmoType <> amSwitch)) then + inc(uTot, Ammoz[i].Probability); + +t:= uTot; +i:= Low(TAmmoType); +if (t > 0) then + begin + t:= GetRandom(t); + while t >= 0 do + begin + inc(i); + if ((Ammoz[i].Ammo.Propz and ammoprop_Utility) <> 0) and ((Hedgehog^.Team^.HedgehogsNumber > 1) + or (Ammoz[i].Ammo.AmmoType <> amSwitch)) then + dec(t, Ammoz[i].Probability) + end + end; +GetUtility:= i +end; + + end.