diff --git a/OpenRA.Mods.RA/CrateDrop.cs b/OpenRA.Mods.RA/CrateDrop.cs index 6256caa3e9..e68142456e 100644 --- a/OpenRA.Mods.RA/CrateDrop.cs +++ b/OpenRA.Mods.RA/CrateDrop.cs @@ -18,7 +18,7 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA { - public class CrateDropInfo : TraitInfo + public class CrateDropInfo : ITraitInfo { public readonly int Minimum = 1; // Minumum number of crates public readonly int Maximum = 255; // Maximum number of crates @@ -26,67 +26,80 @@ namespace OpenRA.Mods.RA public readonly string[] ValidWater = {"Water"}; public readonly int SpawnInterval = 180; // Average time (seconds) between crate spawn public readonly float WaterChance = .2f; // Chance of generating a water crate instead of a land crate + + public object Create (ActorInitializer init) { return new CrateDrop(this); } } public class CrateDrop : ITick { List crates = new List(); int ticks = 0; + CrateDropInfo Info; + + public CrateDrop(CrateDropInfo info) { Info = info; } public void Tick(Actor self) { if (--ticks <= 0) { - var info = self.Info.Traits.Get(); - ticks = info.SpawnInterval * 25; // todo: randomize + ticks = Info.SpawnInterval * 25; // todo: randomize crates.RemoveAll(x => !x.IsInWorld); // BUG: this removes crates that are cargo of a BADR! - var toSpawn = Math.Max(0, info.Minimum - crates.Count) - + (crates.Count < info.Maximum ? 1 : 0); + var toSpawn = Math.Max(0, Info.Minimum - crates.Count) + + (crates.Count < Info.Maximum ? 1 : 0); for (var n = 0; n < toSpawn; n++) - SpawnCrate(self, info); + SpawnCrate(self); } } - - void SpawnCrate(Actor self, CrateDropInfo info) + + int2? ChooseDropCell(Actor self, bool inWater, int maxTries) { - var threshold = 100; - var inWater = self.World.SharedRandom.NextDouble() < info.WaterChance; - - for (var n = 0; n < threshold; n++) + for( var n = 0; n < maxTries; n++ ) { var p = self.World.ChooseRandomCell(self.World.SharedRandom); // Is this valid terrain? var terrainType = self.World.GetTerrainType(p); - if (!(inWater ? info.ValidWater : info.ValidGround).Contains(terrainType)) continue; + if (!(inWater ? Info.ValidWater : Info.ValidGround).Contains(terrainType)) continue; // Don't drop on any actors if (self.World.WorldActor.Trait().GetBuildingAt(p) != null) continue; if (self.World.WorldActor.Trait().GetUnitsAt(p).Any()) continue; - self.World.AddFrameEndTask(w => - { - var crate = w.CreateActor(false, "crate", new TypeDictionary { new OwnerInit(w.WorldActor.Owner) }); - crates.Add(crate); - - var startPos = w.ChooseRandomEdgeCell(); - var plane = w.CreateActor("badr", new TypeDictionary - { - new LocationInit( startPos ), - new OwnerInit( w.WorldActor.Owner), - new FacingInit( Util.GetFacing(p - startPos, 0) ), - new AltitudeInit( Rules.Info["badr"].Traits.Get().CruiseAltitude ), - }); - plane.CancelActivity(); - plane.QueueActivity(new FlyAttack(Target.FromCell(p))); - plane.Trait().SetLZ(p); - plane.Trait().Load(plane, crate); - }); - return; + return p; } + + return null; + } + + void SpawnCrate(Actor self) + { + var inWater = self.World.SharedRandom.NextDouble() < Info.WaterChance; + var pp = ChooseDropCell(self, inWater, 100); + if (pp == null) return; + + var p = pp.Value; // + self.World.AddFrameEndTask(w => + { + var crate = w.CreateActor(false, "crate", new TypeDictionary { new OwnerInit(w.WorldActor.Owner) }); + crates.Add(crate); + + var startPos = w.ChooseRandomEdgeCell(); + var plane = w.CreateActor("badr", new TypeDictionary + { + new LocationInit( startPos ), + new OwnerInit( w.WorldActor.Owner), + new FacingInit( Util.GetFacing(p - startPos, 0) ), + new AltitudeInit( Rules.Info["badr"].Traits.Get().CruiseAltitude ), + }); + + plane.CancelActivity(); + plane.QueueActivity(new FlyAttack(Target.FromCell(p))); + plane.Trait().SetLZ(p); + plane.Trait().Load(plane, crate); + }); } } }