From f57625f9e652db42e7e13b1ffb47e66657482972 Mon Sep 17 00:00:00 2001 From: penev92 Date: Wed, 3 Dec 2014 06:29:49 +0200 Subject: [PATCH] Add WormAttack notification, fix worm min count and spawn interval Enhance usage of WormManager Minimum and Maximum properties, add escape radius to AttackSwallow --- OpenRA.Mods.D2k/AttackSwallow.cs | 10 +++-- OpenRA.Mods.D2k/SwallowActor.cs | 57 ++++++++++++++++++------- OpenRA.Mods.D2k/WormManager.cs | 64 +++++++++++++++------------- OpenRA.Mods.RA/Attack/AttackBase.cs | 6 +-- mods/cnc/rules/civilian.yaml | 2 +- mods/d2k/maps/death-depths.oramap | Bin 13205 -> 13205 bytes mods/d2k/maps/shellmap/map.yaml | 2 + mods/ts/rules/infantry.yaml | 2 +- 8 files changed, 89 insertions(+), 54 deletions(-) diff --git a/OpenRA.Mods.D2k/AttackSwallow.cs b/OpenRA.Mods.D2k/AttackSwallow.cs index 16616e5cf0..a5c56bc4bf 100644 --- a/OpenRA.Mods.D2k/AttackSwallow.cs +++ b/OpenRA.Mods.D2k/AttackSwallow.cs @@ -21,17 +21,19 @@ namespace OpenRA.Mods.D2k [Desc("The number of ticks it takes to get in place under the target to attack.")] public int AttackTime = 30; + public readonly string WormAttackNotification = "WormAttack"; + public override object Create(ActorInitializer init) { return new AttackSwallow(init.self, this); } } class AttackSwallow : AttackFrontal { - public readonly AttackSwallowInfo AttackSwallowInfo; + new public readonly AttackSwallowInfo Info; - public AttackSwallow(Actor self, AttackSwallowInfo attackSwallowInfo) - : base(self, attackSwallowInfo) + public AttackSwallow(Actor self, AttackSwallowInfo info) + : base(self, info) { - AttackSwallowInfo = attackSwallowInfo; + Info = info; } public override void DoAttack(Actor self, Target target) diff --git a/OpenRA.Mods.D2k/SwallowActor.cs b/OpenRA.Mods.D2k/SwallowActor.cs index 6c4798375c..db2c49baea 100644 --- a/OpenRA.Mods.D2k/SwallowActor.cs +++ b/OpenRA.Mods.D2k/SwallowActor.cs @@ -8,11 +8,12 @@ */ #endregion -using System; +using System.Drawing; using System.Linq; using OpenRA.GameRules; +using OpenRA.Mods.Common; +using OpenRA.Mods.Common.Traits; using OpenRA.Mods.RA.Move; -using OpenRA.Mods.RA.Render; using OpenRA.Traits; namespace OpenRA.Mods.D2k @@ -21,9 +22,13 @@ namespace OpenRA.Mods.D2k class SwallowActor : Activity { + const int NearEnough = 1; + + readonly CPos location; readonly Target target; readonly WeaponInfo weapon; readonly RenderUnit renderUnit; + readonly RadarPings radarPings; readonly AttackSwallow swallow; readonly IPositionable positionable; @@ -34,18 +39,23 @@ namespace OpenRA.Mods.D2k { this.target = target; this.weapon = weapon; - positionable = self.TraitOrDefault(); - swallow = self.TraitOrDefault(); - renderUnit = self.TraitOrDefault(); - countdown = swallow.AttackSwallowInfo.AttackTime; + positionable = self.Trait(); + swallow = self.Trait(); + renderUnit = self.Trait(); + radarPings = self.World.WorldActor.TraitOrDefault(); + countdown = swallow.Info.AttackTime; renderUnit.DefaultAnimation.ReplaceAnim("burrowed"); stance = AttackState.Burrowed; + location = target.Actor.Location; } bool WormAttack(Actor worm) { var targetLocation = target.Actor.Location; + // The target has moved too far away + if ((location - targetLocation).Length > NearEnough) + return false; var lunch = worm.World.ActorMap.GetUnitsAt(targetLocation) .Where(t => !t.Equals(worm) && weapon.IsValidAgainst(t, worm)); @@ -54,11 +64,17 @@ namespace OpenRA.Mods.D2k stance = AttackState.EmergingAboveGround; - lunch.Do(t => t.World.AddFrameEndTask(_ => { t.World.Remove(t); t.Kill(t); })); // Dispose of the evidence (we don't want husks) + foreach (var actor in lunch) + actor.World.AddFrameEndTask(_ => actor.Destroy()); positionable.SetPosition(worm, targetLocation); PlayAttackAnimation(worm); + var attackPosition = worm.CenterPosition; + var affectedPlayers = lunch.Select(x => x.Owner).Distinct(); + foreach (var affectedPlayer in affectedPlayers) + NotifyPlayer(affectedPlayer, attackPosition); + return true; } @@ -68,6 +84,12 @@ namespace OpenRA.Mods.D2k renderUnit.PlayCustomAnim(self, "mouth"); } + void NotifyPlayer(Player player, WPos location) + { + Sound.PlayNotification(player.World.Map.Rules, player, "Speech", swallow.Info.WormAttackNotification, player.Country.Race); + radarPings.Add(() => true, location, Color.Red, 50); + } + public override Activity Tick(Actor self) { if (countdown > 0) @@ -78,17 +100,17 @@ namespace OpenRA.Mods.D2k if (stance == AttackState.ReturningUnderground) // Wait for the worm to get back underground { - if (self.World.SharedRandom.Next()%2 == 0) // There is a 50-50 chance that the worm would just go away + if (self.World.SharedRandom.Next() % 2 == 0) // There is a 50-50 chance that the worm would just go away { - self.CancelActivity(); - self.World.AddFrameEndTask(w => w.Remove(self)); - var wormManager = self.World.WorldActor.TraitOrDefault(); - if (wormManager != null) - wormManager.DecreaseWorms(); + self.CancelActivity(); + self.World.AddFrameEndTask(w => w.Remove(self)); + var wormManager = self.World.WorldActor.TraitOrDefault(); + if (wormManager != null) + wormManager.DecreaseWorms(); } else { - renderUnit.DefaultAnimation.ReplaceAnim("idle"); + renderUnit.DefaultAnimation.ReplaceAnim("idle"); } return NextActivity; } @@ -96,14 +118,17 @@ namespace OpenRA.Mods.D2k if (stance == AttackState.Burrowed) // Wait for the worm to get in position { // This is so that the worm cancels an attack against a target that has reached solid rock - if (positionable == null || !positionable.CanEnterCell(target.Actor.Location, null, false)) + if (!positionable.CanEnterCell(target.Actor.Location, null, false)) return NextActivity; var success = WormAttack(self); if (!success) + { + renderUnit.DefaultAnimation.ReplaceAnim("idle"); return NextActivity; + } - countdown = swallow.AttackSwallowInfo.ReturnTime; + countdown = swallow.Info.ReturnTime; stance = AttackState.ReturningUnderground; } diff --git a/OpenRA.Mods.D2k/WormManager.cs b/OpenRA.Mods.D2k/WormManager.cs index 70cc02d031..867d68e5c8 100644 --- a/OpenRA.Mods.D2k/WormManager.cs +++ b/OpenRA.Mods.D2k/WormManager.cs @@ -9,9 +9,10 @@ #endregion using System; +using System.Collections.Generic; using System.Drawing; using System.Linq; -using OpenRA.Mods.Common; +using OpenRA.Mods.Common.Traits; using OpenRA.Primitives; using OpenRA.Traits; @@ -21,33 +22,34 @@ namespace OpenRA.Mods.D2k class WormManagerInfo : ITraitInfo { [Desc("Minimum number of worms")] - public readonly int Minimum = 1; + public readonly int Minimum = 2; [Desc("Maximum number of worms")] - public readonly int Maximum = 8; + public readonly int Maximum = 4; [Desc("Average time (seconds) between worm spawn")] - public readonly int SpawnInterval = 180; + public readonly int SpawnInterval = 120; public readonly string WormSignNotification = "WormSign"; public readonly string WormSignature = "sandworm"; public readonly string WormOwnerPlayer = "Creeps"; - public object Create (ActorInitializer init) { return new WormManager(this, init.self); } + public object Create(ActorInitializer init) { return new WormManager(this, init.self); } } class WormManager : ITick { int countdown; int wormsPresent; - RadarPings radarPings; readonly WormManagerInfo info; readonly Lazy spawnPoints; + readonly Lazy radarPings; public WormManager(WormManagerInfo info, Actor self) { this.info = info; + radarPings = Exts.Lazy(() => self.World.WorldActor.Trait()); spawnPoints = Exts.Lazy(() => self.World.ActorsWithTrait().Select(x => x.Actor).ToArray()); } @@ -59,31 +61,40 @@ namespace OpenRA.Mods.D2k if (!spawnPoints.Value.Any()) return; - if (--countdown > 0) + // Apparantly someone doesn't want worms or the maximum number of worms has been reached + if (info.Maximum < 1 || wormsPresent >= info.Maximum) + return; + + if (--countdown > 0 && wormsPresent >= info.Minimum) return; countdown = info.SpawnInterval * 25; - if (wormsPresent < info.Maximum) - SpawnWorm(self); + + var wormLocations = new List(); + + wormLocations.Add(SpawnWorm(self)); + while (wormsPresent < info.Minimum) + wormLocations.Add(SpawnWorm(self)); + + AnnounceWormSign(self, wormLocations); } - void SpawnWorm (Actor self) + WPos SpawnWorm(Actor self) { - var spawnPosition = GetRandomSpawnPosition(self); - var spawnLocation = self.World.Map.CellContaining(spawnPosition); + var spawnPoint = GetRandomSpawnPoint(self); self.World.AddFrameEndTask(w => w.CreateActor(info.WormSignature, new TypeDictionary { new OwnerInit(w.Players.First(x => x.PlayerName == info.WormOwnerPlayer)), - new LocationInit(spawnLocation) + new LocationInit(spawnPoint.Location) })); wormsPresent++; - - AnnounceWormSign(self, spawnPosition); + + return spawnPoint.CenterPosition; } - WPos GetRandomSpawnPosition(Actor self) + Actor GetRandomSpawnPoint(Actor self) { - return spawnPoints.Value.Random(self.World.SharedRandom).CenterPosition; + return spawnPoints.Value.Random(self.World.SharedRandom); } public void DecreaseWorms() @@ -91,22 +102,17 @@ namespace OpenRA.Mods.D2k wormsPresent--; } - void AnnounceWormSign(Actor self, WPos wormSpawnPosition) + void AnnounceWormSign(Actor self, IEnumerable wormLocations) { - if (self.World.LocalPlayer == null) + if (self.World.LocalPlayer != null) + Sound.PlayNotification(self.World.Map.Rules, self.World.LocalPlayer, "Speech", info.WormSignNotification, self.World.LocalPlayer.Country.Race); + + if (radarPings.Value == null) return; - - Sound.PlayNotification(self.World.Map.Rules, self.World.LocalPlayer, "Speech", info.WormSignNotification, self.World.LocalPlayer.Country.Race); - if (radarPings == null) - { - if (self.World.WorldActor == null) - return; - - radarPings = self.World.WorldActor.TraitOrDefault(); - } + foreach (var wormLocation in wormLocations) + radarPings.Value.Add(() => true, wormLocation, Color.Red, 50); - radarPings.Add(() => true, wormSpawnPosition, Color.Red, 50); } } diff --git a/OpenRA.Mods.RA/Attack/AttackBase.cs b/OpenRA.Mods.RA/Attack/AttackBase.cs index 4a3f54a24b..89ba53efc7 100644 --- a/OpenRA.Mods.RA/Attack/AttackBase.cs +++ b/OpenRA.Mods.RA/Attack/AttackBase.cs @@ -14,7 +14,6 @@ using System.Drawing; using System.Linq; using OpenRA.GameRules; using OpenRA.Mods.RA.Buildings; -using OpenRA.Mods.RA.Move; using OpenRA.Traits; namespace OpenRA.Mods.RA @@ -39,6 +38,7 @@ namespace OpenRA.Mods.RA public IEnumerable Armaments { get { return GetArmaments(); } } protected Lazy facing; protected Lazy building; + protected Lazy positionable; protected Func> GetArmaments; readonly Actor self; @@ -56,6 +56,7 @@ namespace OpenRA.Mods.RA facing = Exts.Lazy(() => self.TraitOrDefault()); building = Exts.Lazy(() => self.TraitOrDefault()); + positionable = Exts.Lazy(() => self.Trait()); } protected virtual bool CanAttack(Actor self, Target target) @@ -146,8 +147,7 @@ namespace OpenRA.Mods.RA { if (Info.AttackRequiresEnteringCell) { - var positionable = self.TraitOrDefault(); - if (positionable == null || !positionable.CanEnterCell(t.Actor.Location, null, false)) + if (!positionable.Value.CanEnterCell(t.Actor.Location, null, false)) return false; } diff --git a/mods/cnc/rules/civilian.yaml b/mods/cnc/rules/civilian.yaml index f82793b58d..2e07980ef2 100644 --- a/mods/cnc/rules/civilian.yaml +++ b/mods/cnc/rules/civilian.yaml @@ -458,7 +458,7 @@ VICE: MuzzleSplitFacings: 8 AttackFrontal: AttackWander: - WanderMoveRadius: 4 + WanderMoveRadius: 2 RenderUnit: WithMuzzleFlash: SplitFacings: true diff --git a/mods/d2k/maps/death-depths.oramap b/mods/d2k/maps/death-depths.oramap index fd3b9bdfe761fa2dccd4d060b0870da1a35f16d6..4b5832580d31e5cdcb475caba352634392ae9dd0 100644 GIT binary patch delta 688 zcmV;h0#E&wXO(BLJ}?IY00;n)G=q~xFgJhdsEcp5aSdMAefnX$S-P#__OQD&MTDOu zBq7*B1C`Ua4HVIC7=e&W-LK8iYF9)lAtl_8^#JzL?2Bm6zY?;m-L&`uv^)6k-W@C< z7htQQ?pe>i-CNW5#Z8{e+kOCyD7a``N=hWMCJOy*Mp=7Wbp3Qg?gPdhu-sZ4G|!=L3_GF&ckW z<;H! zykc@5+8j^6aW+e0ssgAku-xvvC>xPwgLbE WVhaEO2mk;800000001D9a5E*h7DD*| delta 688 zcmV;h0#E&wXO(BLJ}?IW00;n3uVRx$FgJf1tBY^8alu~KefnX$S-P#__OQD)L4=x?daH>Y<2ILQ1$FYYXnuR7F(ruY~OCVOo3vdN}ycemFQn zF2L<=-4C_tib#ADk+IQwy&_~a4hLh4=-jlobqD90l169m!JSQt8gSsvtjcor;oX0B zHodKXc;!r`)c+Im#*AI%{DhbNUlP-4_OpYP+a924THP1XS~t!+zI*IpGSuCV;08jj zW_Mgc$frg>g7u?U%cz7qu+Z({^#;bl>c;=_YNK0^KTUY~>Y;Nt#x~VcVEhWxP213e z?uK8JrQUl?4;JbQ+}{>1$7ZPGlYtjS_TsegS=^7BO5Iha_2SzO+8X@c&n=UYF&cl> zelT+y=0RLUZSQ*h(0S&g+3Tfxl7vdW#2@Ulgv<$x@o2dEj{F^CXaXj#pZmQ-<#kFBlcm47Z2ZOP&T!Ajj*4`|gS6o#A=s zaiD>UK#P%~0u{JHmZ(586g+qY749ltYC=+lhDP9}CO8#n_Z2eGWW1y3H6cVo-6^30 zPks?S`1jd-34;CoI%71)cZhTTX@%csNx+`)uQH620eimMa8RfKDP^EPi7Y^}{Kepq zZ97(9V0tE&V>5q~?J^k)hWf5v3{CRR>drNj5i>j^GXN9-000O8P_JS|vC>xPwgLbE WVhaEO2mk;8000000001!a5E*DEJ+yv diff --git a/mods/d2k/maps/shellmap/map.yaml b/mods/d2k/maps/shellmap/map.yaml index 686209c4be..0d28aee1ae 100644 --- a/mods/d2k/maps/shellmap/map.yaml +++ b/mods/d2k/maps/shellmap/map.yaml @@ -121,6 +121,8 @@ Rules: -MPStartLocations: ResourceType@Spice: ValuePerUnit: 0 + WormManager: + Minimum: 1 Sequences: diff --git a/mods/ts/rules/infantry.yaml b/mods/ts/rules/infantry.yaml index b70348c923..78422e3035 100644 --- a/mods/ts/rules/infantry.yaml +++ b/mods/ts/rules/infantry.yaml @@ -583,7 +583,7 @@ DOGGIE: Weapon: FiendShard AttackFrontal: AttackWander: - WanderMoveRadius: 4 + WanderMoveRadius: 2 VISSML: Inherits: ^Infantry