diff --git a/OpenRA.Game/GameRules/Footprint.cs b/OpenRA.Game/GameRules/Footprint.cs index 5ac5f528d1..c14bb82bf6 100644 --- a/OpenRA.Game/GameRules/Footprint.cs +++ b/OpenRA.Game/GameRules/Footprint.cs @@ -42,7 +42,7 @@ namespace OpenRA.GameRules return TilesWhere( name, dim, footprint.ToArray(), a => a != '_' ).Select( t => t + topLeft ); } - public static IEnumerable Tiles(Actor a, Traits.Building building) + public static IEnumerable Tiles(Actor a) { return Tiles( a.Info.Name, a.Info.Traits.Get(), a.Location ); } diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index c37aae5b8b..bf8989a28a 100755 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -1,4 +1,4 @@ - + Debug @@ -78,6 +78,7 @@ + diff --git a/OpenRA.Game/Traits/AI/EmitInfantryOnSell.cs b/OpenRA.Game/Traits/AI/EmitInfantryOnSell.cs new file mode 100644 index 0000000000..7bbaa802bb --- /dev/null +++ b/OpenRA.Game/Traits/AI/EmitInfantryOnSell.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRA.GameRules; + +namespace OpenRA.Traits.AI +{ + class EmitInfantryOnSellInfo : StatelessTraitInfo + { + public readonly float ValueFraction = .4f; + public readonly float MinHpFraction = .3f; + public readonly string[] ActorTypes = { "e1" }; // todo: cN as well + } + + class EmitInfantryOnSell : INotifySold, INotifyDamage + { + public void Selling(Actor self) { } + + void Emit(Actor self) + { + var info = self.Info.Traits.Get(); + var csv = self.Info.Traits.GetOrDefault(); + var cost = csv != null ? csv.Value : self.Info.Traits.Get().Cost; + var hp = self.Info.Traits.Get().HP; + var hpFraction = Math.Max(info.MinHpFraction, hp / self.GetMaxHP()); + var dudesValue = (int)(hpFraction * info.ValueFraction * cost); + var eligibleLocations = Footprint.Tiles(self).ToList(); + // todo: fix this for unbuildables in ActorTypes, like civilians. + var actorTypes = info.ActorTypes.Select(a => new { Name = a, Cost = Rules.Info[a].Traits.Get().Cost }).ToArray(); + + while (eligibleLocations.Count > 0 && actorTypes.Any(a => a.Cost <= dudesValue)) + { + var at = actorTypes.Where(a => a.Cost <= dudesValue).Random(self.World.SharedRandom); + var loc = eligibleLocations.Random(self.World.SharedRandom); + + eligibleLocations.Remove(loc); + dudesValue -= at.Cost; + + self.World.AddFrameEndTask(w => w.CreateActor(at.Name, loc, self.Owner)); + } + } + + public void Sold(Actor self) { Emit(self); } + + public void Damaged(Actor self, AttackInfo e) + { + if (e.DamageStateChanged && e.DamageState == DamageState.Dead) + Emit(self); + } + } +} diff --git a/OpenRA.Game/Traits/ProductionSurround.cs b/OpenRA.Game/Traits/ProductionSurround.cs index 51cd2de585..1ea16aa510 100644 --- a/OpenRA.Game/Traits/ProductionSurround.cs +++ b/OpenRA.Game/Traits/ProductionSurround.cs @@ -34,7 +34,7 @@ namespace OpenRA.Traits static int2? FindAdjacentTile(Actor self, bool waterBound) { - var tiles = Footprint.Tiles(self, self.traits.Get()); + var tiles = Footprint.Tiles(self); var min = tiles.Aggregate(int2.Min) - new int2(1, 1); var max = tiles.Aggregate(int2.Max) + new int2(1, 1); diff --git a/mods/ra/defaults.yaml b/mods/ra/defaults.yaml index 913a376d10..c3c7349a68 100644 --- a/mods/ra/defaults.yaml +++ b/mods/ra/defaults.yaml @@ -49,6 +49,7 @@ Dimensions: 1,1 Footprint: x RenderBuilding: + EmitInfantryOnSell: ^Wall: Category: Building diff --git a/mods/ra/structures.yaml b/mods/ra/structures.yaml index b594abb1e8..a1f7b2adc5 100644 --- a/mods/ra/structures.yaml +++ b/mods/ra/structures.yaml @@ -66,6 +66,7 @@ SPEN: ProductionSurround: Produces: Ship IronCurtainable: + -EmitInfantryOnSell: SYRD: InfiltrateForSonarPulse: @@ -92,6 +93,7 @@ SYRD: ProductionSurround: Produces: Ship IronCurtainable: + -EmitInfantryOnSell: IRON: RequiresPower: @@ -743,6 +745,7 @@ SYRF: RenderBuilding: Image: SYRD Fake: + -EmitInfantryOnSell: SPEF: Inherits: ^Building @@ -759,6 +762,7 @@ SPEF: RenderBuilding: Image: SPEN Fake: + -EmitInfantryOnSell: DOMF: Inherits: ^Building