public void RenderAfterWorld(WorldRenderer wr, World world) { var position = wr.Position(wr.Viewport.ViewToWorldPx(Viewport.LastMousePos)).ToCPos(); var topLeft = position - FootprintUtils.AdjustForBuildingSize(BuildingInfo); var actorInfo = Rules.Info[Building]; foreach (var dec in actorInfo.Traits.WithInterface <IPlaceBuildingDecoration>()) { dec.Render(wr, world, actorInfo, position.CenterPosition); /* hack hack */ } var cells = new Dictionary <CPos, bool>(); // Linebuild for walls. // Assumes a 1x1 footprint; weird things will happen for other footprints if (Rules.Info[Building].Traits.Contains <LineBuildInfo>()) { foreach (var t in BuildingUtils.GetLineBuildCells(world, topLeft, Building, BuildingInfo)) { cells.Add(t, BuildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, Building, t)); } } else { if (!initialized) { var rbi = Rules.Info[Building].Traits.Get <RenderBuildingInfo>(); var palette = rbi.Palette ?? (Producer.Owner != null ? rbi.PlayerPalette + Producer.Owner.InternalName : null); preview = rbi.RenderPreview(Rules.Info[Building], wr.Palette(palette)); initialized = true; } var offset = topLeft.CenterPosition + FootprintUtils.CenterOffset(BuildingInfo) - WPos.Zero; foreach (var r in preview) { r.OffsetBy(offset).Render(wr); } var res = world.WorldActor.Trait <ResourceLayer>(); var isCloseEnough = BuildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, Building, topLeft); foreach (var t in FootprintUtils.Tiles(Building, BuildingInfo, topLeft)) { cells.Add(t, isCloseEnough && world.IsCellBuildable(t, BuildingInfo) && res.GetResource(t) == null); } } var pal = wr.Palette("terrain"); foreach (var c in cells) { var tile = c.Value ? buildOk : buildBlocked; new SpriteRenderable(tile, c.Key.CenterPosition, WVec.Zero, -511, pal, 1f, true).Render(wr); } }
IEnumerable <IRenderable> IOrderGenerator.RenderAboveShroud(WorldRenderer wr, World world) { var topLeft = TopLeft; var footprint = new Dictionary <CPos, PlaceBuildingCellType>(); var activeVariant = variants[variant]; var actorInfo = activeVariant.ActorInfo; var buildingInfo = activeVariant.BuildingInfo; var plugInfo = activeVariant.PlugInfo; var lineBuildInfo = activeVariant.LineBuildInfo; var preview = activeVariant.Preview; var owner = queue.Actor.Owner; if (plugInfo != null) { if (buildingInfo.Dimensions.X != 1 || buildingInfo.Dimensions.Y != 1) { throw new InvalidOperationException("Plug requires a 1x1 sized Building"); } footprint.Add(topLeft, MakeCellType(AcceptsPlug(topLeft, plugInfo))); } else if (lineBuildInfo != null && owner.Shroud.IsExplored(topLeft)) { // Linebuild for walls. if (buildingInfo.Dimensions.X != 1 || buildingInfo.Dimensions.Y != 1) { throw new InvalidOperationException("LineBuild requires a 1x1 sized Building"); } if (!Game.GetModifierKeys().HasModifier(Modifiers.Shift)) { foreach (var t in BuildingUtils.GetLineBuildCells(world, topLeft, actorInfo, buildingInfo, owner)) { var lineBuildable = world.IsCellBuildable(t.Cell, actorInfo, buildingInfo); var lineCloseEnough = buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, actorInfo, t.Cell); footprint.Add(t.Cell, MakeCellType(lineBuildable && lineCloseEnough, true)); } } var buildable = world.IsCellBuildable(topLeft, actorInfo, buildingInfo); var closeEnough = buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, actorInfo, topLeft); footprint[topLeft] = MakeCellType(buildable && closeEnough); } else { var isCloseEnough = buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, actorInfo, topLeft); foreach (var t in buildingInfo.Tiles(topLeft)) { footprint.Add(t, MakeCellType(isCloseEnough && world.IsCellBuildable(t, actorInfo, buildingInfo) && (resourceLayer == null || resourceLayer.GetResource(t).Type == null))); } } return(preview?.Render(wr, topLeft, footprint) ?? Enumerable.Empty <IRenderable>()); }
public void RenderBeforeWorld(WorldRenderer wr, World world) { var position = Game.viewport.ViewToWorld(Viewport.LastMousePos); var topLeft = position - FootprintUtils.AdjustForBuildingSize(BuildingInfo); var actorInfo = Rules.Info[Building]; foreach (var dec in actorInfo.Traits.WithInterface <IPlaceBuildingDecoration>()) { dec.Render(wr, world, actorInfo, Traits.Util.CenterOfCell(position)); /* hack hack */ } var cells = new Dictionary <CPos, bool>(); // Linebuild for walls. // Assumes a 1x1 footprint; weird things will happen for other footprints if (Rules.Info[Building].Traits.Contains <LineBuildInfo>()) { foreach (var t in BuildingUtils.GetLineBuildCells(world, topLeft, Building, BuildingInfo)) { cells.Add(t, BuildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, Building, t)); } } else { if (!initialized) { var rbi = Rules.Info[Building].Traits.Get <RenderBuildingInfo>(); var palette = rbi.Palette ?? (Producer.Owner != null ? rbi.PlayerPalette + Producer.Owner.InternalName : null); preview = rbi.RenderPreview(Rules.Info[Building], wr.Palette(palette)); initialized = true; } foreach (var r in preview) { r.Sprite.DrawAt(topLeft.ToPPos().ToFloat2() + r.Pos, r.Palette.Index, r.Scale * r.Sprite.size); } var res = world.WorldActor.Trait <ResourceLayer>(); var isCloseEnough = BuildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, Building, topLeft); foreach (var t in FootprintUtils.Tiles(Building, BuildingInfo, topLeft)) { cells.Add(t, isCloseEnough && world.IsCellBuildable(t, BuildingInfo) && res.GetResource(t) == null); } } foreach (var c in cells) { (c.Value ? buildOk : buildBlocked).DrawAt(wr, c.Key.ToPPos().ToFloat2(), "terrain"); } }
protected override IEnumerable <IRenderable> RenderAboveShroud(WorldRenderer wr, World world) { var topLeft = TopLeft; var footprint = new Dictionary <CPos, PlaceBuildingCellType>(); var plugInfo = actorInfo.TraitInfoOrDefault <PlugInfo>(); if (plugInfo != null) { if (buildingInfo.Dimensions.X != 1 || buildingInfo.Dimensions.Y != 1) { throw new InvalidOperationException("Plug requires a 1x1 sized Building"); } footprint.Add(topLeft, MakeCellType(AcceptsPlug(topLeft, plugInfo))); } else if (actorInfo.HasTraitInfo <LineBuildInfo>()) { // Linebuild for walls. if (buildingInfo.Dimensions.X != 1 || buildingInfo.Dimensions.Y != 1) { throw new InvalidOperationException("LineBuild requires a 1x1 sized Building"); } if (!Game.GetModifierKeys().HasModifier(Modifiers.Shift)) { foreach (var t in BuildingUtils.GetLineBuildCells(world, topLeft, actorInfo, buildingInfo)) { var lineBuildable = world.IsCellBuildable(t.First, actorInfo, buildingInfo); var lineCloseEnough = buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, actorInfo, t.First); footprint.Add(t.First, MakeCellType(lineBuildable && lineCloseEnough, true)); } } var buildable = world.IsCellBuildable(topLeft, actorInfo, buildingInfo); var closeEnough = buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, actorInfo, topLeft); footprint[topLeft] = MakeCellType(buildable && closeEnough); } else { var res = world.WorldActor.TraitOrDefault <ResourceLayer>(); var isCloseEnough = buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, actorInfo, topLeft); foreach (var t in buildingInfo.Tiles(topLeft)) { footprint.Add(t, MakeCellType(isCloseEnough && world.IsCellBuildable(t, actorInfo, buildingInfo) && (res == null || res.GetResource(t) == null))); } } return(preview != null?preview.Render(wr, topLeft, footprint) : Enumerable.Empty <IRenderable>()); }
public void RenderBeforeWorld(WorldRenderer wr, World world) { var position = Game.viewport.ViewToWorld(Viewport.LastMousePos).ToInt2(); var topLeft = position - FootprintUtils.AdjustForBuildingSize(BuildingInfo); var actorInfo = Rules.Info[Building]; foreach (var dec in actorInfo.Traits.WithInterface <IPlaceBuildingDecoration>()) { dec.Render(wr, world, actorInfo, Traits.Util.CenterOfCell(position)); /* hack hack */ } var cells = new Dictionary <int2, bool>(); // Linebuild for walls. // Assumes a 1x1 footprint; weird things will happen for other footprints if (Rules.Info[Building].Traits.Contains <LineBuildInfo>()) { foreach (var t in BuildingUtils.GetLineBuildCells(world, topLeft, Building, BuildingInfo)) { cells.Add(t, BuildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, Building, t)); } } else { foreach (var r in Preview) { r.Sprite.DrawAt(Game.CellSize * topLeft + r.Pos, wr.GetPaletteIndex(r.Palette), r.Scale * r.Sprite.size); } var res = world.WorldActor.Trait <ResourceLayer>(); var isCloseEnough = BuildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, Building, topLeft); foreach (var t in FootprintUtils.Tiles(Building, BuildingInfo, topLeft)) { cells.Add(t, isCloseEnough && world.IsCellBuildable(t, BuildingInfo) && res.GetResource(t) == null); } } foreach (var c in cells) { (c.Value ? buildOk : buildBlocked).DrawAt(wr, Game.CellSize * c.Key, "terrain"); } }
public IEnumerable <IRenderable> RenderAboveShroud(WorldRenderer wr, World world) { var xy = wr.Viewport.ViewToWorld(Viewport.LastMousePos); var topLeft = xy - FootprintUtils.AdjustForBuildingSize(buildingInfo); var offset = world.Map.CenterOfCell(topLeft) + FootprintUtils.CenterOffset(world, buildingInfo); var rules = world.Map.Rules; var actorInfo = rules.Actors[building]; foreach (var dec in actorInfo.TraitInfos <IPlaceBuildingDecorationInfo>()) { foreach (var r in dec.Render(wr, world, actorInfo, offset)) { yield return(r); } } var cells = new Dictionary <CPos, bool>(); var plugInfo = rules.Actors[building].TraitInfoOrDefault <PlugInfo>(); if (plugInfo != null) { if (buildingInfo.Dimensions.X != 1 || buildingInfo.Dimensions.Y != 1) { throw new InvalidOperationException("Plug requires a 1x1 sized Building"); } cells.Add(topLeft, AcceptsPlug(topLeft, plugInfo)); } else if (rules.Actors[building].HasTraitInfo <LineBuildInfo>()) { // Linebuild for walls. if (buildingInfo.Dimensions.X != 1 || buildingInfo.Dimensions.Y != 1) { throw new InvalidOperationException("LineBuild requires a 1x1 sized Building"); } if (!Game.GetModifierKeys().HasModifier(Modifiers.Shift)) { foreach (var t in BuildingUtils.GetLineBuildCells(world, topLeft, building, buildingInfo)) { cells.Add(t, buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, building, t)); } } else { cells.Add(topLeft, buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, building, topLeft)); } } else { if (!initialized) { var td = new TypeDictionary() { new FactionInit(faction), new OwnerInit(queue.Actor.Owner), new HideBibPreviewInit() }; var init = new ActorPreviewInitializer(rules.Actors[building], wr, td); preview = rules.Actors[building].TraitInfos <IRenderActorPreviewInfo>() .SelectMany(rpi => rpi.RenderPreview(init)) .ToArray(); initialized = true; } var previewRenderables = preview .SelectMany(p => p.Render(wr, offset)) .OrderBy(WorldRenderer.RenderableScreenZPositionComparisonKey); foreach (var r in previewRenderables) { yield return(r); } var res = world.WorldActor.Trait <ResourceLayer>(); var isCloseEnough = buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, building, topLeft); foreach (var t in FootprintUtils.Tiles(rules, building, buildingInfo, topLeft)) { cells.Add(t, isCloseEnough && world.IsCellBuildable(t, buildingInfo) && res.GetResource(t) == null); } } var pal = wr.Palette(placeBuildingInfo.Palette); var topLeftPos = world.Map.CenterOfCell(topLeft); foreach (var c in cells) { var tile = c.Value ? buildOk : buildBlocked; var pos = world.Map.CenterOfCell(c.Key); yield return(new SpriteRenderable(tile, pos, new WVec(0, 0, topLeftPos.Z - pos.Z), -511, pal, 1f, true)); } }
public IEnumerable <IRenderable> RenderAfterWorld(WorldRenderer wr, World world) { var xy = wr.Viewport.ViewToWorld(Viewport.LastMousePos); var topLeft = xy - FootprintUtils.AdjustForBuildingSize(BuildingInfo); var rules = world.Map.Rules; var actorInfo = rules.Actors[Building]; foreach (var dec in actorInfo.Traits.WithInterface <IPlaceBuildingDecoration>()) { foreach (var r in dec.Render(wr, world, actorInfo, world.Map.CenterOfCell(xy))) { yield return(r); } } var cells = new Dictionary <CPos, bool>(); // Linebuild for walls. // Requires a 1x1 footprint if (rules.Actors[Building].Traits.Contains <LineBuildInfo>()) { if (BuildingInfo.Dimensions.X != 1 || BuildingInfo.Dimensions.Y != 1) { throw new InvalidOperationException("LineBuild requires a 1x1 sized Building"); } foreach (var t in BuildingUtils.GetLineBuildCells(world, topLeft, Building, BuildingInfo)) { cells.Add(t, BuildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, Building, t)); } } else { if (!initialized) { var init = new ActorPreviewInitializer(rules.Actors[Building], Producer.Owner, wr, new TypeDictionary()); preview = rules.Actors[Building].Traits.WithInterface <IRenderActorPreviewInfo>() .SelectMany(rpi => rpi.RenderPreview(init)) .ToArray(); initialized = true; } var comparer = new RenderableComparer(wr); var offset = world.Map.CenterOfCell(topLeft) + FootprintUtils.CenterOffset(world, BuildingInfo); var previewRenderables = preview .SelectMany(p => p.Render(wr, offset)) .OrderBy(r => r, comparer); foreach (var r in previewRenderables) { yield return(r); } var res = world.WorldActor.Trait <ResourceLayer>(); var isCloseEnough = BuildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, Building, topLeft); foreach (var t in FootprintUtils.Tiles(rules, Building, BuildingInfo, topLeft)) { cells.Add(t, isCloseEnough && world.IsCellBuildable(t, BuildingInfo) && res.GetResource(t) == null); } } var pal = wr.Palette("terrain"); foreach (var c in cells) { var tile = c.Value ? buildOk : buildBlocked; yield return(new SpriteRenderable(tile, world.Map.CenterOfCell(c.Key), WVec.Zero, -511, pal, 1f, true)); } }
public void ResolveOrder(Actor self, Order order) { if (order.OrderString == "PlaceBuilding" || order.OrderString == "LineBuild") { self.World.AddFrameEndTask(w => { var prevItems = GetNumBuildables(self.Owner); // Find the queue with the target actor var queue = w.ActorsWithTrait <ProductionQueue>() .Where(p => p.Actor.Owner == self.Owner && p.Trait.CurrentItem() != null && p.Trait.CurrentItem().Item == order.TargetString && p.Trait.CurrentItem().RemainingTime == 0) .Select(p => p.Trait) .FirstOrDefault(); if (queue == null) { return; } var unit = Rules.Info[order.TargetString]; var buildingInfo = unit.Traits.Get <BuildingInfo>(); if (order.OrderString == "LineBuild") { bool playSounds = true; foreach (var t in BuildingUtils.GetLineBuildCells(w, order.TargetLocation, order.TargetString, buildingInfo)) { var building = w.CreateActor(order.TargetString, new TypeDictionary { new LocationInit(t), new OwnerInit(order.Player), }); if (playSounds) { foreach (var s in buildingInfo.BuildSounds) { Sound.PlayToPlayer(order.Player, s, building.CenterPosition); } } playSounds = false; } } else { if (!self.World.CanPlaceBuilding(order.TargetString, buildingInfo, order.TargetLocation, null) || !buildingInfo.IsCloseEnoughToBase(self.World, order.Player, order.TargetString, order.TargetLocation)) { return; } var building = w.CreateActor(order.TargetString, new TypeDictionary { new LocationInit(order.TargetLocation), new OwnerInit(order.Player), }); foreach (var s in buildingInfo.BuildSounds) { Sound.PlayToPlayer(order.Player, s, building.CenterPosition); } } PlayBuildAnim(self, unit); queue.FinishProduction(); if (buildingInfo.RequiresBaseProvider) { // May be null if the build anywhere cheat is active // BuildingInfo.IsCloseEnoughToBase has already verified that this is a valid build location var producer = buildingInfo.FindBaseProvider(w, self.Owner, order.TargetLocation); if (producer != null) { producer.Trait <BaseProvider>().BeginCooldown(); } } if (GetNumBuildables(self.Owner) > prevItems) { w.Add(new DelayedAction(10, () => Sound.PlayNotification(order.Player, "Speech", "NewOptions", order.Player.Country.Race))); } }); } }
public void ResolveOrder(Actor self, Order order) { if (order.OrderString == "PlaceBuilding" || order.OrderString == "LineBuild") { self.World.AddFrameEndTask(w => { var prevItems = GetNumBuildables(self.Owner); // Find the queue with the target actor var queue = w.ActorsWithTrait <ProductionQueue>() .Where(p => p.Actor.Owner == self.Owner && p.Trait.CurrentItem() != null && p.Trait.CurrentItem().Item == order.TargetString && p.Trait.CurrentItem().RemainingTime == 0) .Select(p => p.Trait) .FirstOrDefault(); if (queue == null) { return; } var unit = Rules.Info[order.TargetString]; var buildingInfo = unit.Traits.Get <BuildingInfo>(); if (order.OrderString == "LineBuild") { bool playSounds = true; foreach (var t in BuildingUtils.GetLineBuildCells(w, order.TargetLocation, order.TargetString, buildingInfo)) { var building = w.CreateActor(order.TargetString, new TypeDictionary { new LocationInit(t), new OwnerInit(order.Player), }); if (playSounds) { foreach (var s in buildingInfo.BuildSounds) { Sound.PlayToPlayer(order.Player, s, building.CenterLocation); } } playSounds = false; } } else { if (!self.World.CanPlaceBuilding(order.TargetString, buildingInfo, order.TargetLocation, null)) { return; } var building = w.CreateActor(order.TargetString, new TypeDictionary { new LocationInit(order.TargetLocation), new OwnerInit(order.Player), }); foreach (var s in buildingInfo.BuildSounds) { Sound.PlayToPlayer(order.Player, s, building.CenterLocation); } } PlayBuildAnim(self, unit); queue.FinishProduction(); if (buildingInfo.RequiresBaseProvider) { var center = buildingInfo.CenterLocation(order.TargetLocation); foreach (var bp in w.ActorsWithTrait <BaseProvider>()) { if (bp.Actor.Owner.Stances[self.Owner] != Stance.Ally || !bp.Trait.Ready()) { continue; } if (Combat.IsInRange(center, bp.Trait.Info.Range, bp.Actor.CenterLocation)) { bp.Trait.BeginCooldown(); break; } } } if (GetNumBuildables(self.Owner) > prevItems) { w.Add(new DelayedAction(10, () => Sound.PlayNotification(order.Player, "Speech", "NewOptions", order.Player.Country.Race))); } }); } }
public IEnumerable <IRenderable> RenderAboveShroud(WorldRenderer wr, World world) { var topLeft = viewport.ViewToWorld(Viewport.LastMousePos + topLeftScreenOffset); var centerPosition = world.Map.CenterOfCell(topLeft) + centerOffset; var rules = world.Map.Rules; var actorInfo = rules.Actors[building]; foreach (var dec in actorInfo.TraitInfos <IPlaceBuildingDecorationInfo>()) { foreach (var r in dec.Render(wr, world, actorInfo, centerPosition)) { yield return(r); } } var cells = new Dictionary <CPos, CellType>(); var plugInfo = rules.Actors[building].TraitInfoOrDefault <PlugInfo>(); if (plugInfo != null) { if (buildingInfo.Dimensions.X != 1 || buildingInfo.Dimensions.Y != 1) { throw new InvalidOperationException("Plug requires a 1x1 sized Building"); } cells.Add(topLeft, MakeCellType(AcceptsPlug(topLeft, plugInfo))); } else if (rules.Actors[building].HasTraitInfo <LineBuildInfo>()) { // Linebuild for walls. if (buildingInfo.Dimensions.X != 1 || buildingInfo.Dimensions.Y != 1) { throw new InvalidOperationException("LineBuild requires a 1x1 sized Building"); } if (!Game.GetModifierKeys().HasModifier(Modifiers.Shift)) { foreach (var t in BuildingUtils.GetLineBuildCells(world, topLeft, building, buildingInfo)) { cells.Add(t.First, MakeCellType(buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, building, t.First), true)); } } cells[topLeft] = MakeCellType(buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, building, topLeft)); } else { if (!initialized) { var actor = rules.Actors[building]; var td = new TypeDictionary() { new FactionInit(faction), new OwnerInit(queue.Actor.Owner), }; foreach (var api in actor.TraitInfos <IActorPreviewInitInfo>()) { foreach (var o in api.ActorPreviewInits(actor, ActorPreviewType.PlaceBuilding)) { td.Add(o); } } var init = new ActorPreviewInitializer(actor, wr, td); preview = actor.TraitInfos <IRenderActorPreviewInfo>() .SelectMany(rpi => rpi.RenderPreview(init)) .ToArray(); initialized = true; } var previewRenderables = preview .SelectMany(p => p.Render(wr, centerPosition)) .OrderBy(WorldRenderer.RenderableScreenZPositionComparisonKey); foreach (var r in previewRenderables) { yield return(r); } var res = world.WorldActor.TraitOrDefault <ResourceLayer>(); var isCloseEnough = buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, building, topLeft); foreach (var t in buildingInfo.Tiles(topLeft)) { cells.Add(t, MakeCellType(isCloseEnough && world.IsCellBuildable(t, buildingInfo) && (res == null || res.GetResource(t) == null))); } } var cellPalette = wr.Palette(placeBuildingInfo.Palette); var linePalette = wr.Palette(placeBuildingInfo.LineBuildSegmentPalette); var topLeftPos = world.Map.CenterOfCell(topLeft); foreach (var c in cells) { var tile = !c.Value.HasFlag(CellType.Invalid) ? buildOk : buildBlocked; var pal = c.Value.HasFlag(CellType.LineBuild) ? linePalette : cellPalette; var pos = world.Map.CenterOfCell(c.Key); yield return(new SpriteRenderable(tile, pos, new WVec(0, 0, topLeftPos.Z - pos.Z), -511, pal, 1f, true)); } }
public void ResolveOrder(Actor self, Order order) { if (order.OrderString == "PlaceBuilding" || order.OrderString == "LineBuild") { self.World.AddFrameEndTask(w => { var prevItems = GetNumBuildables(self.Owner); // Find the queue with the target actor var queue = w.ActorsWithTrait <ProductionQueue>() .Where(p => p.Actor.Owner == self.Owner && p.Trait.CurrentItem() != null && p.Trait.CurrentItem().Item == order.TargetString && p.Trait.CurrentItem().RemainingTime == 0) .Select(p => p.Trait) .FirstOrDefault(); if (queue == null) { return; } var unit = Rules.Info[order.TargetString]; var buildingInfo = unit.Traits.Get <BuildingInfo>(); if (order.OrderString == "LineBuild") { bool playSounds = true; foreach (var t in BuildingUtils.GetLineBuildCells(w, order.TargetLocation, order.TargetString, buildingInfo)) { var building = w.CreateActor(order.TargetString, new TypeDictionary { new LocationInit(t), new OwnerInit(order.Player), }); if (playSounds) { foreach (var s in buildingInfo.BuildSounds) { Sound.PlayToPlayer(order.Player, s, building.CenterLocation); } } playSounds = false; } } else { if (!self.World.CanPlaceBuilding(order.TargetString, buildingInfo, order.TargetLocation, null)) { return; } var building = w.CreateActor(order.TargetString, new TypeDictionary { new LocationInit(order.TargetLocation), new OwnerInit(order.Player), }); foreach (var s in buildingInfo.BuildSounds) { Sound.PlayToPlayer(order.Player, s, building.CenterLocation); } } PlayBuildAnim(self, unit); queue.FinishProduction(); if (GetNumBuildables(self.Owner) > prevItems) { w.Add(new DelayedAction(10, () => Sound.PlayToPlayer(order.Player, w.WorldActor.Info.Traits.Get <EvaAlertsInfo>().NewOptions))); } }); } }